[llvm-branch-commits] [clang] [clang-tools-extra] [compiler-rt] [flang] [lldb] [llvm] [mlir] [KeyInstr] Complex assignment atoms (PR #134638)

Orlando Cazalet-Hyams via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri May 23 01:32:00 PDT 2025


=?utf-8?q?Balázs_Kéri?= <balazs.keri at ericsson.com>,Hans Wennborg
 <hans at hanshq.net>,Benjamin Maxwell <benjamin.maxwell at arm.com>,Hans Wennborg
 <hans at chromium.org>,Simon Pilgrim <llvm-dev at redking.me.uk>,Orlando
 Cazalet-Hyams <orlando.hyams at sony.com>,Orlando Cazalet-Hyams
 <orlando.hyams at sony.com>,Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/134638 at github.com>


https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/134638

>From 9a77af37d8719bcfa97e31a730c1a401b91a8e14 Mon Sep 17 00:00:00 2001
From: Simon Pilgrim <llvm-dev at redking.me.uk>
Date: Thu, 22 May 2025 16:51:00 +0100
Subject: [PATCH 001/105] [X86] lowerV4F64Shuffle - prefer BLEND before UNPCK
 shuffle matching (#141073)

Use the same matching order as other 128/256-bit shuffles

Fixes regression identified in #139741
---
 llvm/lib/Target/X86/X86ISelLowering.cpp       |  9 ++--
 .../fp-round-with-concat-vector-undef-elem.ll |  2 +-
 llvm/test/CodeGen/X86/subvector-broadcast.ll  | 49 ++++++++++++++-----
 3 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 7abc854454348..38be3a82af658 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -16444,15 +16444,14 @@ static SDValue lowerV4F64Shuffle(const SDLoc &DL, ArrayRef<int> Mask,
                                                DAG, Subtarget);
   }
 
-  // Use dedicated unpack instructions for masks that match their pattern.
-  if (SDValue V = lowerShuffleWithUNPCK(DL, MVT::v4f64, V1, V2, Mask, DAG))
-    return V;
-
   if (SDValue Blend = lowerShuffleAsBlend(DL, MVT::v4f64, V1, V2, Mask,
                                           Zeroable, Subtarget, DAG))
     return Blend;
 
-  // Check if the blend happens to exactly fit that of SHUFPD.
+  // Use dedicated unpack instructions for masks that match their pattern.
+  if (SDValue V = lowerShuffleWithUNPCK(DL, MVT::v4f64, V1, V2, Mask, DAG))
+    return V;
+
   if (SDValue Op = lowerShuffleWithSHUFPD(DL, MVT::v4f64, V1, V2, Mask,
                                           Zeroable, Subtarget, DAG))
     return Op;
diff --git a/llvm/test/CodeGen/X86/fp-round-with-concat-vector-undef-elem.ll b/llvm/test/CodeGen/X86/fp-round-with-concat-vector-undef-elem.ll
index 45df725d7a78c..0cdc5458e71ca 100644
--- a/llvm/test/CodeGen/X86/fp-round-with-concat-vector-undef-elem.ll
+++ b/llvm/test/CodeGen/X86/fp-round-with-concat-vector-undef-elem.ll
@@ -7,7 +7,7 @@ define void @foo(<2 x float> %0) {
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    vbroadcastsd %xmm0, %ymm0
 ; CHECK-NEXT:    vxorps %xmm1, %xmm1, %xmm1
-; CHECK-NEXT:    vunpcklpd {{.*#+}} ymm0 = ymm1[0],ymm0[0],ymm1[2],ymm0[2]
+; CHECK-NEXT:    vblendps {{.*#+}} ymm0 = ymm1[0,1,2,3,4,5],ymm0[6,7]
 ; CHECK-NEXT:    vcvtps2phx %ymm0, %xmm0
 ; CHECK-NEXT:    vmovlps %xmm0, 0
 ; CHECK-NEXT:    vzeroupper
diff --git a/llvm/test/CodeGen/X86/subvector-broadcast.ll b/llvm/test/CodeGen/X86/subvector-broadcast.ll
index 76183ac5f8fa3..75333bf835f89 100644
--- a/llvm/test/CodeGen/X86/subvector-broadcast.ll
+++ b/llvm/test/CodeGen/X86/subvector-broadcast.ll
@@ -1662,19 +1662,46 @@ define <4 x double> @broadcast_v4f64_v2f64_4u61(ptr %vp, <4 x double> %default)
   ret <4 x double> %res
 }
 
+; TODO: prefer vblend vs vunpckh on AVX1 targets
 define <8 x float> @broadcast_v8f32_v2f32_u1uu0uEu(ptr %vp, <8 x float> %default) {
-; X86-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
-; X86:       # %bb.0:
-; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    vbroadcastsd (%eax), %ymm1
-; X86-NEXT:    vunpckhpd {{.*#+}} ymm0 = ymm1[1],ymm0[1],ymm1[3],ymm0[3]
-; X86-NEXT:    retl
+; X86-AVX1-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X86-AVX1:       # %bb.0:
+; X86-AVX1-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-AVX1-NEXT:    vbroadcastsd (%eax), %ymm1
+; X86-AVX1-NEXT:    vunpckhpd {{.*#+}} ymm0 = ymm1[1],ymm0[1],ymm1[3],ymm0[3]
+; X86-AVX1-NEXT:    retl
 ;
-; X64-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
-; X64:       # %bb.0:
-; X64-NEXT:    vbroadcastsd (%rdi), %ymm1
-; X64-NEXT:    vunpckhpd {{.*#+}} ymm0 = ymm1[1],ymm0[1],ymm1[3],ymm0[3]
-; X64-NEXT:    retq
+; X86-AVX2-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X86-AVX2:       # %bb.0:
+; X86-AVX2-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-AVX2-NEXT:    vbroadcastsd (%eax), %ymm1
+; X86-AVX2-NEXT:    vblendps {{.*#+}} ymm0 = ymm1[0,1,2,3,4,5],ymm0[6,7]
+; X86-AVX2-NEXT:    retl
+;
+; X86-AVX512-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X86-AVX512:       # %bb.0:
+; X86-AVX512-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-AVX512-NEXT:    vbroadcastsd (%eax), %ymm1
+; X86-AVX512-NEXT:    vblendps {{.*#+}} ymm0 = ymm1[0,1,2,3,4,5],ymm0[6,7]
+; X86-AVX512-NEXT:    retl
+;
+; X64-AVX1-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X64-AVX1:       # %bb.0:
+; X64-AVX1-NEXT:    vbroadcastsd (%rdi), %ymm1
+; X64-AVX1-NEXT:    vunpckhpd {{.*#+}} ymm0 = ymm1[1],ymm0[1],ymm1[3],ymm0[3]
+; X64-AVX1-NEXT:    retq
+;
+; X64-AVX2-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X64-AVX2:       # %bb.0:
+; X64-AVX2-NEXT:    vbroadcastsd (%rdi), %ymm1
+; X64-AVX2-NEXT:    vblendps {{.*#+}} ymm0 = ymm1[0,1,2,3,4,5],ymm0[6,7]
+; X64-AVX2-NEXT:    retq
+;
+; X64-AVX512-LABEL: broadcast_v8f32_v2f32_u1uu0uEu:
+; X64-AVX512:       # %bb.0:
+; X64-AVX512-NEXT:    vbroadcastsd (%rdi), %ymm1
+; X64-AVX512-NEXT:    vblendps {{.*#+}} ymm0 = ymm1[0,1,2,3,4,5],ymm0[6,7]
+; X64-AVX512-NEXT:    retq
   %vec = load <2 x float>, ptr %vp
   %shuf = shufflevector <2 x float> %vec, <2 x float> undef, <8 x i32> <i32 undef, i32 1, i32 undef, i32 undef, i32 0, i32 2, i32 3, i32 undef>
   %res = select <8 x i1> <i1 1, i1 1, i1 1, i1 1, i1 1, i1 1, i1 0, i1 1>, <8 x float> %shuf, <8 x float> %default

>From 8416bace86eb4c3778ae415733549ad3d42f032f Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 22 May 2025 08:58:16 -0700
Subject: [PATCH 002/105] [lldb-dap] In DAP unit tests, add helpers for loading
 a CoreFile. (#140738)

This allows us to have a SBTarget and SBProcess for creating unit tests.
---
 lldb/tools/lldb-dap/Protocol/ProtocolBase.h   |   5 +
 lldb/unittests/DAP/CMakeLists.txt             |   8 +
 lldb/unittests/DAP/Handler/DisconnectTest.cpp |  32 +++-
 .../DAP/Inputs/linux-x86_64.core.yaml         |  49 ++++++
 .../DAP/Inputs/linux-x86_64.out.yaml          | 148 ++++++++++++++++++
 lldb/unittests/DAP/TestBase.cpp               |  63 ++++++++
 lldb/unittests/DAP/TestBase.h                 |  22 +++
 .../TestingSupport/TestUtilities.cpp          |   9 ++
 lldb/unittests/TestingSupport/TestUtilities.h |   3 +
 9 files changed, 337 insertions(+), 2 deletions(-)
 create mode 100644 lldb/unittests/DAP/Inputs/linux-x86_64.core.yaml
 create mode 100644 lldb/unittests/DAP/Inputs/linux-x86_64.out.yaml

diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index 1cb9cb13dd0da..724da59b50cd2 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -141,6 +141,11 @@ using Message = std::variant<Request, Response, Event>;
 bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
 llvm::json::Value toJSON(const Message &);
 
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Message &V) {
+  OS << toJSON(V);
+  return OS;
+}
+
 /// On error (whenever `success` is false), the body can provide more details.
 struct ErrorResponseBody {
   /// A structured error message.
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index d9dc4fd454a59..d8576ff3f371b 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -11,8 +11,16 @@ add_lldb_unittest(DAPTests
   VariablesTest.cpp
 
   LINK_LIBS
+    liblldb
     lldbDAP
+    lldbUtilityHelpers
     LLVMTestingSupport
   LINK_COMPONENTS
     Support
   )
+
+set(test_inputs
+  linux-x86_64.out.yaml
+  linux-x86_64.core.yaml
+  )
+add_unittest_inputs(DAPTests "${test_inputs}")
diff --git a/lldb/unittests/DAP/Handler/DisconnectTest.cpp b/lldb/unittests/DAP/Handler/DisconnectTest.cpp
index 6f3470239e974..0546aeb154d50 100644
--- a/lldb/unittests/DAP/Handler/DisconnectTest.cpp
+++ b/lldb/unittests/DAP/Handler/DisconnectTest.cpp
@@ -10,7 +10,10 @@
 #include "Handler/RequestHandler.h"
 #include "Protocol/ProtocolBase.h"
 #include "TestBase.h"
+#include "lldb/API/SBDefines.h"
+#include "lldb/lldb-enumerations.h"
 #include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 #include <memory>
 #include <optional>
@@ -23,7 +26,7 @@ using namespace lldb_dap::protocol;
 
 class DisconnectRequestHandlerTest : public DAPTestBase {};
 
-TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) {
+TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminated) {
   DisconnectRequestHandler handler(*dap);
   EXPECT_FALSE(dap->disconnecting);
   ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded());
@@ -31,5 +34,30 @@ TEST_F(DisconnectRequestHandlerTest, DisconnectingTriggersTerminated) {
   std::vector<Message> messages = DrainOutput();
   EXPECT_THAT(messages,
               testing::Contains(testing::VariantWith<Event>(testing::FieldsAre(
-                  /*event=*/"terminated", /*body=*/std::nullopt))));
+                  /*event=*/"terminated", /*body=*/testing::_))));
+}
+
+TEST_F(DisconnectRequestHandlerTest, DisconnectTriggersTerminateCommands) {
+  CreateDebugger();
+
+  if (!GetDebuggerSupportsTarget("X86"))
+    GTEST_SKIP() << "Unsupported platform";
+
+  LoadCore();
+
+  DisconnectRequestHandler handler(*dap);
+
+  EXPECT_FALSE(dap->disconnecting);
+  dap->configuration.terminateCommands = {"?script print(1)",
+                                          "script print(2)"};
+  EXPECT_EQ(dap->target.GetProcess().GetState(), lldb::eStateStopped);
+  ASSERT_THAT_ERROR(handler.Run(std::nullopt), Succeeded());
+  EXPECT_TRUE(dap->disconnecting);
+  std::vector<Message> messages = DrainOutput();
+  EXPECT_THAT(messages, testing::ElementsAre(
+                            OutputMatcher("Running terminateCommands:\n"),
+                            OutputMatcher("(lldb) script print(2)\n"),
+                            OutputMatcher("2\n"),
+                            testing::VariantWith<Event>(testing::FieldsAre(
+                                /*event=*/"terminated", /*body=*/testing::_))));
 }
diff --git a/lldb/unittests/DAP/Inputs/linux-x86_64.core.yaml b/lldb/unittests/DAP/Inputs/linux-x86_64.core.yaml
new file mode 100644
index 0000000000000..392418f7e82de
--- /dev/null
+++ b/lldb/unittests/DAP/Inputs/linux-x86_64.core.yaml
@@ -0,0 +1,49 @@
+--- !minidump
+Streams:
+  - Type:            SystemInfo
+    Processor Arch:  AMD64
+    Platform ID:     Linux
+  - Type:            ModuleList
+    Modules:
+      - Base of Image:   0x400000
+        Size of Image:   0x1E0
+        Time Date Stamp: 1747851624
+        Module Name:     'linux-x86_64.out'
+        CodeView Record: 4C45704201DF54A6045E657D3F8FFB9CE111878914F8BD6D
+        Reserved0:       0xFFFFFFF800000001
+        Reserved1:       0x2AE15B07FFFFFFF
+      - Base of Image:   0x7FFC24129000
+        Size of Image:   0xA0C
+        Time Date Stamp: 1747851624
+        Module Name:     '[vdso](0x00007ffc24129000)'
+        CodeView Record: 4C4570428CBE1E6C351152C0C43E68C4EF417DB4C77E8EBD
+        Reserved0:       0xFFFFFFF800000001
+        Reserved1:       0x2AE15B07FFFFFFF
+  - Type:            MiscInfo
+    Content:         1800000001000000037E000000000000509F306F01000000
+  - Type:            ThreadList
+    Threads:
+      - Thread Id:       0x7E03
+        Context:         0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700100000000000FFFFFFFF0000FFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E8150B24FC7F0000E8150B24FC7F00000C014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+        Stack:
+          Start of Memory Range: 0x7FFC240B1568
+          Content:         000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006218160B24FC7F000042014000000000000C0140000000000000000000000000000000000000000000000000000000006638160B24FC7F00005F014000000000000000000000000000000000000000005F0000000000000000010000000000000002200B24FC7F00000000000000000000FE2F0B24FC7F00000000000000000000210000000000000000901224FC7F00001000000000000000FFFBEBBF0000000006000000000000000010000000000000110000000000000064000000000000000300000000000000400040000000000004000000000000003800000000000000050000000000000003000000000000000700000000000000000000000000000008000000000000000000000000000000090000000000000044014000000000000B0000000000000000000000000000000C0000000000000000000000000000000D0000000000000000000000000000000E000000000000000000000000000000170000000000000000000000000000001900000000000000A9170B24FC7F00001A0000000000000000000000000000001F00000000000000FC3F0B24FC7F00000F00000000000000B9170B24FC7F000000000000000000000000000000000000000AB340B9514A4C453C3FB52168ADE70E7838365F36340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574005F3D2F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574002F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574000000000000000000
+  - Type:            Exception
+    Thread ID:       0x7E03
+    Exception Record:
+      Exception Code:  0xB
+      Exception Address: 0x40011C
+    Thread Context:  0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700100000000000FFFFFFFF0000FFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E8150B24FC7F0000E8150B24FC7F00000C014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+  - Type:            MemoryList
+    Memory Ranges:
+      - Start of Memory Range: 0x7FFC240B1568
+        Content:         000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006218160B24FC7F000042014000000000000C0140000000000000000000000000000000000000000000000000000000006638160B24FC7F00005F014000000000000000000000000000000000000000005F0000000000000000010000000000000002200B24FC7F00000000000000000000FE2F0B24FC7F00000000000000000000210000000000000000901224FC7F00001000000000000000FFFBEBBF0000000006000000000000000010000000000000110000000000000064000000000000000300000000000000400040000000000004000000000000003800000000000000050000000000000003000000000000000700000000000000000000000000000008000000000000000000000000000000090000000000000044014000000000000B0000000000000000000000000000000C0000000000000000000000000000000D0000000000000000000000000000000E000000000000000000000000000000170000000000000000000000000000001900000000000000A9170B24FC7F00001A0000000000000000000000000000001F00000000000000FC3F0B24FC7F00000F00000000000000B9170B24FC7F000000000000000000000000000000000000000AB340B9514A4C453C3FB52168ADE70E7838365F36340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574005F3D2F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574002F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F746573742F612E6F7574000000000000000000
+      - Start of Memory Range: 0x400000
+        Content:         7F454C4602010100000000000000000002003E000100000044014000000000004000000000000000F0040000000000000000000040003800030040000D000A000100000005000000000000000000000000004000000000000000400000000000E001000000000000E00100000000000000002000000000000400000004000000E800000000000000E800400000000000E80040000000000024000000000000002400000000000000040000000000000051E5746406000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000040000001400000003000000474E550001DF54A6045E657D3F8FFB9CE111878914F8BD6D554889E548897DE8C645FF62488B45E8C6002F5DC3554889E54883EC2048897DE8488975E0C645FF66488B55E8488B45E04889D7FFD0C9C3554889E54883EC10C645FF5FBE0C014000BF00000000E8C2FFFFFFC9C3000000000000001400000000000000017A5200017810011B0C0708900100001C0000001C00000084FFFFFF1500000000410E108602430D06500C07080000001C0000003C00000079FFFFFF2300000000410E108602430D065E0C07080000001C0000005C0000007CFFFFFF1D00000000410E108602430D06580C07080000004743433A20285562756E747520342E382E342D327562756E7475317E31342E30342920342E382E34002C0000000200000000000800000000000C01400000000000550000000000000000000000000000000000000000000000EC00000004000000000008011300000001070000003F0000000C01400000000000550000000000000000000000026261720001010C014000000000001500000000000000019C65000000030E00000001016500000002915804460001036B00000002916F0005086B0000000601065800000007666F6F00010721014000000000002300000000000000019CB8000000030E00000001076500000002915803000000000107C300000002915004460001096B00000002916F0008C30000000965000000000508B80000000A51000000010D44014000000000001D00000000000000019C044600010F6B00000002916F0000011101250E130B030E1B0E1101120710170000022E0103083A0B3B0B271911011207401897421901130000030500030E3A0B3B0B49130218000004340003083A0B3B0B491302180000050F000B0B491300000624000B0B3E0B030E0000072E0103083A0B3B0B271911011207401896421901130000081501271901130000090500491300000A2E013F19030E3A0B3B0B27191101120740189642190000003F00000002001D0000000101FB0E0D000101010100000001000001006D61696E2E6300000000000009020C0140000000000013834B7531F34BC931834BE50202000101626F6F6D6572006D61696E2E6300626F6F6D00474E55204320342E382E34202D6D74756E653D67656E65726963202D6D617263683D7838362D3634202D67002F686F6D652F6C61626174682F74657374005F7374617274006368617200002E73796D746162002E737472746162002E7368737472746162002E6E6F74652E676E752E6275696C642D6964002E74657874002E65685F6672616D65002E636F6D6D656E74002E64656275675F6172616E676573002E64656275675F696E666F002E64656275675F616262726576002E64656275675F6C696E65002E64656275675F737472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B000000070000000200000000000000E800400000000000E80000000000000024000000000000000000000000000000040000000000000000000000000000002E0000000100000006000000000000000C014000000000000C010000000000005500000000000000000000000000000001000000000000000000000000000000340000000100000002000000000000006801400000000000680100000000000078000000000000000000000000000000080000000000000000000000000000003E0000000100000030000000000000000000000000000000E0010000000000002900000000000000000000000000000001000000000000000100000000000000470000000100000000000000000000000000000000000000090200000000000030000000000000000000000000000000010000000000000000000000000000005600000001000000000000000000000000000000000000003902000000000000F00000000000000000000000000000000100000000000000000000000000000062000000010000000000000000000000000000000000000029030000000000009E00000000000000000000000000000001000000000000000000000000000000700000000100000000000000000000000000000000000000C70300000000000043000000000000000000000000000000010000000000000000000000000000007C00000001000000300000000000000000000000000000000A040000000000005D00000000000000000000000000000001000000000000000100000000000000110000000300000000000000000000000000000000000000670400000000000087000000000000000000000000000000010000000000000000000000000000000100000002000000000000000000000000000000000000003008000000000000B0010000000000000C0000000E00000008000000000000001800000000000000090000000300000000000000000000000000000000000000E0090000000000002F000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000100E800400000000000000000000000000000000000030002000C014000000000000000000000000000000000000300030068014000000000000000000000000000000000000300040000000000000000000000000000000000000000000300050000000000000000000000000000000000000000000300060000000000000000000000000000000000000000000300070000000000000000000000000000000000000000000300080000000000000000000000000000000000000000000300090000000000000000000000000000000000010000000400F1FF0000000000000000000000000000000008000000020002000C0140000000000015000000000000000C0000000200020021014000000000002300000000000000000000000400F1FF00000000000000000000000000000000100000001200020044014000000000001D000000000000001700000010000300001060000000000000000000000000002300000010000300001060000000000000000000000000002A0000001000030000106000000000000000000000000000006D61696E2E630062617200666F6F005F7374617274005F5F6273735F7374617274005F6564617461005F656E6400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+      - Start of Memory Range: 0x7FFC24126000
+        Content:         '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+      - Start of Memory Range: 0x7FFC24129000
+        Content:         7F454C4602010100000000000000000003003E000100000060060000000000004000000000000000D80A00000000000000000000400038000400400010000F0001000000050000000000000000000000000000000000000000000000000000000C0A0000000000000C0A00000000000000100000000000000200000004000000A003000000000000A003000000000000A0030000000000001001000000000000100100000000000008000000000000000400000004000000B004000000000000B004000000000000B00400000000000068000000000000006800000000000000040000000000000050E57464040000001805000000000000180500000000000018050000000000003C000000000000003C000000000000000400000000000000030000000C000000060000000500000008000000000000000000000009000000020000000A000000000000000B0000000100000007000000000000000300000004000000000000000300000001000000010000000600000089343805466500A10100000007000000090000007E55DD7100CA1BB0DA109A9E528F3068864B85E60D8E1E8294789E7C19A3436E8A2AC62626B062656D5887FF0000000000000000000000000000000000000000000000002800000022000B007008000000000000AC000000000000000100000012000B00D00700000000000088000000000000003D00000022000B00200900000000000048000000000000003600000012000B00200900000000000048000000000000000800000022000B00D00700000000000088000000000000001500000012000B00600800000000000010000000000000001C00000022000B00600800000000000010000000000000002100000012000B007008000000000000AC00000000000000680000001100F1FF000000000000000000000000000000004A00000012000B00700900000000000025000000000000005100000022000B0070090000000000002500000000000000005F5F7664736F5F67657474696D656F66646179005F5F7664736F5F74696D65005F5F7664736F5F636C6F636B5F67657474696D65005F5F7664736F5F636C6F636B5F676574726573005F5F7664736F5F676574637075006C696E75782D7664736F2E736F2E31004C494E55585F322E36000000020002000200020002000200020002000200020002000000000000000100010001000100A1BFEE0D140000001C00000058000000000000000100000002000100F675AE03140000000000000068000000000000000E0000000000000058000000000000001000000000000000000000000000000004000000000000002001000000000000F5FEFF6F0000000068010000000000000500000000000000D8020000000000000600000000000000B8010000000000000A0000000000000072000000000000000B000000000000001800000000000000FCFFFF6F000000006803000000000000FDFFFF6F000000000200000000000000F0FFFF6F000000004A030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000004000000000000004C696E75780000000D0505000600000017000000000100004C696E7578000000352E352E31332D3230302E666333312E7838365F36340000040000001400000003000000474E55008CBE1E6C351152C0C43E68C4EF417DB4C77E8EBD011B033B3C000000060000004801000058000000B80200009800000048030000D000000058030000E4000000080400001C0100005804000030010000000000001400000000000000017A5200017810011B0C0708900100003C0000001C000000E80000006E01000000410E108602540D06458D038C048305630AC347CC42CD41C60C0708410B025B0AC342CC45CD41C60C0708460B000000340000005C000000180200008800000000410E108602430D06428C0348830402490AC342CC41C60C0708410B520AC342CC41C60C0708410B100000009400000070020000100000000000000034000000A80000006C020000AC00000000410E108602430D06428D03458C04730ACC44CD41C60C0708410B480ACC49CD41C60C0708410B0010000000E0000000E4020000480000000000000010000000F400000020030000250000000000000000000000554863F64989D24989C948C1E6044C8D04374889E54155415453EB02F3908B3740F6C60175F68B470483F801741A83F8020F84BA00000083F80374755BB8FFFFFFFF415C415D5DC30F01F9669048C1E2204809C2498B4028488B4F084885D278DB448B5F184839D1730A4829CA490FAFD34801D08B4F1C4D8B58208B1739F2759D48D3E8483DFFC99A3B761631D2482D00CA9A3B83C201483DFFC99A3B77EF4901D35B415C4D891A415D5D49890131C0C34C8D25E8E8FFFF418B1C2485DB0F8478FFFFFF4C8B2DDDE8FFFF4C8B1DDEE8FFFF0F01F96690418B0C2439CB75D948C1E2204809D049F7E54C01DAE963FFFFFF8B15A9D8FFFF488D1DA2D8FFFF83E2FE4189D3F605B2D8FFFF010F842BFFFFFF0F01F9669048C1E2204809C24889D00FBE1595D8FFFF482B057AD8FFFF4989C489D1F7D949D3EC89D148D3E085D24C89E28B0D70D8FFFF480F49D04889D048F7E1480FACD020488B0D52D8FFFF8B134139D37599488D1408E9E6FEFFFF6690554889E541544989F4534883EC104885FF74384889FB488D55E0488D4DE831F6488D3D89C8FFFFE864FEFFFF85C0752B488B45E04889038B45E84869C0D34D621048C1E82689C04889430831C04D85E4751F4883C4105B415C5DC34889DF4C89E6B8600000000F054883C4105B415C5DC38B1519C9FFFF418914248B1513C9FFFF4189542404EBCA0F1F840000000000488B0539C8FFFF4885FF7403488907C3554889E541554989F541544189FC83FF0F7731B80100000089F9D3E0A9830800007434488D4E084889F289FE488D3DDDC7FFFFE8B8FDFFFF85C07508415C31C0415D5DC34489E74C89EE415CB8E40000000F05415D5DC3A860751BA81074E5488D4E084889F289FE488D3D91C8FFFFE87CFDFFFFEBC24863CF488D1590C7FFFF4883C10248C1E1044801D1EB02F3908B02A80175F8488B3149897500488B7108498975088B3239F07492EBE30F1F400083FF0F7731B80100000089F98B1536C8FFFFD3E0A98308000074134885F6742548C7060000000031C048895608C3A860750CA81075E5B8E50000000F05C3BA40420F00EBD631C0C39090909090909090B87B0000000F03C0904885FF740A89C281E2FF0F000089174885F67405C1E80C890631C0C313FDFFFF57000000720005050306FDFFFF4F0000003B0005030383FDFFFF45000000720005050376FDFFFF3D0000003B00050303A8FDFFFF3300000072000505039BFDFFFF2B0000003B0005030392FFFFFF2100000016020404010FAEE80F310F01F90FAEE80F310F01F90FAEE80F310F01F9F30FC7F84743433A2028474E552920392E322E3120323031393038323720285265642048617420392E322E312D312900002E7368737472746162002E676E752E68617368002E64796E73796D002E64796E737472002E676E752E76657273696F6E002E676E752E76657273696F6E5F64002E64796E616D6963002E6E6F7465002E65685F6672616D655F686472002E65685F6672616D65002E74657874002E616C74696E737472756374696F6E73002E616C74696E7374725F7265706C6163656D656E74002E636F6D6D656E74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F0000000500000002000000000000002001000000000000200100000000000044000000000000000300000000000000080000000000000004000000000000000B000000F6FFFF6F0200000000000000680100000000000068010000000000005000000000000000030000000000000008000000000000000000000000000000150000000B0000000200000000000000B801000000000000B80100000000000020010000000000000400000001000000080000000000000018000000000000001D000000030000000200000000000000D802000000000000D802000000000000720000000000000000000000000000000100000000000000000000000000000025000000FFFFFF6F02000000000000004A030000000000004A03000000000000180000000000000003000000000000000200000000000000020000000000000032000000FDFFFF6F020000000000000068030000000000006803000000000000380000000000000004000000020000000800000000000000000000000000000041000000060000000300000000000000A003000000000000A00300000000000010010000000000000400000000000000080000000000000010000000000000004A000000070000000200000000000000B004000000000000B004000000000000680000000000000000000000000000000400000000000000000000000000000050000000010000000200000000000000180500000000000018050000000000003C000000000000000000000000000000040000000000000000000000000000005E000000010000000200000000000000580500000000000058050000000000000401000000000000000000000000000008000000000000000000000000000000680000000100000006000000000000006006000000000000600600000000000035030000000000000000000000000000100000000000000000000000000000006E000000010000000200000000000000950900000000000095090000000000005B000000000000000000000000000000010000000000000000000000000000007F000000010000000600000000000000F009000000000000F0090000000000001C000000000000000000000000000000010000000000000000000000000000009500000001000000300000000000000000000000000000000C0A0000000000002C00000000000000000000000000000001000000000000000100000000000000010000000300000000000000000000000000000000000000380A0000000000009E000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+      - Start of Memory Range: 0xFFFFFFFFFF600000
+        Content:         48C7C0600000000F05C3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC48C7C0C90000000F05C3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC48C7C0350100000F05C3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
+...
diff --git a/lldb/unittests/DAP/Inputs/linux-x86_64.out.yaml b/lldb/unittests/DAP/Inputs/linux-x86_64.out.yaml
new file mode 100644
index 0000000000000..b374c57693a4b
--- /dev/null
+++ b/lldb/unittests/DAP/Inputs/linux-x86_64.out.yaml
@@ -0,0 +1,148 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_EXEC
+  Machine:         EM_X86_64
+  Entry:           0x400144
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    FirstSec:        .note.gnu.build-id
+    LastSec:         .eh_frame
+    VAddr:           0x400000
+    Align:           0x200000
+    Offset:          0x0
+  - Type:            PT_NOTE
+    Flags:           [ PF_R ]
+    FirstSec:        .note.gnu.build-id
+    LastSec:         .note.gnu.build-id
+    VAddr:           0x4000E8
+    Align:           0x4
+    Offset:          0xE8
+  - Type:            PT_GNU_STACK
+    Flags:           [ PF_W, PF_R ]
+    Align:           0x10
+    Offset:          0x0
+Sections:
+  - Name:            .note.gnu.build-id
+    Type:            SHT_NOTE
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x4000E8
+    AddressAlign:    0x4
+    Notes:
+      - Name:            GNU
+        Desc:            01DF54A6045E657D3F8FFB9CE111878914F8BD6D
+        Type:            NT_PRPSINFO
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x40010C
+    AddressAlign:    0x1
+    Content:         554889E548897DE8C645FF62488B45E8C6002F5DC3554889E54883EC2048897DE8488975E0C645FF66488B55E8488B45E04889D7FFD0C9C3554889E54883EC10C645FF5FBE0C014000BF00000000E8C2FFFFFFC9C3
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x400168
+    AddressAlign:    0x8
+    Content:         1400000000000000017A5200017810011B0C0708900100001C0000001C00000084FFFFFF1500000000410E108602430D06500C07080000001C0000003C00000079FFFFFF2300000000410E108602430D065E0C07080000001C0000005C0000007CFFFFFF1D00000000410E108602430D06580C0708000000
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x1
+    EntSize:         0x1
+    Content:         4743433A20285562756E747520342E382E342D327562756E7475317E31342E30342920342E382E3400
+  - Name:            .debug_info
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         EC00000004000000000008011300000001070000003F0000000C01400000000000550000000000000000000000026261720001010C014000000000001500000000000000019C65000000030E00000001016500000002915804460001036B00000002916F0005086B0000000601065800000007666F6F00010721014000000000002300000000000000019CB8000000030E00000001076500000002915803000000000107C300000002915004460001096B00000002916F0008C30000000965000000000508B80000000A51000000010D44014000000000001D00000000000000019C044600010F6B00000002916F0000
+  - Name:            .debug_abbrev
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         011101250E130B030E1B0E1101120710170000022E0103083A0B3B0B271911011207401897421901130000030500030E3A0B3B0B49130218000004340003083A0B3B0B491302180000050F000B0B491300000624000B0B3E0B030E0000072E0103083A0B3B0B271911011207401896421901130000081501271901130000090500491300000A2E013F19030E3A0B3B0B2719110112074018964219000000
+  - Name:            .debug_line
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         3F00000002001D0000000101FB0E0D000101010100000001000001006D61696E2E6300000000000009020C0140000000000013834B7531F34BC931834BE50202000101
+Symbols:
+  - Name:            .note.gnu.build-id
+    Type:            STT_SECTION
+    Section:         .note.gnu.build-id
+    Value:           0x4000E8
+  - Name:            .text
+    Type:            STT_SECTION
+    Section:         .text
+    Value:           0x40010C
+  - Name:            .eh_frame
+    Type:            STT_SECTION
+    Section:         .eh_frame
+    Value:           0x400168
+  - Name:            .comment
+    Type:            STT_SECTION
+    Section:         .comment
+  - Name:            .debug_aranges
+    Type:            STT_SECTION
+    Section:         .debug_aranges
+  - Name:            .debug_info
+    Type:            STT_SECTION
+    Section:         .debug_info
+  - Name:            .debug_abbrev
+    Type:            STT_SECTION
+    Section:         .debug_abbrev
+  - Name:            .debug_line
+    Type:            STT_SECTION
+    Section:         .debug_line
+  - Name:            .debug_str
+    Type:            STT_SECTION
+    Section:         .debug_str
+  - Name:            main.c
+    Type:            STT_FILE
+    Index:           SHN_ABS
+  - Name:            bar
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x40010C
+    Size:            0x15
+  - Name:            foo
+    Type:            STT_FUNC
+    Section:         .text
+    Value:           0x400121
+    Size:            0x23
+  - Type:            STT_FILE
+    Index:           SHN_ABS
+  - Name:            _start
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x400144
+    Size:            0x1D
+  - Name:            __bss_start
+    Section:         .eh_frame
+    Binding:         STB_GLOBAL
+    Value:           0x601000
+  - Name:            _edata
+    Section:         .eh_frame
+    Binding:         STB_GLOBAL
+    Value:           0x601000
+  - Name:            _end
+    Section:         .eh_frame
+    Binding:         STB_GLOBAL
+    Value:           0x601000
+DWARF:
+  debug_str:
+    - boomer
+    - main.c
+    - boom
+    - 'GNU C 4.8.4 -mtune=generic -march=x86-64 -g'
+    - '/home/labath/test'
+    - _start
+    - char
+  debug_aranges:
+    - Length:          0x2C
+      Version:         2
+      CuOffset:        0x0
+      AddressSize:     0x8
+      Descriptors:
+        - Address:         0x40010C
+          Length:          0x55
+...
diff --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp
index eb146cb2fa9f4..388d1b901507e 100644
--- a/lldb/unittests/DAP/TestBase.cpp
+++ b/lldb/unittests/DAP/TestBase.cpp
@@ -8,9 +8,16 @@
 
 #include "TestBase.h"
 #include "Protocol/ProtocolBase.h"
+#include "TestingSupport/TestUtilities.h"
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBStructuredData.h"
 #include "lldb/Host/File.h"
 #include "lldb/Host/Pipe.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+#include <memory>
 
 using namespace llvm;
 using namespace lldb;
@@ -55,6 +62,62 @@ void DAPTestBase::SetUp() {
       /*transport=*/*to_dap);
 }
 
+void DAPTestBase::TearDown() {
+  if (core)
+    ASSERT_THAT_ERROR(core->discard(), Succeeded());
+  if (binary)
+    ASSERT_THAT_ERROR(binary->discard(), Succeeded());
+}
+
+void DAPTestBase::SetUpTestSuite() {
+  lldb::SBError error = SBDebugger::InitializeWithErrorHandling();
+  EXPECT_TRUE(error.Success());
+}
+void DAPTestBase::TeatUpTestSuite() { SBDebugger::Terminate(); }
+
+bool DAPTestBase::GetDebuggerSupportsTarget(llvm::StringRef platform) {
+  EXPECT_TRUE(dap->debugger);
+
+  lldb::SBStructuredData data = dap->debugger.GetBuildConfiguration()
+                                    .GetValueForKey("targets")
+                                    .GetValueForKey("value");
+  for (size_t i = 0; i < data.GetSize(); i++) {
+    char buf[100] = {0};
+    size_t size = data.GetItemAtIndex(i).GetStringValue(buf, sizeof(buf));
+    if (llvm::StringRef(buf, size) == platform)
+      return true;
+  }
+
+  return false;
+}
+
+void DAPTestBase::CreateDebugger() {
+  dap->debugger = lldb::SBDebugger::Create();
+  ASSERT_TRUE(dap->debugger);
+}
+
+void DAPTestBase::LoadCore() {
+  ASSERT_TRUE(dap->debugger);
+  llvm::Expected<lldb_private::TestFile> binary_yaml =
+      lldb_private::TestFile::fromYamlFile(k_linux_binary);
+  ASSERT_THAT_EXPECTED(binary_yaml, Succeeded());
+  llvm::Expected<llvm::sys::fs::TempFile> binary_file =
+      binary_yaml->writeToTemporaryFile();
+  ASSERT_THAT_EXPECTED(binary_file, Succeeded());
+  binary = std::move(*binary_file);
+  dap->target = dap->debugger.CreateTarget(binary->TmpName.data());
+  ASSERT_TRUE(dap->target);
+  llvm::Expected<lldb_private::TestFile> core_yaml =
+      lldb_private::TestFile::fromYamlFile(k_linux_core);
+  ASSERT_THAT_EXPECTED(core_yaml, Succeeded());
+  llvm::Expected<llvm::sys::fs::TempFile> core_file =
+      core_yaml->writeToTemporaryFile();
+  ASSERT_THAT_EXPECTED(core_file, Succeeded());
+  this->core = std::move(*core_file);
+  SBProcess process = dap->target.LoadCore(this->core->TmpName.data());
+  ASSERT_TRUE(process);
+}
+
 std::vector<Message> DAPTestBase::DrainOutput() {
   std::vector<Message> msgs;
   output.CloseWriteFileDescriptor();
diff --git a/lldb/unittests/DAP/TestBase.h b/lldb/unittests/DAP/TestBase.h
index c789adf53c225..70b3985271a92 100644
--- a/lldb/unittests/DAP/TestBase.h
+++ b/lldb/unittests/DAP/TestBase.h
@@ -10,6 +10,8 @@
 #include "Protocol/ProtocolBase.h"
 #include "Transport.h"
 #include "lldb/Host/Pipe.h"
+#include "llvm/ADT/StringRef.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 namespace lldb_dap_tests {
@@ -33,12 +35,32 @@ class TransportBase : public PipeBase {
   void SetUp() override;
 };
 
+/// Matches an "output" event.
+inline auto OutputMatcher(const llvm::StringRef output,
+                          const llvm::StringRef category = "console") {
+  return testing::VariantWith<lldb_dap::protocol::Event>(testing::FieldsAre(
+      /*event=*/"output", /*body=*/testing::Optional<llvm::json::Value>(
+          llvm::json::Object{{"category", category}, {"output", output}})));
+}
+
 /// A base class for tests that interact with a `lldb_dap::DAP` instance.
 class DAPTestBase : public TransportBase {
 protected:
   std::unique_ptr<lldb_dap::DAP> dap;
+  std::optional<llvm::sys::fs::TempFile> core;
+  std::optional<llvm::sys::fs::TempFile> binary;
+
+  static constexpr llvm::StringLiteral k_linux_binary = "linux-x86_64.out.yaml";
+  static constexpr llvm::StringLiteral k_linux_core = "linux-x86_64.core.yaml";
 
+  static void SetUpTestSuite();
+  static void TeatUpTestSuite();
   void SetUp() override;
+  void TearDown() override;
+
+  bool GetDebuggerSupportsTarget(llvm::StringRef platform);
+  void CreateDebugger();
+  void LoadCore();
 
   /// Closes the DAP output pipe and returns the remaining protocol messages in
   /// the buffer.
diff --git a/lldb/unittests/TestingSupport/TestUtilities.cpp b/lldb/unittests/TestingSupport/TestUtilities.cpp
index efdc6c5eb234a..b53822e38324b 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.cpp
+++ b/lldb/unittests/TestingSupport/TestUtilities.cpp
@@ -47,3 +47,12 @@ llvm::Expected<TestFile> TestFile::fromYamlFile(const llvm::Twine &Name) {
     return llvm::errorCodeToError(BufferOrError.getError());
   return fromYaml(BufferOrError.get()->getBuffer());
 }
+
+llvm::Expected<llvm::sys::fs::TempFile> TestFile::writeToTemporaryFile() {
+  llvm::Expected<llvm::sys::fs::TempFile> Temp =
+      llvm::sys::fs::TempFile::create("temp%%%%%%%%%%%%%%%%");
+  if (!Temp)
+    return Temp.takeError();
+  llvm::raw_fd_ostream(Temp->FD, /*shouldClose=*/false) << Buffer;
+  return std::move(*Temp);
+}
diff --git a/lldb/unittests/TestingSupport/TestUtilities.h b/lldb/unittests/TestingSupport/TestUtilities.h
index 7d040d64db8d8..65994384059fb 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.h
+++ b/lldb/unittests/TestingSupport/TestUtilities.h
@@ -14,6 +14,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FileUtilities.h"
 #include <string>
 
@@ -45,6 +46,8 @@ class TestFile {
     return ModuleSpec(FileSpec(), UUID(), dataBuffer());
   }
 
+  llvm::Expected<llvm::sys::fs::TempFile> writeToTemporaryFile();
+
 private:
   TestFile(std::string &&Buffer) : Buffer(std::move(Buffer)) {}
 

>From 498121e00454fc306f345b7854cf96cb7282374b Mon Sep 17 00:00:00 2001
From: Luke Hutton <luke.hutton at arm.com>
Date: Thu, 22 May 2025 17:01:19 +0100
Subject: [PATCH 003/105] [mlir][tosa] Allow unranked indices argument for
 gather/scatter (#140618)

This commit allows the indices argument for gather and scatter to be
unranked. This can be computed during shape inference.
---
 mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td       |  4 ++--
 mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td |  2 ++
 mlir/test/Dialect/Tosa/ops.mlir                    | 14 ++++++++++++++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
index 86f9ab94ec152..f93dd901535c3 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaOps.td
@@ -2125,7 +2125,7 @@ def Tosa_GatherOp : Tosa_InferShapedTypeOp<"gather"> {
 
   let arguments = (ins
     Tosa_Tensor3D:$values,
-    TosaTensorRankOf<[Tosa_Int32], [2]>:$indices
+    Tosa_Int32Tensor2D:$indices
   );
 
   let results = (outs
@@ -2159,7 +2159,7 @@ def Tosa_ScatterOp : Tosa_InferShapedTypeOp<"scatter"> {
 
   let arguments = (ins
     Tosa_Tensor3D:$values_in,
-    TosaTensorRankOf<[Tosa_Int32], [2]>:$indices,
+    Tosa_Int32Tensor2D:$indices,
     Tosa_Tensor3D:$input
   );
 
diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
index b9ac1ff705514..536551c8f8437 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaTypesBase.td
@@ -181,6 +181,8 @@ def Tosa_TensorUpto4D : AnyTypeOf<[
 
 def Tosa_Int32TensorUpto4D : AnyTypeOf<[
   Tosa_UnrankedTensor, TosaTensorRankOf<[Tosa_Int32], [0,1,2,3,4]>]>;
+def Tosa_Int32Tensor2D : AnyTypeOf<[
+  Tosa_UnrankedTensor, TosaTensorRankOf<[Tosa_Int32], [2]>]>;
 
 def Tosa_TensorAtLeast1D : AnyTypeOf<[
   Tosa_UnrankedTensor, TosaRankedTensorOf<[Tosa_AnyNumber], [AtLeastRankOne]>], "tosa-conformant tensor of at least rank 1", "::mlir::TensorType">;
diff --git a/mlir/test/Dialect/Tosa/ops.mlir b/mlir/test/Dialect/Tosa/ops.mlir
index 7aea1c06698e8..5ec506a45b3ad 100644
--- a/mlir/test/Dialect/Tosa/ops.mlir
+++ b/mlir/test/Dialect/Tosa/ops.mlir
@@ -719,6 +719,20 @@ func.func @test_scatter(%arg0: tensor<13x21x3xf32>, %arg1: tensor<13x26xi32>, %a
   return %0 : tensor<13x21x3xf32>
 }
 
+// -----
+// CHECK-LABEL: gather_unranked_indices
+func.func @test_gather_unranked_indices(%arg0: tensor<13x21x3xf32>, %arg1: tensor<*xi32>) -> tensor<13x26x3xf32> {
+  %0 = tosa.gather %arg0, %arg1 : (tensor<13x21x3xf32>, tensor<*xi32>) -> tensor<13x26x3xf32>
+  return %0 : tensor<13x26x3xf32>
+}
+
+// -----
+// CHECK-LABEL: scatter_unranked_indices
+func.func @test_scatter_unranked_indices(%arg0: tensor<13x21x3xf32>, %arg1: tensor<*xi32>, %arg2: tensor<13x26x3xf32>) -> tensor<13x21x3xf32> {
+  %0 = tosa.scatter %arg0, %arg1, %arg2 : (tensor<13x21x3xf32>, tensor<*xi32>, tensor<13x26x3xf32>) -> tensor<13x21x3xf32>
+  return %0 : tensor<13x21x3xf32>
+}
+
 // -----
 // CHECK-LABEL: resize
 func.func @test_resize(%arg0: tensor<1x32x32x8xf32>) -> tensor<1x64x64x8xf32> {

>From ed75e2114fd486efc09e35d16e709054a9511eba Mon Sep 17 00:00:00 2001
From: Tim Gymnich <tim at gymni.ch>
Date: Thu, 22 May 2025 18:02:11 +0200
Subject: [PATCH 004/105] Fix build for GenericFloatingPointPredicateUtils
 #140254 (#141095)

Fixes linker issue with #140254  / #140254
---
 .../{ => GlobalISel}/MachineFloatingPointPredicateUtils.h       | 0
 llvm/lib/CodeGen/CMakeLists.txt                                 | 1 -
 llvm/lib/CodeGen/GlobalISel/CMakeLists.txt                      | 1 +
 .../{ => GlobalISel}/MachineFloatingPointPredicateUtils.cpp     | 2 +-
 4 files changed, 2 insertions(+), 2 deletions(-)
 rename llvm/include/llvm/CodeGen/{ => GlobalISel}/MachineFloatingPointPredicateUtils.h (100%)
 rename llvm/lib/CodeGen/{ => GlobalISel}/MachineFloatingPointPredicateUtils.cpp (95%)

diff --git a/llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.h
similarity index 100%
rename from llvm/include/llvm/CodeGen/MachineFloatingPointPredicateUtils.h
rename to llvm/include/llvm/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.h
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index dcf7c08d499e1..5dd6413431255 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -119,7 +119,6 @@ add_llvm_component_library(LLVMCodeGen
   MachineCycleAnalysis.cpp
   MachineDebugify.cpp
   MachineDomTreeUpdater.cpp
-  MachineFloatingPointPredicateUtils.cpp
   MachineDominanceFrontier.cpp
   MachineDominators.cpp
   MachineFrameInfo.cpp
diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt
index 554a2367eb835..27b6ea745921a 100644
--- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt
+++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt
@@ -25,6 +25,7 @@ add_llvm_component_library(LLVMGlobalISel
   LoadStoreOpt.cpp
   Localizer.cpp
   LostDebugLocObserver.cpp
+  MachineFloatingPointPredicateUtils.cpp
   MachineIRBuilder.cpp
   RegBankSelect.cpp
   Utils.cpp
diff --git a/llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp b/llvm/lib/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.cpp
similarity index 95%
rename from llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp
rename to llvm/lib/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.cpp
index 3f640ded22c55..8c3035ad91e87 100644
--- a/llvm/lib/CodeGen/MachineFloatingPointPredicateUtils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/CodeGen/MachineFloatingPointPredicateUtils.h"
+#include "llvm/CodeGen/GlobalISel/MachineFloatingPointPredicateUtils.h"
 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
 #include "llvm/CodeGen/LowLevelTypeUtils.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"

>From 758fea0e995e6128022e5cd2605a92222e130837 Mon Sep 17 00:00:00 2001
From: QiYue <yangzhh at mail.ustc.edu.cn>
Date: Fri, 23 May 2025 00:06:01 +0800
Subject: [PATCH 005/105] [InferAddressSpaces] Handle llvm.lifetime (#141045)

Co-authored-by: Zhenhao Yang <zhenhao.yang at nio.com>
Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 .../Transforms/Scalar/InferAddressSpaces.cpp  | 14 ++++++++++
 .../InferAddressSpaces/AMDGPU/lifetime.ll     | 22 +++++++++++++++
 .../InferAddressSpaces/NVPTX/lifetime.ll      | 27 +++++++++++++++++++
 3 files changed, 63 insertions(+)
 create mode 100644 llvm/test/Transforms/InferAddressSpaces/AMDGPU/lifetime.ll
 create mode 100644 llvm/test/Transforms/InferAddressSpaces/NVPTX/lifetime.ll

diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index 1b7cecc7ceb6a..66836ef05d5db 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -428,6 +428,14 @@ bool InferAddressSpacesImpl::rewriteIntrinsicOperands(IntrinsicInst *II,
     II->replaceUsesOfWith(OldV, NewV);
     return true;
   }
+  case Intrinsic::lifetime_start:
+  case Intrinsic::lifetime_end: {
+    Function *NewDecl = Intrinsic::getOrInsertDeclaration(
+        M, II->getIntrinsicID(), {NewV->getType()});
+    II->setArgOperand(1, NewV);
+    II->setCalledFunction(NewDecl);
+    return true;
+  }
   default: {
     Value *Rewrite = TTI->rewriteIntrinsicWithAddressSpace(II, OldV, NewV);
     if (!Rewrite)
@@ -479,6 +487,12 @@ void InferAddressSpacesImpl::collectRewritableIntrinsicOperands(
 
     break;
   }
+  case Intrinsic::lifetime_start:
+  case Intrinsic::lifetime_end: {
+    appendsFlatAddressExpressionToPostorderStack(II->getArgOperand(1),
+                                                 PostorderStack, Visited);
+    break;
+  }
   default:
     SmallVector<int, 2> OpIndexes;
     if (TTI->collectFlatAddressOperands(OpIndexes, IID)) {
diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/lifetime.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/lifetime.ll
new file mode 100644
index 0000000000000..d39a0b35ce811
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/lifetime.ll
@@ -0,0 +1,22 @@
+; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes=infer-address-spaces %s | FileCheck %s
+
+define i32 @lifetime_flat_pointer() {
+; CHECK-LABEL: define i32 @lifetime_flat_pointer() {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i32, align 4, addrspace(5)
+; CHECK-NEXT:    call void @llvm.lifetime.start.p5(i64 4, ptr addrspace(5) [[ALLOCA]])
+; CHECK-NEXT:    store i32 1, ptr addrspace(5) [[ALLOCA]], align 4
+; CHECK-NEXT:    %ret = load i32, ptr addrspace(5) [[ALLOCA]], align 4
+; CHECK-NEXT:    call void @llvm.lifetime.end.p5(i64 4, ptr addrspace(5) [[ALLOCA]])
+; CHECK-NEXT:    ret i32 %ret
+;
+  %alloca = alloca i32, align 4, addrspace(5)
+  %flat = addrspacecast ptr addrspace(5) %alloca to ptr
+  call void @llvm.lifetime.start.p0(i64 4 , ptr %flat)
+  store i32 1, ptr %flat, align 4
+  %ret = load i32, ptr %flat, align 4
+  call void @llvm.lifetime.end.p0(i64 4 , ptr %flat)
+  ret i32 %ret
+}
+
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
diff --git a/llvm/test/Transforms/InferAddressSpaces/NVPTX/lifetime.ll b/llvm/test/Transforms/InferAddressSpaces/NVPTX/lifetime.ll
new file mode 100644
index 0000000000000..8bf63127ba636
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/NVPTX/lifetime.ll
@@ -0,0 +1,27 @@
+; RUN: opt -S -passes=infer-address-spaces %s | FileCheck %s
+
+target triple = "nvptx64-nvidia-cuda"
+
+define i32 @lifetime_flat_pointer() {
+; CHECK-LABEL: define i32 @lifetime_flat_pointer() {
+; CHECK-NEXT:    [[ALLOCA:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = addrspacecast ptr [[ALLOCA]] to ptr addrspace(5)
+; CHECK-NEXT:    call void @llvm.lifetime.start.p5(i64 4, ptr addrspace(5) [[TMP1]])
+; CHECK-NEXT:    store i32 1, ptr addrspace(5) [[TMP1]], align 4
+; CHECK-NEXT:    %ret = load i32, ptr addrspace(5) [[TMP1]], align 4
+; CHECK-NEXT:    call void @llvm.lifetime.end.p5(i64 4, ptr addrspace(5) [[TMP1]])
+; CHECK-NEXT:    ret i32 %ret
+;
+  %alloca = alloca i32, align 4
+  %1 = addrspacecast ptr %alloca to ptr addrspace(5)
+  %2 = addrspacecast ptr addrspace(5) %1 to ptr
+  %3 = addrspacecast ptr addrspace(5) %1 to ptr
+  call void @llvm.lifetime.start.p0(i64 4, ptr %2)
+  store i32 1, ptr addrspace(5) %1, align 4
+  %ret = load i32, ptr addrspace(5) %1, align 4
+  call void @llvm.lifetime.end.p0(i64 4, ptr %3)
+  ret i32 %ret
+}
+
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)

>From 4e9c3ce39189fc68f83be03f85a6a504de537049 Mon Sep 17 00:00:00 2001
From: Luke Hutton <luke.hutton at arm.com>
Date: Thu, 22 May 2025 17:06:32 +0100
Subject: [PATCH 006/105] [mlir][tosa] Improve invalid operator data types
 error message (#140756)

The error message on invalid operator data types in the validation pass
was not very clear. This commit improves the error message as follows:

Current:
```
'tosa.add' op illegal: operand/result data types not supported
```

Improved:
```
'tosa.add' op illegal: operation operand/result data types did not align with any profile or extension, got (i1,i1,i1), did you mean (i32,i32,i32)? Otherwise, please refer to the 'supported data types' for 'tosa.add' in the specification.
```
---
 .../Dialect/Tosa/IR/TosaProfileCompliance.h   |  2 +
 .../Tosa/Transforms/TosaProfileCompliance.cpp | 63 ++++++++++++++++++-
 .../Tosa/Transforms/TosaValidation.cpp        |  4 +-
 mlir/test/Dialect/Tosa/invalid.mlir           |  6 +-
 4 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h b/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
index 716e55706c625..8f5c72bc5f7a9 100644
--- a/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
+++ b/mlir/include/mlir/Dialect/Tosa/IR/TosaProfileCompliance.h
@@ -164,6 +164,8 @@ class TosaProfileCompliance {
   SmallVector<StringRef>
   stringifyProfile(const SmallVector<ArrayRef<T>> &profileSet);
 
+  static llvm::SmallString<7> stringifyTypeInfo(const TypeInfo &typeInfo);
+
 private:
   template <typename T>
   FailureOr<SmallVector<T>> getOperatorDefinition(Operation *op,
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
index 66ea00b23b9d4..1a896c1464e1c 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaProfileCompliance.cpp
@@ -485,9 +485,52 @@ LogicalResult TosaProfileCompliance::checkInvalid(Operation *op) {
   CheckCondition condition = CheckCondition::invalid;
   const auto maybeProfDef = getOperatorDefinition<Profile>(op, condition);
   const auto maybeExtDef = getOperatorDefinition<Extension>(op, condition);
+
   if (!failed(maybeProfDef) && !failed(maybeExtDef) &&
-      !maybeProfDef.value().size() && !maybeExtDef.value().size())
+      !maybeProfDef.value().size() && !maybeExtDef.value().size()) {
+    std::string message;
+    llvm::raw_string_ostream os(message);
+    os << "illegal: operation operand/result data types did not align with any "
+          "profile or extension, got (";
+
+    ProfileInfoDepot depot(op);
+    SmallVector<TypeInfo> current = depot.getInfo();
+    for (const auto &typeInfo : llvm::drop_end(current))
+      os << stringifyTypeInfo(typeInfo) << ",";
+    os << stringifyTypeInfo(current.back()) << ")";
+
+    // avoid polluting the error message output by outputting only
+    // the best match
+    const std::string opName = op->getName().getStringRef().str();
+    int maxMatches = -1;
+    SmallVector<TypeInfo> bestTypeInfo;
+    const auto searchBestMatch = [&](auto map) {
+      for (const auto &complianceInfos : map[opName]) {
+        for (const auto &typeInfos : complianceInfos.operandTypeInfoSet) {
+          const int matches = llvm::count_if(
+              llvm::zip_equal(current, typeInfos), [&](const auto zipType) {
+                return isSameTypeInfo(std::get<0>(zipType),
+                                      std::get<1>(zipType));
+              });
+          if (matches > maxMatches) {
+            maxMatches = matches;
+            bestTypeInfo = typeInfos;
+          }
+        }
+      }
+    };
+    searchBestMatch(getProfileComplianceMap<Profile>());
+    searchBestMatch(getProfileComplianceMap<Extension>());
+
+    os << ", did you mean (";
+    for (const auto &typeInfo : llvm::drop_end(bestTypeInfo))
+      os << stringifyTypeInfo(typeInfo) << ",";
+    os << stringifyTypeInfo(bestTypeInfo.back()) << ")? ";
+    os << "Otherwise, please refer to the 'supported data types' for '"
+       << opName << "' in the specification.";
+    op->emitOpError(message);
     return failure();
+  }
 
   return success();
 }
@@ -562,3 +605,21 @@ SmallVector<StringRef> TosaProfileCompliance::stringifyProfile(
 
   return debugStrings;
 }
+
+llvm::SmallString<7>
+TosaProfileCompliance::stringifyTypeInfo(const TypeInfo &typeInfo) {
+  if (typeInfo.typeID == mlir::IntegerType::getTypeID()) {
+    return {"i" + llvm::utostr(typeInfo.bitWidth)};
+  } else if (typeInfo.typeID == mlir::Float16Type::getTypeID()) {
+    return {"f16"};
+  } else if (typeInfo.typeID == mlir::Float32Type::getTypeID()) {
+    return {"f32"};
+  } else if (typeInfo.typeID == mlir::BFloat16Type::getTypeID()) {
+    return {"bf16"};
+  } else if (typeInfo.typeID == mlir::Float8E4M3FNType::getTypeID()) {
+    return {"fp8e4m3"};
+  } else if (typeInfo.typeID == mlir::Float8E5M2Type::getTypeID()) {
+    return {"fp8e5m2"};
+  }
+  llvm_unreachable("unknown type");
+}
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index feedc5057bea0..e6d8e7834bf2c 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -1248,10 +1248,8 @@ void TosaValidation::runOnOperation() {
       return signalPassFailure();
 
     if (!allowInvalidOpDatatypeCombinations &&
-        failed(profileComp.checkInvalid(op))) {
-      op->emitOpError("illegal: operand/result data types not supported");
+        failed(profileComp.checkInvalid(op)))
       return signalPassFailure();
-    }
 
     // Some uses of TOSA rely on the constant operands of particular
     // operations.
diff --git a/mlir/test/Dialect/Tosa/invalid.mlir b/mlir/test/Dialect/Tosa/invalid.mlir
index 732c980f3ab92..7b589fa839b44 100644
--- a/mlir/test/Dialect/Tosa/invalid.mlir
+++ b/mlir/test/Dialect/Tosa/invalid.mlir
@@ -35,7 +35,7 @@ func.func @test_conv2d(%arg0: tensor<*xf32>, %arg1: tensor<16x3x3x4xi8>, %arg2:
 
 func.func @test_conv2d(%arg0: tensor<1x29x29x4xi8>, %arg1: tensor<*xi8>, %arg2: tensor<16xi8>) -> tensor<1x27x27x16xi8> {
   %zp = "tosa.const"() {values = dense<0> : tensor<1xi8>} : () -> tensor<1xi8>
-  // expected-error at +1 {{'tosa.conv2d' op illegal: operand/result data types not supported}}
+  // expected-error at +1 {{'tosa.conv2d' op illegal: operation operand/result data types did not align with any profile or extension, got (i8,i8,i8,i8,i8,i32,i8), did you mean (i8,i8,i32,i8,i8,i32,i32)?}}
   %0 = tosa.conv2d %arg0, %arg1, %arg2, %zp, %zp {acc_type = i32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>}
            : (tensor<1x29x29x4xi8>, tensor<*xi8>, tensor<16xi8>, tensor<1xi8>, tensor<1xi8>) -> tensor<1x27x27x16xi8>
   return %0 : tensor<1x27x27x16xi8>
@@ -1888,7 +1888,7 @@ func.func @test_scalar_tile(%arg0: tensor<f32>) -> tensor<*xf32> {
 
 // CHECK-LABEL: test_add_i1
 func.func @test_add_i1(%arg0: tensor<13x21x1xi1>, %arg1: tensor<13x21x3xi1>) -> tensor<13x21x3xi1> {
-  // expected-error at +1 {{'tosa.add' op illegal: operand/result data types not supported}}
+  // expected-error at +1 {{'tosa.add' op illegal: operation operand/result data types did not align with any profile or extension, got (i1,i1,i1), did you mean (i32,i32,i32)? Otherwise, please refer to the 'supported data types' for 'tosa.add' in the specification.}}
   %0 = tosa.add %arg0, %arg1 : (tensor<13x21x1xi1>, tensor<13x21x3xi1>) -> tensor<13x21x3xi1>
   return %0 : tensor<13x21x3xi1>
 }
@@ -1897,7 +1897,7 @@ func.func @test_add_i1(%arg0: tensor<13x21x1xi1>, %arg1: tensor<13x21x3xi1>) ->
 
 // CHECK-LABEL: test_mul_out_i16
 func.func @test_mul_out_i16(%arg0: tensor<13x21x3xi8>, %arg1: tensor<13x1x3xi8>, %shift: tensor<1xi8>) -> tensor<13x21x3xi16> {
-  // expected-error at +1 {{'tosa.mul' op illegal: operand/result data types not supported}}
+  // expected-error at +1 {{'tosa.mul' op illegal: operation operand/result data types did not align with any profile or extension, got (i8,i8,i16), did you mean (i8,i8,i32)?}}
   %0 = tosa.mul %arg0, %arg1, %shift : (tensor<13x21x3xi8>, tensor<13x1x3xi8>, tensor<1xi8>) -> tensor<13x21x3xi16>
   return %0 : tensor<13x21x3xi16>
 }

>From fbf7878a469df18cf95fb6c27ddeda9a0b00e805 Mon Sep 17 00:00:00 2001
From: Luke Hutton <luke.hutton at arm.com>
Date: Thu, 22 May 2025 17:07:10 +0100
Subject: [PATCH 007/105] [mlir][tosa] Fix level check on unranked input tensor
 (#140795)

This commit fixes a segfault that occurred on operators with unranked
input tensors. Operator specific level checks performed before the rank
check incorrectly assumed all inputs were shaped.
---
 .../Tosa/Transforms/TosaValidation.cpp        |   8 +-
 mlir/test/Dialect/Tosa/level_check.mlir       | 166 +++++++++---------
 2 files changed, 91 insertions(+), 83 deletions(-)

diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index e6d8e7834bf2c..9227b0f8fd5b9 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -758,6 +758,10 @@ LogicalResult TosaValidation::applyLevelCheck(Operation *op) {
     return success();
   }
 
+  // check rank and sizes early so later checks can assume shaped operands
+  if (!levelCheckRanksAndSizes(op))
+    return failure();
+
   // additional level checks from spec 0.70
   if (!levelCheckPool<tosa::AvgPool2dOp>(op) ||
       !levelCheckConv<tosa::Conv2DOp>(op) ||
@@ -770,10 +774,6 @@ LogicalResult TosaValidation::applyLevelCheck(Operation *op) {
     return failure();
   }
 
-  if (!levelCheckRanksAndSizes(op)) {
-    return failure();
-  }
-
   // level check MAX_TENSOR_LIST_SIZE
   if (!levelCheckListSize(op)) {
     return failure();
diff --git a/mlir/test/Dialect/Tosa/level_check.mlir b/mlir/test/Dialect/Tosa/level_check.mlir
index d24c1fa57883d..e7d0a0e1fa4ea 100644
--- a/mlir/test/Dialect/Tosa/level_check.mlir
+++ b/mlir/test/Dialect/Tosa/level_check.mlir
@@ -547,20 +547,20 @@ func.func @test_avgpool2d_stride_x(%arg0: tensor<1x32x8194x8xf32>, %arg1: tensor
 
 // -----
 
-func.func @test_conv2d_dilation_y(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv2d_dilation_y(%arg0: tensor<1x8192x8192x1xf32>, %arg1: tensor<16x1025x1024x1xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<1x1x7170x16xf32> {
   // expected-error at +1 {{'tosa.conv2d' op failed level check: dilation_y * KH <= MAX_KERNEL}}
-  %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 4097, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 8, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
+            (tensor<1x8192x8192x1xf32>, tensor<16x1025x1024x1xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x7170x16xf32>
+  return %0 : tensor<1x1x7170x16xf32>
 }
 
 // -----
 
-func.func @test_conv2d_dilation_x(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv2d_dilation_x(%arg0: tensor<1x8192x8192x1xf32>, %arg1: tensor<16x1024x1025x1xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<1x7170x1x16xf32> {
   // expected-error at +1 {{'tosa.conv2d' op failed level check: dilation_x * KW <= MAX_KERNEL}}
-  %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 1, 4097>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 1, 8>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
+            (tensor<1x8192x8192x1xf32>, tensor<16x1024x1025x1xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x7170x1x16xf32>
+  return %0 : tensor<1x7170x1x16xf32>
 }
 
 // -----
@@ -601,200 +601,201 @@ func.func @test_conv2d_pad_right(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x
 
 // -----
 
-func.func @test_conv2d_stride_y(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv2d_stride_y(%arg0: tensor<1x8194x33x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<1x2x33x16xf32> {
   // expected-error at +1 {{'tosa.conv2d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 8193, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x8194x33x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x2x33x16xf32>
+  return %0 : tensor<1x2x33x16xf32>
 }
 
 // -----
 
-func.func @test_conv2d_stride_x(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv2d_stride_x(%arg0: tensor<1x33x8194x8xf32>, %arg1: tensor<16x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>) -> tensor<1x33x2x16xf32> {
   // expected-error at +1 {{'tosa.conv2d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg3 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 8193>} :
-            (tensor<1x32x32x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x33x8194x8xf32>, tensor<16x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x33x2x16xf32>
+  return %0 : tensor<1x33x2x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_dilation_d(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_dilation_d(%arg0: tensor<1x8192x1x1x8xf32>, %arg1: tensor<16x1025x1x1x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x2x2x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: dilation_d * KD <= MAX_KERNEL}}
-  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 4097, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 8, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
+            (tensor<1x8192x1x1x8xf32>, tensor<16x1025x1x1x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x2x2x16xf32>
+  return %0 : tensor<1x1x2x2x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_dilation_y(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_dilation_y(%arg0: tensor<1x1x8192x1x8xf32>, %arg1: tensor<16x1x1025x1x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x2x1x2x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: dilation_y * KH <= MAX_KERNEL}}
-  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 4097, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 8, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
+            (tensor<1x1x8192x1x8xf32>, tensor<16x1x1025x1x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x2x1x2x16xf32>
+  return %0 : tensor<1x2x1x2x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_dilation_x(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_dilation_x(%arg0: tensor<1x1x1x8192x8xf32>, %arg1: tensor<16x1x1x1025x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x2x2x1x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: dilation_x * KW <= MAX_KERNEL}}
-  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 4097>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 8>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
+            (tensor<1x1x1x8192x8xf32>, tensor<16x1x1x1025x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x2x2x1x16xf32>
+  return %0 : tensor<1x2x2x1x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_d0(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_d0(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x8194x32x32x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 8193, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x8194x32x32x16xf32>
+  return %0 : tensor<1x8194x32x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_d1(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_d1(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x8194x32x32x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 1, 8193, 0, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x8194x32x32x16xf32>
+  return %0 : tensor<1x8194x32x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_top(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_top(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x8225x32x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 8193, 1, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x8225x32x16xf32>
+  return %0 : tensor<1x1x8225x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_bottom(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_bottom(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x8224x32x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 8193, 0, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x8224x32x16xf32>
+  return %0 : tensor<1x1x8224x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_left(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_left(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x32x8225x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 1, 8193, 1>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x32x8225x16xf32>
+  return %0 : tensor<1x1x32x8225x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_pad_right(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_pad_right(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x32x8224x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 8193>, stride = array<i64: 1, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x32x8224x16xf32>
+  return %0 : tensor<1x1x32x8224x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_stride_d(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_stride_d(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x32x32x16xf32>{
   // expected-error at +1 {{'tosa.conv3d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 8193, 1, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x32x32x16xf32>
+  return %0 : tensor<1x1x32x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_stride_y(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_stride_y(%arg0: tensor<1x1x8194x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x2x32x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 8193, 1>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x8194x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x2x32x16xf32>
+  return %0 : tensor<1x1x2x32x16xf32>
 }
 
 // -----
 
-func.func @test_conv3d_stride_x(%arg0: tensor<1x1x32x32x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_conv3d_stride_x(%arg0: tensor<1x1x32x8194x8xf32>, %arg1: tensor<16x2x2x2x8xf32>, %arg2: tensor<16xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x32x2x16xf32> {
   // expected-error at +1 {{'tosa.conv3d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.conv3d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1, 1>, pad = array<i64: 0, 1, 0, 1, 0, 1>, stride = array<i64: 1, 1, 8193>} :
-            (tensor<1x1x32x32x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x1x32x8194x8xf32>, tensor<16x2x2x2x8xf32>, tensor<16xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x32x2x16xf32>
+  return %0 : tensor<1x1x32x2x16xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_dilation_y(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_dilation_y(%arg0: tensor<1x8192x8192x4xf32>, %arg1: tensor<1025x16x4x1xf32>, %arg2: tensor<4xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x1x8178x4xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: dilation_y * KH <= MAX_KERNEL}}
-  %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 4097, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 8, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
+            (tensor<1x8192x8192x4xf32>, tensor<1025x16x4x1xf32>, tensor<4xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x1x8178x4xf32>
+  return %0 : tensor<1x1x8178x4xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_dilation_x(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_dilation_x(%arg0: tensor<1x8192x8192x4xf32>, %arg1: tensor<16x1025x4x1xf32>, %arg2: tensor<4xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x8178x1x4xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: dilation_x * KW <= MAX_KERNEL}}
-  %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 4097>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+  %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 8>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 1>} :
+            (tensor<1x8192x8192x4xf32>, tensor<16x1025x4x1xf32>, tensor<4xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x8178x1x4xf32>
+  return %0 : tensor<1x8178x1x4xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_pad_top(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_pad_top(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x8225x32x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 8193, 1, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x8225x32x64xf32>
+  return %0 : tensor<1x8225x32x64xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_pad_bottom(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_pad_bottom(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x8224x32x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 8193, 0, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x8224x32x64xf32>
+  return %0 : tensor<1x8224x32x64xf32>
 }
 
+
 // -----
 
-func.func @test_depthwise_conv2d_pad_left(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_pad_left(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x32x8225x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 8193, 1>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x32x8225x64xf32>
+  return %0 : tensor<1x32x8225x64xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_pad_right(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_pad_right(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x32x8224x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: pad <= MAX_KERNEL}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 0, 8193>, stride = array<i64: 1, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x32x8224x64xf32>
+  return %0 : tensor<1x32x8224x64xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_stride_y(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_stride_y(%arg0: tensor<1x8194x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x2x32x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 8193, 1>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x8194x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x2x32x64xf32>
+  return %0 : tensor<1x2x32x64xf32>
 }
 
 // -----
 
-func.func @test_depthwise_conv2d_stride_x(%arg0: tensor<1x32x32x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+func.func @test_depthwise_conv2d_stride_x(%arg0: tensor<1x32x8194x8xf32>, %arg1: tensor<2x2x8x8xf32>, %arg2: tensor<64xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<1x32x2x64xf32> {
   // expected-error at +1 {{'tosa.depthwise_conv2d' op failed level check: stride <= MAX_STRIDE}}
   %0 = tosa.depthwise_conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 1, 0, 1>, stride = array<i64: 1, 8193>} :
-            (tensor<1x32x32x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
-  return %0 : tensor<*xf32>
+            (tensor<1x32x8194x8xf32>, tensor<2x2x8x8xf32>, tensor<64xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<1x32x2x64xf32>
+  return %0 : tensor<1x32x2x64xf32>
 }
 
 // -----
@@ -1598,3 +1599,10 @@ func.func @test_while_loop_max_nested_depth(%arg0: tensor<i32>) {
   return
 }
 
+// -----
+
+func.func @test_unranked_weight_conv2d(%arg0: tensor<1x4x4x4xf32>, %arg1: tensor<*xf32>, %arg2: tensor<8xf32>, %arg3: tensor<1xf32>, %arg4: tensor<1xf32>) -> tensor<*xf32> {
+  // expected-error at +1 {{'tosa.conv2d' op failed level check: unranked tensor}}
+  %0 = tosa.conv2d %arg0, %arg1, %arg2, %arg3, %arg4 {acc_type = f32, dilation = array<i64: 1, 1>, pad = array<i64: 0, 0, 0, 0>, stride = array<i64: 1, 1>, local_bound = true} : (tensor<1x4x4x4xf32>, tensor<*xf32>, tensor<8xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<*xf32>
+  return %0 : tensor<*xf32>
+}

>From 398a1ac821e01835257206cd3ccf2a71d3a333d6 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Thu, 22 May 2025 17:07:43 +0100
Subject: [PATCH 008/105] [KeyInstr][Clang] Static variable init atom (#134636)

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

RFC:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
---
 clang/lib/CodeGen/CGDecl.cpp                         |  4 +++-
 clang/test/DebugInfo/KeyInstructions/init-static.cpp | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-static.cpp

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 18135384021e8..f4549ab3033b2 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -429,8 +429,10 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
   bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
                          D.hasAttr<CUDASharedAttr>();
   // If this value has an initializer, emit it.
-  if (D.getInit() && !isCudaSharedVar)
+  if (D.getInit() && !isCudaSharedVar) {
+    ApplyAtomGroup Grp(getDebugInfo());
     var = AddInitializerToStaticVarDecl(D, var);
+  }
 
   var->setAlignment(alignment.getAsAlign());
 
diff --git a/clang/test/DebugInfo/KeyInstructions/init-static.cpp b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
new file mode 100644
index 0000000000000..745303a3c9d58
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -gkey-instructions %s -debug-info-kind=line-tables-only -emit-llvm -o -\
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+void g(int *a) {
+    // CHECK: %2 = load ptr, ptr %a.addr{{.*}}, !dbg [[G1R2:!.*]]
+    // CHECK: store ptr %2, ptr @_ZZ1gPiE1b{{.*}}, !dbg [[G1R1:!.*]]
+    static int &b = *a;
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+

>From 3ef1b07a6ce759d5036ccaa78f0e4512528964c6 Mon Sep 17 00:00:00 2001
From: Jerry Zhang Jian <jerry.zhangjian at sifive.com>
Date: Fri, 23 May 2025 00:27:04 +0800
Subject: [PATCH 009/105] [RISCV] add Double Trap extension requires Zicsr
 (#141016)

- The double trap extension requires `mtval2' register, so add Zicsr as
required extension

Signed-off-by: Jerry Zhang Jian <jerry.zhangjian at sifive.com>
---
 llvm/lib/Target/RISCV/RISCVFeatures.td | 4 ++--
 llvm/test/CodeGen/RISCV/attributes.ll  | 8 ++++----
 llvm/test/MC/RISCV/attribute-arch.s    | 4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 28b108c21f385..86576ed190d14 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -922,9 +922,9 @@ def FeatureStdExtSscsrind
     : RISCVExtension<1, 0, "Indirect CSR Access Supervisor Level">;
 
 def FeatureStdExtSmdbltrp
-    : RISCVExtension<1, 0, "Double Trap Machine Level">;
+    : RISCVExtension<1, 0, "Double Trap Machine Level", [FeatureStdExtZicsr]>;
 def FeatureStdExtSsdbltrp
-    : RISCVExtension<1, 0, "Double Trap Supervisor Level">;
+    : RISCVExtension<1, 0, "Double Trap Supervisor Level", [FeatureStdExtZicsr]>;
 
 def FeatureStdExtSmepmp
     : RISCVExtension<1, 0, "Enhanced Physical Memory Protection">;
diff --git a/llvm/test/CodeGen/RISCV/attributes.ll b/llvm/test/CodeGen/RISCV/attributes.ll
index ab73a85bfd7b1..68b472936ecdf 100644
--- a/llvm/test/CodeGen/RISCV/attributes.ll
+++ b/llvm/test/CodeGen/RISCV/attributes.ll
@@ -496,8 +496,8 @@
 ; RV32SSAIA: .attribute 5, "rv32i2p1_ssaia1p0"
 ; RV32SMCSRIND: .attribute 5, "rv32i2p1_smcsrind1p0"
 ; RV32SSCSRIND: .attribute 5, "rv32i2p1_sscsrind1p0"
-; RV32SMDBLTRP: .attribute 5, "rv32i2p1_smdbltrp1p0"
-; RV32SSDBLTRP: .attribute 5, "rv32i2p1_ssdbltrp1p0"
+; RV32SMDBLTRP: .attribute 5, "rv32i2p1_zicsr2p0_smdbltrp1p0"
+; RV32SSDBLTRP: .attribute 5, "rv32i2p1_zicsr2p0_ssdbltrp1p0"
 ; RV32SSQOSID: .attribute 5, "rv32i2p1_ssqosid1p0"
 ; RV32SMCDELEG: .attribute 5, "rv32i2p1_smcdeleg1p0"
 ; RV32SMCNTRPMF: .attribute 5, "rv32i2p1_smcntrpmf1p0"
@@ -653,8 +653,8 @@
 ; RV64SSAIA: .attribute 5, "rv64i2p1_ssaia1p0"
 ; RV64SMCSRIND: .attribute 5, "rv64i2p1_smcsrind1p0"
 ; RV64SSCSRIND: .attribute 5, "rv64i2p1_sscsrind1p0"
-; RV64SMDBLTRP: .attribute 5, "rv64i2p1_smdbltrp1p0"
-; RV64SSDBLTRP: .attribute 5, "rv64i2p1_ssdbltrp1p0"
+; RV64SMDBLTRP: .attribute 5, "rv64i2p1_zicsr2p0_smdbltrp1p0"
+; RV64SSDBLTRP: .attribute 5, "rv64i2p1_zicsr2p0_ssdbltrp1p0"
 ; RV64SSQOSID: .attribute 5, "rv64i2p1_ssqosid1p0"
 ; RV64SMCDELEG: .attribute 5, "rv64i2p1_smcdeleg1p0"
 ; RV64SMCNTRPMF: .attribute 5, "rv64i2p1_smcntrpmf1p0"
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index d3b49d03279a2..202f54172ca74 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -331,10 +331,10 @@
 # CHECK: attribute      5, "rv32i2p1_sscsrind1p0"
 
 .attribute arch, "rv32i_smdbltrp1p0"
-# CHECK: attribute      5, "rv32i2p1_smdbltrp1p0"
+# CHECK: attribute      5, "rv32i2p1_zicsr2p0_smdbltrp1p0"
 
 .attribute arch, "rv32i_ssdbltrp1p0"
-# CHECK: attribute      5, "rv32i2p1_ssdbltrp1p0"
+# CHECK: attribute      5, "rv32i2p1_zicsr2p0_ssdbltrp1p0"
 
 .attribute arch, "rv32i_smcdeleg1p0"
 # CHECK: attribute      5, "rv32i2p1_smcdeleg1p0"

>From a3d39316764726ed9fd939550c7781199b1eb77e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 22 May 2025 09:27:53 -0700
Subject: [PATCH 010/105] [X86] Improve GOT/PLTOFF on local symbol tests

These fixups lead to relocations (not resolved).
---
 llvm/test/MC/X86/elf-reloc-got.s |  2 ++
 llvm/test/MC/X86/gotpcrelx.s     | 10 +++++-----
 llvm/test/MC/X86/pltoff.s        |  3 +++
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/llvm/test/MC/X86/elf-reloc-got.s b/llvm/test/MC/X86/elf-reloc-got.s
index eab24a0ac4a66..485a28377d1f5 100644
--- a/llvm/test/MC/X86/elf-reloc-got.s
+++ b/llvm/test/MC/X86/elf-reloc-got.s
@@ -3,11 +3,13 @@
 # CHECK:      .rela.GOT64 {
 # CHECK-NEXT:   0x2 R_X86_64_GOT64 dat 0x0
 # CHECK-NEXT:   0xC R_X86_64_GOT64 und 0x0
+# CHECK-NEXT:   0x16 R_X86_64_GOT64 .GOT64 0x0
 # CHECK-NEXT: }
 
 .section .GOT64,"ax"
 movabs $dat at GOT, %rax
 movabs $und at GOT, %rax
+movabs $.GOT64 at GOT, %rax
 
 .data
 dat:
diff --git a/llvm/test/MC/X86/gotpcrelx.s b/llvm/test/MC/X86/gotpcrelx.s
index e88c514b22690..0de0c919458db 100644
--- a/llvm/test/MC/X86/gotpcrelx.s
+++ b/llvm/test/MC/X86/gotpcrelx.s
@@ -5,8 +5,8 @@
 
 # COMMON:     Relocations [
 # COMMON-NEXT:  Section ({{.*}}) .rela.text {
-# CHECK-NEXT:     R_X86_64_GOTPCRELX mov
-# CHECK-NEXT:     R_X86_64_GOTPCRELX test
+# CHECK-NEXT:     R_X86_64_GOTPCRELX .text 0xFFFFFFFFFFFFFFFC
+# CHECK-NEXT:     R_X86_64_GOTPCRELX test 0xFFFFFFFFFFFFFFFC
 # CHECK-NEXT:     R_X86_64_GOTPCRELX adc
 # CHECK-NEXT:     R_X86_64_GOTPCRELX add
 # CHECK-NEXT:     R_X86_64_GOTPCRELX and
@@ -49,8 +49,8 @@
 # CHECK-NEXT:     R_X86_64_CODE_4_GOTPCRELX xor
 # CHECK-NEXT:   }
 
-# NORELAX-NEXT:     R_X86_64_GOTPCREL mov
-# NORELAX-NEXT:     R_X86_64_GOTPCREL test
+# NORELAX-NEXT:     R_X86_64_GOTPCREL .text 0xFFFFFFFFFFFFFFFC
+# NORELAX-NEXT:     R_X86_64_GOTPCREL test 0xFFFFFFFFFFFFFFFC
 # NORELAX-NEXT:     R_X86_64_GOTPCREL adc
 # NORELAX-NEXT:     R_X86_64_GOTPCREL add
 # NORELAX-NEXT:     R_X86_64_GOTPCREL and
@@ -93,7 +93,7 @@
 # NORELAX-NEXT:     R_X86_64_GOTPCREL xor
 # NORELAX-NEXT:   }
 
-movl mov at GOTPCREL(%rip), %eax
+movl .text at GOTPCREL(%rip), %eax
 test %eax, test at GOTPCREL(%rip)
 adc adc at GOTPCREL(%rip), %eax
 add add at GOTPCREL(%rip), %eax
diff --git a/llvm/test/MC/X86/pltoff.s b/llvm/test/MC/X86/pltoff.s
index 75b79aed79a66..a30ee6ccb0983 100644
--- a/llvm/test/MC/X86/pltoff.s
+++ b/llvm/test/MC/X86/pltoff.s
@@ -7,8 +7,11 @@
 # ASM:      movabsq $puts at PLTOFF, %rax
 # OBJ:      movabsq $0, %rax
 # OBJ-NEXT:   0000000000000002: R_X86_64_PLTOFF64 puts{{$}}
+# OBJ:      movabsq $0, %rax
+# OBJ-NEXT:   000000000000000c: R_X86_64_PLTOFF64 .text{{$}}
 
 movabsq $puts at PLTOFF, %rax
+movabsq $.text at PLTOFF, %rax
 
 .ifdef ERR
 # ERR: {{.*}}.s:[[#@LINE+1]]:1: error: 64 bit reloc applied to a field with a different size

>From bec038db5c93251140612700f1c5a2991d133654 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 17:32:08 +0100
Subject: [PATCH 011/105] [IVDesc] Prefer empty m_Cmp on unused result (NFC)
 (#141071)

---
 llvm/lib/Analysis/IVDescriptors.cpp | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp
index a273338670164..6b7d31463d3a6 100644
--- a/llvm/lib/Analysis/IVDescriptors.cpp
+++ b/llvm/lib/Analysis/IVDescriptors.cpp
@@ -630,14 +630,12 @@ RecurrenceDescriptor::isAnyOfPattern(Loop *Loop, PHINode *OrigPhi,
                                      Instruction *I, InstDesc &Prev) {
   // We must handle the select(cmp(),x,y) as a single instruction. Advance to
   // the select.
-  CmpPredicate Pred;
-  if (match(I, m_OneUse(m_Cmp(Pred, m_Value(), m_Value())))) {
+  if (match(I, m_OneUse(m_Cmp()))) {
     if (auto *Select = dyn_cast<SelectInst>(*I->user_begin()))
       return InstDesc(Select, Prev.getRecKind());
   }
 
-  if (!match(I,
-             m_Select(m_Cmp(Pred, m_Value(), m_Value()), m_Value(), m_Value())))
+  if (!match(I, m_Select(m_Cmp(), m_Value(), m_Value())))
     return InstDesc(false, I);
 
   SelectInst *SI = cast<SelectInst>(I);
@@ -759,16 +757,14 @@ RecurrenceDescriptor::isMinMaxPattern(Instruction *I, RecurKind Kind,
 
   // We must handle the select(cmp()) as a single instruction. Advance to the
   // select.
-  CmpPredicate Pred;
-  if (match(I, m_OneUse(m_Cmp(Pred, m_Value(), m_Value())))) {
+  if (match(I, m_OneUse(m_Cmp()))) {
     if (auto *Select = dyn_cast<SelectInst>(*I->user_begin()))
       return InstDesc(Select, Prev.getRecKind());
   }
 
   // Only match select with single use cmp condition, or a min/max intrinsic.
   if (!isa<IntrinsicInst>(I) &&
-      !match(I, m_Select(m_OneUse(m_Cmp(Pred, m_Value(), m_Value())), m_Value(),
-                         m_Value())))
+      !match(I, m_Select(m_OneUse(m_Cmp()), m_Value(), m_Value())))
     return InstDesc(false, I);
 
   // Look for a min/max pattern.

>From 5c084a162900f318def6ee70f2215999d1102c2c Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 17:33:53 +0100
Subject: [PATCH 012/105] [InstCombine] Increase coverage of shuffle-gep
 (#139725)

There is an uncovered codepath in InstCombineVectorOps, where a new GEP
instruction is created via buildNew. Fix this coverage hole.
---
 llvm/test/Transforms/InstCombine/vec_shuffle.ll | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/vec_shuffle.ll b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
index dd9fab794917f..fa34a42714c46 100644
--- a/llvm/test/Transforms/InstCombine/vec_shuffle.ll
+++ b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
@@ -248,6 +248,19 @@ define <2 x i8> @test13a(i8 %x1, i8 %x2) {
   ret <2 x i8> %D
 }
 
+define <1 x ptr> @shuffle_gep(ptr %x1, ptr %x2) {
+; CHECK-LABEL: @shuffle_gep(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <1 x ptr> poison, ptr [[X2:%.*]], i64 0
+; CHECK-NEXT:    [[RET:%.*]] = getelementptr i8, <1 x ptr> [[TMP1]], i64 5
+; CHECK-NEXT:    ret <1 x ptr> [[RET]]
+;
+  %ins.1 = insertelement <2 x ptr> poison, ptr %x1, i32 0
+  %ins.2 = insertelement <2 x ptr> %ins.1, ptr %x2, i32 1
+  %gep = getelementptr i8, <2 x ptr> %ins.2, i64 5
+  %ret = shufflevector <2 x ptr> %gep, <2 x ptr> poison, <1 x i32> <i32 1>
+  ret <1 x ptr> %ret
+}
+
 ; Increasing length of vector ops is not a good canonicalization.
 
 define <3 x i32> @add_wider(i32 %y, i32 %z) {

>From 28046438ed2f8c81d1dd5c49be0ea6c2bf169b64 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 17:35:20 +0100
Subject: [PATCH 013/105] [IR] Strip dead code post ConstExpr removals (NFC)
 (#139524)

Strip dead code in Operator.h related to the removal of several constant
expressions. Note that PossiblyExactOperator can no longer be a
ConstantExpr.
---
 llvm/include/llvm/IR/Operator.h | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h
index 4d77860be994e..38f84647ec74e 100644
--- a/llvm/include/llvm/IR/Operator.h
+++ b/llvm/include/llvm/IR/Operator.h
@@ -134,9 +134,7 @@ class OverflowingBinaryOperator : public Operator {
   }
   static bool classof(const ConstantExpr *CE) {
     return CE->getOpcode() == Instruction::Add ||
-           CE->getOpcode() == Instruction::Sub ||
-           CE->getOpcode() == Instruction::Mul ||
-           CE->getOpcode() == Instruction::Shl;
+           CE->getOpcode() == Instruction::Sub;
   }
   static bool classof(const Value *V) {
     return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
@@ -150,7 +148,7 @@ struct OperandTraits<OverflowingBinaryOperator>
 
 DEFINE_TRANSPARENT_OPERAND_ACCESSORS(OverflowingBinaryOperator, Value)
 
-/// A udiv or sdiv instruction, which can be marked as "exact",
+/// A udiv, sdiv, lshr, or ashr instruction, which can be marked as "exact",
 /// indicating that no bits are destroyed.
 class PossiblyExactOperator : public Operator {
 public:
@@ -182,15 +180,11 @@ class PossiblyExactOperator : public Operator {
            OpC == Instruction::LShr;
   }
 
-  static bool classof(const ConstantExpr *CE) {
-    return isPossiblyExactOpcode(CE->getOpcode());
-  }
   static bool classof(const Instruction *I) {
     return isPossiblyExactOpcode(I->getOpcode());
   }
   static bool classof(const Value *V) {
-    return (isa<Instruction>(V) && classof(cast<Instruction>(V))) ||
-           (isa<ConstantExpr>(V) && classof(cast<ConstantExpr>(V)));
+    return (isa<Instruction>(V) && classof(cast<Instruction>(V)));
   }
 };
 

>From 0ee40ca5ccbf036179ee11530cc91de7d31131aa Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Thu, 22 May 2025 17:35:49 +0100
Subject: [PATCH 014/105] [KeyInstr][Clang] Aggregate init + copy (#134639)

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

RFC:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
---
 clang/lib/CodeGen/CGDebugInfo.h            | 14 --------------
 clang/lib/CodeGen/CGExprAgg.cpp            |  4 +++-
 clang/lib/CodeGen/CodeGenFunction.h        | 15 +++++++++++++++
 clang/test/DebugInfo/KeyInstructions/agg.c | 17 +++++++++++++++++
 4 files changed, 35 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/agg.c

diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 10739194fd70f..79d031acbf19e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -892,20 +892,6 @@ class CGDebugInfo {
   }
 };
 
-/// A scoped helper to set the current source atom group for
-/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source construct
-/// that is "interesting" for debug stepping purposes. We use an atom group
-/// number to track the instruction(s) that implement the functionality for the
-/// atom, plus backup instructions/source locations.
-class ApplyAtomGroup {
-  uint64_t OriginalAtom = 0;
-  CGDebugInfo *DI = nullptr;
-
-public:
-  ApplyAtomGroup(CGDebugInfo *DI);
-  ~ApplyAtomGroup();
-};
-
 /// A scoped helper to set the current debug location to the specified
 /// location or preferred location of the specified Expr.
 class ApplyDebugLocation {
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index e6f18505a7d4d..cad6731173700 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1332,6 +1332,7 @@ static bool isBlockVarRef(const Expr *E) {
 }
 
 void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   // For an assignment to work, the value on the right has
   // to be compatible with the value on the left.
   assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
@@ -2393,7 +2394,8 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty,
     }
   }
 
-  auto Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
+  auto *Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
+  addInstToCurrentSourceAtom(Inst, nullptr);
 
   // Determine the metadata to describe the position of any padding in this
   // memcpy, as well as the TBAA tags for the members of the struct, in case
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 1743f558b37e9..78d71fc822bcb 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -258,6 +258,20 @@ template <> struct DominatingValue<RValue> {
   }
 };
 
+/// A scoped helper to set the current source atom group for
+/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source construct
+/// that is "interesting" for debug stepping purposes. We use an atom group
+/// number to track the instruction(s) that implement the functionality for the
+/// atom, plus backup instructions/source locations.
+class ApplyAtomGroup {
+  uint64_t OriginalAtom = 0;
+  CGDebugInfo *DI = nullptr;
+
+public:
+  ApplyAtomGroup(CGDebugInfo *DI);
+  ~ApplyAtomGroup();
+};
+
 /// CodeGenFunction - This class organizes the per-function state that is used
 /// while generating LLVM code.
 class CodeGenFunction : public CodeGenTypeCache {
@@ -3035,6 +3049,7 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Emit an aggregate assignment.
   void EmitAggregateAssign(LValue Dest, LValue Src, QualType EltTy) {
+    ApplyAtomGroup Grp(getDebugInfo());
     bool IsVolatile = hasVolatileMember(EltTy);
     EmitAggregateCopy(Dest, Src, EltTy, AggValueSlot::MayOverlap, IsVolatile);
   }
diff --git a/clang/test/DebugInfo/KeyInstructions/agg.c b/clang/test/DebugInfo/KeyInstructions/agg.c
new file mode 100644
index 0000000000000..06c9ebbb63369
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/agg.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+typedef struct { int a, b, c; } Struct;
+void fun(Struct a) {
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+  Struct b = a;
+
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G2R1:!.*]]
+  b = a;
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)

>From b9361126488ff6749e23a997640f839dd20ac331 Mon Sep 17 00:00:00 2001
From: Sumit Agarwal <sumitagarwal at microsoft.com>
Date: Thu, 22 May 2025 09:43:00 -0700
Subject: [PATCH 015/105] [HLSL] Move FNeg legalization to the DXILLegalization
 pass (#140942)

Fixes #137685
---
 llvm/lib/Target/DirectX/DXILLegalizePass.cpp | 15 +++++++++++++
 llvm/lib/Target/DirectX/DXILPrepare.cpp      |  9 --------
 llvm/test/CodeGen/DirectX/fneg-conversion.ll | 16 --------------
 llvm/test/CodeGen/DirectX/legalize-fneg.ll   | 23 ++++++++++++++++++++
 4 files changed, 38 insertions(+), 25 deletions(-)
 delete mode 100644 llvm/test/CodeGen/DirectX/fneg-conversion.ll
 create mode 100644 llvm/test/CodeGen/DirectX/legalize-fneg.ll

diff --git a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
index 7f8903a9d5925..23883c936a20d 100644
--- a/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
+++ b/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
@@ -405,6 +405,20 @@ static void removeMemSet(Instruction &I,
   ToRemove.push_back(CI);
 }
 
+static void updateFnegToFsub(Instruction &I,
+                             SmallVectorImpl<Instruction *> &ToRemove,
+                             DenseMap<Value *, Value *> &) {
+  const Intrinsic::ID ID = I.getOpcode();
+  if (ID != Instruction::FNeg)
+    return;
+
+  IRBuilder<> Builder(&I);
+  Value *In = I.getOperand(0);
+  Value *Zero = ConstantFP::get(In->getType(), -0.0);
+  I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
+  ToRemove.push_back(&I);
+}
+
 namespace {
 class DXILLegalizationPipeline {
 
@@ -438,6 +452,7 @@ class DXILLegalizationPipeline {
     LegalizationPipeline.push_back(legalizeFreeze);
     LegalizationPipeline.push_back(legalizeMemCpy);
     LegalizationPipeline.push_back(removeMemSet);
+    LegalizationPipeline.push_back(updateFnegToFsub);
   }
 };
 
diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp
index e9a05a7b90aca..e0068787f5e5a 100644
--- a/llvm/lib/Target/DirectX/DXILPrepare.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp
@@ -204,15 +204,6 @@ class DXILPrepareModule : public ModulePass {
 
           I.dropUnknownNonDebugMetadata(DXILCompatibleMDs);
 
-          if (I.getOpcode() == Instruction::FNeg) {
-            Builder.SetInsertPoint(&I);
-            Value *In = I.getOperand(0);
-            Value *Zero = ConstantFP::get(In->getType(), -0.0);
-            I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
-            I.eraseFromParent();
-            continue;
-          }
-
           // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
           // unmodified as it reserves instruction IDs during contruction.
           if (auto LI = dyn_cast<LoadInst>(&I)) {
diff --git a/llvm/test/CodeGen/DirectX/fneg-conversion.ll b/llvm/test/CodeGen/DirectX/fneg-conversion.ll
deleted file mode 100644
index 3acf4790de4b1..0000000000000
--- a/llvm/test/CodeGen/DirectX/fneg-conversion.ll
+++ /dev/null
@@ -1,16 +0,0 @@
-; RUN: llc %s --filetype=asm -o - | FileCheck %s
-target triple = "dxil-unknown-shadermodel6.7-library"
-
-define float @negateF(float %0) #0 {
-; CHECK:  %2 = fsub float -0.000000e+00, %0
-  %2 = fneg float %0
-  ret float %2
-}
-
-define double @negateD(double %0) #0 {
-; CHECK: %2 = fsub double -0.000000e+00, %0
-  %2 = fneg double %0
-  ret double %2
-}
-
-attributes #0 = { convergent norecurse nounwind "hlsl.export"}
\ No newline at end of file
diff --git a/llvm/test/CodeGen/DirectX/legalize-fneg.ll b/llvm/test/CodeGen/DirectX/legalize-fneg.ll
new file mode 100644
index 0000000000000..8e85a455ae1a7
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/legalize-fneg.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S -passes='dxil-legalize' -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+define float @negateF(float %x) {
+; CHECK-LABEL: define float @negateF(
+; CHECK-SAME: float [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[Y:%.*]] = fsub float -0.000000e+00, [[X]]
+; CHECK-NEXT:    ret float [[Y]]
+entry:  
+  %y = fneg float %x
+  ret float %y
+}
+
+define double @negateD(double %x) {
+; CHECK-LABEL: define double @negateD(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[Y:%.*]] = fsub double -0.000000e+00, [[X]]
+; CHECK-NEXT:    ret double [[Y]]
+entry:  
+  %y = fneg double %x
+  ret double %y
+}

>From 111ac6987642e9ff1b8ae18ab6e573e0cd3b7129 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 17:43:29 +0100
Subject: [PATCH 016/105] [AggressiveInstCombine] Check GEP nusw, not inbounds
 (#139708)

---
 .../AggressiveInstCombine.cpp                 |  4 ++--
 .../lower-table-based-cttz-basics.ll          | 22 +++++++++++++++++++
 .../AggressiveInstCombine/patterned-load.ll   | 14 ++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
index 8f1a216004b08..c128687062ade 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
@@ -530,7 +530,7 @@ static bool tryToRecognizeTableBasedCttz(Instruction &I) {
     return false;
 
   GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(LI->getPointerOperand());
-  if (!GEP || !GEP->isInBounds() || GEP->getNumIndices() != 2)
+  if (!GEP || !GEP->hasNoUnsignedSignedWrap() || GEP->getNumIndices() != 2)
     return false;
 
   if (!GEP->getSourceElementType()->isArrayTy())
@@ -899,7 +899,7 @@ getStrideAndModOffsetOfGEP(Value *PtrOp, const DataLayout &DL) {
 
     for (auto [V, Scale] : VarOffsets) {
       // Only keep a power of two factor for non-inbounds
-      if (!GEP->isInBounds())
+      if (!GEP->hasNoUnsignedSignedWrap())
         Scale = APInt::getOneBitSet(Scale.getBitWidth(), Scale.countr_zero());
 
       if (!Stride)
diff --git a/llvm/test/Transforms/AggressiveInstCombine/lower-table-based-cttz-basics.ll b/llvm/test/Transforms/AggressiveInstCombine/lower-table-based-cttz-basics.ll
index 9a6c59b91aca5..4d571999df372 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/lower-table-based-cttz-basics.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/lower-table-based-cttz-basics.ll
@@ -113,6 +113,28 @@ entry:
   ret i32 %conv
 }
 
+define i32 @ctz1_nusw(i32 %x) {
+; CHECK-LABEL: @ctz1_nusw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i32 0, i32 [[TMP0]]
+; CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
+; CHECK-NEXT:    [[CONV:%.*]] = zext i8 [[TMP3]] to i32
+; CHECK-NEXT:    ret i32 [[CONV]]
+;
+entry:
+  %sub = sub i32 0, %x
+  %and = and i32 %sub, %x
+  %mul = mul i32 %and, 125613361
+  %shr = lshr i32 %mul, 27
+  %idxprom = zext i32 %shr to i64
+  %arrayidx = getelementptr nusw [32 x i8], ptr @ctz7.table, i64 0, i64 %idxprom
+  %0 = load i8, ptr %arrayidx, align 1
+  %conv = zext i8 %0 to i32
+  ret i32 %conv
+}
+
 @ctz2.table = internal unnamed_addr constant [64 x i16] [i16 32, i16 0, i16 1, i16 12, i16 2, i16 6, i16 0, i16 13, i16 3, i16 0, i16 7, i16 0, i16 0, i16 0, i16 0, i16 14, i16 10, i16 4, i16 0, i16 0, i16 8, i16 0, i16 0, i16 25, i16 0, i16 0, i16 0, i16 0, i16 0, i16 21, i16 27, i16 15, i16 31, i16 11, i16 5, i16 0, i16 0, i16 0, i16 0, i16 0, i16 9, i16 0, i16 0, i16 24, i16 0, i16 0, i16 20, i16 26, i16 30, i16 0, i16 0, i16 0, i16 0, i16 23, i16 0, i16 19, i16 29, i16 0, i16 22, i16 18, i16 28, i16 17, i16 16, i16 0], align 2
 
 define i32 @ctz2(i32 %x) {
diff --git a/llvm/test/Transforms/AggressiveInstCombine/patterned-load.ll b/llvm/test/Transforms/AggressiveInstCombine/patterned-load.ll
index e43dad2ca0893..55e75230148c5 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/patterned-load.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/patterned-load.ll
@@ -140,6 +140,20 @@ define i32 @gep_load_i32_align2_const_offset_wrap(i64 %idx){
   ret i32 %3
 }
 
+define i32 @gep_load_i32_align2_const_offset_nusw(i64 %idx){
+; LE-LABEL: @gep_load_i32_align2_const_offset_nusw(
+; LE-NEXT:    ret i32 65537
+;
+; BE-LABEL: @gep_load_i32_align2_const_offset_nusw(
+; BE-NEXT:    ret i32 16777472
+;
+  %1 = getelementptr nusw i16, ptr @constarray2, i64 -2
+  %2 = getelementptr nusw [3 x i16], ptr %1, i64 %idx
+  %3 = load i32, ptr %2, align 2
+  ret i32 %3
+}
+
+
 define i32 @inbounds_gep_i32_load_i32_const_ptr_array(i64 %idx){
 ; CHECK-LABEL: @inbounds_gep_i32_load_i32_const_ptr_array(
 ; CHECK-NEXT:    ret i32 42

>From 1aa746d300d72042aaa48e7982f76a823aed8cb3 Mon Sep 17 00:00:00 2001
From: Jakob Widauer <jakob.widauer at gmail.com>
Date: Thu, 22 May 2025 18:44:53 +0200
Subject: [PATCH 017/105] [tsan] Fix nested signal handling (#138599)

This PR fixes the bug reported in #134358.

In the current implementation of the tsan posix interceptors, the signal
set does not get restored to the correct original set, if a signal
handler gets called, while already inside of a signal handler. This
leads to the wrong signal set being set for the thread in which the
signal handler was called.

To fix this I introduced a stack of `__sanitizer_sigset_t` to keep all
the correct old signal sets and restore them in the correct order.

There was also already an existing test that tested nested / recursive
signal handlers, but it was disabled.
I therefore reenabled it, made it more robust by waiting for the second
thread to have been properly started and added checks for the signal
sets.
This test then failed before the introduction of the interceptor fix and
didn't fail with the fix.

@dvyukov What are your thoughts?
---
 .../lib/tsan/rtl/tsan_interceptors_posix.cpp  | 28 ++++---
 compiler-rt/lib/tsan/rtl/tsan_rtl.h           |  1 +
 compiler-rt/test/tsan/signal_recursive.cpp    | 81 ++++++++++++++-----
 3 files changed, 81 insertions(+), 29 deletions(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 6d79b80593379..7c4d23a6a0d74 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -12,6 +12,9 @@
 // sanitizer_common/sanitizer_common_interceptors.inc
 //===----------------------------------------------------------------------===//
 
+#include <stdarg.h>
+
+#include "interception/interception.h"
 #include "sanitizer_common/sanitizer_allocator_dlsym.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_errno.h"
@@ -24,16 +27,14 @@
 #include "sanitizer_common/sanitizer_posix.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
-#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_vector.h"
+#include "tsan_fd.h"
 #include "tsan_interceptors.h"
 #include "tsan_interface.h"
+#include "tsan_mman.h"
 #include "tsan_platform.h"
-#include "tsan_suppressions.h"
 #include "tsan_rtl.h"
-#include "tsan_mman.h"
-#include "tsan_fd.h"
-
-#include <stdarg.h>
+#include "tsan_suppressions.h"
 
 using namespace __tsan;
 
@@ -177,7 +178,7 @@ struct ThreadSignalContext {
   SignalDesc pending_signals[kSigCount];
   // emptyset and oldset are too big for stack.
   __sanitizer_sigset_t emptyset;
-  __sanitizer_sigset_t oldset;
+  __sanitizer::Vector<__sanitizer_sigset_t> oldset;
 };
 
 void EnterBlockingFunc(ThreadState *thr) {
@@ -558,6 +559,7 @@ static void SetJmp(ThreadState *thr, uptr sp) {
   buf->shadow_stack_pos = thr->shadow_stack_pos;
   ThreadSignalContext *sctx = SigCtx(thr);
   buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
+  buf->oldset_stack_size = sctx ? sctx->oldset.Size() : 0;
   buf->in_blocking_func = atomic_load(&thr->in_blocking_func, memory_order_relaxed);
   buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
       memory_order_relaxed);
@@ -574,8 +576,11 @@ static void LongJmp(ThreadState *thr, uptr *env) {
       while (thr->shadow_stack_pos > buf->shadow_stack_pos)
         FuncExit(thr);
       ThreadSignalContext *sctx = SigCtx(thr);
-      if (sctx)
+      if (sctx) {
         sctx->int_signal_send = buf->int_signal_send;
+        while (sctx->oldset.Size() > buf->oldset_stack_size)
+          sctx->oldset.PopBack();
+      }
       atomic_store(&thr->in_blocking_func, buf->in_blocking_func,
           memory_order_relaxed);
       atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
@@ -980,6 +985,7 @@ void PlatformCleanUpThreadState(ThreadState *thr) {
       &thr->signal_ctx, memory_order_relaxed);
   if (sctx) {
     atomic_store(&thr->signal_ctx, 0, memory_order_relaxed);
+    sctx->oldset.Reset();
     UnmapOrDie(sctx, sizeof(*sctx));
   }
 }
@@ -2176,7 +2182,8 @@ void ProcessPendingSignalsImpl(ThreadState *thr) {
     return;
   atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
   internal_sigfillset(&sctx->emptyset);
-  int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset);
+  __sanitizer_sigset_t *oldset = sctx->oldset.PushBack();
+  int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, oldset);
   CHECK_EQ(res, 0);
   for (int sig = 0; sig < kSigCount; sig++) {
     SignalDesc *signal = &sctx->pending_signals[sig];
@@ -2186,8 +2193,9 @@ void ProcessPendingSignalsImpl(ThreadState *thr) {
                             &signal->ctx);
     }
   }
-  res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0);
+  res = REAL(pthread_sigmask)(SIG_SETMASK, oldset, 0);
   CHECK_EQ(res, 0);
+  sctx->oldset.PopBack();
   atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
 }
 
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 49bee9c67d303..4dc5e630c5249 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -98,6 +98,7 @@ struct JmpBuf {
   uptr sp;
   int int_signal_send;
   bool in_blocking_func;
+  uptr oldset_stack_size;
   uptr in_signal_handler;
   uptr *shadow_stack_pos;
 };
diff --git a/compiler-rt/test/tsan/signal_recursive.cpp b/compiler-rt/test/tsan/signal_recursive.cpp
index 40be2d01502b6..fca8757d2a952 100644
--- a/compiler-rt/test/tsan/signal_recursive.cpp
+++ b/compiler-rt/test/tsan/signal_recursive.cpp
@@ -3,8 +3,6 @@
 // Test case for recursive signal handlers, adopted from:
 // https://github.com/google/sanitizers/issues/478
 
-// REQUIRES: disabled
-
 #include "test.h"
 #include <semaphore.h>
 #include <signal.h>
@@ -15,8 +13,6 @@ static const int kSigRestart = SIGUSR2;
 
 static sem_t g_thread_suspend_ack_sem;
 
-static bool g_busy_thread_received_restart;
-
 static volatile bool g_busy_thread_garbage_collected;
 
 static void SaveRegistersInStack() {
@@ -30,22 +26,51 @@ static void fail(const char *what) {
   exit(1);
 }
 
+static void CheckSigBlocked(const sigset_t &oldset, const sigset_t &newset,
+                            int sig) {
+  const int is_old_member = sigismember(&oldset, sig);
+  const int is_new_member = sigismember(&newset, sig);
+
+  if (is_old_member == -1 || is_new_member == -1)
+    fail("sigismember failed");
+
+  if (is_old_member != is_new_member)
+    fail("restoring signals failed");
+}
+
+sigset_t GetCurrentSigSet() {
+  sigset_t set;
+  if (sigemptyset(&set) != 0)
+    fail("sigemptyset failed");
+
+  if (pthread_sigmask(SIG_BLOCK, NULL, &set) != 0)
+    fail("pthread_sigmask failed");
+
+  return set;
+}
+
 static void SuspendHandler(int sig) {
   int old_errno = errno;
   SaveRegistersInStack();
 
   // Enable kSigRestart handling, tsan disables signals around signal handlers.
-  sigset_t sigset;
-  sigemptyset(&sigset);
-  pthread_sigmask(SIG_SETMASK, &sigset, 0);
+  const auto oldset = GetCurrentSigSet();
 
   // Acknowledge that thread is saved and suspended
   if (sem_post(&g_thread_suspend_ack_sem) != 0)
     fail("sem_post failed");
 
   // Wait for wakeup signal.
-  while (!g_busy_thread_received_restart)
-    usleep(100);  // wait for kSigRestart signal
+  sigset_t sigset;
+  sigemptyset(&sigset);
+  if (sigsuspend(&sigset) != 0 && errno != EINTR)
+    fail("sigsuspend failed");
+
+  const auto newset = GetCurrentSigSet();
+
+  // Check that the same signals are blocked as before
+  CheckSigBlocked(oldset, newset, kSigSuspend);
+  CheckSigBlocked(oldset, newset, kSigRestart);
 
   // Acknowledge that thread restarted
   if (sem_post(&g_thread_suspend_ack_sem) != 0)
@@ -56,31 +81,33 @@ static void SuspendHandler(int sig) {
   errno = old_errno;
 }
 
-static void RestartHandler(int sig) {
-  g_busy_thread_received_restart = true;
+static void RestartHandler(int sig) {}
+
+static void WaitSem() {
+  while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
+    if (errno != EINTR)
+      fail("sem_wait failed");
+  }
 }
 
 static void StopWorld(pthread_t thread) {
   if (pthread_kill(thread, kSigSuspend) != 0)
     fail("pthread_kill failed");
 
-  while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
-    if (errno != EINTR)
-      fail("sem_wait failed");
-  }
+  WaitSem();
 }
 
 static void StartWorld(pthread_t thread) {
   if (pthread_kill(thread, kSigRestart) != 0)
     fail("pthread_kill failed");
 
-  while (sem_wait(&g_thread_suspend_ack_sem) != 0) {
-    if (errno != EINTR)
-      fail("sem_wait failed");
-  }
+  WaitSem();
 }
 
 static void CollectGarbage(pthread_t thread) {
+  // Wait for the thread to start
+  WaitSem();
+
   StopWorld(thread);
   // Walk stacks
   StartWorld(thread);
@@ -102,21 +129,37 @@ static void Init() {
 
 void* BusyThread(void *arg) {
   (void)arg;
+  const auto oldset = GetCurrentSigSet();
+
+  if (sem_post(&g_thread_suspend_ack_sem) != 0)
+    fail("sem_post failed");
+
   while (!g_busy_thread_garbage_collected) {
     usleep(100); // Tsan deadlocks without these sleeps
   }
+
+  const auto newset = GetCurrentSigSet();
+
+  // Check that we have the same signals blocked as before
+  CheckSigBlocked(oldset, newset, kSigSuspend);
+  CheckSigBlocked(oldset, newset, kSigRestart);
+
   return NULL;
 }
 
 int main(int argc, const char *argv[]) {
   Init();
+
   pthread_t busy_thread;
   if (pthread_create(&busy_thread, NULL, &BusyThread, NULL) != 0)
     fail("pthread_create failed");
+
   CollectGarbage(busy_thread);
   if (pthread_join(busy_thread, 0) != 0)
     fail("pthread_join failed");
+
   fprintf(stderr, "DONE\n");
+
   return 0;
 }
 

>From 586e1dffd8d2fab0b4f386c51eff23f3640f45d9 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <xlauko at mail.muni.cz>
Date: Thu, 22 May 2025 18:48:14 +0200
Subject: [PATCH 018/105] [CIR] Implement `AnyScalarType` constraint (#141033)

This mirrors incubator changes from https://github.com/llvm/clangir/pull/1625
---
 .../clang/CIR/Dialect/IR/CIRTypeConstraints.td | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
index 902d6535ff717..ec461cab961c7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td
@@ -31,6 +31,12 @@ class CIR_ConfinedType<Type type, list<Pred> preds, string summary = "">
     : Type<And<[type.predicate, CIR_CastedSelfsToType<type.cppType, preds>]>,
          summary, type.cppType>;
 
+//===----------------------------------------------------------------------===//
+// Bool Type predicates
+//===----------------------------------------------------------------------===//
+
+def CIR_AnyBoolType : CIR_TypeBase<"::cir::BoolType", "boolean type">;
+
 //===----------------------------------------------------------------------===//
 // IntType predicates
 //===----------------------------------------------------------------------===//
@@ -193,4 +199,16 @@ def IntegerVector : Type<
 // Any Integer or Vector of Integer Constraints
 def CIR_AnyIntOrVecOfInt: AnyTypeOf<[CIR_AnyIntType, IntegerVector]>;
 
+//===----------------------------------------------------------------------===//
+// Scalar Type predicates
+//===----------------------------------------------------------------------===//
+
+defvar CIR_ScalarTypes = [
+    CIR_AnyBoolType, CIR_AnyIntType, CIR_AnyFloatType, CIR_AnyPtrType
+];
+
+def CIR_AnyScalarType : AnyTypeOf<CIR_ScalarTypes, "cir scalar type"> {
+  let cppFunctionName = "isScalarType";
+}
+
 #endif // CLANG_CIR_DIALECT_IR_CIRTYPECONSTRAINTS_TD

>From 68472a39a0fbf38f5da7bb4ebe43e2ca87ff8308 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 22 May 2025 09:49:27 -0700
Subject: [PATCH 019/105] [MC] Restore MCAsmBackend::shouldForceRelocation to
 false

For IsPCRel fixups, we had the `A->getKind() != MCSymbolRefExpr::VK_None`
condition to force relocations. The condition has then been changed to
`Target.getSpecifier()` (086af836889436baffc71c743c7c8259bad8ed60).

38c3ad36be1facbe6db2dede7e93c0f12fb4e1dc updated
shouldForceRelocation to test `Target.getSpecifier`.
It is not a good fit as many targets with %lo/%hi style specifiers
(SPARC, MIPS, PowerPC, RISC-V) do not force relocations for these
specifiers.

Revert the Target.getSpecifier implementation
(38c3ad36be1facbe6db2dede7e93c0f12fb4e1dc) and update
targets that need it (SystemZAsmBackend/X86AsmBackend) instead.
Targets need customization might define addReloc instead.

Note: The X86AsmBackend implementation is too conservative.
GNU Assembler doesn't emit a relocation for `call local at plt; local`
a3d39316764726ed9fd939550c7781199b1eb77e added missing coverage
for GOT/PLT related relocations.
---
 llvm/include/llvm/MC/MCAsmBackend.h                   |  7 ++++---
 llvm/lib/MC/MCAsmBackend.cpp                          |  6 ------
 .../lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp |  6 ------
 .../SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp      | 10 ++++++++++
 llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp    | 11 +++++++++++
 5 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h
index 27fdd23c88cf3..9eabacf2f7f10 100644
--- a/llvm/include/llvm/MC/MCAsmBackend.h
+++ b/llvm/include/llvm/MC/MCAsmBackend.h
@@ -88,10 +88,11 @@ class MCAsmBackend {
   /// Get information on a fixup kind.
   virtual MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const;
 
-  // Hook to check if a relocation is needed. The default implementation tests
-  // whether the MCValue has a relocation specifier.
+  // Hook used by the default `addReloc` to check if a relocation is needed.
   virtual bool shouldForceRelocation(const MCAssembler &, const MCFixup &,
-                                     const MCValue &, const MCSubtargetInfo *);
+                                     const MCValue &, const MCSubtargetInfo *) {
+    return false;
+  }
 
   /// Hook to check if extra nop bytes must be inserted for alignment directive.
   /// For some targets this may be necessary in order to support linker
diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
index 0c43b2e473559..2dae9c0266722 100644
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -109,12 +109,6 @@ MCFixupKindInfo MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
   return Builtins[Kind - FK_NONE];
 }
 
-bool MCAsmBackend::shouldForceRelocation(const MCAssembler &, const MCFixup &,
-                                         const MCValue &Target,
-                                         const MCSubtargetInfo *) {
-  return Target.getSpecifier();
-}
-
 bool MCAsmBackend::fixupNeedsRelaxationAdvanced(const MCAssembler &,
                                                 const MCFixup &Fixup,
                                                 const MCValue &, uint64_t Value,
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
index 3ea8bede91ea4..9ef335a5af4a3 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -200,12 +200,6 @@ namespace {
       return Info;
     }
 
-    bool shouldForceRelocation(const MCAssembler &, const MCFixup &,
-                               const MCValue &,
-                               const MCSubtargetInfo *) override {
-      return false;
-    }
-
     void relaxInstruction(MCInst &Inst,
                           const MCSubtargetInfo &STI) const override {
       // FIXME.
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
index 58bb7baea1d47..bbb405ff77068 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp
@@ -17,6 +17,7 @@
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
 
 using namespace llvm;
 
@@ -112,6 +113,8 @@ class SystemZMCAsmBackend : public MCAsmBackend {
   // Override MCAsmBackend
   std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
+  bool shouldForceRelocation(const MCAssembler &, const MCFixup &,
+                             const MCValue &, const MCSubtargetInfo *) override;
   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                   const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsResolved,
@@ -152,6 +155,13 @@ MCFixupKindInfo SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
   return SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind];
 }
 
+bool SystemZMCAsmBackend::shouldForceRelocation(const MCAssembler &,
+                                                const MCFixup &,
+                                                const MCValue &Target,
+                                                const MCSubtargetInfo *) {
+  return Target.getSpecifier();
+}
+
 void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,
                                      const MCFixup &Fixup,
                                      const MCValue &Target,
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index 3cee53a886ebf..81bdd8cb24b88 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -169,6 +169,9 @@ class X86AsmBackend : public MCAsmBackend {
 
   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
 
+  bool shouldForceRelocation(const MCAssembler &, const MCFixup &,
+                             const MCValue &, const MCSubtargetInfo *) override;
+
   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                   const MCValue &Target, MutableArrayRef<char> Data,
                   uint64_t Value, bool IsResolved,
@@ -687,6 +690,14 @@ static unsigned getFixupKindSize(unsigned Kind) {
   }
 }
 
+// Force relocation when there is a specifier. This might be too conservative -
+// GAS doesn't emit a relocation for call local at plt; local:.
+bool X86AsmBackend::shouldForceRelocation(const MCAssembler &, const MCFixup &,
+                                          const MCValue &Target,
+                                          const MCSubtargetInfo *) {
+  return Target.getSpecifier();
+}
+
 void X86AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                                const MCValue &, MutableArrayRef<char> Data,
                                uint64_t Value, bool IsResolved,

>From 58ab005d8db2bb9fc54275f3398172e0691ecc91 Mon Sep 17 00:00:00 2001
From: "S. VenkataKeerthy" <31350914+svkeerthy at users.noreply.github.com>
Date: Thu, 22 May 2025 09:50:21 -0700
Subject: [PATCH 020/105] Adding IR2Vec as an analysis pass (#134004)

This PR introduces IR2Vec as an analysis pass. The changes include:
- Logic for generating Symbolic encodings.
- 75D learned vocabulary.
- lit tests.

Here is the link to the RFC -
https://discourse.llvm.org/t/rfc-enhancing-mlgo-inlining-with-ir2vec-embeddings

Acknowledgements: contributors -
https://github.com/IITH-Compilers/IR2Vec/graphs/contributors

---------

Co-authored-by: svkeerthy <venkatakeerthy at google.com>
Co-authored-by: Mircea Trofin <mtrofin at google.com>
---
 llvm/docs/MLGO.rst                            |  93 ++++++
 llvm/include/llvm/Analysis/IR2Vec.h           | 200 ++++++++++++
 llvm/lib/Analysis/CMakeLists.txt              |   1 +
 llvm/lib/Analysis/IR2Vec.cpp                  | 306 ++++++++++++++++++
 .../models/seedEmbeddingVocab75D.json         |  65 ++++
 llvm/lib/Passes/PassBuilder.cpp               |   1 +
 llvm/lib/Passes/PassRegistry.def              |   2 +
 .../IR2Vec/Inputs/dummy_3D_vocab.json         |   7 +
 .../IR2Vec/Inputs/dummy_5D_vocab.json         |  11 +
 llvm/test/Analysis/IR2Vec/basic.ll            |  50 +++
 llvm/test/Analysis/IR2Vec/if-else.ll          |  38 +++
 11 files changed, 774 insertions(+)
 create mode 100644 llvm/include/llvm/Analysis/IR2Vec.h
 create mode 100644 llvm/lib/Analysis/IR2Vec.cpp
 create mode 100644 llvm/lib/Analysis/models/seedEmbeddingVocab75D.json
 create mode 100644 llvm/test/Analysis/IR2Vec/Inputs/dummy_3D_vocab.json
 create mode 100644 llvm/test/Analysis/IR2Vec/Inputs/dummy_5D_vocab.json
 create mode 100644 llvm/test/Analysis/IR2Vec/basic.ll
 create mode 100644 llvm/test/Analysis/IR2Vec/if-else.ll

diff --git a/llvm/docs/MLGO.rst b/llvm/docs/MLGO.rst
index c88d8d68a7ce3..49efea3519c5a 100644
--- a/llvm/docs/MLGO.rst
+++ b/llvm/docs/MLGO.rst
@@ -347,3 +347,96 @@ clang.
     TODO(mtrofin): 
         - logging, and the use in interactive mode.
         - discuss an example (like the inliner)
+
+IR2Vec Embeddings
+=================
+
+IR2Vec is a program embedding approach designed specifically for LLVM IR. It
+is implemented as a function analysis pass in LLVM. The IR2Vec embeddings
+capture syntactic, semantic, and structural properties of the IR through 
+learned representations. These representations are obtained as a JSON 
+vocabulary that maps the entities of the IR (opcodes, types, operands) to 
+n-dimensional floating point vectors (embeddings). 
+
+With IR2Vec, representation at different granularities of IR, such as
+instructions, functions, and basic blocks, can be obtained. Representations 
+of loops and regions can be derived from these representations, which can be
+useful in different scenarios. The representations can be useful for various
+downstream tasks, including ML-guided compiler optimizations.
+
+The core components are:
+  - **Vocabulary**: A mapping from IR entities (opcodes, types, etc.) to their
+    vector representations. This is managed by ``IR2VecVocabAnalysis``.
+  - **Embedder**: A class (``ir2vec::Embedder``) that uses the vocabulary to
+    compute embeddings for instructions, basic blocks, and functions.
+
+Using IR2Vec
+------------
+
+For generating embeddings, first the vocabulary should be obtained. Then, the 
+embeddings can be computed and accessed via an ``ir2vec::Embedder`` instance.
+
+1. **Get the Vocabulary**:
+   In a ModulePass, get the vocabulary analysis result:
+
+   .. code-block:: c++
+
+      auto &VocabRes = MAM.getResult<IR2VecVocabAnalysis>(M);
+      if (!VocabRes.isValid()) {
+        // Handle error: vocabulary is not available or invalid
+        return;
+      }
+      const ir2vec::Vocab &Vocabulary = VocabRes.getVocabulary();
+      unsigned Dimension = VocabRes.getDimension();
+
+    Note that ``IR2VecVocabAnalysis`` pass is immutable.
+
+2. **Create Embedder instance**:
+   With the vocabulary, create an embedder for a specific function:
+
+   .. code-block:: c++
+
+      // Assuming F is an llvm::Function&
+      // For example, using IR2VecKind::Symbolic:
+      Expected<std::unique_ptr<ir2vec::Embedder>> EmbOrErr =
+          ir2vec::Embedder::create(IR2VecKind::Symbolic, F, Vocabulary, Dimension);
+
+      if (auto Err = EmbOrErr.takeError()) {
+        // Handle error in embedder creation
+        return;
+      }
+      std::unique_ptr<ir2vec::Embedder> Emb = std::move(*EmbOrErr);
+
+3. **Compute and Access Embeddings**:
+   Call ``computeEmbeddings()`` on the embedder instance to compute the 
+   embeddings. Then the embeddings can be accessed using different getter 
+   methods. Currently, ``Embedder`` can generate embeddings at three levels:
+   Instructions, Basic Blocks, and Functions.
+
+   .. code-block:: c++
+
+      Emb->computeEmbeddings();
+      const ir2vec::Embedding &FuncVector = Emb->getFunctionVector();
+      const ir2vec::InstEmbeddingsMap &InstVecMap = Emb->getInstVecMap();
+      const ir2vec::BBEmbeddingsMap &BBVecMap = Emb->getBBVecMap();
+
+      // Example: Iterate over instruction embeddings
+      for (const auto &Entry : InstVecMap) {
+        const Instruction *Inst = Entry.getFirst();
+        const ir2vec::Embedding &InstEmbedding = Entry.getSecond();
+        // Use Inst and InstEmbedding
+      }
+
+4. **Working with Embeddings:**
+   Embeddings are represented as ``std::vector<double>``. These
+   vectors as features for machine learning models, compute similarity scores
+   between different code snippets, or perform other analyses as needed.
+
+Further Details
+---------------
+
+For more detailed information about the IR2Vec algorithm, its parameters, and
+advanced usage, please refer to the original paper:
+`IR2Vec: LLVM IR Based Scalable Program Embeddings <https://doi.org/10.1145/3418463>`_.
+The LLVM source code for ``IR2Vec`` can also be explored to understand the 
+implementation details.
diff --git a/llvm/include/llvm/Analysis/IR2Vec.h b/llvm/include/llvm/Analysis/IR2Vec.h
new file mode 100644
index 0000000000000..31768a32060e1
--- /dev/null
+++ b/llvm/include/llvm/Analysis/IR2Vec.h
@@ -0,0 +1,200 @@
+//===- IR2Vec.h - Implementation of IR2Vec ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions. See the LICENSE file for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the IR2Vec vocabulary analysis(IR2VecVocabAnalysis),
+/// the core ir2vec::Embedder interface for generating IR embeddings,
+/// and related utilities like the IR2VecPrinterPass.
+///
+/// Program Embeddings are typically or derived-from a learned
+/// representation of the program. Such embeddings are used to represent the
+/// programs as input to machine learning algorithms. IR2Vec represents the
+/// LLVM IR as embeddings.
+///
+/// The IR2Vec algorithm is described in the following paper:
+///
+///   IR2Vec: LLVM IR Based Scalable Program Embeddings, S. VenkataKeerthy,
+///   Rohit Aggarwal, Shalini Jain, Maunendra Sankar Desarkar, Ramakrishna
+///   Upadrasta, and Y. N. Srikant, ACM Transactions on Architecture and
+///   Code Optimization (TACO), 2020. https://doi.org/10.1145/3418463.
+///   https://arxiv.org/abs/1909.06228
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_IR2VEC_H
+#define LLVM_ANALYSIS_IR2VEC_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Support/ErrorOr.h"
+#include <map>
+
+namespace llvm {
+
+class Module;
+class BasicBlock;
+class Instruction;
+class Function;
+class Type;
+class Value;
+class raw_ostream;
+
+/// IR2Vec computes two kinds of embeddings: Symbolic and Flow-aware.
+/// Symbolic embeddings capture the "syntactic" and "statistical correlation"
+/// of the IR entities. Flow-aware embeddings build on top of symbolic
+/// embeddings and additionally capture the flow information in the IR.
+/// IR2VecKind is used to specify the type of embeddings to generate.
+/// Currently, only Symbolic embeddings are supported.
+enum class IR2VecKind { Symbolic };
+
+namespace ir2vec {
+using Embedding = std::vector<double>;
+using InstEmbeddingsMap = DenseMap<const Instruction *, Embedding>;
+using BBEmbeddingsMap = DenseMap<const BasicBlock *, Embedding>;
+// FIXME: Current the keys are strings. This can be changed to
+// use integers for cheaper lookups.
+using Vocab = std::map<std::string, Embedding>;
+
+/// Embedder provides the interface to generate embeddings (vector
+/// representations) for instructions, basic blocks, and functions. The vector
+/// representations are generated using IR2Vec algorithms.
+///
+/// The Embedder class is an abstract class and it is intended to be
+/// subclassed for different IR2Vec algorithms like Symbolic and Flow-aware.
+class Embedder {
+protected:
+  const Function &F;
+  const Vocab &Vocabulary;
+
+  /// Dimension of the vector representation; captured from the input vocabulary
+  const unsigned Dimension;
+
+  /// Weights for different entities (like opcode, arguments, types)
+  /// in the IR instructions to generate the vector representation.
+  const float OpcWeight, TypeWeight, ArgWeight;
+
+  // Utility maps - these are used to store the vector representations of
+  // instructions, basic blocks and functions.
+  Embedding FuncVector;
+  BBEmbeddingsMap BBVecMap;
+  InstEmbeddingsMap InstVecMap;
+
+  Embedder(const Function &F, const Vocab &Vocabulary, unsigned Dimension);
+
+  /// Lookup vocabulary for a given Key. If the key is not found, it returns a
+  /// zero vector.
+  Embedding lookupVocab(const std::string &Key) const;
+
+  /// Adds two vectors: Dst += Src
+  static void addVectors(Embedding &Dst, const Embedding &Src);
+
+  /// Adds Src vector scaled by Factor to Dst vector: Dst += Src * Factor
+  static void addScaledVector(Embedding &Dst, const Embedding &Src,
+                              float Factor);
+
+public:
+  virtual ~Embedder() = default;
+
+  /// Top level function to compute embeddings. It generates embeddings for all
+  /// the instructions and basic blocks in the function F. Logic of computing
+  /// the embeddings is specific to the kind of embeddings being computed.
+  virtual void computeEmbeddings() = 0;
+
+  /// Factory method to create an Embedder object.
+  static Expected<std::unique_ptr<Embedder>> create(IR2VecKind Mode,
+                                                    const Function &F,
+                                                    const Vocab &Vocabulary,
+                                                    unsigned Dimension);
+
+  /// Returns a map containing instructions and the corresponding vector
+  /// representations for a given module corresponding to the IR2Vec
+  /// algorithm.
+  const InstEmbeddingsMap &getInstVecMap() const { return InstVecMap; }
+
+  /// Returns a map containing basic block and the corresponding vector
+  /// representations for a given module corresponding to the IR2Vec
+  /// algorithm.
+  const BBEmbeddingsMap &getBBVecMap() const { return BBVecMap; }
+
+  /// Returns the vector representation for a given function corresponding to
+  /// the IR2Vec algorithm.
+  const Embedding &getFunctionVector() const { return FuncVector; }
+};
+
+/// Class for computing the Symbolic embeddings of IR2Vec.
+/// Symbolic embeddings are constructed based on the entity-level
+/// representations obtained from the Vocabulary.
+class SymbolicEmbedder : public Embedder {
+private:
+  /// Utility function to compute the vector representation for a given basic
+  /// block.
+  Embedding computeBB2Vec(const BasicBlock &BB);
+
+  /// Utility function to compute the vector representation for a given type.
+  Embedding getTypeEmbedding(const Type *Ty) const;
+
+  /// Utility function to compute the vector representation for a given
+  /// operand.
+  Embedding getOperandEmbedding(const Value *Op) const;
+
+public:
+  SymbolicEmbedder(const Function &F, const Vocab &Vocabulary,
+                   unsigned Dimension)
+      : Embedder(F, Vocabulary, Dimension) {
+    FuncVector = Embedding(Dimension, 0);
+  }
+  void computeEmbeddings() override;
+};
+
+} // namespace ir2vec
+
+/// Class for storing the result of the IR2VecVocabAnalysis.
+class IR2VecVocabResult {
+  ir2vec::Vocab Vocabulary;
+  bool Valid = false;
+
+public:
+  IR2VecVocabResult() = default;
+  IR2VecVocabResult(ir2vec::Vocab &&Vocabulary);
+
+  bool isValid() const { return Valid; }
+  const ir2vec::Vocab &getVocabulary() const;
+  unsigned getDimension() const;
+  bool invalidate(Module &M, const PreservedAnalyses &PA,
+                  ModuleAnalysisManager::Invalidator &Inv) const;
+};
+
+/// This analysis provides the vocabulary for IR2Vec. The vocabulary provides a
+/// mapping between an entity of the IR (like opcode, type, argument, etc.) and
+/// its corresponding embedding.
+class IR2VecVocabAnalysis : public AnalysisInfoMixin<IR2VecVocabAnalysis> {
+  ir2vec::Vocab Vocabulary;
+  Error readVocabulary();
+
+public:
+  static AnalysisKey Key;
+  IR2VecVocabAnalysis() = default;
+  using Result = IR2VecVocabResult;
+  Result run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+/// This pass prints the IR2Vec embeddings for instructions, basic blocks, and
+/// functions.
+class IR2VecPrinterPass : public PassInfoMixin<IR2VecPrinterPass> {
+  raw_ostream &OS;
+  void printVector(const ir2vec::Embedding &Vec) const;
+
+public:
+  explicit IR2VecPrinterPass(raw_ostream &OS) : OS(OS) {}
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+  static bool isRequired() { return true; }
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_IR2VEC_H
diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt
index e884f11f0f758..8fe03d46946a4 100644
--- a/llvm/lib/Analysis/CMakeLists.txt
+++ b/llvm/lib/Analysis/CMakeLists.txt
@@ -79,6 +79,7 @@ add_llvm_component_library(LLVMAnalysis
   GlobalsModRef.cpp
   GuardUtils.cpp
   HeatUtils.cpp
+  IR2Vec.cpp
   IRSimilarityIdentifier.cpp
   IVDescriptors.cpp
   IVUsers.cpp
diff --git a/llvm/lib/Analysis/IR2Vec.cpp b/llvm/lib/Analysis/IR2Vec.cpp
new file mode 100644
index 0000000000000..d4d6bfc910abc
--- /dev/null
+++ b/llvm/lib/Analysis/IR2Vec.cpp
@@ -0,0 +1,306 @@
+//===- IR2Vec.cpp - Implementation of IR2Vec -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM
+// Exceptions. See the LICENSE file for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the IR2Vec algorithm.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Analysis/IR2Vec.h"
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace ir2vec;
+
+#define DEBUG_TYPE "ir2vec"
+
+STATISTIC(VocabMissCounter,
+          "Number of lookups to entites not present in the vocabulary");
+
+static cl::OptionCategory IR2VecCategory("IR2Vec Options");
+
+// FIXME: Use a default vocab when not specified
+static cl::opt<std::string>
+    VocabFile("ir2vec-vocab-path", cl::Optional,
+              cl::desc("Path to the vocabulary file for IR2Vec"), cl::init(""),
+              cl::cat(IR2VecCategory));
+static cl::opt<float> OpcWeight("ir2vec-opc-weight", cl::Optional,
+                                cl::init(1.0),
+                                cl::desc("Weight for opcode embeddings"),
+                                cl::cat(IR2VecCategory));
+static cl::opt<float> TypeWeight("ir2vec-type-weight", cl::Optional,
+                                 cl::init(0.5),
+                                 cl::desc("Weight for type embeddings"),
+                                 cl::cat(IR2VecCategory));
+static cl::opt<float> ArgWeight("ir2vec-arg-weight", cl::Optional,
+                                cl::init(0.2),
+                                cl::desc("Weight for argument embeddings"),
+                                cl::cat(IR2VecCategory));
+
+AnalysisKey IR2VecVocabAnalysis::Key;
+
+// ==----------------------------------------------------------------------===//
+// Embedder and its subclasses
+//===----------------------------------------------------------------------===//
+
+Embedder::Embedder(const Function &F, const Vocab &Vocabulary,
+                   unsigned Dimension)
+    : F(F), Vocabulary(Vocabulary), Dimension(Dimension),
+      OpcWeight(::OpcWeight), TypeWeight(::TypeWeight), ArgWeight(::ArgWeight) {
+}
+
+Expected<std::unique_ptr<Embedder>> Embedder::create(IR2VecKind Mode,
+                                                     const Function &F,
+                                                     const Vocab &Vocabulary,
+                                                     unsigned Dimension) {
+  switch (Mode) {
+  case IR2VecKind::Symbolic:
+    return std::make_unique<SymbolicEmbedder>(F, Vocabulary, Dimension);
+  default:
+    return make_error<StringError>("Unknown IR2VecKind",
+                                   errc::invalid_argument);
+  }
+}
+
+void Embedder::addVectors(Embedding &Dst, const Embedding &Src) {
+  std::transform(Dst.begin(), Dst.end(), Src.begin(), Dst.begin(),
+                 std::plus<double>());
+}
+
+void Embedder::addScaledVector(Embedding &Dst, const Embedding &Src,
+                               float Factor) {
+  assert(Dst.size() == Src.size() && "Vectors must have the same dimension");
+  for (size_t i = 0; i < Dst.size(); ++i) {
+    Dst[i] += Src[i] * Factor;
+  }
+}
+
+// FIXME: Currently lookups are string based. Use numeric Keys
+// for efficiency
+Embedding Embedder::lookupVocab(const std::string &Key) const {
+  Embedding Vec(Dimension, 0);
+  // FIXME: Use zero vectors in vocab and assert failure for
+  // unknown entities rather than silently returning zeroes here.
+  auto It = Vocabulary.find(Key);
+  if (It != Vocabulary.end())
+    return It->second;
+  LLVM_DEBUG(errs() << "cannot find key in map : " << Key << "\n");
+  ++VocabMissCounter;
+  return Vec;
+}
+
+#define RETURN_LOOKUP_IF(CONDITION, KEY_STR)                                   \
+  if (CONDITION)                                                               \
+    return lookupVocab(KEY_STR);
+
+Embedding SymbolicEmbedder::getTypeEmbedding(const Type *Ty) const {
+  RETURN_LOOKUP_IF(Ty->isVoidTy(), "voidTy");
+  RETURN_LOOKUP_IF(Ty->isFloatingPointTy(), "floatTy");
+  RETURN_LOOKUP_IF(Ty->isIntegerTy(), "integerTy");
+  RETURN_LOOKUP_IF(Ty->isFunctionTy(), "functionTy");
+  RETURN_LOOKUP_IF(Ty->isStructTy(), "structTy");
+  RETURN_LOOKUP_IF(Ty->isArrayTy(), "arrayTy");
+  RETURN_LOOKUP_IF(Ty->isPointerTy(), "pointerTy");
+  RETURN_LOOKUP_IF(Ty->isVectorTy(), "vectorTy");
+  RETURN_LOOKUP_IF(Ty->isEmptyTy(), "emptyTy");
+  RETURN_LOOKUP_IF(Ty->isLabelTy(), "labelTy");
+  RETURN_LOOKUP_IF(Ty->isTokenTy(), "tokenTy");
+  RETURN_LOOKUP_IF(Ty->isMetadataTy(), "metadataTy");
+  return lookupVocab("unknownTy");
+}
+
+Embedding SymbolicEmbedder::getOperandEmbedding(const Value *Op) const {
+  RETURN_LOOKUP_IF(isa<Function>(Op), "function");
+  RETURN_LOOKUP_IF(isa<PointerType>(Op->getType()), "pointer");
+  RETURN_LOOKUP_IF(isa<Constant>(Op), "constant");
+  return lookupVocab("variable");
+}
+
+#undef RETURN_LOOKUP_IF
+
+void SymbolicEmbedder::computeEmbeddings() {
+  if (F.isDeclaration())
+    return;
+  for (const auto &BB : F) {
+    auto [It, WasInserted] = BBVecMap.try_emplace(&BB, computeBB2Vec(BB));
+    assert(WasInserted && "Basic block already exists in the map");
+    addVectors(FuncVector, It->second);
+  }
+}
+
+Embedding SymbolicEmbedder::computeBB2Vec(const BasicBlock &BB) {
+  Embedding BBVector(Dimension, 0);
+
+  for (const auto &I : BB) {
+    Embedding InstVector(Dimension, 0);
+
+    const auto OpcVec = lookupVocab(I.getOpcodeName());
+    addScaledVector(InstVector, OpcVec, OpcWeight);
+
+    // FIXME: Currently lookups are string based. Use numeric Keys
+    // for efficiency.
+    const auto Type = I.getType();
+    const auto TypeVec = getTypeEmbedding(Type);
+    addScaledVector(InstVector, TypeVec, TypeWeight);
+
+    for (const auto &Op : I.operands()) {
+      const auto OperandVec = getOperandEmbedding(Op.get());
+      addScaledVector(InstVector, OperandVec, ArgWeight);
+    }
+    InstVecMap[&I] = InstVector;
+    addVectors(BBVector, InstVector);
+  }
+  return BBVector;
+}
+
+// ==----------------------------------------------------------------------===//
+// IR2VecVocabResult and IR2VecVocabAnalysis
+//===----------------------------------------------------------------------===//
+
+IR2VecVocabResult::IR2VecVocabResult(ir2vec::Vocab &&Vocabulary)
+    : Vocabulary(std::move(Vocabulary)), Valid(true) {}
+
+const ir2vec::Vocab &IR2VecVocabResult::getVocabulary() const {
+  assert(Valid && "IR2Vec Vocabulary is invalid");
+  return Vocabulary;
+}
+
+unsigned IR2VecVocabResult::getDimension() const {
+  assert(Valid && "IR2Vec Vocabulary is invalid");
+  return Vocabulary.begin()->second.size();
+}
+
+// For now, assume vocabulary is stable unless explicitly invalidated.
+bool IR2VecVocabResult::invalidate(
+    Module &M, const PreservedAnalyses &PA,
+    ModuleAnalysisManager::Invalidator &Inv) const {
+  auto PAC = PA.getChecker<IR2VecVocabAnalysis>();
+  return !(PAC.preservedWhenStateless());
+}
+
+// FIXME: Make this optional. We can avoid file reads
+// by auto-generating a default vocabulary during the build time.
+Error IR2VecVocabAnalysis::readVocabulary() {
+  auto BufOrError = MemoryBuffer::getFileOrSTDIN(VocabFile, /*IsText=*/true);
+  if (!BufOrError) {
+    return createFileError(VocabFile, BufOrError.getError());
+  }
+  auto Content = BufOrError.get()->getBuffer();
+  json::Path::Root Path("");
+  Expected<json::Value> ParsedVocabValue = json::parse(Content);
+  if (!ParsedVocabValue)
+    return ParsedVocabValue.takeError();
+
+  bool Res = json::fromJSON(*ParsedVocabValue, Vocabulary, Path);
+  if (!Res) {
+    return createStringError(errc::illegal_byte_sequence,
+                             "Unable to parse the vocabulary");
+  }
+  assert(Vocabulary.size() > 0 && "Vocabulary is empty");
+
+  unsigned Dim = Vocabulary.begin()->second.size();
+  assert(Dim > 0 && "Dimension of vocabulary is zero");
+  assert(std::all_of(Vocabulary.begin(), Vocabulary.end(),
+                     [Dim](const std::pair<StringRef, Embedding> &Entry) {
+                       return Entry.second.size() == Dim;
+                     }) &&
+         "All vectors in the vocabulary are not of the same dimension");
+  return Error::success();
+}
+
+IR2VecVocabAnalysis::Result
+IR2VecVocabAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
+  auto Ctx = &M.getContext();
+  if (VocabFile.empty()) {
+    // FIXME: Use default vocabulary
+    Ctx->emitError("IR2Vec vocabulary file path not specified");
+    return IR2VecVocabResult(); // Return invalid result
+  }
+  if (auto Err = readVocabulary()) {
+    handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+      Ctx->emitError("Error reading vocabulary: " + EI.message());
+    });
+    return IR2VecVocabResult();
+  }
+  // FIXME: Scale the vocabulary here once. This would avoid scaling per use
+  // later.
+  return IR2VecVocabResult(std::move(Vocabulary));
+}
+
+// ==----------------------------------------------------------------------===//
+// IR2VecPrinterPass
+//===----------------------------------------------------------------------===//
+
+void IR2VecPrinterPass::printVector(const Embedding &Vec) const {
+  OS << " [";
+  for (const auto &Elem : Vec)
+    OS << " " << format("%.2f", Elem) << " ";
+  OS << "]\n";
+}
+
+PreservedAnalyses IR2VecPrinterPass::run(Module &M,
+                                         ModuleAnalysisManager &MAM) {
+  auto IR2VecVocabResult = MAM.getResult<IR2VecVocabAnalysis>(M);
+  assert(IR2VecVocabResult.isValid() && "IR2Vec Vocabulary is invalid");
+
+  auto Vocab = IR2VecVocabResult.getVocabulary();
+  auto Dim = IR2VecVocabResult.getDimension();
+  for (Function &F : M) {
+    Expected<std::unique_ptr<Embedder>> EmbOrErr =
+        Embedder::create(IR2VecKind::Symbolic, F, Vocab, Dim);
+    if (auto Err = EmbOrErr.takeError()) {
+      handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+        OS << "Error creating IR2Vec embeddings: " << EI.message() << "\n";
+      });
+      continue;
+    }
+
+    std::unique_ptr<Embedder> Emb = std::move(*EmbOrErr);
+    Emb->computeEmbeddings();
+
+    OS << "IR2Vec embeddings for function " << F.getName() << ":\n";
+    OS << "Function vector: ";
+    printVector(Emb->getFunctionVector());
+
+    OS << "Basic block vectors:\n";
+    const auto &BBMap = Emb->getBBVecMap();
+    for (const BasicBlock &BB : F) {
+      auto It = BBMap.find(&BB);
+      if (It != BBMap.end()) {
+        OS << "Basic block: " << BB.getName() << ":\n";
+        printVector(It->second);
+      }
+    }
+
+    OS << "Instruction vectors:\n";
+    const auto &InstMap = Emb->getInstVecMap();
+    for (const BasicBlock &BB : F) {
+      for (const Instruction &I : BB) {
+        auto It = InstMap.find(&I);
+        if (It != InstMap.end()) {
+          OS << "Instruction: ";
+          I.print(OS);
+          printVector(It->second);
+        }
+      }
+    }
+  }
+  return PreservedAnalyses::all();
+}
diff --git a/llvm/lib/Analysis/models/seedEmbeddingVocab75D.json b/llvm/lib/Analysis/models/seedEmbeddingVocab75D.json
new file mode 100644
index 0000000000000..65ca240deba13
--- /dev/null
+++ b/llvm/lib/Analysis/models/seedEmbeddingVocab75D.json
@@ -0,0 +1,65 @@
+{
+"add":[0.09571152, 0.08334279, 0.07070262, 0.14084256, 0.04825167, -0.12893851, -0.12180215, -0.07194936, -0.05329844, -0.28276998, 0.00202254, 0.07488817, -0.16139749, 0.07618549, -0.06084673, 0.10536429, -0.03031596, 0.16402271, 0.22730531, -0.0015432, 0.01986631, -0.15808797, 0.03030382, -0.04201249, 0.01689876, -0.30041003, -0.06479812, 0.1282431, -0.09032831, 0.14007935, -0.23540203, 0.00552223, 0.15325953, 0.13147154, -0.15204638, 0.1616615, 0.05758473, -0.1385157, 0.16438901, -0.14482859, 0.07895052, 0.18407233, 0.15283448, -0.00081216, -0.17934133, -0.16779658, 0.09044863, -0.18453072, -0.00552684, 0.01191218, 0.18504514, 0.13140059, -0.0174882, -0.18127315, 0.02269725, -0.02048657, 0.10858727, 0.0074029, 0.09485064, -0.13431476, 0.07491371, -0.17498694, -0.32914585, -0.14159656, -0.03594542, 0.04091231, 0.00298631, -0.08933277, -0.07178984, 0.04144038, 0.12151367, -0.09504163, 0.13691336, 0.07825345, 0.13958281],
+"alloca":[0.12644756, -0.20912014, 0.07298578, 0.13963142, 0.03932726, -0.12778169, -0.13084207, -0.09090705, -0.01497083, 0.0646746, 0.14847252, 0.08546949, -0.11579383, 0.07812478, -0.16431178, 0.08578802, 0.06094746, -0.1239017, -0.02789196, -0.01074964, -0.1738938, -0.1629063, -0.07137732, -0.02845656, 0.1728318, 0.13779363, -0.06250989, 0.03479109, -0.08423121, 0.14009888, 0.09620709, -0.02287545, -0.04616966, -0.19591278, -0.19636007, 0.21825573, 0.07949521, -0.14614704, 0.17752613, -0.15099092, -0.04518029, 0.17774306, 0.18947133, -0.00197501, -0.12619424, -0.18458585, -0.09960615, 0.01162648, 0.21306573, 0.0468024, 0.201505, 0.09970672, 0.06599383, 0.17757463, -0.11899275, 0.10299123, 0.06038174, -0.07116731, -0.15743989, -0.1258558, 0.1535076, 0.01872367, -0.14336765, -0.19708565, -0.26796287, 0.02628843, -0.0009325, -0.08809827, -0.12970725, 0.17223337, -0.10651242, -0.09162157, 0.03264611, 0.0911452, 0.09506542],
+"and":[-0.12902537, 0.07848564, 0.07048505, 0.13578993, 0.03570583, -0.1242408, -0.12619697, -0.06914084, -0.0515872, 0.13225996, 0.01673339, 0.0763608, 0.18325369, 0.07690141, -0.09591792, 0.10353354, -0.02401061, 0.16493416, 0.21942355, -0.00400911, 0.03811587, -0.15406959, -0.07134877, -0.02946596, -0.03854588, 0.28656727, -0.06625008, 0.12780443, -0.04631379, 0.13919763, -0.15808977, -0.00312698, 0.14692454, 0.18495218, -0.14863448, 0.13449706, 0.06471325, -0.13883992, 0.17630532, -0.16833898, 0.07391811, 0.17909151, 0.18229873, -0.00381102, -0.17680968, -0.1645554, 0.10016466, -0.07963493, 0.00130218, 0.05646244, 0.18222143, 0.10511146, -0.0191175, -0.08713559, 0.25423968, -0.02557301, 0.04319789, 0.03259414, 0.07209402, -0.13169754, 0.07424775, -0.17216511, -0.32057068, -0.13833733, -0.0658454, 0.02420194, -0.04393166, -0.08238692, -0.07023077, 0.04014502, 0.20101993, -0.09093616, 0.13076238, 0.09114857, -0.06483845],
+"ashr":[0.16414718, -0.02078147, 0.07353837, 0.14210321, 0.08068018, -0.13586298, -0.15728961, -0.10365791, 0.00359197, 0.04608767, 0.35770142, 0.08003625, 0.00944533, 0.08471741, 0.05809571, 0.09202059, -0.18349345, 0.22169511, 0.24418135, 0.19192688, -0.1956347, -0.17401719, -0.07583863, -0.02781139, 0.0952112, -0.01444751, -0.27259794, 0.14392436, -0.13541143, 0.1410963, 0.04314299, -0.01641751, -0.05448177, -0.22287542, -0.2131822, 0.25112826, 0.06918604, -0.14414005, 0.060288, -0.09658266, -0.09122665, -0.02779044, 0.20349248, 0.0041391, 0.10610974, -0.20890503, -0.09881835, -0.07368057, 0.22467837, 0.00075097, 0.2147348, -0.02612463, -0.01696278, -0.0649786, 0.15041149, 0.02361087, 0.0211603, -0.03706622, 0.18296233, -0.14298625, 0.14614436, 0.02273145, 0.0209446, -0.21062987, 0.16911499, -0.03668665, 0.00197532, -0.09607943, -0.08398084, 0.02006913, 0.05739584, -0.07919859, 0.19634944, 0.11082727, -0.06584227],
+"bitcast":[0.1675692, -0.12870269, 0.04048132, -0.1670965, -0.1279611, 0.02615386, -0.16829294, -0.09034907, 0.10913523, -0.07819421, 0.23986322, -0.05966561, 0.08410738, 0.19072439, 0.06047394, 0.02999627, -0.16747619, -0.06076627, -0.02673951, -0.1619169, 0.06443421, -0.13788716, -0.05644303, 0.01361013, -0.06858975, -0.06005004, 0.10011288, -0.05508338, -0.10613093, -0.11281271, -0.00758647, -0.12425531, 0.05333719, -0.16881412, -0.20088236, 0.06015657, -0.16405901, 0.06226884, 0.09171099, -0.09500738, 0.07907875, 0.0776544, -0.18457057, -0.11278627, -0.12111131, -0.10180638, 0.18328871, 0.18770072, 0.20346186, 0.10305139, -0.18344335, 0.10693213, -0.10920919, -0.05994263, 0.20354497, -0.03093485, 0.14214055, 0.00580597, 0.10480052, -0.09955201, -0.134185, -0.02904563, 0.00175069, 0.17646657, 0.01348841, -0.02030338, -0.06537742, 0.10032237, 0.15315783, 0.0102667, 0.07717734, -0.01060431, 0.14727928, -0.16261302, -0.06770234],
+"br":[0.11499645, 0.0824301, 0.07218035, 0.13258332, -0.13419574, -0.12916718, -0.12626709, -0.06741403, -0.02857593, -0.2543893, 0.02193022, 0.0760875, -0.1562702, 0.07712954, 0.3149361, 0.10217083, -0.041038, 0.16601022, 0.01906607, -0.02043359, 0.05471838, -0.15233372, -0.06945753, -0.02313732, -0.07342829, 0.3331809, -0.05246306, -0.0269839, -0.05435036, 0.13908924, 0.32604694, 0.00170966, 0.14997493, 0.13026518, -0.14908995, 0.12238151, -0.06773318, -0.13566032, 0.16068587, -0.12842499, 0.04970508, 0.17827724, 0.09729939, -0.00447832, -0.1739753, -0.16429187, 0.09886666, -0.08058207, 0.00714044, 0.04585538, 0.13424252, 0.11376464, -0.01675582, 0.17901348, -0.00653374, -0.01570439, 0.13032894, 0.01734108, 0.16833901, -0.1173776, 0.07662185, -0.15942436, -0.21173944, -0.10505079, 0.0597497, 0.03491669, 0.00338842, -0.04969047, -0.07644061, 0.04528612, 0.254365, -0.09514527, 0.12015092, 0.08262096, -0.02352029],
+"call":[0.10815012, -0.12419116, 0.18759736, -0.1905027, 0.01619313, -0.13483052, -0.12278763, -0.07051246, -0.0083437, 0.25107145, -0.16601063, 0.08127163, -0.17432374, -0.18380919, 0.24335551, 0.07208319, -0.04401246, 0.11606008, -0.02733191, 0.02098145, 0.019888, -0.13705409, -0.07569158, -0.03072285, 0.16870692, -0.09787013, -0.09340432, 0.01931342, -0.03557841, 0.14359893, -0.1592094, -0.00055867, 0.159316, 0.1099042, -0.11837319, 0.08741318, 0.03364393, -0.12831019, 0.10450637, -0.12699029, -0.20213994, 0.18390144, 0.11092624, -0.00209971, -0.13063665, 0.19996215, 0.09006448, -0.07840014, 0.22549215, 0.02587176, 0.13374338, 0.11009877, -0.01874998, -0.21446206, 0.02377797, -0.01036531, 0.05427047, 0.01418843, 0.00771817, -0.12639529, -0.10334941, -0.12244401, 0.30014148, -0.09857437, 0.21212636, 0.03429029, -0.04947309, 0.1023307, -0.07743628, 0.03006962, -0.24868701, -0.02357339, 0.11574048, 0.06895301, -0.363474],
+"constant":[-0.2850312, -0.22839, 0.12669143, -0.0674703, -0.12639391, -0.00477266, 0.04786542, 0.06336267, 0.08660185, 0.12805316, -0.07146342, 0.21539183, -0.0624397, -0.02638953, -0.28688517, 0.28374302, 0.05338082, 0.05559688, -0.13133128, 0.12440272, -0.03583231, 0.29848817, 0.13930812, 0.15453401, 0.0538353, -0.06874479, 0.00262802, 0.27964258, 0.19028014, -0.16371843, -0.05762961, 0.20059372, -0.20804578, -0.06549844, 0.09732475, -0.01551855, 0.21226783, 0.05889762, -0.07560658, 0.11312829, -0.04594622, -0.27309528, -0.05293005, 0.18953343, 0.05463868, -0.31045213, -0.04364616, 0.11005993, 0.12489324, -0.05413342, -0.05814561, -0.26131225, -0.18863814, 0.31165487, -0.08796364, -0.19958755, -0.10849535, 0.14899114, -0.01385941, 0.29359573, -0.01349372, 0.0562498, 0.10977754, 0.08993197, 0.06231657, -0.13509868, -0.20968516, 0.03578237, 0.15356435, -0.17766887, -0.11509016, 0.06898113, -0.06665445, -0.14065051, 0.34711906],
+"extractelement":[-1.62098512e-01, -2.00751424e-02, 1.71776459e-01, 1.38723463e-01, -1.60769299e-01, 9.30800363e-02, -1.24304645e-01, 1.45934001e-01, -5.04420400e-02, -7.54220188e-02, -5.30924797e-02, 8.55294541e-02, 1.17488159e-02, -1.82809234e-01, 9.37484950e-02, 8.38199258e-02, 1.26266479e-01, 9.31843743e-02, -2.26742271e-02, 6.50950940e-03, 5.02749532e-03, -1.14133619e-01, 1.80842891e-01, -9.63811725e-02, 1.67923152e-01, -5.84629439e-02, 1.04362026e-01, 8.92093012e-05, 7.93750137e-02, 1.39107972e-01, -8.40696543e-02, -1.59506593e-02, 1.99361086e-01, 1.93857521e-01, -1.46850392e-01, -1.78695560e-01, 9.88712162e-03, -1.40836969e-01, 1.77736521e-01, -1.61047727e-01, 3.51648539e-01, 1.79638579e-01, 1.49385989e-01, -6.06128015e-03, -1.72102928e-01, -1.81016047e-02, 1.01466164e-01, -1.28312945e-01, -8.05212185e-02, 6.28385469e-02, 1.15654446e-01, 1.91848025e-01, 3.03963851e-02, 3.55794169e-02, 1.40873834e-01, -1.44319711e-02, 1.85423180e-01, 1.16111919e-01, -7.47816712e-02, -1.14719503e-01, 1.02934733e-01, -1.83810964e-01, -2.64400076e-02, -8.99282843e-02, -1.90383971e-01, 7.31386840e-02, -4.36249487e-02, -4.71482053e-02, 1.07486300e-01, 1.09736443e-01, 4.15226035e-02, -1.42309800e-01, 8.96709636e-02, 6.64985999e-02, -6.13647103e-02],
+"extractvalue":[0.08820406, -0.0182279, 0.01493346, -0.17219813, 0.02927338, -0.17379265, -0.05663937, -0.06805898, -0.21235467, -0.01969833, -0.15152055, -0.18049374, 0.01062911, 0.07935719, -0.01993761, 0.12405304, -0.03198355, 0.13872959, 0.18017697, -0.0100032, 0.22617207, -0.21553156, -0.18403597, 0.10906533, 0.17709404, 0.07438782, 0.0875822, -0.22567064, -0.00636844, 0.06691552, 0.05859367, -0.06149556, 0.15721355, 0.01889951, 0.2164152, -0.07916643, -0.03927743, -0.02665933, 0.13756634, -0.08835335, -0.01159343, -0.19749148, 0.09438482, -0.1696074, -0.18197437, 0.19907822, -0.20855112, 0.21903005, -0.2204043, -0.07439119, 0.1308343, 0.10343243, -0.10401972, 0.02784402, -0.12545246, -0.18498465, 0.02385085, 0.22105947, -0.01296441, 0.19779074, -0.09320201, -0.07345647, -0.06985376, -0.0657003, -0.15406364, 0.14981052, 0.01336148, 0.18544021, -0.07248794, 0.0511543, -0.00308717, 0.01915094, 0.079139, 0.19975829, -0.06093699],
+"fadd":[0.0851364, -0.01757606, 0.20865884, 0.17407735, -0.17661206, 0.16181652, -0.11895371, -0.06142977, -0.05126655, 0.04448467, -0.03589934, 0.11921146, 0.0143434, -0.18255684, 0.05196553, 0.10967412, 0.15810761, 0.13785522, -0.01255003, -0.00134187, 0.03563518, -0.12446801, 0.18817455, -0.08609993, 0.1893248, 0.13434686, 0.25903776, -0.00467659, 0.09800702, 0.14749499, 0.03458502, -0.00238901, -0.1395337, 0.19306736, -0.11638073, 0.10491668, 0.04428702, 0.18128034, 0.1797104, -0.1929282, 0.07353631, 0.19062985, 0.10042762, -0.0040207, -0.18379262, 0.07060277, 0.09594815, -0.18272707, -0.12928157, 0.07631373, 0.13005428, 0.24108389, -0.01617561, -0.05803563, 0.02686582, -0.02223067, 0.21217403, 0.17594706, 0.00500477, -0.07345455, -0.08176229, -0.19486704, 0.02177307, -0.09052874, -0.14158368, 0.0890988, -0.06339125, -0.04612265, 0.10199347, 0.11777309, 0.07302366, -0.13303186, 0.09683178, 0.05031883, -0.05881981],
+"fcmp":[1.02981135e-01, -2.43355539e-02, 5.85255250e-02, 1.09401904e-01, -1.87941462e-01, 1.74530044e-01, -1.20533399e-01, -8.64934921e-02, -5.54629341e-02, 1.41877215e-02, 4.80354428e-02, 1.56707644e-01, 2.56910548e-02, -1.94340080e-01, 5.11265621e-02, 8.82050097e-02, 1.67082191e-01, 1.14665776e-01, -2.00159680e-02, -1.82088744e-02, 2.09244549e-01, -1.15076765e-01, 2.03621030e-01, -8.38057026e-02, -4.32270877e-02, 6.39017820e-02, -6.50197491e-02, -2.72039324e-03, 8.68055448e-02, 1.25798717e-01, -4.21847135e-01, 2.64590848e-02, 1.56372517e-01, 2.14883089e-01, -1.12701654e-01, 9.43767577e-02, -1.97456375e-01, -1.72886148e-01, 2.04119727e-01, -1.56766623e-01, 7.38008767e-02, 2.05716744e-01, 3.48394439e-02, -2.48072352e-02, -2.03255862e-01, 5.07165631e-03, 1.12850599e-01, -1.94697857e-01, -6.29984289e-02, 8.21878910e-02, 1.23685144e-01, 1.40430763e-01, -2.20402889e-02, -6.55216798e-02, 2.90598303e-01, -7.66792744e-02, 2.16097474e-01, 6.28568381e-02, 2.69129931e-04, -1.17002167e-01, -1.60454452e-01, -2.07048669e-01, 2.62669493e-02, -9.61467475e-02, -1.88501909e-01, 8.80606323e-02, -5.39420024e-02, -5.08916602e-02, 1.09891914e-01, 1.21375419e-01, 5.10863326e-02, -1.43003076e-01, 8.39024931e-02, 9.51330177e-03, -6.65674359e-02],
+"fdiv":[-0.14435205, -0.02003789, 0.07479589, 0.13465217, -0.18792528, 0.16504793, -0.12187403, 0.00537306, -0.04864043, 0.04958175, -0.14890797, 0.10156095, 0.01710029, -0.1809697, 0.06765524, 0.18452686, 0.16923915, 0.11264159, -0.01412142, -0.00287484, 0.01297035, 0.06755029, 0.18517323, -0.08975757, 0.16194478, 0.04174679, 0.10903918, 0.00072231, 0.10999232, 0.14989018, 0.05669819, -0.00733533, 0.20606744, 0.22580206, -0.14587933, 0.13480443, 0.05984581, -0.19580479, 0.20258778, -0.17146486, 0.07523733, 0.19139282, 0.03738374, -0.01550991, -0.21507922, 0.07425626, 0.10224851, -0.18437587, -0.06662318, 0.07977687, 0.12355862, 0.1434375, -0.01888226, 0.03870944, 0.07555477, -0.01191964, 0.23488866, 0.06922436, -0.07203218, -0.06884275, 0.07191673, -0.19515742, 0.02168754, -0.08983592, -0.20972523, 0.08903123, -0.05095004, -0.04967143, 0.0985181, 0.15771264, 0.09441628, -0.14769785, -0.16405083, 0.05066825, -0.058015],
+"floatTy":[-0.04556743, 0.03822431, -0.08842288, -0.12055657, 0.0960574, 0.2371231, 0.09947137, 0.11064581, -0.12371849, -0.06109007, 0.06440615, 0.14924356, 0.13218448, -0.04400141, 0.01761996, -0.13240574, 0.21056518, -0.14215694, -0.14700417, -0.16416645, -0.07137518, 0.05240471, -0.10071051, 0.12556827, 0.08208757, 0.06504779, 0.1578807, -0.09501757, 0.00659264, -0.00527758, -0.01085964, -0.17290565, 0.00501871, -0.10288252, 0.09658113, -0.107755, -0.1718967, 0.16306138, -0.080802, 0.10203532, -0.02934794, -0.02899184, -0.17915869, -0.19883338, -0.05124965, 0.16747124, -0.05587617, 0.14325564, -0.18054038, -0.161391, -0.1149613, 0.01600737, -0.0704658, 0.01935361, -0.04516762, -0.1305524, 0.04487818, -0.07881694, -0.18929696, 0.05364102, -0.17827097, 0.09934752, -0.04212811, 0.15036745, -0.18782069, 0.19947147, 0.1102478, -0.1304183, 0.17145109, 0.22485495, 0.02270225, 0.08804839, -0.12520337, -0.07780997, 0.00057234],
+"fmul":[-0.05690098, -0.02700638, 0.20705073, 0.16630849, -0.17719169, 0.16012336, -0.12955493, 0.19698587, -0.04035136, -0.03197788, 0.08116172, 0.1013689, 0.01416616, -0.17855197, 0.15503113, 0.13990149, 0.15355295, 0.12397105, -0.01912402, 0.01684221, 0.00669227, -0.11869009, 0.17604592, -0.05788622, 0.10467764, -0.0807798, 0.10300152, 0.10780353, 0.08334652, 0.1446782, 0.03546653, -0.00421023, 0.19682531, 0.19603632, -0.1466306, 0.12923796, 0.06296455, -0.14397427, 0.183406, -0.19625223, 0.08244827, 0.1860209, 0.10110238, -0.002166, -0.18034802, 0.06406105, 0.09568714, -0.17962225, -0.05463478, 0.04498994, 0.11928298, 0.1694295, -0.01222703, 0.14453876, 0.13506988, -0.01149808, 0.20273286, 0.05309585, -0.07139173, -0.07370458, 0.09957068, -0.19369006, 0.02577178, -0.09011577, -0.21375039, 0.07624438, -0.04969844, -0.04844297, 0.08409201, 0.11113621, 0.14570779, -0.13936704, 0.07202481, 0.05272412, -0.05747499],
+"fneg":[-0.04075071, -0.09381824, 0.17104743, 0.0744117, -0.15771168, 0.16444896, -0.11586417, 0.00200867, 0.17323531, -0.10421973, -0.05619403, 0.07496857, 0.05573901, -0.18903743, 0.06586835, 0.03499747, 0.17244707, 0.02476844, -0.02552369, 0.00063759, 0.04312319, -0.04501259, 0.1850581, -0.14339973, -0.04433612, 0.01609048, 0.10461161, -0.12243931, 0.07718915, 0.15313269, 0.12116063, -0.03062805, 0.21040255, 0.21582894, -0.10389283, 0.09344483, -0.20219979, -0.20113027, 0.19945832, -0.17248249, 0.07845841, 0.19814597, 0.06085683, -0.02476168, -0.18729973, 0.0674377, 0.1058675, -0.04973035, -0.10124692, 0.12834774, 0.0900365, -0.17527112, 0.09901146, -0.05764115, 0.03708475, 0.13003437, 0.2325445, 0.19712777, -0.07403741, -0.05580256, 0.18192469, -0.19122703, -0.05592606, 0.09128745, -0.15161441, 0.08734331, -0.0963953, -0.0377482, 0.18287936, 0.16522603, 0.03490613, -0.13519889, 0.08505893, 0.02470117, -0.06158587],
+"fpext":[0.1312062, -0.0272035, 0.1562131, 0.11956131, -0.18370572, 0.16904335, -0.18538451, -0.0905571, -0.05687085, -0.12067703, 0.15717801, 0.06977441, 0.04604319, -0.18692835, 0.07965986, 0.03840762, 0.17120989, 0.03048515, -0.02593113, -0.02722386, 0.0637762, -0.08012746, 0.03968937, -0.09751038, -0.04150679, -0.05797326, 0.09053179, -0.06100635, 0.01466092, 0.1521789, 0.0178679, 0.00468684, 0.09077137, 0.22244066, -0.21890686, 0.09471557, -0.18849488, 0.06589299, 0.20329474, -0.20006016, 0.06712949, 0.19578859, -0.00594554, -0.03142307, -0.18011327, 0.00516408, 0.18754548, -0.18884791, 0.2184627, 0.09512166, 0.07513344, 0.12641825, -0.0237517, -0.06020509, 0.15404698, -0.02384854, 0.22717056, 0.11279562, 0.16759154, -0.09342691, -0.09703359, -0.19393681, -0.06580188, 0.190172, -0.21666776, 0.09756065, -0.06633368, -0.04663929, 0.16539453, 0.16365078, 0.04338961, -0.1387515, 0.07042016, 0.03850469, -0.06256048],
+"fptosi":[-0.09471355, -0.01413281, 0.20098655, 0.17478812, -0.0103814, 0.11870264, -0.10561193, 0.19406088, -0.04215302, 0.09856935, -0.05858651, 0.11069191, -0.02667271, -0.17638545, 0.00591833, 0.12538631, 0.1609231, 0.143028, 0.00411847, 0.06113226, -0.1577999, -0.12172183, 0.18763137, -0.04490714, 0.0262733, 0.12005143, 0.08305117, -0.00109107, 0.03972085, 0.13256785, 0.12486281, -0.00920427, 0.19794717, 0.13488762, -0.08073806, 0.11790548, -0.1865304, -0.18761554, 0.15602915, -0.1440169, -0.01538679, 0.18490645, 0.05900477, -0.01250085, -0.17872328, 0.07583775, 0.09906318, -0.16909951, -0.12062778, 0.03089247, 0.11974704, 0.23940024, -0.00561649, 0.03862159, 0.13437317, -0.0128777, 0.2149731, 0.07683202, -0.10922348, -0.04304254, -0.20104879, -0.16371554, -0.08326109, -0.08942039, -0.03989649, 0.07596397, 0.18141732, 0.08706582, -0.06605583, 0.09984156, -0.05919264, -0.13918152, -0.11102735, -0.04074531, -0.05989955],
+"fptoui":[0.13186027, -0.02009563, 0.05399049, 0.22092278, 0.0764356, -0.12116565, -0.10575569, -0.08263665, -0.05279351, 0.00392524, -0.06554782, 0.15926358, 0.01012308, -0.18726377, 0.02134197, 0.12730621, -0.05603928, 0.1433069, -0.21253656, -0.1455532, 0.23767456, -0.13623604, 0.21878564, -0.05533312, -0.02895407, 0.03911315, -0.2773476, -0.00738798, 0.08483762, -0.14270262, 0.04603437, 0.21681121, -0.20425414, 0.12532364, -0.04144387, -0.1759266, 0.06860236, -0.14378744, 0.16322674, -0.09162073, -0.04966446, 0.1867569, 0.11250684, 0.04158355, -0.20126882, 0.0963328, 0.06281191, -0.17627244, -0.16096021, 0.00596877, 0.12892367, 0.2650723, 0.0032763, -0.05754196, 0.14840715, -0.09938947, 0.13039768, 0.04905574, -0.04759435, -0.18545668, -0.22984591, -0.22227132, -0.02666637, -0.09771203, -0.15587328, 0.07147411, 0.21007161, 0.09932306, -0.06597851, 0.04478595, -0.00686691, -0.14754876, -0.16366987, -0.22182341, -0.05699158],
+"fptrunc":[0.1180348, -0.01865118, 0.19759397, 0.00099745, -0.20069243, 0.15863162, -0.10404988, -0.03822596, -0.04113388, 0.02389156, -0.15024376, 0.10156121, 0.01125149, -0.17805247, -0.01032893, 0.11541142, 0.16151612, 0.08652765, -0.01421094, -0.02742836, 0.03890061, 0.16992694, -0.19120258, -0.08296357, 0.16136265, 0.13252915, 0.08675185, -0.05066127, 0.14796199, 0.16224207, 0.07839199, -0.0724185, 0.17859218, 0.20112462, -0.11284997, 0.04566038, -0.19799039, -0.17690767, 0.18034197, -0.14002973, -0.0558032, 0.18783137, -0.14857374, -0.03776158, -0.21491641, 0.04907086, 0.10290487, -0.17882703, -0.06566726, 0.09571292, -0.1965507, 0.1673165, -0.03019422, 0.04259395, 0.10474471, -0.01224911, 0.2133804, 0.08484804, -0.01221132, -0.04942748, -0.06522352, -0.16705054, -0.07432696, -0.01365143, -0.14369024, 0.09237107, -0.06833915, -0.04292256, 0.10805372, 0.10829192, -0.04953781, -0.16152975, 0.08096681, 0.12343118, -0.04967185],
+"freeze":[-0.10947239, 0.16156663, 0.0653074, -0.16102187, 0.05866997, -0.11313032, 0.18013522, 0.00849657, -0.13109621, 0.00250287, 0.12335391, -0.19474623, 0.00160397, 0.18526912, -0.02094408, 0.10131565, -0.17163642, 0.1624736, 0.20699912, 0.1198829, -0.15380894, -0.13946483, -0.0666218, -0.02034315, 0.06200019, 0.04227962, 0.07729523, 0.1244237, -0.07141764, 0.12154905, 0.0300131, 0.01618693, 0.13966976, 0.08918943, -0.07834358, 0.19349128, -0.06925047, -0.11661758, 0.01764905, -0.06631834, -0.19618054, 0.07797705, -0.18398666, -0.08675893, -0.14833811, -0.1468038, 0.18818453, -0.06729261, -0.00497526, -0.08958972, 0.16964634, -0.10325264, -0.10212341, -0.04745837, 0.12241088, -0.03629779, -0.00606445, 0.01766711, 0.0036858, -0.10732682, -0.13172524, -0.10182981, -0.06431175, -0.13082966, 0.04738441, 0.02668242, 0.15197244, -0.12880892, -0.06579075, 0.03165649, -0.00145413, -0.02683991, 0.13963282, -0.14597963, -0.05104417],
+"fsub":[-0.15878558, -0.01853204, 0.07496438, 0.13546987, -0.1904581, 0.16564278, -0.1120265, -0.05418859, -0.08075086, 0.1190263, -0.030006, 0.07342444, 0.01767328, -0.18650489, 0.04966565, 0.17190282, 0.1616953, 0.10582477, -0.00931773, 0.00157398, 0.00862398, 0.08480153, 0.17171694, -0.0916861, 0.17196383, 0.03703162, 0.11399966, -0.12855959, 0.05810672, 0.15144408, 0.05618297, -0.00800864, 0.20814295, 0.20056027, -0.1153914, 0.10849892, -0.1970011, -0.1813781, 0.1921156, -0.16984123, 0.07333071, 0.19433162, -0.01313439, -0.02830642, -0.17687869, 0.05937865, 0.1070236, -0.18605019, -0.07227098, 0.10597191, 0.1225975, 0.12388534, -0.02131494, -0.02420847, 0.00146665, -0.01353394, 0.22151577, 0.19731705, -0.07575841, 0.08710405, -0.07411117, -0.17442936, -0.1831972, -0.0886184, -0.17084508, 0.10038229, -0.06385624, -0.04644644, 0.10368951, 0.12130242, 0.24595715, -0.14661786, 0.09260331, 0.0455667, -0.05950425],
+"function":[-0.08280793, -0.18925415, -0.1866685, -0.04932962, 0.13478681, 0.203617, 0.05739383, 0.09856346, -0.17600478, 0.07619468, -0.12438924, -0.02529626, -0.07468224, 0.03905433, 0.11325707, -0.04229602, -0.16354711, -0.08952031, -0.15966323, 0.11114867, 0.07319006, 0.02678379, -0.13364255, 0.15032487, 0.0822423, 0.03195171, -0.00871139, -0.1128016, 0.19261838, -0.07204764, -0.05823177, 0.1990249, -0.2057403, -0.08260711, 0.09775644, -0.12436705, 0.15814295, 0.0463977, -0.0493853, 0.1450742, -0.07108644, -0.03192589, -0.11917686, -0.19753116, 0.09248564, 0.13522607, 0.16347136, 0.11065657, -0.0850426, -0.19110996, -0.15060848, -0.25829738, 0.11464069, -0.15613398, -0.07256057, 0.16283846, -0.11428182, -0.1879146, -0.10537492, 0.03637636, -0.02642156, 0.0344548, -0.00722412, 0.13349552, 0.05913915, 0.17941767, -0.20852967, 0.04403022, -0.13914339, -0.17848521, -0.07228794, 0.23070297, -0.11848032, -0.14098541, -0.23762096],
+"getelementptr":[0.09870283, 0.07089636, 0.07129486, 0.13141522, 0.0512748, -0.12164738, -0.10822044, -0.06830852, -0.03589667, 0.23281692, 0.00221914, 0.07347875, -0.14414017, -0.1762956, 0.2280886, 0.09720317, -0.02157139, 0.1186724, 0.16809724, 0.01354192, 0.00843806, -0.1289462, -0.06982945, -0.03921828, 0.11689314, -0.27946517, -0.06115843, 0.0435549, -0.04346889, 0.13182928, -0.13756175, -0.00165133, 0.14864644, 0.1256485, -0.10831792, 0.1638358, 0.05359713, -0.12713233, 0.15040766, -0.14046451, 0.06688947, 0.17097251, 0.11004995, 0.00303981, -0.17120391, -0.15561967, -0.0996208, -0.07566627, -0.0092614, 0.03340579, 0.12288038, 0.11154807, -0.01677553, 0.161112, 0.01968472, -0.01360116, 0.05185669, 0.03974737, 0.08288419, -0.11881893, 0.09566113, -0.14562541, 0.27193576, -0.08737413, -0.13493136, 0.06975145, -0.01905861, -0.04629398, -0.06382514, 0.03648283, 0.32102475, -0.07868497, 0.11246872, 0.06408555, 0.21986632],
+"icmp":[0.10752141, 0.08221146, 0.07407488, 0.13139327, -0.17970721, 0.02754223, -0.13538423, -0.06698897, -0.02524848, 0.29738554, 0.00894943, 0.07728788, 0.01191065, 0.07896648, 0.26208735, 0.10498706, -0.03250087, 0.1684631, 0.23128033, 0.00553169, 0.05936556, -0.15531996, -0.06056314, -0.03261358, 0.09216364, -0.31626984, -0.07434817, 0.12870958, -0.08664963, 0.14354071, 0.2156426, -0.0043262, 0.16025512, 0.13890502, -0.153901, 0.12319393, 0.01295959, -0.14369431, 0.17033054, -0.12931693, 0.07678536, 0.19203088, 0.11493351, -0.00601692, -0.18671934, -0.16845967, 0.11059918, -0.08381938, -0.00690406, 0.04286021, 0.13590424, 0.12681794, -0.01967513, -0.21233313, 0.02998303, -0.01612004, 0.17794448, 0.02153118, 0.09134272, -0.12414944, 0.08073039, -0.17339677, -0.0417021, -0.1026428, -0.0270442, 0.02959586, -0.05658696, -0.05483485, -0.07289126, 0.036765, 0.20820136, -0.0922353, 0.1438483, 0.06928346, -0.37188163],
+"insertelement":[-0.08810953, 0.19707826, 0.23040843, 0.15133125, -0.22085261, 0.18197243, -0.13767323, 0.00611759, -0.03750934, 0.05303819, -0.00140541, 0.13628025, 0.01222425, -0.19765897, 0.02197562, 0.17957552, 0.17369562, 0.13818526, -0.01018569, 0.07335348, -0.00122391, -0.05268616, 0.03798695, -0.07208619, 0.13593383, -0.08763747, 0.10625125, 0.12024429, -0.01286297, 0.16619073, 0.03609107, 0.00169814, 0.21330379, 0.22023544, -0.11971844, 0.23055589, -0.21922874, -0.18983133, 0.21032487, -0.19545083, 0.39695147, 0.2116961, 0.03465794, -0.01642283, -0.23929499, 0.05254361, 0.1186865, -0.20114459, -0.01001151, 0.06816892, 0.13270052, 0.13516793, -0.02193176, 0.13708963, 0.15222688, -0.01366894, 0.22591114, 0.07127486, -0.08461929, -0.08140475, 0.06961198, -0.18172547, 0.03001983, -0.09530003, -0.03038635, 0.09877217, -0.06264398, -0.06664777, 0.08449566, 0.13536829, 0.04701871, -0.1011354, 0.08900025, 0.0484806, -0.0840841],
+"insertvalue":[-0.18927452, 0.0174884, -0.14182499, 0.13622768, 0.0860026, 0.09214608, 0.19103362, -0.21386355, -0.08520557, 0.0039752, 0.11396001, -0.20266375, 0.17875974, -0.19441572, 0.06652557, -0.1076987, -0.15872131, -0.20631677, -0.06141828, 0.01331364, 0.02354101, 0.08883859, 0.18617646, -0.1524484, -0.00485444, -0.06658852, -0.06168855, -0.15898797, 0.02933339, -0.19443747, -0.08171376, -0.10284599, -0.14775087, 0.20585667, -0.03085143, -0.20518455, 0.05644068, 0.18632361, -0.14686832, 0.03718346, 0.10764548, -0.01129938, 0.19590198, 0.02194332, -0.04761516, 0.0276675, 0.01006511, -0.05134218, -0.10854474, 0.23528893, 0.09621219, -0.17192629, 0.10312149, -0.14351319, 0.15347119, 0.19321586, -0.20537563, 0.19100618, 0.11280359, 0.07242113, 0.18901348, 0.19133772, 0.02062779, -0.07726028, 0.00578185, -0.02625765, -0.10374335, -0.02086248, 0.18915856, 0.00862997, 0.04699488, -0.0631949, 0.18942626, 0.01894571, 0.02351614],
+"integerTy":[-0.02392217, 0.13147527, -0.12684862, -0.00286194, 0.18320721, -0.03383226, 0.10688385, 0.20315196, 0.16910973, 0.01749469, 0.09163074, 0.18359211, 0.08457439, 0.17821081, -0.01359864, -0.09173124, -0.1060688, -0.0317139, 0.089481, -0.13937937, 0.1258349, -0.00968946, -0.00211832, -0.13140695, -0.11206195, -0.0249014, -0.09646855, 0.16041876, -0.20260467, -0.1008801, -0.02906649, -0.148828, -0.01750175, -0.10806648, 0.10094456, -0.09347772, -0.11941694, 0.0714565, -0.13869469, 0.09965917, -0.02859109, -0.04663063, -0.03677037, -0.17767252, 0.19819601, -0.00728577, -0.07156438, 0.14130634, -0.16161495, -0.14514765, -0.0230404, 0.14609018, 0.12496789, -0.02587292, 0.06375326, -0.1703029, -0.14651431, -0.15148057, -0.11655853, 0.00689279, -0.21302195, 0.10692985, 0.00105841, 0.05685481, -0.05294221, 0.13358746, 0.17953119, 0.01200722, 0.00904744, 0.13893746, -0.01024614, 0.14703822, -0.08035436, 0.18355256, -0.00407319],
+"inttoptr":[0.04721976, 0.16880296, 0.06448112, -0.17660472, 0.02998716, -0.1156636, 0.13852204, -0.06320232, -0.03162635, -0.06644673, -0.136013, -0.06916367, -0.02801188, 0.10646518, 0.05828808, 0.03782522, -0.02227561, 0.02234134, 0.16369314, -0.08557447, 0.03853939, -0.14319475, -0.05599201, -0.01060566, -0.1136315, 0.0201032, 0.01836221, -0.05016, -0.1216938, 0.12626994, 0.03450989, -0.19574732, 0.14352062, -0.17880194, -0.13339539, -0.04630446, 0.03136644, -0.13006681, 0.1445991, -0.09556036, 0.09764113, 0.16694036, 0.09833785, 0.05145761, 0.17970908, -0.14575475, -0.13704927, -0.06876626, -0.00955433, -0.16089469, -0.14152728, 0.1012365, -0.18291287, -0.07371435, -0.13809073, 0.02210419, 0.090786, 0.02507522, 0.15311833, -0.11663677, 0.10619268, 0.1758742, -0.04052401, 0.19525726, 0.15682434, -0.19402866, 0.08792165, 0.19677114, 0.1986662, -0.2065629, 0.04007441, -0.01697999, 0.17015004, 0.07224851, -0.06042317],
+"invoke":[0.11604629, -0.02348489, -0.11863736, -0.16840768, -0.01534824, -0.13232489, -0.09663513, -0.1576129, -0.2348036, 0.00802987, -0.0517984, -0.05321365, 0.01174416, -0.11655734, 0.05259984, -0.16816719, -0.09482966, -0.00228002, -0.12152751, -0.00498575, 0.03465938, -0.02950593, 0.04545004, -0.2172498, -0.07073424, -0.08918925, 0.0623108, -0.20881031, -0.04182759, -0.20031597, -0.1351732, 0.069332, -0.00361818, 0.11065516, 0.13967985, -0.08796342, -0.00256544, -0.11508698, 0.09178918, 0.2073513, 0.04010937, -0.07716485, 0.06940974, 0.20694868, -0.08160415, 0.1820004, -0.12159622, 0.04531517, -0.00216078, -0.11625812, -0.10868325, 0.11549117, 0.19036727, 0.0365869, -0.09580094, 0.22367325, 0.11756624, -0.2184826, 0.27060437, 0.14232084, 0.01686368, -0.10716032, 0.02151413, -0.02634864, 0.19014603, -0.22087607, -0.05267305, -0.2422757, -0.06234193, -0.0299236, 0.01296355, 0.0901266, 0.09916983, -0.00811885, -0.02482844],
+"label":[-0.06294985, -0.07393633, -0.07793023, 0.19617933, -0.25141802, -0.16856542, 0.05546749, 0.2207709, -0.12299901, -0.10727913, -0.04701709, -0.05162717, 0.2220566, 0.14470658, -0.07780463, -0.02452197, 0.21929401, 0.10171317, -0.09900579, -0.11624218, -0.21602261, 0.11818817, 0.23674524, -0.0676048, -0.15250057, -0.06562828, 0.14570533, -0.0063743, 0.12755615, 0.18377739, -0.05544094, -0.03191924, -0.12098482, -0.04439923, 0.0412157, -0.13413347, -0.03934726, 0.04211318, -0.02061427, 0.04409805, -0.06535667, -0.10373748, -0.11245634, -0.07654405, 0.1734968, -0.01024228, -0.05300638, 0.08171037, 0.1142247, 0.13233529, -0.04136537, -0.00692873, -0.13803534, 0.0900873, -0.18191165, 0.05589029, -0.05146271, -0.11442295, 0.17379795, 0.11092487, 0.18033165, 0.03263773, -0.09051663, 0.05547883, 0.09321848, -0.13325489, 0.07476224, -0.16582265, -0.14871986, -0.11099493, 0.08359679, -0.2101298, -0.05699859, -0.08379642, 0.10380454],
+"landingpad":[0.12086448, 0.16615215, -0.11424457, -0.08484724, -0.09069939, -0.15767984, 0.10221493, -0.17647022, -0.18533581, -0.02190816, 0.1541339, -0.15779817, 0.03144602, -0.10866319, -0.01497394, -0.1721984, -0.07559271, -0.11889227, -0.1177194, -0.02792813, 0.04734257, -0.03713308, -0.17093344, 0.17252314, 0.02917121, 0.01523044, -0.08545186, -0.20184867, -0.08280238, -0.04850229, 0.03705949, 0.07665683, 0.01846915, 0.00205453, 0.1709319, -0.10548064, -0.07096241, 0.12575251, -0.1177155, 0.17698564, 0.03965896, -0.10821396, 0.07917166, 0.17810985, 0.01715738, 0.16967225, -0.16826203, 0.16891196, -0.15257767, 0.10498544, -0.10490264, 0.06432237, 0.18670914, -0.00099873, -0.13853344, 0.21604276, 0.13351974, -0.15664832, -0.08585881, 0.1024329, 0.02737338, 0.11940238, -0.01797596, -0.00314033, 0.12023867, 0.11616865, 0.05652065, 0.1415307, -0.15827312, -0.03440882, 0.02146849, 0.01478402, -0.13532415, -0.02099262, 0.00462938],
+"load":[0.06383128, 0.0803676, 0.07070765, 0.1284488, 0.053152, -0.11878661, -0.09626942, -0.05779593, -0.04309646, -0.31707463, -0.01623556, 0.0741919, -0.0051238, 0.07403108, -0.25466156, 0.09440999, -0.01665624, 0.14732535, 0.17144501, -0.00878042, 0.04688795, -0.15015227, -0.06462591, -0.04178058, -0.0378243, 0.33024567, -0.07477789, -0.04902143, -0.0476392, 0.13162148, -0.17537315, -0.01750547, 0.14473993, 0.1732234, -0.1423584, 0.11269526, 0.03678195, -0.1315726, 0.15341991, -0.10186778, 0.00435855, 0.16657132, 0.17959148, -0.00966169, -0.16982812, -0.02318787, 0.09485581, -0.07465204, -0.06222337, 0.01743078, 0.12776802, 0.09864764, -0.01487866, 0.03529362, 0.13232034, -0.01328148, 0.09440556, 0.06241368, 0.03618008, -0.11342508, 0.09918994, -0.15651965, -0.07195813, -0.09057574, -0.10321549, 0.06875013, -0.00129774, -0.04545839, -0.07164564, 0.05073486, 0.34142092, -0.08255292, 0.12089149, 0.08211686, 0.21363957],
+"lshr":[0.1238757, -0.02033522, 0.05549098, 0.11646183, 0.08761991, -0.12349915, -0.18941326, -0.08920491, 0.09122052, 0.03471606, 0.2897465, 0.07269037, 0.01238082, 0.07473343, 0.02699653, 0.08085709, -0.04658483, 0.2076412, 0.22355735, -0.03676752, 0.18093167, -0.15845503, -0.0710993, -0.02861892, -0.24865082, -0.00123379, -0.23955399, 0.13371961, -0.11877617, 0.07246234, 0.01312172, 0.01923358, -0.04966315, 0.1200467, -0.2137276, 0.10946998, 0.07409713, -0.12598129, 0.02809012, -0.09355168, 0.06742698, 0.08053191, 0.18937954, 0.00296521, 0.10038757, -0.19544551, 0.08368544, -0.07828917, 0.20687084, 0.01422358, 0.19612609, 0.03323235, -0.01736557, -0.2952406, 0.15087438, -0.07250606, 0.01719518, -0.01060284, 0.16445734, -0.16287296, 0.07179926, -0.14751296, 0.02352273, -0.17620452, 0.12871586, 0.01027796, -0.00240841, -0.08637159, -0.07440444, 0.02873684, 0.05644969, -0.07749362, 0.17137784, 0.09177881, -0.06086624],
+"mul":[9.14543942e-02, 7.25680292e-02, 1.87143609e-01, 1.56122670e-01, 8.18791837e-02, -1.13938227e-01, -1.17102735e-01, 1.78440675e-01, -5.71394851e-03, 3.98688577e-02, -1.22035742e-02, 9.62941721e-02, 9.87940375e-03, 6.54331893e-02, -1.18242744e-02, 1.01057030e-01, -3.37237865e-02, 1.82104349e-01, 1.98254153e-01, 4.89455797e-02, -1.38579145e-01, -1.43827185e-01, -7.30315745e-02, -2.81286202e-02, -3.69295813e-02, -7.32784346e-02, -7.52561465e-02, 1.15158796e-01, -8.05188417e-02, 1.22851163e-01, 1.18959583e-01, -6.19116612e-03, 1.14142060e-01, 1.15443885e-01, -1.32043362e-01, 1.91231743e-01, 6.71850219e-02, -1.18121214e-01, 1.39134541e-01, -9.38180089e-02, 7.00822175e-02, 1.52467072e-01, 1.72531351e-01, 2.39370289e-04, 8.84519666e-02, -1.74602866e-01, 7.58597329e-02, -7.24562407e-02, 2.30801646e-02, 2.31582299e-02, 1.77945897e-01, 2.19754413e-01, -1.05254715e-02, -5.34405783e-02, 1.28701046e-01, -8.88467114e-03, 2.39838846e-02, -2.52107698e-02, 4.09773886e-02, -1.43636853e-01, 9.37281698e-02, -1.36706889e-01, 3.18117648e-01, -1.72676995e-01, 9.86104552e-03, 1.59371197e-02, -2.31163911e-04, -7.84823969e-02, -7.37200677e-02, 3.27852108e-02, 1.85986701e-02, -7.93214887e-02, 1.19079717e-01, 9.70832258e-02, -5.25254011e-02],
+"or":[-0.15830125, 0.08118854, 0.06019896, 0.1351512, 0.0696514, -0.12829824, -0.12040509, -0.07483122, -0.05365232, -0.21453764, 0.01100464, 0.07939477, 0.01512126, 0.07680329, 0.20671816, 0.10159217, -0.03416578, 0.18844754, 0.2232867, 0.00390219, 0.17268041, -0.16189471, -0.07818128, -0.02745846, -0.03785938, -0.28434664, -0.23963155, 0.13414037, -0.03098747, 0.1290441, -0.04272285, 0.00627589, 0.15120292, 0.13505426, -0.14509544, 0.1633035, 0.07651295, -0.1345261, 0.15650204, -0.10334036, 0.08041331, 0.17568573, 0.18555732, -0.00240171, 0.09882613, -0.1697568, 0.08491044, -0.07938255, -0.00502023, 0.04242367, 0.19246665, 0.10571583, -0.01717717, -0.0940207, 0.19319834, -0.06771892, 0.03723063, 0.00987004, 0.08289062, -0.14470372, 0.07547856, -0.14796427, 0.03079064, -0.18788183, -0.06784894, 0.02374648, 0.00680319, -0.08787614, -0.0762485, 0.04015802, -0.31986576, -0.08643831, 0.14352895, 0.1116055, -0.09564826],
+"phi":[-0.17533, -0.14122052, 0.25121832, -0.20197222, -0.02265841, 0.08878156, -0.12254399, -0.05334119, 0.17813319, 0.25582585, -0.24652013, 0.08741698, -0.20831233, -0.12509026, -0.19707216, 0.15587404, -0.07037015, 0.00634299, 0.02692973, 0.20398706, 0.09076547, 0.2106457, 0.02665563, -0.01256549, 0.20547326, -0.01408568, -0.11248078, 0.17035946, 0.00720961, -0.24428545, -0.19424082, 0.02588499, -0.09168262, 0.12671804, -0.13895495, 0.11016023, 0.06885135, -0.1585114, 0.1442796, -0.09209647, -0.25246575, -0.18171434, 0.07803512, 0.01651475, -0.05719611, -0.18895395, 0.13336438, -0.09516547, 0.04140934, -0.13787958, 0.14149408, -0.15089944, -0.02157312, 0.2192603, 0.02856141, -0.05521443, 0.0077216, 0.2731221, -0.09575493, 0.2032519, -0.12885517, -0.18518618, 0.16917716, -0.11144329, 0.25175345, -0.30578047, -0.07883886, 0.14204925, 0.26059705, 0.01635692, -0.2599762, 0.1671248, 0.07727495, 0.06118969, 0.27382395],
+"pointer":[0.01122629, 0.03439064, 0.12280786, -0.03425089, 0.17276576, 0.21717595, 0.09126496, -0.17714174, 0.27793115, 0.08274158, -0.08821795, -0.16903219, -0.06300986, -0.23226759, 0.1235508, -0.11923615, -0.21793933, -0.17721081, 0.07182363, 0.27753174, 0.0920836, 0.06713749, -0.04808864, 0.15279293, 0.05296317, 0.04695908, -0.00205181, -0.14607918, 0.177891, -0.01903534, -0.05020404, 0.20370306, 0.03707821, -0.08771795, 0.10304545, 0.13130909, 0.18650576, 0.05210593, -0.09720453, 0.14389311, -0.05903525, 0.01644695, -0.11466363, 0.18700723, 0.07347484, 0.13623913, 0.13876125, 0.10103971, 0.11578573, -0.21065098, -0.07865446, -0.02068869, 0.16991298, -0.16359806, -0.07672877, 0.11908785, -0.14677979, 0.16077666, -0.21696989, 0.03678338, -0.02173937, 0.08764295, 0.18778177, 0.0974953, 0.05379327, -0.10313212, -0.2190201, 0.25079602, -0.1224342, -0.17659691, -0.10354815, 0.12724441, -0.11835013, -0.15596658, -0.262892],
+"pointerTy":[-5.16731367e-02, 1.41998947e-01, -1.03678465e-01, -2.35795856e-01, 1.67232469e-01, -3.50435115e-02, 1.31282926e-01, 8.77518952e-02, -1.61656141e-01, -1.89439468e-02, 6.89205006e-02, -1.47259831e-01, -1.85588151e-02, 1.95201755e-01, 1.53539265e-02, -1.11738130e-01, 7.46774301e-02, -1.60889581e-01, -1.51122361e-01, -1.64823771e-01, -7.43334070e-02, 1.79255735e-02, -8.14272910e-02, -1.60337687e-01, 7.73334429e-02, 1.45058706e-02, -1.51032144e-02, -1.70947760e-01, -1.48217022e-01, -7.63990656e-02, -8.62834305e-02, -1.66838810e-01, 4.88951942e-03, -1.25664428e-01, 1.13860749e-01, -2.08933145e-01, -1.30075082e-01, 7.92812705e-02, -7.94121996e-02, 1.08121462e-01, -2.62738355e-02, -4.07571979e-02, -9.88764390e-02, 1.00676276e-01, -2.82900538e-02, 7.71642849e-02, -2.50683606e-01, -1.28315210e-01, -1.78229675e-01, -2.19585538e-01, -8.51736143e-02, -1.43008991e-04, 1.66052416e-01, 6.89304620e-02, -1.85903355e-01, 1.39382124e-01, -1.14323251e-01, 6.72841072e-02, -1.73793092e-01, 1.37479026e-02, -6.61165267e-02, 1.28709331e-01, -3.70565802e-02, 1.15480699e-01, -1.72476366e-01, 1.86700657e-01, 1.71808466e-01, 1.25800788e-01, 1.42911309e-02, -1.19691528e-01, 1.48811145e-02, -1.66594520e-01, -1.34164989e-01, 1.62748635e-01, 3.45790684e-02],
+"ptrtoint":[0.13572109, 0.07109733, -0.01410782, 0.13761328, 0.06249858, -0.12742682, -0.03786812, -0.08852433, -0.00890332, -0.12647949, -0.23919484, 0.07803643, -0.29866624, 0.07854372, 0.0690124, 0.08534926, -0.03230691, -0.11528994, 0.2259676, -0.09829737, 0.10256737, -0.16430771, -0.0642257, -0.01210832, -0.12542038, 0.01087978, -0.2651048, 0.10121775, -0.12749597, -0.00404411, 0.08437401, -0.01521534, -0.05364794, -0.20650637, -0.15205501, 0.16177334, 0.08448336, -0.13946855, 0.15794401, -0.08243193, -0.05839634, 0.17580664, 0.19553919, 0.02601502, 0.14116347, -0.17160966, -0.09532923, -0.07157483, 0.20540062, -0.00341362, 0.20416199, 0.09911527, -0.01078249, -0.0624228, 0.14551571, 0.07151687, 0.04763724, -0.02011446, 0.16194499, -0.18160547, 0.13115011, 0.01976459, -0.01537652, -0.19834353, -0.14665273, -0.20727639, 0.03673945, -0.09134132, -0.15628532, -0.04004635, -0.02747078, 0.14147465, 0.17462312, 0.11279432, -0.07561264],
+"resume":[0.16280797, -0.14593223, -0.12683636, -0.1562535, -0.03300981, -0.13968605, 0.16718441, -0.19515003, 0.01863662, -0.05534162, -0.01442544, 0.0425216, 0.0093952, -0.16576275, 0.03578432, -0.15065056, -0.06406866, -0.16523188, -0.05909818, 0.06044476, -0.0871481, 0.15487999, -0.18122765, 0.1956721, -0.04706432, 0.08488349, 0.04219154, 0.02599989, -0.02276746, -0.18513387, 0.12803178, -0.09826294, -0.11191379, 0.04426758, 0.11935913, -0.14695078, -0.00907954, 0.15606298, -0.13066523, 0.01243626, 0.07249606, -0.13709828, 0.10189614, 0.18291259, -0.04105699, 0.1736963, -0.12169949, 0.09442408, 0.20398152, 0.22682573, -0.08286698, -0.13903227, 0.09133334, 0.03095248, 0.11325783, 0.1569758, -0.17479569, -0.12558746, -0.12676957, -0.12449513, 0.17823087, 0.16940698, -0.06061083, -0.1153774, 0.11211671, 0.03377679, -0.05404395, 0.10726969, -0.120761, 0.01132012, 0.00449077, 0.00602859, -0.13664234, 0.00466423, -0.02339442],
+"ret":[0.14368142, 0.0712266, 0.05669672, 0.13478386, -0.14595962, -0.12663847, -0.12403987, -0.09207936, 0.00078773, -0.20975904, 0.08747889, 0.07683876, -0.14989862, -0.18156855, 0.38113984, 0.05973466, -0.05483145, 0.00884139, -0.013859, -0.03841434, 0.05703019, -0.04955313, 0.04577729, -0.05112582, -0.25303054, 0.13709044, -0.06985793, -0.04175208, -0.06085019, 0.12376258, 0.08259401, -0.01146284, 0.05020906, 0.18525098, -0.15137392, 0.07154816, 0.06121736, -0.14056544, 0.16508178, -0.12329083, 0.22687763, 0.17450114, 0.18714464, 0.01847176, -0.02590629, -0.15461633, 0.0910584, -0.07975882, 0.03339317, 0.08106077, 0.10348453, 0.12415495, -0.01464526, -0.20166221, 0.23424618, -0.0058443, 0.13251036, -0.01039419, 0.19171973, -0.14341427, 0.11032798, -0.17445254, -0.21265155, -0.11035369, 0.09180369, -0.01410731, -0.05983369, -0.0549278, 0.11081824, 0.02046819, -0.04516792, -0.09715447, 0.14870624, 0.05914663, 0.10917712],
+"sdiv":[7.54674971e-02, 2.70023555e-01, 2.15832815e-01, 1.51102781e-01, 3.86169888e-02, -1.27587810e-01, -1.64553642e-01, 2.08858803e-01, 2.49577500e-03, 3.39335836e-02, 2.95089424e-01, 7.44504854e-02, 1.75000988e-02, 7.48216212e-02, 4.57024798e-02, 1.14481322e-01, -5.15110120e-02, 1.97094589e-01, 2.28497684e-01, 1.89727977e-01, -2.03567356e-01, -1.53853878e-01, -7.04708546e-02, -2.87290998e-02, -4.15551029e-02, -8.37634057e-02, 2.48096928e-01, 1.39052629e-01, -1.18507713e-01, 1.37168303e-01, 4.37297896e-02, -2.56327417e-04, 1.03771754e-01, 1.18692242e-01, -1.97971940e-01, 2.48502731e-01, 5.65373003e-02, -8.69503245e-02, -9.03292373e-03, -2.25797057e-01, 7.20400363e-02, 4.09315303e-02, 1.83778912e-01, -2.47538835e-03, -2.83727050e-02, -2.00868785e-01, 8.99481177e-02, -7.83472061e-02, 4.22467515e-02, 2.67557669e-02, 1.77338138e-01, -1.42202228e-02, -1.59657858e-02, -6.30925298e-02, 3.13569121e-02, -2.22823601e-02, 6.28621271e-03, -1.85963176e-02, 1.17826000e-01, -1.24646917e-01, 1.02576114e-01, -1.52709767e-01, 2.57164501e-02, -1.40907198e-01, 1.74567476e-01, 1.61048099e-02, -5.03884954e-03, -8.63459408e-02, -7.52566457e-02, 3.38615589e-02, 1.36013612e-01, -8.77554864e-02, 1.03453219e-01, 7.68808499e-02, -6.49084374e-02],
+"select":[0.05093412, 0.07767349, 0.07669216, 0.1312176, 0.0579063, 0.1616888, -0.11760561, 0.00115628, -0.04131674, -0.29780418, -0.01691337, 0.0748211, 0.0864482, 0.07403006, 0.25878662, 0.10279866, -0.01487916, 0.15694329, 0.22207598, 0.01221279, 0.02520609, -0.1521685, -0.06417656, -0.03086487, 0.12268542, 0.3565569, -0.08125142, 0.1072576, -0.02930279, 0.14090922, -0.14309497, -0.00379189, 0.15369308, 0.12072479, -0.11386253, 0.17081785, 0.0359251, -0.13158213, 0.15140608, -0.08365479, 0.04333765, 0.17864218, 0.09735203, -0.01021584, -0.1817566, -0.17009453, 0.10480749, -0.07720621, -0.06324099, 0.01645014, 0.13028447, 0.10660475, -0.02038397, -0.05975712, 0.02713404, -0.01552912, 0.07295278, 0.05679769, 0.02740115, -0.11240587, 0.07162624, -0.15834542, -0.32627442, -0.08725446, -0.07952213, 0.07846557, -0.01865849, -0.04569499, -0.0728619, 0.0374458, -0.27716625, -0.07809193, 0.11488006, 0.06656368, -0.06777868],
+"sext":[-0.03718835, 0.08533189, 0.21354397, 0.13909821, 0.04430787, -0.13043992, -0.12707381, 0.14811471, -0.01397946, -0.24312808, -0.01538438, 0.08007284, -0.20212536, 0.07967917, 0.16868502, 0.10560705, -0.01859606, 0.16425593, 0.23104599, 0.04822871, -0.15584451, -0.16572693, -0.07367796, -0.02386475, -0.04161641, -0.28961626, 0.26639512, 0.13398732, -0.09589424, 0.14068675, 0.16089684, -0.01488031, 0.16961882, 0.11251253, -0.15109386, 0.20157905, 0.04388804, -0.14243662, 0.17028852, -0.17495492, 0.08312923, 0.18138759, 0.19254005, -0.00167047, 0.1016985, -0.17693631, 0.09644604, -0.07967581, -0.01462245, 0.00063264, 0.19925497, 0.10426001, -0.01645718, -0.0897459, 0.02190982, -0.00871549, 0.03981987, 0.01151098, 0.07275884, -0.13166158, 0.11194995, -0.15796044, -0.02378252, -0.17802656, -0.05159309, 0.03235529, 0.00206553, -0.0869719, -0.07645953, 0.05517219, 0.01411109, -0.08648386, 0.1488923, 0.11236069, -0.14168048],
+"shl":[-1.21411718e-01, 8.12682733e-02, 7.26464316e-02, 1.38484403e-01, 8.17928985e-02, -1.24320365e-01, -1.29878476e-01, 1.89510286e-01, -6.82524173e-03, 4.69798781e-02, 7.76179358e-02, 7.87331015e-02, -1.99450791e-01, 7.40546957e-02, 1.56282917e-01, 1.49098694e-01, -3.80089432e-02, 1.97095275e-01, 2.20074877e-01, 9.85120013e-02, -1.51519790e-01, -1.56306505e-01, -6.62787706e-02, -2.89262943e-02, -8.50795880e-02, -3.77611667e-01, -8.08443353e-02, 1.29505768e-01, -9.56492350e-02, 1.34987608e-01, 1.17273629e-01, -8.01561028e-03, 2.01825440e-01, 1.25738055e-01, -1.46153197e-01, 2.18217447e-01, 7.04046711e-02, -1.39466003e-01, 6.33412227e-02, -1.05604395e-01, 7.39852190e-02, 1.70712352e-01, 1.86249197e-01, 1.75760695e-04, 9.54905152e-02, -1.82715610e-01, 8.42701495e-02, -7.70764053e-02, 3.44463770e-04, 2.22381260e-02, 1.92770571e-01, 6.70530349e-02, -8.68750829e-03, -5.87612167e-02, 1.35470673e-01, -9.91571508e-03, 3.54958773e-02, -1.26978569e-02, 3.80189577e-03, -1.57232955e-01, 1.05788536e-01, -1.48979709e-01, -6.13744035e-02, -1.79459959e-01, 1.58743337e-02, 1.66407768e-02, 3.78276110e-02, -8.67255181e-02, -7.59592950e-02, 3.41174081e-02, -1.17456488e-01, -8.46017748e-02, 1.42491326e-01, 8.54357481e-02, -6.05630279e-02],
+"shufflevector":[-1.64276063e-01, -1.40854018e-02, 2.16989160e-01, 1.48834497e-01, -1.81232363e-01, 1.71089604e-01, -1.51962206e-01, 9.34694987e-03, -6.01843521e-02, 1.57123819e-01, 1.49263054e-01, 1.57006048e-02, 8.54564831e-03, -1.46307275e-01, -9.97107551e-02, 2.03836277e-01, -1.10085299e-02, 1.58312604e-01, 3.98286656e-02, 1.22957818e-01, -4.54752985e-03, -1.51905298e-01, 2.56421398e-02, -9.66223106e-02, 1.35936990e-01, 1.13613196e-01, 8.88981670e-02, 1.39288589e-01, 2.35020537e-02, 1.54158428e-01, 1.38836756e-01, -7.45062644e-05, 1.85534820e-01, 2.31408417e-01, -1.86368376e-01, 2.18553007e-01, -1.25940442e-01, 6.19565435e-02, 2.09610596e-01, -2.28297710e-01, 2.30249181e-01, 1.89029738e-01, -6.89853504e-02, -3.19687016e-02, -1.80848792e-01, 4.24141204e-03, 1.89942136e-01, -1.91565320e-01, -2.52943840e-02, 5.65835461e-02, 1.32085189e-01, 1.23422973e-01, -2.14130040e-02, -2.95120943e-02, 1.43252522e-01, -2.44392790e-02, 1.89641267e-01, 3.69141959e-02, 5.39628556e-03, -1.15757883e-01, 6.42104596e-02, -2.11238548e-01, 1.83569789e-02, -9.20821503e-02, -9.48524103e-02, 8.56385827e-02, -5.02256379e-02, -8.02270398e-02, 8.46109912e-02, 7.74170980e-02, 3.27805057e-02, -1.08585857e-01, 1.16238609e-01, 5.87845854e-02, 1.14851862e-01],
+"sitofp":[0.05548016, 0.16714495, 0.21498686, 0.14356636, -0.16821964, 0.16527581, -0.15967155, 0.21070401, -0.01250376, -0.11125261, -0.06026782, 0.07956001, -0.13129172, -0.18479359, 0.08652773, 0.08131526, 0.15925482, 0.08148654, -0.00736642, 0.19463325, -0.20742258, -0.11578189, 0.02654804, -0.08633579, -0.05612461, 0.01452674, 0.11379433, 0.03724489, -0.12955493, 0.15072383, -0.0232376, -0.01797887, 0.20284739, 0.20505717, -0.18686672, 0.25398365, -0.11697914, -0.09353511, 0.19472948, -0.18606324, 0.13722429, 0.19458178, 0.03767281, -0.01490554, -0.15784514, -0.0030121, 0.1061831, -0.18870111, -0.04370302, 0.06840985, 0.12218294, 0.133711, -0.01636076, -0.05479606, -0.09695652, -0.01025795, 0.2093504, 0.08853228, -0.07362932, -0.06125485, 0.10777287, -0.17920133, 0.03073885, -0.09303376, -0.18211918, 0.09700941, -0.05694851, -0.0481168, 0.10195274, 0.11961144, 0.14820483, -0.10259698, 0.07829086, 0.06143153, -0.06575584],
+"srem":[0.12748273, -0.01354557, 0.07656507, 0.13586837, 0.09215222, -0.12957662, -0.22408909, 0.21526249, 0.0899937, 0.03087448, 0.23878594, 0.07816898, 0.0165252, 0.07721527, 0.0565106, 0.08858381, -0.13782543, 0.2185999, 0.2350998, 0.20486632, -0.22521928, -0.16895708, -0.07120457, -0.03142672, -0.193668, -0.06093899, 0.098878, 0.13780232, -0.13592266, 0.13956556, 0.03245056, -0.01644238, 0.1208498, 0.11854354, -0.20298819, 0.27215648, 0.06262159, -0.13207191, -0.22367987, 0.18101601, 0.07210222, -0.035157, 0.19500516, -0.0082911, 0.04821047, -0.2052546, 0.0944626, -0.08101162, 0.05265743, -0.00286297, 0.2012179, -0.02560825, -0.01475919, -0.06332223, -0.21597023, -0.00943558, 0.00891592, -0.04312498, 0.11415429, 0.08646774, 0.10881357, -0.15501237, 0.02134495, -0.15064926, 0.14675559, 0.01146032, 0.0020576, 0.09925999, -0.07733848, 0.03300545, 0.05376984, -0.08198962, 0.17412202, 0.08533774, -0.06574512],
+"store":[0.09998547, 0.07416256, 0.06472399, 0.12126696, 0.03879403, -0.12036075, -0.11504382, -0.06913467, -0.03769127, -0.33070236, -0.00644616, 0.07156026, -0.02137089, 0.07216891, -0.05470073, 0.09415297, -0.04082007, 0.1056991, -0.0013265, -0.00926145, 0.04998971, -0.14578499, -0.05182505, -0.02615017, 0.08348413, 0.31976137, -0.07019657, -0.05163203, -0.04972167, 0.12658256, 0.04289434, -0.0016057, 0.14311627, 0.12263075, -0.13941614, 0.13760482, 0.04816094, -0.12741822, 0.14878556, -0.11523844, 0.05825484, 0.1649721, 0.09197503, -0.0012878, -0.1629092, -0.1414969, 0.09324066, -0.07395344, -0.00317431, 0.01789259, 0.12094813, 0.10764453, -0.01553114, 0.11882594, 0.02442449, -0.01568008, 0.11022279, 0.03307666, 0.08506706, -0.10825977, 0.06488108, -0.15164001, -0.30984077, -0.08653892, -0.06201477, 0.01810287, -0.04473237, -0.04719033, -0.06153039, 0.03287021, 0.29479045, -0.07162003, 0.13225412, 0.05114779, -0.33301073],
+"structTy":[-5.22783101e-02, 1.48193806e-01, -1.73157901e-01, -8.37061405e-02, 1.75303683e-01, 1.41080663e-01, 1.32847771e-01, 9.91027430e-02, -1.22380503e-01, -5.10943905e-02, 7.63119832e-02, -1.28850952e-01, 1.66698098e-01, 1.32489190e-01, -4.90079597e-02, -1.37256354e-01, 4.85256799e-02, -1.78637013e-01, -1.86148569e-01, -1.64286211e-01, -6.26875609e-02, 8.13696086e-02, -1.20131724e-01, -1.59142628e-01, 3.36435549e-02, 2.20832378e-02, -2.72354912e-02, -1.38390273e-01, -1.38179898e-01, -1.23813316e-01, -9.40988287e-02, -1.55397400e-01, -1.58612743e-01, -1.14575408e-01, 1.55034050e-01, -1.50801614e-01, -1.07854791e-01, 1.55085072e-01, -1.68802753e-01, 1.61272466e-01, -2.05100384e-02, -8.52123126e-02, -9.58884135e-02, -1.21472001e-01, 7.77167231e-02, 1.36054471e-01, 1.28906265e-01, 1.30557746e-01, -1.81647420e-01, 1.45003811e-01, -1.11549668e-01, -1.79680258e-01, 1.72399670e-01, 1.51102387e-04, -4.99001816e-02, 1.28895119e-01, -1.17917232e-01, -9.13353860e-02, -1.21147677e-01, 9.76096392e-02, -1.77910581e-01, 1.50892287e-01, -2.25245636e-02, 1.24061532e-01, -1.16433218e-01, -6.76782504e-02, 1.45374849e-01, 2.35193707e-02, -1.35173321e-01, 1.46973729e-01, -1.22685850e-01, 1.27605781e-01, -1.51997164e-01, 1.60292000e-01, 7.63390437e-02],
+"sub":[-0.13264543, 0.07865644, 0.0717167, 0.1342318, 0.05076935, -0.12322044, -0.12266772, 0.00524008, -0.00201612, 0.05315073, 0.00274359, 0.0742974, 0.0123115, 0.07594631, 0.21857306, 0.10421466, -0.02275163, 0.17884067, 0.21873002, 0.00927466, 0.00893607, -0.154156, -0.06820294, -0.02856713, -0.03866831, -0.2793768, -0.06824332, 0.13080892, -0.08803294, 0.13524993, 0.21245252, -0.01117309, 0.20007995, 0.12509634, -0.14541206, 0.19173518, 0.0613077, -0.13841055, 0.15438707, -0.14274515, 0.07382213, 0.17015299, 0.18052574, -0.00206174, -0.15260881, -0.17803495, 0.08986183, -0.07603207, -0.0163452, 0.02869452, 0.186938, 0.07764658, -0.01459899, 0.10072613, 0.02469735, -0.01351501, 0.03415474, 0.0135162, 0.04113324, -0.12325168, 0.11012445, -0.14946231, 0.04155808, -0.1440628, -0.06376708, 0.01838643, 0.00198335, -0.07941123, -0.07066227, 0.0376416, 0.24301553, -0.0862716, 0.1351057, 0.0891021, -0.3352],
+"switch":[-0.16398937, -0.1353046, 0.08524002, 0.1561178, -0.22488637, -0.14185904, -0.10160676, 0.17193311, -0.05567684, -0.01794963, -0.22830375, 0.08948597, 0.1698675, 0.08543108, -0.18870668, 0.13391507, 0.1591491, 0.21046144, 0.02533695, -0.05875827, -0.15551412, 0.19997434, 0.19250119, -0.03397122, -0.05150964, -0.15923595, 0.0701151, 0.14852029, -0.01560177, 0.15765266, -0.2304326, -0.01416684, -0.05115065, 0.12840182, -0.17300242, -0.03878057, 0.07419615, -0.16339742, 0.18437031, -0.14087205, -0.2714784, -0.17547078, -0.01152283, -0.00396952, 0.11226111, -0.18184493, 0.1166721, -0.09108577, 0.23214185, 0.07350235, 0.14699937, 0.08840676, -0.01411979, 0.2082167, -0.10539865, -0.01378542, 0.04486391, -0.01463741, 0.14504644, 0.19353367, 0.11889812, -0.19718692, -0.04798679, -0.12421229, 0.29124823, -0.32081923, -0.00218598, -0.1037329, -0.08444938, 0.04092982, -0.03067664, -0.1606894, 0.07095047, 0.08663001, 0.25936154],
+"trunc":[0.11878826, 0.08377917, 0.05513672, 0.14270523, 0.07370453, -0.14921571, -0.16542384, -0.07493053, -0.00377195, -0.20950364, 0.12958477, 0.07888171, -0.00595982, 0.07865481, 0.16519356, 0.10834014, -0.04326443, 0.19355299, 0.23304398, 0.07385943, -0.11257231, -0.16919497, -0.082918, -0.0285878, -0.05886409, -0.25552744, 0.08462781, 0.13503358, -0.09682789, 0.12824969, 0.08024148, -0.01201469, 0.15677036, 0.14443342, -0.1907149, 0.23856063, -0.00528661, -0.14044978, 0.16222948, -0.10748056, 0.08127003, 0.17631039, 0.19577822, -0.01176626, 0.09836395, -0.16917923, 0.10726047, -0.10182234, 0.20931682, 0.04668214, 0.2017859, 0.11306392, -0.018347, -0.06246869, 0.24337131, -0.07117373, 0.03053473, -0.00658053, 0.03026612, -0.16877551, 0.10491424, -0.17555256, 0.14634104, -0.18189284, -0.11786141, 0.02876267, -0.00210879, -0.08721989, -0.07824761, 0.03958495, 0.20243248, -0.09376816, 0.11082744, 0.12096685, -0.12131985],
+"udiv":[0.08154505, 0.17510523, -0.19362096, 0.08671232, 0.11330891, -0.19157314, -0.2145219, -0.06051004, 0.1371807, 0.04572224, -0.06733968, 0.07146493, 0.00681373, 0.07493957, -0.02997438, 0.08688152, -0.04591569, 0.23223788, 0.22175628, 0.01500544, 0.14273156, -0.16111672, -0.08531193, 0.19467805, -0.00517966, -0.06020893, -0.06077334, 0.13201268, -0.12358853, 0.00868457, 0.06033499, 0.01196855, 0.14756525, 0.11571166, -0.11228922, 0.13696799, 0.21417981, 0.20094916, -0.21627706, 0.18220317, -0.06209835, 0.1076472, 0.20395155, 0.00197578, 0.13577849, -0.20195886, 0.0833538, -0.07554612, 0.00410905, 0.00158071, 0.1938367, 0.02883399, -0.01710817, 0.03711469, 0.13843457, -0.06804645, -0.00379174, -0.00144552, 0.13146468, -0.18377277, 0.07351629, -0.14530504, 0.01042824, -0.1766743, 0.01462858, 0.01206683, -0.12541275, 0.09634796, -0.07832152, 0.02791307, 0.02765011, 0.19757621, 0.16267568, 0.12346987, -0.0413983],
+"uitofp":[-0.15078814, 0.1826288, 0.11165173, 0.13953921, -0.1842304, 0.16399114, -0.11256697, -0.05694728, -0.04820754, -0.17459138, -0.12022546, 0.08202647, 0.05924561, -0.17365019, 0.1614662, 0.07272313, 0.14744736, 0.09281041, -0.00596566, -0.01817355, 0.09689283, -0.0900236, 0.03450679, -0.0848825, 0.17167987, -0.07416291, 0.09088556, 0.07786386, 0.08914284, 0.14832556, -0.07537761, 0.00234627, 0.15249911, 0.19451788, -0.15017514, 0.14780688, 0.11764529, -0.02274906, 0.1920297, -0.17293543, 0.22891366, 0.1852529, 0.0128901, -0.00331702, -0.18161494, -0.0123833, 0.10250985, -0.1877487, -0.02335341, 0.06747307, 0.12578565, 0.12541758, -0.01838141, -0.08433985, 0.26602918, -0.01791255, 0.18907419, 0.04615575, 0.22383852, -0.13418758, 0.07736338, -0.18702815, 0.06279426, -0.09547485, -0.14973089, 0.09295561, -0.04817062, -0.05371717, -0.01254407, 0.12052637, 0.14356695, -0.1381116, 0.17813013, 0.0863996, -0.10018482],
+"unreachable":[1.6576199e-01, -1.7907834e-02, -5.7712890e-02, 9.4339609e-02, -9.3380272e-02, -1.9464681e-01, 7.7050277e-03, -1.9517663e-01, 2.6435368e-03, 9.1913566e-02, 1.3639191e-02, 7.0288680e-02, -3.2517979e-01, 7.4262276e-02, -8.9507200e-02, -1.7191246e-01, -5.2555885e-02, -1.4688279e-01, 1.0220077e-01, -4.8814032e-02, -1.3367063e-01, -6.1610699e-02, -1.8777388e-01, 2.0192388e-01, 1.7102915e-01, 1.3610463e-01, -2.6177135e-01, -3.3939917e-02, -5.4787207e-02, 1.1302987e-01, 1.0523112e-01, 8.6424664e-02, -3.6340270e-02, 4.7679577e-02, 1.0370419e-02, 3.9357133e-03, 1.5754176e-02, -4.6523277e-02, -1.2651871e-01, -5.0250064e-03, -2.1445632e-01, -1.5226135e-01, 1.7948903e-01, 1.9091401e-01, 1.1402745e-01, -1.9978039e-01, -8.4826022e-02, -3.7182060e-03, 2.1397528e-01, -1.9490053e-03, 3.8303059e-02, 5.5778958e-02, -1.1436568e-02, 7.7554718e-02, 3.7896037e-02, 7.5804755e-02, -1.7246161e-02, -1.4188807e-01, 4.9074650e-02, -1.9401214e-01, 1.9030276e-01, 1.1096356e-01, -1.5253071e-01, -1.9243342e-01, 1.6415399e-01, 2.7355237e-02, 7.6516271e-03, -9.3317330e-02, -1.7084104e-01, 3.9767768e-02, -1.1136789e-01, -9.4884530e-02, 2.1568926e-04, 1.3515340e-01, 8.2443848e-02],
+"urem":[0.1196936, 0.18855006, -0.20257552, 0.01738752, 0.15161008, -0.14784957, -0.02992235, -0.0674265, 0.14330001, -0.00208072, -0.08096982, -0.06099883, 0.01042207, 0.1028357, 0.05679855, 0.08465453, -0.05227959, 0.21925992, 0.22556421, -0.059273, 0.1825322, 0.17631407, -0.08938511, -0.0277707, -0.2572769, -0.06195913, -0.24406035, 0.13713413, -0.13801506, 0.02009896, 0.02613169, 0.01552499, 0.14668229, 0.12454724, -0.14865053, 0.09922966, 0.2130675, -0.11827406, 0.01006878, -0.09671234, 0.06660412, 0.0945213, 0.20740281, 0.00239918, 0.14173026, -0.1632753, 0.08587474, -0.07923763, 0.02992029, 0.2015828, 0.2007573, -0.11056472, -0.01871637, -0.06330916, 0.14348209, -0.07483656, 0.00636646, -0.01837422, 0.17499712, -0.17495239, 0.07653105, -0.1475833, 0.02116938, -0.17941074, 0.1734715, -0.01114943, 0.03780977, -0.15019819, -0.07816306, -0.08282368, 0.05129486, 0.19702028, 0.18443331, 0.10329096, -0.06307837],
+"variable":[-0.00726075, -0.19133486, 0.11386976, -0.02404008, 0.18218324, 0.2147853, 0.05924276, -0.14287908, 0.2636781, 0.08127253, -0.08004244, -0.151082, -0.05468801, -0.14080277, 0.09922418, -0.09297107, -0.2022257, -0.0631255, 0.08962703, 0.2616532, -0.05850444, 0.00352755, -0.1646196, 0.12995376, 0.04720275, -0.04833887, 0.0210924, 0.23275656, 0.20620209, -0.01313339, -0.04938933, 0.18796188, 0.03722439, -0.0570973, 0.07931395, 0.12533784, 0.19275506, 0.04549298, -0.06122055, -0.27613187, -0.03735771, 0.0223406, -0.09128818, 0.15596932, -0.02494176, 0.10621183, -0.03121548, 0.09133425, 0.11494032, 0.1616893, -0.05987769, -0.01591593, -0.15986548, -0.13643607, -0.07331984, -0.21545175, -0.13974416, 0.14965075, -0.19167605, 0.03849319, -0.01465273, 0.04467848, 0.16016744, 0.08067682, 0.05409591, -0.1172289, -0.20374107, 0.21127956, 0.14046785, -0.15151982, -0.07432669, 0.1618207, -0.09742998, -0.14227344, 0.07137881],
+"vectorTy":[-0.03294902, 0.14949119, -0.09443742, 0.01450515, 0.19603784, 0.25139496, 0.07845286, 0.11937284, 0.16359204, 0.06099452, 0.09465881, -0.1069911, 0.09603978, 0.16709542, -0.00486909, -0.07722043, 0.22341618, -0.03857102, 0.09912027, -0.12520577, 0.13405597, 0.01585144, 0.08918274, -0.19392243, 0.02501151, 0.00475938, 0.15233898, 0.17524292, -0.19524728, -0.01515534, 0.08875454, -0.14749287, 0.01111115, -0.0826562, 0.09034086, -0.04994484, -0.10947519, 0.11695202, -0.15125127, 0.10647643, 0.03638166, -0.01116771, -0.14471221, -0.14233877, -0.05823282, 0.16917565, -0.06123812, -0.2417991, -0.17791323, -0.11769169, -0.07800104, -0.08785082, 0.11596312, -0.02590095, 0.06086191, -0.18129952, -0.15834333, -0.13579826, -0.14008556, 0.05263453, -0.1810565, 0.05645358, 0.05425795, 0.11036766, -0.15751451, 0.20713197, 0.15679651, -0.17410725, 0.00938685, 0.2128002, 0.05759892, 0.03854589, -0.12531556, 0.19853209, -0.00149427],
+"voidTy":[0.01605093, -0.0537584, -0.20252232, -0.08176173, -0.01439075, -0.0382277, 0.15691687, -0.104895, 0.06642336, -0.06327856, 0.09566005, 0.1357376, -0.06892086, -0.00750719, 0.00474408, -0.20349212, -0.05127234, -0.17626588, -0.17354688, -0.18703477, -0.10801363, 0.09327657, 0.10076355, 0.12450968, -0.14411868, 0.09044765, 0.01168226, -0.15345524, -0.14508787, -0.04046924, 0.04365833, -0.11735097, -0.1433241, -0.1147697, 0.18176553, -0.18558215, -0.13961768, 0.12200661, -0.13001354, 0.16781498, 0.01012573, -0.09670691, -0.10543029, 0.09294511, 0.08037758, 0.14874886, -0.1797814, -0.12390587, -0.0998297, 0.12955485, -0.15814209, -0.03254232, 0.17421001, 0.10237212, -0.07504516, -0.112073, -0.11584745, -0.20020956, 0.11506493, 0.01263643, -0.10729685, 0.12432116, -0.1172537, 0.10430267, 0.06826, -0.06138111, 0.13390729, -0.1675781, 0.00966638, 0.13989863, -0.00030718, 0.10629188, -0.15517116, -0.08125519, 0.03691618],
+"xor":[0.10254283, 0.18058334, 0.05268734, 0.1032732, 0.10089786, -0.1597949, -0.11678528, -0.07392009, 0.00164178, -0.3411041, -0.05760791, 0.14810716, 0.01395016, 0.07759612, 0.0478027, 0.10309431, -0.04646098, 0.22321403, 0.22373965, -0.0018288, 0.20699704, -0.16503152, -0.18555428, -0.02829313, -0.04340088, -0.09629976, -0.07565032, 0.12829013, -0.1184216, 0.05327054, -0.2091556, 0.01997479, 0.14617224, 0.12249397, -0.11211042, 0.17021945, 0.21050954, -0.1381692, 0.0287271, -0.09731391, 0.07712973, 0.0957914, 0.19754209, 0.00280226, -0.22004068, -0.19650316, 0.08103254, -0.07884329, 0.01431314, 0.01774853, 0.20215395, 0.04173042, -0.01757454, -0.06132229, 0.14705223, -0.07607429, 0.01276137, -0.02355135, 0.1687547, -0.16499719, 0.07755739, -0.15042275, 0.04714211, -0.19073205, 0.01791589, 0.00800123, -0.00147503, -0.08897253, -0.07817551, 0.02938494, 0.07296588, -0.08095124, 0.19651005, 0.12599285, -0.06209126],
+"zext":[0.07005657, 0.08003729, 0.07546207, 0.13528231, 0.02506938, -0.12476956, -0.14581475, 0.00614589, -0.00503257, -0.24861531, 0.09526423, 0.07557298, 0.01302374, 0.07628334, 0.04175617, 0.09726538, -0.02312024, 0.16171065, 0.22212435, 0.0079543, 0.07804493, -0.15814242, -0.06840046, -0.03052379, -0.0414926, 0.26214772, -0.07542547, 0.12756911, -0.08823611, 0.13954116, -0.18143456, -0.01209466, 0.15410358, 0.20636739, -0.1831482, 0.19437483, 0.06973958, -0.13698913, 0.19432417, -0.16362838, 0.09032086, 0.18127388, 0.18287036, -0.01740397, -0.17513882, -0.16302226, 0.10199076, -0.07994232, 0.029813, 0.04575716, 0.19189098, 0.10111669, -0.01755602, -0.0832833, 0.1540967, -0.01496344, 0.04155953, 0.00536162, 0.0699449, -0.13122603, 0.10352977, -0.18122241, 0.17052825, -0.15459219, -0.06903189, 0.05887637, -0.00081859, -0.08415917, -0.07304011, 0.08401199, -0.25388402, -0.09779947, 0.12506351, 0.09557163, -0.12431429]
+}
\ No newline at end of file
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 56e91703cb019..aa2ca77d1798d 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -42,6 +42,7 @@
 #include "llvm/Analysis/EphemeralValuesCache.h"
 #include "llvm/Analysis/FunctionPropertiesAnalysis.h"
 #include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/IR2Vec.h"
 #include "llvm/Analysis/IRSimilarityIdentifier.h"
 #include "llvm/Analysis/IVUsers.h"
 #include "llvm/Analysis/InlineAdvisor.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 94dabe290213d..be93a7b1f5ba6 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -26,6 +26,7 @@ MODULE_ANALYSIS("dxil-resources", DXILResourceAnalysis())
 MODULE_ANALYSIS("dxil-resource-type", DXILResourceTypeAnalysis())
 MODULE_ANALYSIS("dxil-resource-bindings", DXILResourceBindingAnalysis())
 MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
+MODULE_ANALYSIS("ir2vec-vocab", IR2VecVocabAnalysis())
 MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
 MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
 MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
@@ -133,6 +134,7 @@ MODULE_PASS("print-stack-safety", StackSafetyGlobalPrinterPass(errs()))
 MODULE_PASS("print<dxil-metadata>", DXILMetadataAnalysisPrinterPass(errs()))
 MODULE_PASS("print<dxil-resources>", DXILResourcePrinterPass(errs()))
 MODULE_PASS("print<inline-advisor>", InlineAdvisorAnalysisPrinterPass(errs()))
+MODULE_PASS("print<ir2vec>", IR2VecPrinterPass(errs()))
 MODULE_PASS("print<module-debuginfo>", ModuleDebugInfoPrinterPass(errs()))
 MODULE_PASS("print<reg-usage>", PhysicalRegisterUsageInfoPrinterPass(errs()))
 MODULE_PASS("pseudo-probe", SampleProfileProbePass(TM))
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/dummy_3D_vocab.json b/llvm/test/Analysis/IR2Vec/Inputs/dummy_3D_vocab.json
new file mode 100644
index 0000000000000..0ff5fdd959e9c
--- /dev/null
+++ b/llvm/test/Analysis/IR2Vec/Inputs/dummy_3D_vocab.json
@@ -0,0 +1,7 @@
+{
+    "alloca": [1, 2, 3],
+    "load": [4, 5, 6],
+    "store": [7, 8, 9],
+    "add": [10, 11, 12],
+    "mul": [13, 14, 15]
+}
diff --git a/llvm/test/Analysis/IR2Vec/Inputs/dummy_5D_vocab.json b/llvm/test/Analysis/IR2Vec/Inputs/dummy_5D_vocab.json
new file mode 100644
index 0000000000000..d6506f06bb320
--- /dev/null
+++ b/llvm/test/Analysis/IR2Vec/Inputs/dummy_5D_vocab.json
@@ -0,0 +1,11 @@
+{
+    "alloca": [-0.1, -0.2, -0.3, 1, 2],
+    "load": [-0.4, -0.5, -0.6, 4, 5],
+    "store": [-0.7, -0.8, -0.9, 7, 8],
+    "add": [-1.0, -1.1, -1.2, 10, 11],
+    "mul": [12, 13, 14, -1.2, -1.3],
+    "integerTy": [0.2, 0.4, 0.6, 1, 0.5],
+    "pointer": [0, 1, 2, 3, 4],
+    "variable": [2, 4, 6, 8, 10],
+    "ret": [5, 6, 7, 8, 9]
+}
diff --git a/llvm/test/Analysis/IR2Vec/basic.ll b/llvm/test/Analysis/IR2Vec/basic.ll
new file mode 100644
index 0000000000000..b10e735a54587
--- /dev/null
+++ b/llvm/test/Analysis/IR2Vec/basic.ll
@@ -0,0 +1,50 @@
+; RUN: opt -passes='print<ir2vec>' -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_3D_vocab.json %s 2>&1 | FileCheck %s -check-prefix=3D-CHECK
+; RUN: opt -passes='print<ir2vec>' -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_5D_vocab.json %s 2>&1 | FileCheck %s -check-prefix=5D-CHECK
+
+define dso_local i32 @abc(i32 %0, i32 %1) {
+entry:
+  %3 = alloca i32, align 4
+  %4 = alloca i32, align 4
+  store i32 %0, ptr %3, align 4
+  store i32 %1, ptr %4, align 4
+  %5 = load i32, ptr %3, align 4
+  %6 = load i32, ptr %4, align 4
+  %7 = load i32, ptr %3, align 4
+  %8 = mul nsw i32 %6, %7
+  %9 = add nsw i32 %5, %8
+  ret i32 %9
+}
+
+; 3D-CHECK: IR2Vec embeddings for function abc:
+; 3D-CHECK-NEXT: Function vector:  [ 51.00 60.00 69.00 ]
+; 3D-CHECK-NEXT: Basic block vectors:
+; 3D-CHECK-NEXT: Basic block: entry:
+; 3D-CHECK-NEXT:  [ 51.00 60.00 69.00 ]
+; 3D-CHECK-NEXT: Instruction vectors:
+; 3D-CHECK-NEXT: Instruction:   %2 = alloca i32, align 4 [ 1.00 2.00 3.00 ]
+; 3D-CHECK-NEXT: Instruction:   %3 = alloca i32, align 4 [ 1.00 2.00 3.00 ]
+; 3D-CHECK-NEXT: Instruction:   store i32 %0, ptr %2, align 4 [ 7.00 8.00 9.00 ]
+; 3D-CHECK-NEXT: Instruction:   store i32 %1, ptr %3, align 4 [ 7.00 8.00 9.00 ]
+; 3D-CHECK-NEXT: Instruction:   %4 = load i32, ptr %2, align 4 [ 4.00 5.00 6.00 ]
+; 3D-CHECK-NEXT: Instruction:   %5 = load i32, ptr %3, align 4 [ 4.00 5.00 6.00 ]
+; 3D-CHECK-NEXT: Instruction:   %6 = load i32, ptr %2, align 4 [ 4.00 5.00 6.00 ]
+; 3D-CHECK-NEXT: Instruction:   %7 = mul nsw i32 %5, %6 [ 13.00 14.00 15.00 ]
+; 3D-CHECK-NEXT: Instruction:   %8 = add nsw i32 %4, %7 [ 10.00 11.00 12.00 ]
+; 3D-CHECK-NEXT: Instruction:   ret i32 %8 [ 0.00 0.00 0.00 ]
+
+; 5D-CHECK: IR2Vec embeddings for function abc:
+; 5D-CHECK-NEXT: Function vector:  [ 16.50  22.00  27.50  61.50  72.95 ]
+; 5D-CHECK-NEXT: Basic block vectors:
+; 5D-CHECK-NEXT: Basic block: entry:
+; 5D-CHECK-NEXT:  [ 16.50  22.00  27.50  61.50  72.95 ]
+; 5D-CHECK-NEXT: Instruction vectors:
+; 5D-CHECK-NEXT: Instruction:   %2 = alloca i32, align 4 [ -0.10  -0.20  -0.30  1.00  2.00 ]
+; 5D-CHECK-NEXT: Instruction:   %3 = alloca i32, align 4 [ -0.10  -0.20  -0.30  1.00  2.00 ]
+; 5D-CHECK-NEXT: Instruction:   store i32 %0, ptr %2, align 4 [ -0.30  0.20  0.70  9.20  10.80 ]
+; 5D-CHECK-NEXT: Instruction:   store i32 %1, ptr %3, align 4 [ -0.30  0.20  0.70  9.20  10.80 ]
+; 5D-CHECK-NEXT: Instruction:   %4 = load i32, ptr %2, align 4 [ -0.30  -0.10  0.10  5.10  6.05 ]
+; 5D-CHECK-NEXT: Instruction:   %5 = load i32, ptr %3, align 4 [ -0.30  -0.10  0.10  5.10  6.05 ]
+; 5D-CHECK-NEXT: Instruction:   %6 = load i32, ptr %2, align 4 [ -0.30  -0.10  0.10  5.10  6.05 ]
+; 5D-CHECK-NEXT: Instruction:   %7 = mul nsw i32 %5, %6 [ 12.90  14.80  16.70  2.50  2.95 ]
+; 5D-CHECK-NEXT: Instruction:   %8 = add nsw i32 %4, %7 [ -0.10  0.70  1.50  13.70  15.25 ]
+; 5D-CHECK-NEXT: Instruction:   ret i32 %8 [ 5.40  6.80  8.20  9.60  11.00 ]
diff --git a/llvm/test/Analysis/IR2Vec/if-else.ll b/llvm/test/Analysis/IR2Vec/if-else.ll
new file mode 100644
index 0000000000000..b1c64224e5328
--- /dev/null
+++ b/llvm/test/Analysis/IR2Vec/if-else.ll
@@ -0,0 +1,38 @@
+; RUN: opt -passes='print<ir2vec>' -o /dev/null -ir2vec-vocab-path=%S/Inputs/dummy_3D_vocab.json %s 2>&1 | FileCheck %s
+
+define dso_local i32 @abc(i32 noundef %a, i32 noundef %b) #0 {
+entry:
+  %retval = alloca i32, align 4
+  %a.addr = alloca i32, align 4
+  %b.addr = alloca i32, align 4
+  store i32 %a, ptr %a.addr, align 4
+  store i32 %b, ptr %b.addr, align 4
+  %0 = load i32, ptr %a.addr, align 4
+  %1 = load i32, ptr %b.addr, align 4
+  %cmp = icmp sgt i32 %0, %1
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %2 = load i32, ptr %b.addr, align 4
+  store i32 %2, ptr %retval, align 4
+  br label %return
+
+if.else:                                          ; preds = %entry
+  %3 = load i32, ptr %a.addr, align 4
+  store i32 %3, ptr %retval, align 4
+  br label %return
+
+return:                                           ; preds = %if.else, %if.then
+  %4 = load i32, ptr %retval, align 4
+  ret i32 %4
+}
+
+; CHECK: Basic block vectors:
+; CHECK-NEXT: Basic block: entry:
+; CHECK-NEXT:  [ 25.00 32.00 39.00 ]
+; CHECK-NEXT: Basic block: if.then:
+; CHECK-NEXT:  [ 11.00 13.00 15.00 ]
+; CHECK-NEXT: Basic block: if.else:
+; CHECK-NEXT:  [ 11.00 13.00 15.00 ]
+; CHECK-NEXT: Basic block: return:
+; CHECK-NEXT:  [ 4.00 5.00 6.00 ]

>From dc68166912baf5120389304ba317f818f406b4bd Mon Sep 17 00:00:00 2001
From: Henrich Lauko <xlauko at mail.muni.cz>
Date: Thu, 22 May 2025 18:53:09 +0200
Subject: [PATCH 021/105] [CIR] Simplify error emission to return failures
 directly (#141032)

Mirrors incubator changes from https://github.com/llvm/clangir/pull/1634
---
 clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 47 +++++++++++----------------
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 23 +++++--------
 2 files changed, 28 insertions(+), 42 deletions(-)

diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
index 6f41cd4388ac2..c4fb4942aec75 100644
--- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp
@@ -138,17 +138,13 @@ void IntAttr::print(AsmPrinter &printer) const {
 
 LogicalResult IntAttr::verify(function_ref<InFlightDiagnostic()> emitError,
                               Type type, APInt value) {
-  if (!mlir::isa<IntType>(type)) {
-    emitError() << "expected 'simple.int' type";
-    return failure();
-  }
+  if (!mlir::isa<IntType>(type))
+    return emitError() << "expected 'simple.int' type";
 
   auto intType = mlir::cast<IntType>(type);
-  if (value.getBitWidth() != intType.getWidth()) {
-    emitError() << "type and value bitwidth mismatch: " << intType.getWidth()
-                << " != " << value.getBitWidth();
-    return failure();
-  }
+  if (value.getBitWidth() != intType.getWidth())
+    return emitError() << "type and value bitwidth mismatch: "
+                       << intType.getWidth() << " != " << value.getBitWidth();
 
   return success();
 }
@@ -182,10 +178,8 @@ FPAttr FPAttr::getZero(Type type) {
 LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
                              CIRFPTypeInterface fpType, APFloat value) {
   if (APFloat::SemanticsToEnum(fpType.getFloatSemantics()) !=
-      APFloat::SemanticsToEnum(value.getSemantics())) {
-    emitError() << "floating-point semantics mismatch";
-    return failure();
-  }
+      APFloat::SemanticsToEnum(value.getSemantics()))
+    return emitError() << "floating-point semantics mismatch";
 
   return success();
 }
@@ -195,10 +189,10 @@ LogicalResult FPAttr::verify(function_ref<InFlightDiagnostic()> emitError,
 //===----------------------------------------------------------------------===//
 
 LogicalResult
-ConstArrayAttr::verify(function_ref<::mlir::InFlightDiagnostic()> emitError,
-                       Type type, Attribute elts, int trailingZerosNum) {
+ConstArrayAttr::verify(function_ref<InFlightDiagnostic()> emitError, Type type,
+                       Attribute elts, int trailingZerosNum) {
 
-  if (!(mlir::isa<ArrayAttr>(elts) || mlir::isa<StringAttr>(elts)))
+  if (!(mlir::isa<ArrayAttr, StringAttr>(elts)))
     return emitError() << "constant array expects ArrayAttr or StringAttr";
 
   if (auto strAttr = mlir::dyn_cast<StringAttr>(elts)) {
@@ -206,11 +200,10 @@ ConstArrayAttr::verify(function_ref<::mlir::InFlightDiagnostic()> emitError,
     const auto intTy = mlir::dyn_cast<IntType>(arrayTy.getElementType());
 
     // TODO: add CIR type for char.
-    if (!intTy || intTy.getWidth() != 8) {
-      emitError() << "constant array element for string literals expects "
-                     "!cir.int<u, 8> element type";
-      return failure();
-    }
+    if (!intTy || intTy.getWidth() != 8)
+      return emitError()
+             << "constant array element for string literals expects "
+                "!cir.int<u, 8> element type";
     return success();
   }
 
@@ -303,22 +296,20 @@ void ConstArrayAttr::print(AsmPrinter &printer) const {
 // CIR ConstVectorAttr
 //===----------------------------------------------------------------------===//
 
-LogicalResult cir::ConstVectorAttr::verify(
-    function_ref<::mlir::InFlightDiagnostic()> emitError, Type type,
-    ArrayAttr elts) {
+LogicalResult
+cir::ConstVectorAttr::verify(function_ref<InFlightDiagnostic()> emitError,
+                             Type type, ArrayAttr elts) {
 
-  if (!mlir::isa<cir::VectorType>(type)) {
+  if (!mlir::isa<cir::VectorType>(type))
     return emitError() << "type of cir::ConstVectorAttr is not a "
                           "cir::VectorType: "
                        << type;
-  }
 
   const auto vecType = mlir::cast<cir::VectorType>(type);
 
-  if (vecType.getSize() != elts.size()) {
+  if (vecType.getSize() != elts.size())
     return emitError()
            << "number of constant elements should match vector size";
-  }
 
   // Check if the types of the elements match
   LogicalResult elementTypeCheck = success();
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9a44f923ac143..479d249516699 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -205,10 +205,8 @@ RecordType::verify(function_ref<mlir::InFlightDiagnostic()> emitError,
                    llvm::ArrayRef<mlir::Type> members, mlir::StringAttr name,
                    bool incomplete, bool packed, bool padded,
                    RecordType::RecordKind kind) {
-  if (name && name.getValue().empty()) {
-    emitError() << "identified records cannot have an empty name";
-    return mlir::failure();
-  }
+  if (name && name.getValue().empty())
+    return emitError() << "identified records cannot have an empty name";
   return mlir::success();
 }
 
@@ -421,12 +419,10 @@ uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
 mlir::LogicalResult
 IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
                 unsigned width, bool isSigned) {
-  if (width < IntType::minBitwidth() || width > IntType::maxBitwidth()) {
-    emitError() << "IntType only supports widths from "
-                << IntType::minBitwidth() << " up to "
-                << IntType::maxBitwidth();
-    return mlir::failure();
-  }
+  if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
+    return emitError() << "IntType only supports widths from "
+                       << IntType::minBitwidth() << " up to "
+                       << IntType::maxBitwidth();
   return mlir::success();
 }
 
@@ -631,10 +627,9 @@ mlir::LogicalResult
 FuncType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
                  llvm::ArrayRef<mlir::Type> argTypes, mlir::Type returnType,
                  bool isVarArg) {
-  if (returnType && mlir::isa<cir::VoidType>(returnType)) {
-    emitError() << "!cir.func cannot have an explicit 'void' return type";
-    return mlir::failure();
-  }
+  if (mlir::isa_and_nonnull<cir::VoidType>(returnType))
+    return emitError()
+           << "!cir.func cannot have an explicit 'void' return type";
   return mlir::success();
 }
 

>From 6fd3c20d25a88ccc3f2b5275e67de8b88ad5f873 Mon Sep 17 00:00:00 2001
From: Alan Li <me at alanli.org>
Date: Thu, 22 May 2025 13:05:37 -0400
Subject: [PATCH 022/105] [MLIR] Add a utility pass to linearize `memref`
 (#136797)

To add a transformation that simplifies memory access patterns, this PR
adds a memref linearizer which is based on the GPU/DecomposeMemRefs
pass, with the following changes:
* support vector dialect ops
* instead of decompose memrefs to rank-0 memrefs, flatten higher-ranked
memrefs to rank-1.

Notes:
* After the linearization, a MemRef's offset is kept, so a
`memref<4x8xf32, strided<[8, 1], offset: 100>>` becomes `memref<32xf32,
strided<[1], offset: 100>>`.
* It also works with dynamic shapes and strides and offsets (see test
cases for details).
* The shape of the casted memref is computed as 1d, flattened.
---
 .../mlir/Dialect/MemRef/Transforms/Passes.td  |  10 +
 .../Dialect/MemRef/Transforms/Transforms.h    |   2 +
 .../Dialect/MemRef/Transforms/CMakeLists.txt  |   1 +
 .../MemRef/Transforms/FlattenMemRefs.cpp      | 286 +++++++++++++++++
 mlir/test/Dialect/MemRef/flatten_memref.mlir  | 300 ++++++++++++++++++
 5 files changed, 599 insertions(+)
 create mode 100644 mlir/lib/Dialect/MemRef/Transforms/FlattenMemRefs.cpp
 create mode 100644 mlir/test/Dialect/MemRef/flatten_memref.mlir

diff --git a/mlir/include/mlir/Dialect/MemRef/Transforms/Passes.td b/mlir/include/mlir/Dialect/MemRef/Transforms/Passes.td
index a46f73350bb3c..a8d135caa74f0 100644
--- a/mlir/include/mlir/Dialect/MemRef/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/MemRef/Transforms/Passes.td
@@ -245,5 +245,15 @@ def ExpandReallocPass : Pass<"expand-realloc"> {
   ];
 }
 
+def FlattenMemrefsPass : Pass<"flatten-memref"> {
+  let summary = "Flatten a multiple dimensional memref to 1-dimensional";
+  let description = [{
+
+  }];
+  let dependentDialects = [
+      "affine::AffineDialect", "memref::MemRefDialect", "vector::VectorDialect"
+  ];
+}
+
 #endif // MLIR_DIALECT_MEMREF_TRANSFORMS_PASSES
 
diff --git a/mlir/include/mlir/Dialect/MemRef/Transforms/Transforms.h b/mlir/include/mlir/Dialect/MemRef/Transforms/Transforms.h
index 62a2297c80e78..c2b8cb05be922 100644
--- a/mlir/include/mlir/Dialect/MemRef/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/MemRef/Transforms/Transforms.h
@@ -144,6 +144,8 @@ FailureOr<memref::AllocOp> multiBuffer(memref::AllocOp allocOp,
 /// ```
 void populateExtractAddressComputationsPatterns(RewritePatternSet &patterns);
 
+void populateFlattenMemrefsPatterns(RewritePatternSet &patterns);
+
 /// Build a new memref::AllocaOp whose dynamic sizes are independent of all
 /// given independencies. If the op is already independent of all
 /// independencies, the same AllocaOp result is returned.
diff --git a/mlir/lib/Dialect/MemRef/Transforms/CMakeLists.txt b/mlir/lib/Dialect/MemRef/Transforms/CMakeLists.txt
index ecab97bc2b8e7..637f5ec1c9f9b 100644
--- a/mlir/lib/Dialect/MemRef/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/MemRef/Transforms/CMakeLists.txt
@@ -8,6 +8,7 @@ add_mlir_dialect_library(MLIRMemRefTransforms
   EmulateWideInt.cpp
   EmulateNarrowType.cpp
   ExtractAddressComputations.cpp
+  FlattenMemRefs.cpp
   FoldMemRefAliasOps.cpp
   IndependenceTransforms.cpp
   MultiBuffer.cpp
diff --git a/mlir/lib/Dialect/MemRef/Transforms/FlattenMemRefs.cpp b/mlir/lib/Dialect/MemRef/Transforms/FlattenMemRefs.cpp
new file mode 100644
index 0000000000000..e9729a4766a0a
--- /dev/null
+++ b/mlir/lib/Dialect/MemRef/Transforms/FlattenMemRefs.cpp
@@ -0,0 +1,286 @@
+//===----- FlattenMemRefs.cpp - MemRef ops flattener pass  ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains patterns for flattening an multi-rank memref-related
+// ops into 1-d memref ops.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Affine/IR/AffineOps.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/MemRef/Transforms/Passes.h"
+#include "mlir/Dialect/MemRef/Transforms/Transforms.h"
+#include "mlir/Dialect/MemRef/Utils/MemRefUtils.h"
+#include "mlir/Dialect/Utils/IndexingUtils.h"
+#include "mlir/Dialect/Utils/StaticValueUtils.h"
+#include "mlir/Dialect/Vector/IR/VectorOps.h"
+#include "mlir/IR/AffineExpr.h"
+#include "mlir/IR/Attributes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/OpDefinition.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+#include <numeric>
+
+namespace mlir {
+namespace memref {
+#define GEN_PASS_DEF_FLATTENMEMREFSPASS
+#include "mlir/Dialect/MemRef/Transforms/Passes.h.inc"
+} // namespace memref
+} // namespace mlir
+
+using namespace mlir;
+
+static Value getValueFromOpFoldResult(OpBuilder &rewriter, Location loc,
+                                      OpFoldResult in) {
+  if (Attribute offsetAttr = dyn_cast<Attribute>(in)) {
+    return rewriter.create<arith::ConstantIndexOp>(
+        loc, cast<IntegerAttr>(offsetAttr).getInt());
+  }
+  return cast<Value>(in);
+}
+
+/// Returns a collapsed memref and the linearized index to access the element
+/// at the specified indices.
+static std::pair<Value, Value> getFlattenMemrefAndOffset(OpBuilder &rewriter,
+                                                         Location loc,
+                                                         Value source,
+                                                         ValueRange indices) {
+  int64_t sourceOffset;
+  SmallVector<int64_t, 4> sourceStrides;
+  auto sourceType = cast<MemRefType>(source.getType());
+  if (failed(sourceType.getStridesAndOffset(sourceStrides, sourceOffset))) {
+    assert(false);
+  }
+
+  memref::ExtractStridedMetadataOp stridedMetadata =
+      rewriter.create<memref::ExtractStridedMetadataOp>(loc, source);
+
+  auto typeBit = sourceType.getElementType().getIntOrFloatBitWidth();
+  OpFoldResult linearizedIndices;
+  memref::LinearizedMemRefInfo linearizedInfo;
+  std::tie(linearizedInfo, linearizedIndices) =
+      memref::getLinearizedMemRefOffsetAndSize(
+          rewriter, loc, typeBit, typeBit,
+          stridedMetadata.getConstifiedMixedOffset(),
+          stridedMetadata.getConstifiedMixedSizes(),
+          stridedMetadata.getConstifiedMixedStrides(),
+          getAsOpFoldResult(indices));
+
+  return std::make_pair(
+      rewriter.create<memref::ReinterpretCastOp>(
+          loc, source,
+          /* offset = */ linearizedInfo.linearizedOffset,
+          /* shapes = */
+          ArrayRef<OpFoldResult>{linearizedInfo.linearizedSize},
+          /* strides = */
+          ArrayRef<OpFoldResult>{rewriter.getIndexAttr(1)}),
+      getValueFromOpFoldResult(rewriter, loc, linearizedIndices));
+}
+
+static bool needFlattening(Value val) {
+  auto type = cast<MemRefType>(val.getType());
+  return type.getRank() > 1;
+}
+
+static bool checkLayout(Value val) {
+  auto type = cast<MemRefType>(val.getType());
+  return type.getLayout().isIdentity() ||
+         isa<StridedLayoutAttr>(type.getLayout());
+}
+
+namespace {
+static Value getTargetMemref(Operation *op) {
+  return llvm::TypeSwitch<Operation *, Value>(op)
+      .template Case<memref::LoadOp, memref::StoreOp, memref::AllocaOp,
+                     memref::AllocOp>([](auto op) { return op.getMemref(); })
+      .template Case<vector::LoadOp, vector::StoreOp, vector::MaskedLoadOp,
+                     vector::MaskedStoreOp, vector::TransferReadOp,
+                     vector::TransferWriteOp>(
+          [](auto op) { return op.getBase(); })
+      .Default([](auto) { return Value{}; });
+}
+
+template <typename T>
+static void castAllocResult(T oper, T newOper, Location loc,
+                            PatternRewriter &rewriter) {
+  memref::ExtractStridedMetadataOp stridedMetadata =
+      rewriter.create<memref::ExtractStridedMetadataOp>(loc, oper);
+  rewriter.replaceOpWithNewOp<memref::ReinterpretCastOp>(
+      oper, cast<MemRefType>(oper.getType()), newOper,
+      /*offset=*/rewriter.getIndexAttr(0),
+      stridedMetadata.getConstifiedMixedSizes(),
+      stridedMetadata.getConstifiedMixedStrides());
+}
+
+template <typename T>
+static void replaceOp(T op, PatternRewriter &rewriter, Value flatMemref,
+                      Value offset) {
+  Location loc = op->getLoc();
+  llvm::TypeSwitch<Operation *>(op.getOperation())
+      .template Case<memref::AllocOp>([&](auto oper) {
+        auto newAlloc = rewriter.create<memref::AllocOp>(
+            loc, cast<MemRefType>(flatMemref.getType()),
+            oper.getAlignmentAttr());
+        castAllocResult(oper, newAlloc, loc, rewriter);
+      })
+      .template Case<memref::AllocaOp>([&](auto oper) {
+        auto newAlloca = rewriter.create<memref::AllocaOp>(
+            loc, cast<MemRefType>(flatMemref.getType()),
+            oper.getAlignmentAttr());
+        castAllocResult(oper, newAlloca, loc, rewriter);
+      })
+      .template Case<memref::LoadOp>([&](auto op) {
+        auto newLoad = rewriter.create<memref::LoadOp>(
+            loc, op->getResultTypes(), flatMemref, ValueRange{offset});
+        newLoad->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newLoad.getResult());
+      })
+      .template Case<memref::StoreOp>([&](auto op) {
+        auto newStore = rewriter.create<memref::StoreOp>(
+            loc, op->getOperands().front(), flatMemref, ValueRange{offset});
+        newStore->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newStore);
+      })
+      .template Case<vector::LoadOp>([&](auto op) {
+        auto newLoad = rewriter.create<vector::LoadOp>(
+            loc, op->getResultTypes(), flatMemref, ValueRange{offset});
+        newLoad->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newLoad.getResult());
+      })
+      .template Case<vector::StoreOp>([&](auto op) {
+        auto newStore = rewriter.create<vector::StoreOp>(
+            loc, op->getOperands().front(), flatMemref, ValueRange{offset});
+        newStore->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newStore);
+      })
+      .template Case<vector::MaskedLoadOp>([&](auto op) {
+        auto newMaskedLoad = rewriter.create<vector::MaskedLoadOp>(
+            loc, op.getType(), flatMemref, ValueRange{offset}, op.getMask(),
+            op.getPassThru());
+        newMaskedLoad->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newMaskedLoad.getResult());
+      })
+      .template Case<vector::MaskedStoreOp>([&](auto op) {
+        auto newMaskedStore = rewriter.create<vector::MaskedStoreOp>(
+            loc, flatMemref, ValueRange{offset}, op.getMask(),
+            op.getValueToStore());
+        newMaskedStore->setAttrs(op->getAttrs());
+        rewriter.replaceOp(op, newMaskedStore);
+      })
+      .template Case<vector::TransferReadOp>([&](auto op) {
+        auto newTransferRead = rewriter.create<vector::TransferReadOp>(
+            loc, op.getType(), flatMemref, ValueRange{offset}, op.getPadding());
+        rewriter.replaceOp(op, newTransferRead.getResult());
+      })
+      .template Case<vector::TransferWriteOp>([&](auto op) {
+        auto newTransferWrite = rewriter.create<vector::TransferWriteOp>(
+            loc, op.getVector(), flatMemref, ValueRange{offset});
+        rewriter.replaceOp(op, newTransferWrite);
+      })
+      .Default([&](auto op) {
+        op->emitOpError("unimplemented: do not know how to replace op.");
+      });
+}
+
+template <typename T>
+static ValueRange getIndices(T op) {
+  if constexpr (std::is_same_v<T, memref::AllocaOp> ||
+                std::is_same_v<T, memref::AllocOp>) {
+    return ValueRange{};
+  } else {
+    return op.getIndices();
+  }
+}
+
+template <typename T>
+static LogicalResult canBeFlattened(T op, PatternRewriter &rewriter) {
+  return llvm::TypeSwitch<Operation *, LogicalResult>(op.getOperation())
+      .template Case<vector::TransferReadOp, vector::TransferWriteOp>(
+          [&](auto oper) {
+            // For vector.transfer_read/write, must make sure:
+            // 1. all accesses are inbound, and
+            // 2. has an identity or minor identity permutation map.
+            auto permutationMap = oper.getPermutationMap();
+            if (!permutationMap.isIdentity() &&
+                !permutationMap.isMinorIdentity()) {
+              return rewriter.notifyMatchFailure(
+                  oper, "only identity permutation map is supported");
+            }
+            mlir::ArrayAttr inbounds = oper.getInBounds();
+            if (llvm::any_of(inbounds, [](Attribute attr) {
+                  return !cast<BoolAttr>(attr).getValue();
+                })) {
+              return rewriter.notifyMatchFailure(oper,
+                                                 "only inbounds are supported");
+            }
+            return success();
+          })
+      .Default([&](auto op) { return success(); });
+}
+
+template <typename T>
+struct MemRefRewritePattern : public OpRewritePattern<T> {
+  using OpRewritePattern<T>::OpRewritePattern;
+  LogicalResult matchAndRewrite(T op,
+                                PatternRewriter &rewriter) const override {
+    LogicalResult canFlatten = canBeFlattened(op, rewriter);
+    if (failed(canFlatten)) {
+      return canFlatten;
+    }
+
+    Value memref = getTargetMemref(op);
+    if (!needFlattening(memref) || !checkLayout(memref))
+      return failure();
+    auto &&[flatMemref, offset] = getFlattenMemrefAndOffset(
+        rewriter, op->getLoc(), memref, getIndices<T>(op));
+    replaceOp<T>(op, rewriter, flatMemref, offset);
+    return success();
+  }
+};
+
+struct FlattenMemrefsPass
+    : public mlir::memref::impl::FlattenMemrefsPassBase<FlattenMemrefsPass> {
+  using Base::Base;
+
+  void getDependentDialects(DialectRegistry &registry) const override {
+    registry.insert<affine::AffineDialect, arith::ArithDialect,
+                    memref::MemRefDialect, vector::VectorDialect>();
+  }
+
+  void runOnOperation() override {
+    RewritePatternSet patterns(&getContext());
+
+    memref::populateFlattenMemrefsPatterns(patterns);
+
+    if (failed(applyPatternsGreedily(getOperation(), std::move(patterns))))
+      return signalPassFailure();
+  }
+};
+
+} // namespace
+
+void memref::populateFlattenMemrefsPatterns(RewritePatternSet &patterns) {
+  patterns.insert<MemRefRewritePattern<memref::LoadOp>,
+                  MemRefRewritePattern<memref::StoreOp>,
+                  MemRefRewritePattern<memref::AllocOp>,
+                  MemRefRewritePattern<memref::AllocaOp>,
+                  MemRefRewritePattern<vector::LoadOp>,
+                  MemRefRewritePattern<vector::StoreOp>,
+                  MemRefRewritePattern<vector::TransferReadOp>,
+                  MemRefRewritePattern<vector::TransferWriteOp>,
+                  MemRefRewritePattern<vector::MaskedLoadOp>,
+                  MemRefRewritePattern<vector::MaskedStoreOp>>(
+      patterns.getContext());
+}
diff --git a/mlir/test/Dialect/MemRef/flatten_memref.mlir b/mlir/test/Dialect/MemRef/flatten_memref.mlir
new file mode 100644
index 0000000000000..e45a10ca0d431
--- /dev/null
+++ b/mlir/test/Dialect/MemRef/flatten_memref.mlir
@@ -0,0 +1,300 @@
+// RUN: mlir-opt --flatten-memref %s --split-input-file --verify-diagnostics | FileCheck %s
+
+func.func @load_scalar_from_memref(%input: memref<4x8xf32, strided<[8, 1], offset: 100>>) -> f32 {
+  %c1 = arith.constant 1 : index
+  %c2 = arith.constant 2 : index
+  %value = memref.load %input[%c1, %c2] : memref<4x8xf32, strided<[8, 1], offset: 100>>
+  return %value : f32
+}
+// CHECK-LABEL: func @load_scalar_from_memref
+// CHECK-NEXT: %[[C10:.*]] = arith.constant 10 : index
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast %arg0 to offset: [100], sizes: [32], strides: [1]
+// CHECK-SAME: memref<4x8xf32, strided<[8, 1], offset: 100>> to memref<32xf32, strided<[1], offset: 100>>
+// CHECK-NEXT: memref.load %[[REINT]][%[[C10]]] : memref<32xf32, strided<[1], offset: 100>>
+
+
+// -----
+
+func.func @load_scalar_from_memref_dynamic_dim(%input: memref<?x?xf32, strided<[?, ?], offset: ?>>, %row: index, %col: index) -> f32 {
+  %value = memref.load %input[%col, %row] : memref<?x?xf32, strided<[?, ?], offset: ?>>
+  return %value : f32
+}
+
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1, s2, s3] -> (s0 * s1 + s2 * s3)>
+// CHECK: #[[MAP1:.*]] = affine_map<()[s0, s1, s2, s3] -> (s0 * s1, s2 * s3)>
+// CHECK: func @load_scalar_from_memref_dynamic_dim
+// CHECK-SAME: (%[[ARG0:.*]]: memref<?x?xf32, strided<[?, ?], offset: ?>>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index)
+// CHECK: %[[BASE:.*]], %[[OFFSET:.*]], %[[SIZES:.*]]:2, %[[STRIDES:.*]]:2 = memref.extract_strided_metadata %[[ARG0]]
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[STRIDES]]#0, %[[ARG1]], %[[STRIDES]]#1]
+// CHECK: %[[SIZE:.*]] = affine.max #[[MAP1]]()[%[[STRIDES]]#0, %[[SIZES]]#0, %[[STRIDES]]#1, %[[SIZES]]#1]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %arg0 to offset: [%[[OFFSET]]], sizes: [%[[SIZE]]], strides: [1] : memref<?x?xf32, strided<[?, ?], offset: ?>> to memref<?xf32, strided<[1], offset: ?>> 
+// CHECK: memref.load %[[REINT]][%[[IDX]]]
+
+// -----
+
+func.func @load_scalar_from_memref_static_dim(%input: memref<8x12xf32, strided<[24, 2], offset: 100>>) -> f32 {
+   %c7 = arith.constant 7 : index
+   %c10 = arith.constant 10 : index
+  %value = memref.load %input[%c7, %c10] : memref<8x12xf32, strided<[24, 2], offset: 100>>
+  return %value : f32
+}
+
+// CHECK-LABEL: func @load_scalar_from_memref_static_dim
+// CHECK-SAME: (%[[ARG0:.*]]: memref<8x12xf32, strided<[24, 2], offset: 100>>)
+// CHECK: %[[C188:.*]] = arith.constant 188 : index
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]] to offset: [100], sizes: [192], strides: [1] : memref<8x12xf32, strided<[24, 2], offset: 100>> to memref<192xf32, strided<[1], offset: 100>>
+// CHECK: memref.load %[[REINT]][%[[C188]]] : memref<192xf32, strided<[1], offset: 100>>
+
+// -----
+
+func.func @store_scalar_from_memref_padded(%input: memref<4x8xf32, strided<[18, 2], offset: 100>>, %row: index, %col: index, %value: f32) {
+  memref.store %value, %input[%col, %row] : memref<4x8xf32, strided<[18, 2], offset: 100>>
+  return
+}
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 18 + s1 * 2)>
+// CHECK: func @store_scalar_from_memref_padded
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xf32, strided<[18, 2], offset: 100>>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: f32)
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[ARG1]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]]
+// CHECK: memref.store %[[ARG3]], %[[REINT]][%[[IDX]]] : memref<72xf32, strided<[1], offset: 100>>
+
+// -----
+
+func.func @store_scalar_from_memref_dynamic_dim(%input: memref<?x?xf32, strided<[?, ?], offset: ?>>, %row: index, %col: index, %value: f32) {
+  memref.store %value, %input[%col, %row] : memref<?x?xf32, strided<[?, ?], offset: ?>>
+  return
+}
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1, s2, s3] -> (s0 * s1 + s2 * s3)>
+// CHECK: #[[MAP1:.*]] = affine_map<()[s0, s1, s2, s3] -> (s0 * s1, s2 * s3)>
+// CHECK: func @store_scalar_from_memref_dynamic_dim
+// CHECK-SAME: (%[[ARG0:.*]]: memref<?x?xf32, strided<[?, ?], offset: ?>>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: f32)
+// CHECK: %[[BASE:.*]], %[[OFFSET:.*]], %[[SIZES:.*]]:2, %[[STRIDES:.*]]:2 = memref.extract_strided_metadata %[[ARG0]]
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[STRIDES]]#0, %[[ARG1]], %[[STRIDES]]#1]
+// CHECK: %[[SIZE:.*]] = affine.max #[[MAP1]]()[%[[STRIDES]]#0, %[[SIZES]]#0, %[[STRIDES]]#1, %[[SIZES]]#1]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]] to offset: [%[[OFFSET]]], sizes: [%[[SIZE]]], strides: [1]
+// CHECK: memref.store %[[ARG3]], %[[REINT]][%[[IDX]]]
+
+// -----
+
+func.func @load_vector_from_memref(%input: memref<4x8xf32>) -> vector<8xf32> {
+  %c3 = arith.constant 3 : index
+  %c6 = arith.constant 6 : index
+  %value = vector.load %input[%c3, %c6] : memref<4x8xf32>, vector<8xf32>
+  return %value : vector<8xf32>
+}
+// CHECK-LABEL: func @load_vector_from_memref
+// CHECK: %[[C30:.*]] = arith.constant 30
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast %arg0 to offset: [0], sizes: [32], strides: [1]
+// CHECK-NEXT: vector.load %[[REINT]][%[[C30]]]
+
+// -----
+
+func.func @load_vector_from_memref_odd(%input: memref<3x7xi2>) -> vector<3xi2> {
+  %c1 = arith.constant 1 : index
+  %c3 = arith.constant 3 : index
+  %value = vector.load %input[%c1, %c3] : memref<3x7xi2>, vector<3xi2>
+  return %value : vector<3xi2>
+}
+// CHECK-LABEL: func @load_vector_from_memref_odd
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast
+// CHECK-NEXT: vector.load %[[REINT]][%[[C10]]]
+
+// -----
+
+func.func @load_vector_from_memref_dynamic(%input: memref<3x7xi2>, %row: index, %col: index) -> vector<3xi2> {
+  %value = vector.load %input[%col, %row] : memref<3x7xi2>, vector<3xi2>
+  return %value : vector<3xi2>
+}
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 7 + s1)>
+// CHECK: func @load_vector_from_memref_dynamic
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast
+// CHECK: vector.load %[[REINT]][%[[IDX]]] : memref<21xi2, strided<[1]>>, vector<3xi2>
+
+// -----
+
+func.func @store_vector_to_memref_odd(%input: memref<3x7xi2>, %value: vector<3xi2>) {
+  %c1 = arith.constant 1 : index
+  %c3 = arith.constant 3 : index
+  vector.store %value, %input[%c1, %c3] : memref<3x7xi2>, vector<3xi2>
+  return
+}
+// CHECK-LABEL: func @store_vector_to_memref_odd
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[ARG1:.*]]: vector<3xi2>)
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast
+// CHECK-NEXT: vector.store %[[ARG1]], %[[REINT]][%[[C10]]] : memref<21xi2, strided<[1]>
+
+// -----
+
+func.func @store_vector_to_memref_dynamic(%input: memref<3x7xi2>, %value: vector<3xi2>, %row: index, %col: index) {
+  vector.store %value, %input[%col, %row] : memref<3x7xi2>, vector<3xi2>
+  return
+}
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 7 + s1)>
+// CHECK: func @store_vector_to_memref_dynamic
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[ARG1:.*]]: vector<3xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index)
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG3]], %[[ARG2]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]] to offset: [0], sizes: [21], strides: [1]
+// CHECK: vector.store %[[ARG1]], %[[REINT]][%[[IDX]]]
+
+// -----
+
+func.func @mask_store_vector_to_memref_odd(%input: memref<3x7xi2>, %value: vector<3xi2>, %mask: vector<3xi1>) {
+  %c1 = arith.constant 1 : index
+  %c3 = arith.constant 3 : index
+  vector.maskedstore %input[%c1, %c3], %mask, %value  : memref<3x7xi2>, vector<3xi1>, vector<3xi2>
+  return
+}
+// CHECK-LABEL: func @mask_store_vector_to_memref_odd
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[ARG1:.*]]: vector<3xi2>, %[[ARG2:.*]]: vector<3xi1>)
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast
+// CHECK: vector.maskedstore %[[REINT]][%[[C10]]], %[[ARG2]], %[[ARG1]]
+
+// -----
+
+func.func @mask_store_vector_to_memref_dynamic(%input: memref<3x7xi2>, %value: vector<3xi2>, %row: index, %col: index, %mask: vector<3xi1>) {
+  vector.maskedstore %input[%col, %row], %mask, %value : memref<3x7xi2>, vector<3xi1>, vector<3xi2>
+  return
+}
+// CHECK: #map = affine_map<()[s0, s1] -> (s0 * 7 + s1)>
+// CHECK: func @mask_store_vector_to_memref_dynamic
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[ARG1:.*]]: vector<3xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index, %[[ARG4:.*]]: vector<3xi1>)
+// CHECK: %[[IDX:.*]] = affine.apply #map()[%[[ARG3]], %[[ARG2]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]]
+// CHECK: vector.maskedstore %[[REINT]][%[[IDX]]], %[[ARG4]], %[[ARG1]]
+
+// -----
+func.func @mask_load_vector_from_memref_odd(%input: memref<3x7xi2>, %mask: vector<3xi1>, %passthru: vector<3xi2>) -> vector<3xi2> {
+  %c1 = arith.constant 1 : index
+  %c3 = arith.constant 3 : index
+  %result = vector.maskedload %input[%c1, %c3], %mask, %passthru : memref<3x7xi2>, vector<3xi1>, vector<3xi2> into vector<3xi2>
+  return %result : vector<3xi2>
+}
+// CHECK-LABEL: func @mask_load_vector_from_memref_odd
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[MASK:.*]]: vector<3xi1>, %[[PASSTHRU:.*]]: vector<3xi2>)
+// CHECK: %[[C10:.*]] = arith.constant 10 : index
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]] to offset: [0], sizes: [21], strides: [1]
+// CHECK: vector.maskedload %[[REINT]][%[[C10]]], %[[MASK]], %[[PASSTHRU]]
+
+// -----
+
+func.func @mask_load_vector_from_memref_dynamic(%input: memref<3x7xi2>, %row: index, %col: index, %mask: vector<3xi1>, %passthru: vector<3xi2>) -> vector<3xi2> {
+  %result = vector.maskedload %input[%col, %row], %mask, %passthru : memref<3x7xi2>, vector<3xi1>, vector<3xi2> into vector<3xi2>
+  return %result : vector<3xi2>
+}
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 7 + s1)>
+// CHECK: func @mask_load_vector_from_memref_dynamic
+// CHECK-SAME: (%[[ARG0:.*]]: memref<3x7xi2>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: vector<3xi1>, %[[ARG4:.*]]: vector<3xi2>)
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[ARG1]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]]
+// CHECK: vector.maskedload %[[REINT]][%[[IDX]]], %[[ARG3]]
+
+// -----
+
+func.func @transfer_read_memref(%input: memref<4x8xi2>, %value: vector<8xi2>, %row: index, %col: index) -> vector<8xi2> {
+   %c0 = arith.constant 0 : i2
+   %0 = vector.transfer_read %input[%col, %row], %c0 {in_bounds = [true]} : memref<4x8xi2>, vector<8xi2>
+   return %0 : vector<8xi2>
+}
+
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 8 + s1)>
+// CHECK: func @transfer_read_memref
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xi2>, %[[ARG1:.*]]: vector<8xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index)
+// CHECK: %[[C0:.*]] = arith.constant 0 : i2
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG3]], %[[ARG2]]]
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]]
+// CHECK-NEXT: vector.transfer_read %[[REINT]][%[[IDX]]], %[[C0]]
+
+// -----
+
+func.func @transfer_read_memref_not_inbound(%input: memref<4x8xi2>, %value: vector<8xi2>, %row: index, %col: index) -> vector<8xi2> {
+   %c0 = arith.constant 0 : i2
+   %0 = vector.transfer_read %input[%col, %row], %c0 {in_bounds = [false]} : memref<4x8xi2>, vector<8xi2>
+   return %0 : vector<8xi2>
+}
+
+// CHECK-LABEL: func @transfer_read_memref_not_inbound
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xi2>, %[[ARG1:.*]]: vector<8xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index)
+// CHECK: vector.transfer_read %[[ARG0]][%[[ARG3]], %[[ARG2]]]
+
+// -----
+
+func.func @transfer_read_memref_non_id(%input: memref<4x8xi2>, %value: vector<8xi2>, %row: index, %col: index) -> vector<8xi2> {
+   %c0 = arith.constant 0 : i2
+   %0 = vector.transfer_read %input[%col, %row], %c0 {permutation_map = affine_map<(d0, d1) -> (d0)>, in_bounds = [true]} : memref<4x8xi2>, vector<8xi2>
+   return %0 : vector<8xi2>
+}
+
+// CHECK-LABEL: func @transfer_read_memref_non_id
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xi2>, %[[ARG1:.*]]: vector<8xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index)
+// CHECK: vector.transfer_read %[[ARG0]][%[[ARG3]], %[[ARG2]]]
+
+// -----
+
+func.func @transfer_write_memref(%input: memref<4x8xi2>, %value: vector<8xi2>, %row: index, %col: index) {
+   vector.transfer_write %value, %input[%col, %row] {in_bounds = [true]} : vector<8xi2>, memref<4x8xi2>
+   return
+}
+
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 * 8 + s1)>
+// CHECK: func @transfer_write_memref
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xi2>, %[[ARG1:.*]]: vector<8xi2>, %[[ARG2:.*]]: index, %[[ARG3:.*]]: index)
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG3]], %[[ARG2]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]]
+// CHECK: vector.transfer_write %[[ARG1]], %[[REINT]][%[[IDX]]]
+
+// -----
+
+func.func @alloc() -> memref<4x8xf32> {
+  %0 = memref.alloc() : memref<4x8xf32>
+  return %0 : memref<4x8xf32>
+}
+
+// CHECK-LABEL: func @alloc
+// CHECK-SAME: () -> memref<4x8xf32>
+// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc() : memref<32xf32, strided<[1]>>
+// CHECK-NEXT: %[[REINT:.*]] = memref.reinterpret_cast %[[ALLOC]] to offset: [0], sizes: [4, 8], strides: [8, 1] : memref<32xf32, strided<[1]>> to memref<4x8xf32>
+
+// -----
+
+func.func @alloca() -> memref<4x8xf32> {
+  %0 = memref.alloca() : memref<4x8xf32>
+  return %0 : memref<4x8xf32>
+}
+
+// CHECK-LABEL: func.func @alloca() -> memref<4x8xf32>
+// CHECK: %[[ALLOC:.*]] = memref.alloca() : memref<32xf32, strided<[1]>>
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ALLOC]] to offset: [0], sizes: [4, 8], strides: [8, 1] : memref<32xf32, strided<[1]>> to memref<4x8xf32>
+
+// -----
+
+func.func @chained_alloc_load() -> vector<8xf32> {
+  %c3 = arith.constant 3 : index
+  %c6 = arith.constant 6 : index
+  %0 = memref.alloc() : memref<4x8xf32>
+  %value = vector.load %0[%c3, %c6] : memref<4x8xf32>, vector<8xf32>
+  return %value : vector<8xf32>
+}
+
+// CHECK-LABEL: func @chained_alloc_load
+// CHECK-SAME: () -> vector<8xf32>
+// CHECK-NEXT: %[[C30:.*]] = arith.constant 30 : index
+// CHECK-NEXT: %[[ALLOC:.*]] = memref.alloc() : memref<32xf32, strided<[1]>>
+// CHECK-NEXT: vector.load %[[ALLOC]][%[[C30]]] : memref<32xf32, strided<[1]>>, vector<8xf32>
+
+// -----
+
+func.func @load_scalar_from_memref_static_dim_col_major(%input: memref<4x8xf32, strided<[1, 4], offset: 100>>, %row: index, %col: index) -> f32 {
+  %value = memref.load %input[%col, %row] : memref<4x8xf32, strided<[1, 4], offset: 100>>
+  return %value : f32
+}
+
+// CHECK: #[[MAP:.*]] = affine_map<()[s0, s1] -> (s0 + s1 * 4)>
+// CHECK: func @load_scalar_from_memref_static_dim_col_major
+// CHECK-SAME: (%[[ARG0:.*]]: memref<4x8xf32, strided<[1, 4], offset: 100>>, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index)
+// CHECK: %[[IDX:.*]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[ARG1]]]
+// CHECK: %[[REINT:.*]] = memref.reinterpret_cast %[[ARG0]] to offset: [100], sizes: [32], strides: [1] : memref<4x8xf32, strided<[1, 4], offset: 100>> to memref<32xf32, strided<[1], offset: 100>>
+// CHECK: memref.load %[[REINT]][%[[IDX]]] : memref<32xf32, strided<[1], offset: 100>>

>From 30a9d9d25be2a7688e835ee66d6a7061c9079976 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 10:12:25 -0700
Subject: [PATCH 023/105] [Analysis] Fix warnings

This patch fixes:

  llvm/lib/Analysis/IR2Vec.cpp:76:3: error: default label in switch
  which covers all enumeration values
  [-Werror,-Wcovered-switch-default]

  llvm/lib/Analysis/IR2Vec.cpp:218:12: error: unused variable 'Dim'
  [-Werror,-Wunused-variable]
---
 llvm/lib/Analysis/IR2Vec.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/IR2Vec.cpp b/llvm/lib/Analysis/IR2Vec.cpp
index d4d6bfc910abc..4c40d5b558143 100644
--- a/llvm/lib/Analysis/IR2Vec.cpp
+++ b/llvm/lib/Analysis/IR2Vec.cpp
@@ -73,10 +73,8 @@ Expected<std::unique_ptr<Embedder>> Embedder::create(IR2VecKind Mode,
   switch (Mode) {
   case IR2VecKind::Symbolic:
     return std::make_unique<SymbolicEmbedder>(F, Vocabulary, Dimension);
-  default:
-    return make_error<StringError>("Unknown IR2VecKind",
-                                   errc::invalid_argument);
   }
+  return make_error<StringError>("Unknown IR2VecKind", errc::invalid_argument);
 }
 
 void Embedder::addVectors(Embedding &Dst, const Embedding &Src) {
@@ -217,6 +215,7 @@ Error IR2VecVocabAnalysis::readVocabulary() {
 
   unsigned Dim = Vocabulary.begin()->second.size();
   assert(Dim > 0 && "Dimension of vocabulary is zero");
+  (void)Dim;
   assert(std::all_of(Vocabulary.begin(), Vocabulary.end(),
                      [Dim](const std::pair<StringRef, Embedding> &Entry) {
                        return Entry.second.size() == Dim;

>From 35434f2cd9b0920df93bda743eff99fbcf9de3b7 Mon Sep 17 00:00:00 2001
From: Andres-Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 22 May 2025 12:23:06 -0500
Subject: [PATCH 024/105] [CIR] Upstream support for lowering cir.switch to
 LLVM (#140425)

This PR adds support for lowering the `cir.switch` operation to LLVM. It
includes tests for lowering from `.cir` as well as end-to-end source
code tests.
---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  28 ++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h   |  10 +
 clang/test/CIR/CodeGen/switch.cpp             | 424 +++++++++++++++++-
 clang/test/CIR/Lowering/switch.cir            | 190 ++++++++
 4 files changed, 651 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/Lowering/switch.cir

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index ff4a083b15d75..3d86f3d4deffb 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1065,6 +1065,33 @@ mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMSwitchFlatOpLowering::matchAndRewrite(
+    cir::SwitchFlatOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+
+  llvm::SmallVector<mlir::APInt, 8> caseValues;
+  for (mlir::Attribute val : op.getCaseValues()) {
+    auto intAttr = cast<cir::IntAttr>(val);
+    caseValues.push_back(intAttr.getValue());
+  }
+
+  llvm::SmallVector<mlir::Block *, 8> caseDestinations;
+  llvm::SmallVector<mlir::ValueRange, 8> caseOperands;
+
+  for (mlir::Block *x : op.getCaseDestinations())
+    caseDestinations.push_back(x);
+
+  for (mlir::OperandRange x : op.getCaseOperands())
+    caseOperands.push_back(x);
+
+  // Set switch op to branch to the newly created blocks.
+  rewriter.setInsertionPoint(op);
+  rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
+      op, adaptor.getCondition(), op.getDefaultDestination(),
+      op.getDefaultOperands(), caseValues, caseDestinations, caseOperands);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
     cir::UnaryOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
@@ -1681,6 +1708,7 @@ void ConvertCIRToLLVMPass::runOnOperation() {
                CIRToLLVMGetGlobalOpLowering,
                CIRToLLVMGetMemberOpLowering,
                CIRToLLVMSelectOpLowering,
+               CIRToLLVMSwitchFlatOpLowering,
                CIRToLLVMShiftOpLowering,
                CIRToLLVMStackSaveOpLowering,
                CIRToLLVMStackRestoreOpLowering,
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
index bd077e3d1d1e0..dde0cfcabe395 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
@@ -149,6 +149,16 @@ class CIRToLLVMFuncOpLowering : public mlir::OpConversionPattern<cir::FuncOp> {
                   mlir::ConversionPatternRewriter &) const override;
 };
 
+class CIRToLLVMSwitchFlatOpLowering
+    : public mlir::OpConversionPattern<cir::SwitchFlatOp> {
+public:
+  using mlir::OpConversionPattern<cir::SwitchFlatOp>::OpConversionPattern;
+
+  mlir::LogicalResult
+  matchAndRewrite(cir::SwitchFlatOp op, OpAdaptor,
+                  mlir::ConversionPatternRewriter &) const override;
+};
+
 class CIRToLLVMGetGlobalOpLowering
     : public mlir::OpConversionPattern<cir::GetGlobalOp> {
 public:
diff --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp
index 0bd4e0759e634..a3dbac89fb856 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
 /// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
 // RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
 // RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
 void sw1(int a) {
@@ -28,6 +30,36 @@ void sw1(int a) {
 // CIR: cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init]
 // CIR: cir.break
 
+// LLVM: define void @_Z3sw1i
+// LLVM:   store i32 1, ptr %[[B_ADDR:.*]], align 4
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
+// LLVM:   br label %[[BB7:.*]]
+// LLVM: [[BB7]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM-DAG:   i32 0, label %[[CASE0:.*]]
+// LLVM-DAG:   i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:   i32 2, label %[[CASE2:.*]]
+// LLVM:   ]
+// LLVM: [[CASE0]]:
+// LLVM:   %[[B:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[INC0:.*]] = add nsw i32 %[[B]], 1
+// LLVM:   store i32 %[[INC0]], ptr %[[B_ADDR]], align 4
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[CASE2]]:
+// LLVM:   br label %[[BB14:.*]]
+// LLVM: [[BB14]]:
+// LLVM:   %[[B2:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[INC2:.*]] = add nsw i32 %[[B2]], 1
+// LLVM:   store i32 %[[INC2]], ptr %[[B_ADDR]], align 4
+// LLVM:   store i32 100, ptr %[[YOLO:.*]], align 4
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[DEFAULT:.*]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw1i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -74,6 +106,26 @@ void sw2(int a) {
 // CIR-NEXT:     %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
 // CIR-NEXT:     cir.store %[[ZERO]], %[[FOMO]] : !s32i, !cir.ptr<!s32i>
 
+// LLVM: define void @_Z3sw2i
+// LLVM:   store i32 2, ptr %[[YOLO_ADDR:.*]], align 4
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM:     i32 3, label %[[CASE3:.*]]
+// LLVM:   ]
+// LLVM: [[CASE3]]:
+// LLVM:   store i32 0, ptr %[[FOMO_ADDR:.*]], align 4
+// LLVM:   %[[YOLO_VAL:.*]] = load i32, ptr %[[YOLO_ADDR]], align 4
+// LLVM:   %[[FOMO_VAL:.*]] = load i32, ptr %[[FOMO_ADDR]], align 4
+// LLVM:   %[[YOLO_PLUS_FOMO:.*]] = add nsw i32 %[[YOLO_VAL]], %[[FOMO_VAL]]
+// LLVM:   store i32 %[[YOLO_PLUS_FOMO]], ptr %[[YOLO_ADDR]], align 4
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw2i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -109,6 +161,19 @@ void sw3(int a) {
 // CIR-NEXT:   cir.yield
 // CIR-NEXT:   }
 
+// LLVM-LABEL: define void @_Z3sw3i
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
+// LLVM:   ]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT:.*]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw3i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -150,6 +215,32 @@ int sw4(int a) {
 // CIR-NEXT:       cir.yield
 // CIR-NEXT:  }
 
+// LLVM: define i32 @_Z3sw4i
+// LLVM:   %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   %[[RET_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   br label %[[ENTRY:.*]]
+// LLVM: [[ENTRY]]:
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 42, label %[[CASE42:.*]]
+// LLVM:   ]
+// LLVM: [[CASE42]]:
+// LLVM:   br label %[[CASE42_BODY:.*]]
+// LLVM: [[CASE42_BODY]]:
+// LLVM:   store i32 3, ptr %[[RET_ADDR]], align 4
+// LLVM:   %[[RET3:.*]] = load i32, ptr %[[RET_ADDR]], align 4
+// LLVM:   ret i32 %[[RET3]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   store i32 2, ptr %[[RET_ADDR]], align 4
+// LLVM:   %[[RET2:.*]] = load i32, ptr %[[RET_ADDR]], align 4
+// LLVM:   ret i32 %[[RET2]]
+// LLVM: [[EXIT_UNRE:.*]]:
+// LLVM:   store i32 0, ptr %[[RET_ADDR]], align 4
+// LLVM:   %[[RET0:.*]] = load i32, ptr %[[RET_ADDR]], align 4
+// LLVM:   ret i32 %[[RET0]]
+
 // OGCG: define dso_local noundef i32 @_Z3sw4i
 // OGCG: entry:
 // OGCG:   %[[RETVAL:.*]] = alloca i32, align 4
@@ -180,6 +271,23 @@ void sw5(int a) {
 // CIR-NEXT:   cir.yield
 // CIR-NEXT:   }
 
+// LLVM-LABEL: define void @_Z3sw5i
+// LLVM:   %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   br label %[[ENTRY:.*]]
+// LLVM: [[ENTRY]]:
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM:   ]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw5i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -226,6 +334,42 @@ void sw6(int a) {
 // CIR-NEXT:     cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z3sw6i
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM-DAG:     i32 0, label %[[CASE0:.*]]
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:     i32 2, label %[[CASE2:.*]]
+// LLVM-DAG:     i32 3, label %[[CASE3:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE4:.*]]
+// LLVM-DAG:     i32 5, label %[[CASE5:.*]]
+// LLVM:   ]
+// LLVM: [[CASE0]]:
+// LLVM:   br label %[[CASE0_CONT:.*]]
+// LLVM: [[CASE0_CONT]]:
+// LLVM:   br label %[[CASE1]]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[CASE1_CONT:.*]]
+// LLVM: [[CASE1_CONT]]:
+// LLVM:   br label %[[CASE2]]
+// LLVM: [[CASE2]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[CASE3]]:
+// LLVM:   br label %[[CASE3_CONT:.*]]
+// LLVM: [[CASE3_CONT]]:
+// LLVM:   br label %[[CASE4]]
+// LLVM: [[CASE4]]:
+// LLVM:   br label %[[CASE4_CONT:.*]]
+// LLVM: [[CASE4_CONT]]:
+// LLVM:   br label %[[CASE5]]
+// LLVM: [[CASE5]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
 
 // OGCG: define dso_local void @_Z3sw6i
 // OGCG: entry:
@@ -284,6 +428,45 @@ void sw7(int a) {
 // CIR-NEXT: cir.yield
 // CIR: }
 
+// LLVM: define void @_Z3sw7i
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR:.*]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM-DAG:     i32 0, label %[[CASE0:.*]]
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:     i32 2, label %[[CASE2:.*]]
+// LLVM-DAG:     i32 3, label %[[CASE3:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE4:.*]]
+// LLVM-DAG:     i32 5, label %[[CASE5:.*]]
+// LLVM:   ]
+// LLVM: [[CASE0]]:
+// LLVM:   br label %[[CASE0_CONT:.*]]
+// LLVM: [[CASE0_CONT]]:
+// LLVM:   br label %[[CASE1]]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[CASE1_CONT:.*]]
+// LLVM: [[CASE1_CONT]]:
+// LLVM:   br label %[[CASE2]]
+// LLVM: [[CASE2]]:
+// LLVM:   br label %[[CASE2_CONT:.*]]
+// LLVM: [[CASE2_CONT]]:
+// LLVM:   br label %[[CASE3]]
+// LLVM: [[CASE3]]:
+// LLVM:   br label %[[CASE3_CONT:.*]]
+// LLVM: [[CASE3_CONT]]:
+// LLVM:   br label %[[CASE4]]
+// LLVM: [[CASE4]]:
+// LLVM:   br label %[[CASE4_CONT:.*]]
+// LLVM: [[CASE4_CONT]]:
+// LLVM:   br label %[[CASE5]]
+// LLVM: [[CASE5]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw7i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -327,6 +510,23 @@ void sw8(int a) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z3sw8i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:  i32 3, label %[[CASE3:.*]]
+// LLVM-DAG:  i32 4, label %[[CASE4:.*]]
+// LLVM:   ]
+// LLVM: [[CASE3]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[CASE4]]:
+// LLVM:   br label %[[CASE4_CONT:.*]]
+// LLVM: [[CASE4_CONT]]:
+// LLVM:   br label %[[DEFAULT]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT]]:
+// LLVM:    br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
 
 // OGCG: define dso_local void @_Z3sw8i
 // OGCG: entry:
@@ -368,6 +568,24 @@ void sw9(int a) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z3sw9i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 3, label %[[CASE3:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE4:.*]]
+// LLVM:   ]
+// LLVM: [[CASE3]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[DEFAULT_CONT:.*]]
+// LLVM: [[DEFAULT_CONT]]:
+// LLVM:   br label %[[CASE4]]
+// LLVM: [[CASE4]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z3sw9i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -412,6 +630,29 @@ void sw10(int a) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z4sw10i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 3, label %[[CASE_3:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE_4:.*]]
+// LLVM-DAG:     i32 5, label %[[CASE_5:.*]]
+// LLVM:   ]
+// LLVM: [[CASE_3]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[CASE_4]]:
+// LLVM:   br label %[[CASE4_CONT:.*]]
+// LLVM: [[CASE4_CONT]]:
+// LLVM:   br label %[[DEFAULT]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[DEFAULT_CONT:.*]]
+// LLVM: [[DEFAULT_CONT]]:
+// LLVM:   br label %[[CASE_5]]
+// LLVM: [[CASE_5]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw10i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -467,6 +708,39 @@ void sw11(int a) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z4sw11i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 3, label %[[CASE_3:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE_4:.*]]
+// LLVM-DAG:     i32 5, label %[[CASE_5:.*]]
+// LLVM-DAG:     i32 6, label %[[CASE_6:.*]]
+// LLVM-DAG:     i32 7, label %[[CASE_7:.*]]
+// LLVM:   ]
+// LLVM: [[CASE_3]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[CASE_4]]:
+// LLVM:   br label %[[CASE4_CONT:.*]]
+// LLVM: [[CASE4_CONT]]:
+// LLVM:   br label %[[CASE_5]]
+// LLVM: [[CASE_5]]:
+// LLVM:   br label %[[CASE5_CONT:.*]]
+// LLVM: [[CASE5_CONT]]:
+// LLVM:   br label %[[DEFAULT]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[DEFAULT_CONT:.*]]
+// LLVM: [[DEFAULT_CONT]]:
+// LLVM:   br label %[[CASE_6]]
+// LLVM: [[CASE_6]]:
+// LLVM:   br label %[[CASE6_CONT:.*]]
+// LLVM: [[CASE6_CONT]]:
+// LLVM:   br label %[[CASE_7]]
+// LLVM: [[CASE_7]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw11i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -507,6 +781,19 @@ void sw12(int a) {
 // CIR-NEXT:       cir.break
 // CIR-NEXT:     }
 
+// LLVM: define void @_Z4sw12i
+// LLVM:   switch i32 %[[COND:.*]], label %[[EXIT:.*]] [
+// LLVM-DAG:     i32 3, label %[[CASE_3:.*]]
+// LLVM:   ]
+// LLVM: [[CASE_3]]:
+// LLVM:   ret void
+// LLVM: [[UNREACHABLE:.*]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw12i
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -545,6 +832,32 @@ void sw13(int a, int b) {
 //      CIR:    }
 //      CIR:    cir.return
 
+// LLVM: define void @_Z4sw13ii
+// LLVM:   switch i32 %[[COND:.*]], label %[[OUTER_EXIT:.*]] [
+// LLVM-DAG:     i32 1, label %[[CASE_A_1:.*]]
+// LLVM:   ]
+// LLVM: [[CASE_A_1]]:
+// LLVM:   br label %[[LOAD_B:.*]]
+// LLVM: [[LOAD_B]]:
+// LLVM:   %[[B_VAL:.*]] = load i32, ptr %[[B_ADDR:.*]], align 4
+// LLVM:   br label %[[INNER_SWITCH:.*]]
+// LLVM: [[INNER_SWITCH]]:
+// LLVM:   switch i32 %[[B_VAL]], label %[[INNER_EXIT:.*]] [
+// LLVM-DAG:     i32 2, label %[[CASE_B_2:.*]]
+// LLVM:   ]
+// LLVM: [[CASE_B_2]]:
+// LLVM:   br label %[[INNER_EXIT]]
+// LLVM: [[INNER_EXIT]]:
+// LLVM:   br label %[[INNER_EXIT_CONT:.*]]
+// LLVM: [[INNER_EXIT_CONT]]:
+// LLVM:   br label %[[MERGE:.*]]
+// LLVM: [[MERGE]]:
+// LLVM:   br label %[[OUTER_EXIT]]
+// LLVM: [[OUTER_EXIT]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[EXIT]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw13ii
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
@@ -595,12 +908,42 @@ void sw14(int x) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z4sw14i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:     i32 2, label %[[CASE2:.*]]
+// LLVM-DAG:     i32 3, label %[[CASE3_TO_6:.*]]
+// LLVM-DAG:     i32 4, label %[[CASE3_TO_6]]
+// LLVM-DAG:     i32 5, label %[[CASE3_TO_6]]
+// LLVM-DAG:     i32 6, label %[[CASE3_TO_6]]
+// LLVM-DAG:     i32 7, label %[[CASE7:.*]]
+// LLVM:   ]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[AFTER1:.*]]
+// LLVM: [[AFTER1]]:
+// LLVM:   br label %[[CASE2]]
+// LLVM: [[CASE2]]:
+// LLVM:   br label %[[AFTER2:.*]]
+// LLVM: [[AFTER2]]:
+// LLVM:   br label %[[CASE3_TO_6]]
+// LLVM: [[CASE3_TO_6]]:
+// LLVM:   br label %[[AFTER3_6:.*]]
+// LLVM: [[AFTER3_6]]:
+// LLVM:   br label %[[CASE7]]
+// LLVM: [[CASE7]]:
+// LLVM:   br label %[[EXIT1:.*]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[EXIT1]]
+// LLVM: [[EXIT1]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw14i
 // OGCG: entry:
 // OGCG:   %[[X_ADDR:.*]] = alloca i32, align 4
 // OGCG:   store i32 %x, ptr %[[X_ADDR]], align 4
 // OGCG:   %[[X_VAL:.*]] = load i32, ptr %[[X_ADDR]], align 4
-
 // OGCG:   switch i32 %[[X_VAL]], label %[[DEFAULT:.*]] [
 // OGCG-DAG:     i32 1, label %[[BB1:.*]]
 // OGCG-DAG:     i32 2, label %[[BB1]]
@@ -652,6 +995,30 @@ void sw15(int x) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
+// LLVM: define void @_Z4sw15i
+// LLVM:   switch i32 %[[COND:.*]], label %[[DEFAULT:.*]] [
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:     i32 2, label %[[CASE2:.*]]
+// LLVM-DAG:     i32 3, label %[[CASE3:.*]]
+// LLVM:   ]
+// LLVM: [[CASE1]]:
+// LLVM:   br label %[[CASE1_CONT:.*]]
+// LLVM: [[CASE1_CONT]]:
+// LLVM:   br label %[[CASE2]]
+// LLVM: [[CASE2]]:
+// LLVM:   store i32 0, ptr %[[Y_ADDR:.*]], align 4
+// LLVM:   br label %[[CASE2_CONT:.*]]
+// LLVM: [[CASE2_CONT]]:
+// LLVM:   br label %[[CASE3]]
+// LLVM: [[CASE3]]:
+// LLVM:   br label %[[EXIT:.*]]
+// LLVM: [[DEFAULT]]:
+// LLVM:   br label %[[EXIT]]
+// LLVM: [[EXIT]]:
+// LLVM:   br label %[[RET:.*]]
+// LLVM: [[RET]]:
+// LLVM:   ret void
+
 // OGCG: define dso_local void @_Z4sw15i
 // OGCG: entry:
 // OGCG:   %[[X_ADDR:.*]] = alloca i32, align 4
@@ -714,6 +1081,61 @@ int nested_switch(int a) {
 // CIR:           cir.case(equal, [#cir.int<7> : !s32i]) {
 // CIR:           cir.return
 
+// LLVM: define i32 @_Z13nested_switchi
+// LLVM:   %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   %[[RES_ADDR:.*]] = alloca i32, i64 1, align 4
+// LLVM:   store i32 %[[ARG:.*]], ptr %[[A_ADDR]], align 4
+// LLVM:   br label %[[ENTRY:.*]]
+// LLVM: [[ENTRY]]:
+// LLVM:   store i32 1, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM:   br label %[[SWITCH:.*]]
+// LLVM: [[SWITCH]]:
+// LLVM:   switch i32 %[[A_VAL]], label %[[EXIT:.*]] [
+// LLVM-DAG:     i32 0, label %[[CASE0:.*]]
+// LLVM-DAG:     i32 1, label %[[CASE1:.*]]
+// LLVM-DAG:     i32 2, label %[[CASE2:.*]]
+// LLVM-DAG:     i32 9, label %[[CASE9:.*]]
+// LLVM-DAG:     i32 7, label %[[CASE7:.*]]
+// LLVM:   ]
+// LLVM: [[CASE0]]:
+// LLVM:   %[[B0:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[B1:.*]] = add nsw i32 %[[B0]], 1
+// LLVM:   store i32 %[[B1]], ptr %[[B_ADDR]], align 4
+// LLVM:   br label %[[CASE0_CONT:.*]]
+// LLVM: [[CASE0_CONT]]:
+// LLVM:   br label %[[CASE1]]
+// LLVM: [[CASE1]]:
+// LLVM:   %[[B1a:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   store i32 %[[B1a]], ptr %[[RES_ADDR]], align 4
+// LLVM:   %[[RET1:.*]] = load i32, ptr %[[RES_ADDR]], align 4
+// LLVM:   ret i32 %[[RET1]]
+// LLVM: [[CASE2]]:
+// LLVM:   br label %[[CASE2_BODY:.*]]
+// LLVM: [[CASE2_BODY]]:
+// LLVM:   %[[B2:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[B3:.*]] = add nsw i32 %[[B2]], 1
+// LLVM:   store i32 %[[B3]], ptr %[[B_ADDR]], align 4
+// LLVM:   br label %[[CASE2_CONT:.*]]
+// LLVM: [[CASE9]]:
+// LLVM:   %[[A9:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM:   %[[B4:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[SUM9:.*]] = add nsw i32 %[[A9]], %[[B4]]
+// LLVM:   store i32 %[[SUM9]], ptr %[[B_ADDR]], align 4
+// LLVM:   br label %[[CASE2_CONT1:.*]]
+// LLVM: [[CASE7]]:
+// LLVM:   %[[A7:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// LLVM:   %[[B5:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// LLVM:   %[[SUM7:.*]] = add nsw i32 %[[A7]], %[[B5]]
+// LLVM:   store i32 %[[SUM7]], ptr %[[RES_ADDR]], align 4
+// LLVM:   %[[RET7:.*]] = load i32, ptr %[[RES_ADDR]], align 4
+// LLVM:   ret i32 %[[RET7]]
+// LLVM: [[EXIT]]:
+// LLVM:   store i32 0, ptr %[[RES_ADDR]], align 4
+// LLVM:   %[[RET0:.*]] = load i32, ptr %[[RES_ADDR]], align 4
+// LLVM:   ret i32 %[[RET0]]
+
 // OGCG: define dso_local noundef i32 @_Z13nested_switchi
 // OGCG: entry:
 // OGCG:   %[[RETVAL:.*]] = alloca i32, align 4
diff --git a/clang/test/CIR/Lowering/switch.cir b/clang/test/CIR/Lowering/switch.cir
new file mode 100644
index 0000000000000..9434b7337f7ed
--- /dev/null
+++ b/clang/test/CIR/Lowering/switch.cir
@@ -0,0 +1,190 @@
+// RUN: cir-opt %s -cir-to-llvm -o %t.mlir
+// RUN: FileCheck --input-file=%t.mlir %s
+
+!s8i = !cir.int<s, 8>
+!s32i = !cir.int<s, 32>
+!s64i = !cir.int<s, 64>
+
+module {
+  cir.func @shouldLowerSwitchWithDefault(%arg0: !s8i) {
+    cir.switch (%arg0 : !s8i) {
+    // CHECK: llvm.switch %arg0 : i8, ^bb[[#DEFAULT:]] [
+    // CHECK:   1: ^bb[[#CASE1:]]
+    // CHECK: ]
+    cir.case (equal, [#cir.int<1> : !s8i]) {
+      cir.break
+    }
+    // CHECK: ^bb[[#CASE1]]:
+    // CHECK:   llvm.br ^bb[[#EXIT:]]
+    cir.case (default, []) {
+      cir.break
+    }
+    // CHECK: ^bb[[#DEFAULT]]:
+    // CHECK:   llvm.br ^bb[[#EXIT]]
+    cir.yield
+    }
+    // CHECK: ^bb[[#EXIT]]:
+    cir.return
+  }
+
+
+  cir.func @shouldLowerSwitchWithoutDefault(%arg0: !s32i) {
+    cir.switch (%arg0 : !s32i) {
+    // Default block is the exit block:
+    // CHECK: llvm.switch %arg0 : i32, ^bb[[#EXIT:]] [
+    // CHECK:   1: ^bb[[#CASE1:]]
+    // CHECK: ]
+    cir.case (equal, [#cir.int<1> : !s32i]) {
+      cir.break
+    }
+    // CHECK: ^bb[[#CASE1]]:
+    // CHECK:   llvm.br ^bb[[#EXIT]]
+    cir.yield
+    }
+    // CHECK: ^bb[[#EXIT]]:
+    cir.return
+  }
+
+
+  cir.func @shouldLowerSwitchWithImplicitFallthrough(%arg0: !s64i) {
+    cir.switch (%arg0 : !s64i) {
+    // CHECK: llvm.switch %arg0 : i64, ^bb[[#EXIT:]] [
+    // CHECK:   1: ^bb[[#CASE1N2:]],
+    // CHECK:   2: ^bb[[#CASE1N2]]
+    // CHECK: ]
+    cir.case (anyof, [#cir.int<1> : !s64i, #cir.int<2> : !s64i]) { // case 1 and 2 use same region
+      cir.break
+    }
+    // CHECK: ^bb[[#CASE1N2]]:
+    // CHECK:   llvm.br ^bb[[#EXIT]]
+    cir.yield
+    }
+    // CHECK: ^bb[[#EXIT]]:
+    cir.return
+  }
+
+
+  cir.func @shouldLowerSwitchWithExplicitFallthrough(%arg0: !s64i) {
+      cir.switch (%arg0 : !s64i) {
+      // CHECK: llvm.switch %arg0 : i64, ^bb[[#EXIT:]] [
+      // CHECK:   1: ^bb[[#CASE1:]],
+      // CHECK:   2: ^bb[[#CASE2:]]
+      // CHECK: ]
+      cir.case (equal, [#cir.int<1> : !s64i]) { // case 1 has its own region
+        cir.yield // fallthrough to case 2
+      }
+      // CHECK: ^bb[[#CASE1]]:
+      // CHECK:   llvm.br ^bb[[#CASE2]]
+      cir.case (equal, [#cir.int<2> : !s64i]) {
+        cir.break
+      }
+      // CHECK: ^bb[[#CASE2]]:
+      // CHECK:   llvm.br ^bb[[#EXIT]]
+      cir.yield
+      }
+      // CHECK: ^bb[[#EXIT]]:
+    cir.return
+  }
+
+
+  cir.func @shouldLowerSwitchWithFallthroughToExit(%arg0: !s64i) {
+      cir.switch (%arg0 : !s64i) {
+      // CHECK: llvm.switch %arg0 : i64, ^bb[[#EXIT:]] [
+      // CHECK:   1: ^bb[[#CASE1:]]
+      // CHECK: ]
+       cir.case (equal, [#cir.int<1> : !s64i]) {
+        cir.yield // fallthrough to exit
+      }
+      // CHECK: ^bb[[#CASE1]]:
+      // CHECK:   llvm.br ^bb[[#EXIT]]
+      cir.yield
+      }
+      // CHECK: ^bb[[#EXIT]]:
+    cir.return
+  }
+
+
+  cir.func @shouldDropEmptySwitch(%arg0: !s64i) {
+    cir.switch (%arg0 : !s64i) {
+      cir.yield
+    }
+    // CHECK-NOT: llvm.switch
+    cir.return
+  }
+
+  cir.func @shouldLowerMultiBlockCase(%arg0: !s32i) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%1 : !s32i) {
+      cir.case (equal, [#cir.int<3> : !s32i]) {
+        cir.return
+      ^bb1:  // no predecessors
+        cir.break
+      }
+      cir.yield
+      }
+    }
+    cir.return
+  }
+  // CHECK: llvm.func @shouldLowerMultiBlockCase
+  // CHECK: ^bb1:  // pred: ^bb0
+  // CHECK:   llvm.switch {{.*}} : i32, ^[[DEFAULT_BB:.+]] [
+  // CHECK:     3: ^[[DIRECTLY_RET_BB:.+]]
+  // CHECK:   ]
+  // CHECK: ^[[DIRECTLY_RET_BB]]:
+  // CHECK:   llvm.return
+  // CHECK: ^[[DEFAULT_BB:.+]]:
+  // CHECK:   llvm.br ^[[RET_BB:.+]]
+  // CHECK: ^[[RET_BB:.+]]:  // pred: ^[[DEFAULT_BB:.+]]
+  // CHECK:   llvm.return
+  // CHECK: }
+
+  cir.func @shouldLowerNestedBreak(%arg0: !s32i, %arg1: !s32i) -> !s32i {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init] {alignment = 4 : i64}
+    %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init] {alignment = 4 : i64}
+    %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.store %arg1, %1 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %5 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%5 : !s32i) {
+      cir.case (equal, [#cir.int<0> : !s32i]) {
+        cir.scope {
+          %6 = cir.load %1 : !cir.ptr<!s32i>, !s32i
+          %7 = cir.const #cir.int<0> : !s32i
+          %8 = cir.cmp(ge, %6, %7) : !s32i, !cir.bool
+          cir.if %8 {
+            cir.break
+          }
+        }
+        cir.break
+      }
+      cir.yield
+      }
+    }
+    %3 = cir.const #cir.int<3> : !s32i
+    cir.store %3, %2 : !s32i, !cir.ptr<!s32i>
+    %4 = cir.load %2 : !cir.ptr<!s32i>, !s32i
+    cir.return %4 : !s32i
+  }
+  // CHECK:  llvm.func @shouldLowerNestedBreak
+  // CHECK:    llvm.switch %6 : i32, ^[[DEFAULT_BB:.+]] [
+  // CHECK:      0: ^[[ZERO_BB:.+]]
+  // CHECK:    ]
+  // CHECK:  ^[[ZERO_BB]]:
+  // CHECK:    llvm.br ^[[ZERO_BB_SUCC:.+]]
+  // CHECK:  ^[[ZERO_BB_SUCC]]:  // pred: ^[[ZERO_BB:]]
+  // CHECK:    llvm.cond_br {{%.*}}, ^[[DEFAULT_BB_PRED1:.+]], ^[[DEFAULT_BB_PRED12:.+]]
+  // CHECK:  ^[[DEFAULT_BB_PRED1]]:  // pred: ^[[ZERO_BB_SUCC]]
+  // CHECK:    llvm.br ^[[DEFAULT_BB]]
+  // CHECK:  ^[[DEFAULT_BB_PRED12]]:  // pred: ^[[ZERO_BB_SUCC]]
+  // CHECK:    llvm.br ^[[DEFAULT_BB_PRED1:.+]]
+  // CHECK:  ^[[DEFAULT_BB_PRED1]]:  // pred: ^[[DEFAULT_BB_PRED12]]
+  // CHECK:    llvm.br ^[[DEFAULT_BB]]
+  // CHECK:  ^[[DEFAULT_BB]]:
+  // CHECK:    llvm.br ^[[RET_BB:.+]]
+  // CHECK:  ^[[RET_BB]]:  // pred: ^[[DEFAULT_BB]]
+  // CHECK:    llvm.return
+}

>From 3eb9e7715ea520d56ab0d8009111fd08ab4d4b03 Mon Sep 17 00:00:00 2001
From: Andres-Salamanca <andrealebarbaritos at gmail.com>
Date: Thu, 22 May 2025 12:27:23 -0500
Subject: [PATCH 025/105] [CIR] Implement switch case simplify (#140649)

This PR introduces a new **CIR simplify for `switch` cases**, which
folds multiple **cascading `Equal` cases** (that contain only a
`YieldOp`) into a single `CaseOp` of kind `AnyOf`.

This logic is based on the suggestion from this discussion:
https://github.com/llvm/llvm-project/pull/138003#discussion_r2070564458
---
 clang/include/clang/CIR/MissingFeatures.h     |   1 -
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp          |   6 -
 .../CIR/Dialect/Transforms/CIRSimplify.cpp    | 106 +++++++++-
 clang/test/CIR/Transforms/switch-fold.cir     | 196 ++++++++++++++++++
 4 files changed, 300 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/CIR/Transforms/switch-fold.cir

diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 52f2ed2d298a7..d4952da326ac0 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -120,7 +120,6 @@ struct MissingFeatures {
   static bool opUnaryPromotionType() { return false; }
 
   // SwitchOp handling
-  static bool foldCascadingCases() { return false; }
   static bool foldRangeCase() { return false; }
 
   // Clang early optimizations or things defered to LLVM lowering.
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 4187762741808..763d2b087cc85 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -533,12 +533,6 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
     value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
                                   cir::IntAttr::get(condType, endVal)});
     kind = cir::CaseOpKind::Range;
-
-    // We don't currently fold case range statements with other case statements.
-    // TODO(cir): Add this capability. Folding these cases is going to be
-    // implemented in CIRSimplify when it is upstreamed.
-    assert(!cir::MissingFeatures::foldRangeCase());
-    assert(!cir::MissingFeatures::foldCascadingCases());
   } else {
     value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
     kind = cir::CaseOpKind::Equal;
diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp
index b969569b0081c..67ed4124f26cc 100644
--- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp
@@ -159,6 +159,107 @@ struct SimplifySelect : public OpRewritePattern<SelectOp> {
   }
 };
 
+/// Simplify `cir.switch` operations by folding cascading cases
+/// into a single `cir.case` with the `anyof` kind.
+///
+/// This pattern identifies cascading cases within a `cir.switch` operation.
+/// Cascading cases are defined as consecutive `cir.case` operations of kind
+/// `equal`, each containing a single `cir.yield` operation in their body.
+///
+/// The pattern merges these cascading cases into a single `cir.case` operation
+/// with kind `anyof`, aggregating all the case values.
+///
+/// The merging process continues until a `cir.case` with a different body
+/// (e.g., containing `cir.break` or compound stmt) is encountered, which
+/// breaks the chain.
+///
+/// Example:
+///
+/// Before:
+///   cir.case equal, [#cir.int<0> : !s32i] {
+///     cir.yield
+///   }
+///   cir.case equal, [#cir.int<1> : !s32i] {
+///     cir.yield
+///   }
+///   cir.case equal, [#cir.int<2> : !s32i] {
+///     cir.break
+///   }
+///
+/// After applying SimplifySwitch:
+///   cir.case anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> :
+///   !s32i] {
+///     cir.break
+///   }
+struct SimplifySwitch : public OpRewritePattern<SwitchOp> {
+  using OpRewritePattern<SwitchOp>::OpRewritePattern;
+  LogicalResult matchAndRewrite(SwitchOp op,
+                                PatternRewriter &rewriter) const override {
+
+    LogicalResult changed = mlir::failure();
+    SmallVector<CaseOp, 8> cases;
+    SmallVector<CaseOp, 4> cascadingCases;
+    SmallVector<mlir::Attribute, 4> cascadingCaseValues;
+
+    op.collectCases(cases);
+    if (cases.empty())
+      return mlir::failure();
+
+    auto flushMergedOps = [&]() {
+      for (CaseOp &c : cascadingCases)
+        rewriter.eraseOp(c);
+      cascadingCases.clear();
+      cascadingCaseValues.clear();
+    };
+
+    auto mergeCascadingInto = [&](CaseOp &target) {
+      rewriter.modifyOpInPlace(target, [&]() {
+        target.setValueAttr(rewriter.getArrayAttr(cascadingCaseValues));
+        target.setKind(CaseOpKind::Anyof);
+      });
+      changed = mlir::success();
+    };
+
+    for (CaseOp c : cases) {
+      cir::CaseOpKind kind = c.getKind();
+      if (kind == cir::CaseOpKind::Equal &&
+          isa<YieldOp>(c.getCaseRegion().front().front())) {
+        // If the case contains only a YieldOp, collect it for cascading merge
+        cascadingCases.push_back(c);
+        cascadingCaseValues.push_back(c.getValue()[0]);
+      } else if (kind == cir::CaseOpKind::Equal && !cascadingCases.empty()) {
+        // merge previously collected cascading cases
+        cascadingCaseValues.push_back(c.getValue()[0]);
+        mergeCascadingInto(c);
+        flushMergedOps();
+      } else if (kind != cir::CaseOpKind::Equal && cascadingCases.size() > 1) {
+        // If a Default, Anyof or Range case is found and there are previous
+        // cascading cases, merge all of them into the last cascading case.
+        // We don't currently fold case range statements with other case
+        // statements.
+        assert(!cir::MissingFeatures::foldRangeCase());
+        CaseOp lastCascadingCase = cascadingCases.back();
+        mergeCascadingInto(lastCascadingCase);
+        cascadingCases.pop_back();
+        flushMergedOps();
+      } else {
+        cascadingCases.clear();
+        cascadingCaseValues.clear();
+      }
+    }
+
+    // Edge case: all cases are simple cascading cases
+    if (cascadingCases.size() == cases.size()) {
+      CaseOp lastCascadingCase = cascadingCases.back();
+      mergeCascadingInto(lastCascadingCase);
+      cascadingCases.pop_back();
+      flushMergedOps();
+    }
+
+    return changed;
+  }
+};
+
 //===----------------------------------------------------------------------===//
 // CIRSimplifyPass
 //===----------------------------------------------------------------------===//
@@ -173,7 +274,8 @@ void populateMergeCleanupPatterns(RewritePatternSet &patterns) {
   // clang-format off
   patterns.add<
     SimplifyTernary,
-    SimplifySelect
+    SimplifySelect,
+    SimplifySwitch
   >(patterns.getContext());
   // clang-format on
 }
@@ -186,7 +288,7 @@ void CIRSimplifyPass::runOnOperation() {
   // Collect operations to apply patterns.
   llvm::SmallVector<Operation *, 16> ops;
   getOperation()->walk([&](Operation *op) {
-    if (isa<TernaryOp, SelectOp>(op))
+    if (isa<TernaryOp, SelectOp, SwitchOp>(op))
       ops.push_back(op);
   });
 
diff --git a/clang/test/CIR/Transforms/switch-fold.cir b/clang/test/CIR/Transforms/switch-fold.cir
new file mode 100644
index 0000000000000..62a94f4fde2c3
--- /dev/null
+++ b/clang/test/CIR/Transforms/switch-fold.cir
@@ -0,0 +1,196 @@
+// RUN: cir-opt -cir-canonicalize -cir-simplify -o %t.cir %s
+// RUN: FileCheck --input-file=%t.cir %s
+
+!s32i = !cir.int<s, 32>
+
+module {
+    cir.func @foldCascade(%arg0: !s32i) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%1 : !s32i) {
+        cir.case(equal, [#cir.int<1> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<2> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<3> : !s32i]) {
+          %2 = cir.const #cir.int<2> : !s32i
+          cir.store %2, %0 : !s32i, !cir.ptr<!s32i>
+          cir.break
+        }
+        cir.yield
+      }
+    }
+    cir.return
+  }
+  //CHECK: cir.func @foldCascade
+  //CHECK:   cir.switch (%[[COND:.*]] : !s32i) {
+  //CHECK-NEXT:     cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]) {
+  //CHECK-NEXT:       %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+  //CHECK-NEXT:       cir.store %[[TWO]], %[[ARG0:.*]] : !s32i, !cir.ptr<!s32i>
+  //CHECK-NEXT:       cir.break
+  //CHECK-NEXT:     }
+  //CHECK-NEXT:     cir.yield
+  //CHECK-NEXT:   }
+
+    cir.func @foldCascade2(%arg0: !s32i) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%1 : !s32i) {
+        cir.case(equal, [#cir.int<0> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<2> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<4> : !s32i]) {
+          cir.break
+        }
+        cir.case(equal, [#cir.int<1> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<3> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<5> : !s32i]) {
+          cir.break
+        }
+        cir.yield
+      }
+    }
+    cir.return
+  }
+  //CHECK: @foldCascade2
+  //CHECK:   cir.switch (%[[COND2:.*]] : !s32i) {
+  //CHECK:     cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<2> : !s32i, #cir.int<4> : !s32i]) {
+  //CHECK:       cir.break
+  //cehck:     }
+  //CHECK:     cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<3> : !s32i, #cir.int<5> : !s32i]) {
+  //CHECK:       cir.break
+  //CHECK:     }
+  //CHECK:     cir.yield
+  //CHECK:   }
+  cir.func @foldCascade3(%arg0: !s32i ) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"] {alignment = 4 : i64}
+      %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%2 : !s32i) {
+        cir.case(equal, [#cir.int<0> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<1> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<2> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<3> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<4> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<5> : !s32i]) {
+          cir.break
+        }
+        cir.yield
+      }
+    }
+    cir.return
+  }
+  //CHECK: cir.func @foldCascade3
+  //CHECK:   cir.switch (%[[COND3:.*]] : !s32i) {
+  //CHECK:     cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
+  //CHECK:       cir.break
+  //CHECK:    }
+  //CHECK:    cir.yield
+  //CHECK:   }
+  cir.func @foldCascadeWithDefault(%arg0: !s32i ) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%1 : !s32i) {
+        cir.case(equal, [#cir.int<3> : !s32i]) {
+          cir.break
+        }
+        cir.case(equal, [#cir.int<4> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<5> : !s32i]) {
+          cir.yield
+        }
+        cir.case(default, []) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<6> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<7> : !s32i]) {
+          cir.break
+        }
+        cir.yield
+      }
+    }
+    cir.return
+  }
+  //CHECK: cir.func @foldCascadeWithDefault
+  //CHECK:   cir.switch (%[[COND:.*]] : !s32i) {
+  //CHECK:      cir.case(equal, [#cir.int<3> : !s32i]) {
+  //CHECK:        cir.break
+  //CHECK:      }
+  //CHECK:      cir.case(anyof, [#cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
+  //CHECK:        cir.yield
+  //CHECK:      }
+  //CHECK:      cir.case(default, []) {
+  //CHECK:        cir.yield
+  //CHECK:      }
+  //CHECK:      cir.case(anyof, [#cir.int<6> : !s32i, #cir.int<7> : !s32i]) {
+  //CHECK:        cir.break
+  //CHECK:      }
+  //CHECK:      cir.yield
+  //CHECK:   }
+  cir.func @foldAllCascade(%arg0: !s32i ) {
+    %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64}
+    cir.store %arg0, %0 : !s32i, !cir.ptr<!s32i>
+    cir.scope {
+      %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+      cir.switch (%1 : !s32i) {
+        cir.case(equal, [#cir.int<0> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<1> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<2> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<3> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<4> : !s32i]) {
+          cir.yield
+        }
+        cir.case(equal, [#cir.int<5> : !s32i]) {
+          cir.yield
+        }
+        cir.yield
+      }
+    }
+    cir.return
+  }
+  //CHECK: cir.func @foldAllCascade
+  //CHECK:   cir.switch (%[[COND:.*]] : !s32i) {
+  //CHECK:     cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
+  //CHECK:       cir.yield
+  //CHECK:     }
+  //CHECK:     cir.yield
+  //CHECK:   }
+}

>From e72d8b25531cb5a4fd1e802bac8c9aa6efee0aa1 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Thu, 22 May 2025 17:28:43 +0000
Subject: [PATCH 026/105] Revert "[NVPTX] Unify and extend barrier{.cta}
 intrinsic support (#140615)"

This reverts commit 735209c0688b10a66c24750422b35d8c2ad01bb5.
---
 clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp    |  16 --
 clang/test/CodeGen/builtins-nvptx-ptx60.cu    |   4 +-
 clang/test/CodeGen/builtins-nvptx.c           |   4 +-
 clang/test/Headers/gpuintrin.c                |   2 +-
 llvm/docs/NVPTXUsage.rst                      |  47 +-----
 llvm/include/llvm/IR/IntrinsicsNVVM.td        |  37 ++---
 llvm/lib/IR/AutoUpgrade.cpp                   |  34 +---
 llvm/lib/Target/NVPTX/NVPTXInstrInfo.td       |  41 -----
 llvm/lib/Target/NVPTX/NVPTXIntrinsics.td      |  71 ++++----
 .../Transforms/IPO/AttributorAttributes.cpp   |   3 +-
 .../GlobalsModRef/functions_without_nosync.ll |  19 ++-
 .../Assembler/auto_upgrade_nvvm_intrinsics.ll |  22 ---
 llvm/test/CodeGen/NVPTX/barrier.ll            | 153 +++---------------
 llvm/test/CodeGen/NVPTX/named-barriers.ll     |  42 +++++
 .../CodeGen/NVPTX/noduplicate-syncthreads.ll  |   6 +-
 llvm/test/Feature/intrinsic-noduplicate.ll    |   6 +-
 .../Transforms/FunctionAttrs/convergent.ll    |   6 +-
 .../JumpThreading/thread-two-bbs-cuda.ll      |   8 +-
 .../test/Transforms/OpenMP/barrier_removal.ll |  28 ++--
 mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td   |  24 ++-
 mlir/test/Target/LLVMIR/Import/nvvmir.ll      |   3 +-
 mlir/test/Target/LLVMIR/nvvmir.mlir           |  10 +-
 22 files changed, 197 insertions(+), 389 deletions(-)
 create mode 100644 llvm/test/CodeGen/NVPTX/named-barriers.ll

diff --git a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
index 21c01a08549d0..002af4f931c09 100644
--- a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
@@ -1160,22 +1160,6 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
   case NVPTX::BI__nvvm_fence_sc_cluster:
     return Builder.CreateCall(
         CGM.getIntrinsic(Intrinsic::nvvm_fence_sc_cluster));
-  case NVPTX::BI__nvvm_bar_sync:
-    return Builder.CreateCall(
-        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all),
-        EmitScalarExpr(E->getArg(0)));
-  case NVPTX::BI__syncthreads:
-    return Builder.CreateCall(
-        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all),
-        Builder.getInt32(0));
-  case NVPTX::BI__nvvm_barrier_sync:
-    return Builder.CreateCall(
-        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_all),
-        EmitScalarExpr(E->getArg(0)));
-  case NVPTX::BI__nvvm_barrier_sync_cnt:
-    return Builder.CreateCall(
-        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync),
-        {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});
   default:
     return nullptr;
   }
diff --git a/clang/test/CodeGen/builtins-nvptx-ptx60.cu b/clang/test/CodeGen/builtins-nvptx-ptx60.cu
index 0c40ecaa95615..599d09a20e04a 100644
--- a/clang/test/CodeGen/builtins-nvptx-ptx60.cu
+++ b/clang/test/CodeGen/builtins-nvptx-ptx60.cu
@@ -32,10 +32,10 @@ __device__ void nvvm_sync(unsigned mask, int i, float f, int a, int b,
   // CHECK: call void @llvm.nvvm.bar.warp.sync(i32
   // expected-error at +1 {{'__nvvm_bar_warp_sync' needs target feature ptx60}}
   __nvvm_bar_warp_sync(mask);
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync.all(i32
+  // CHECK: call void @llvm.nvvm.barrier.sync(i32
   // expected-error at +1 {{'__nvvm_barrier_sync' needs target feature ptx60}}
   __nvvm_barrier_sync(mask);
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync(i32
+  // CHECK: call void @llvm.nvvm.barrier.sync.cnt(i32
   // expected-error at +1 {{'__nvvm_barrier_sync_cnt' needs target feature ptx60}}
   __nvvm_barrier_sync_cnt(mask, i);
 
diff --git a/clang/test/CodeGen/builtins-nvptx.c b/clang/test/CodeGen/builtins-nvptx.c
index cef529163bb39..7904762709df6 100644
--- a/clang/test/CodeGen/builtins-nvptx.c
+++ b/clang/test/CodeGen/builtins-nvptx.c
@@ -198,7 +198,7 @@ __device__ int read_pms() {
 
 __device__ void sync() {
 
-// CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+// CHECK: call void @llvm.nvvm.bar.sync(i32 0)
 
   __nvvm_bar_sync(0);
 
@@ -259,7 +259,7 @@ __device__ void nvvm_math(float f1, float f2, double d1, double d2) {
   __nvvm_membar_gl();
 // CHECK: call void @llvm.nvvm.membar.sys()
   __nvvm_membar_sys();
-// CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+// CHECK: call void @llvm.nvvm.barrier0()
   __syncthreads();
 }
 
diff --git a/clang/test/Headers/gpuintrin.c b/clang/test/Headers/gpuintrin.c
index b254423ec4a1e..f7dfb86ac4652 100644
--- a/clang/test/Headers/gpuintrin.c
+++ b/clang/test/Headers/gpuintrin.c
@@ -887,7 +887,7 @@ __gpu_kernel void foo() {
 // NVPTX-LABEL: define internal void @__gpu_sync_threads(
 // NVPTX-SAME: ) #[[ATTR0]] {
 // NVPTX-NEXT:  [[ENTRY:.*:]]
-// NVPTX-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+// NVPTX-NEXT:    call void @llvm.nvvm.barrier0()
 // NVPTX-NEXT:    ret void
 //
 //
diff --git a/llvm/docs/NVPTXUsage.rst b/llvm/docs/NVPTXUsage.rst
index 07750579f5a5e..e0a5c02114779 100644
--- a/llvm/docs/NVPTXUsage.rst
+++ b/llvm/docs/NVPTXUsage.rst
@@ -199,58 +199,21 @@ map in the following way to CUDA builtins:
 Barriers
 --------
 
-'``llvm.nvvm.barrier.cta.*``'
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+'``llvm.nvvm.barrier0``'
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Syntax:
 """""""
 
 .. code-block:: llvm
 
-  declare void @llvm.nvvm.barrier.cta.sync(i32 %id, i32 %n)
-  declare void @llvm.nvvm.barrier.cta.sync.all(i32 %id)
-  declare void @llvm.nvvm.barrier.cta.arrive(i32 %id, i32 %n)
-
-  declare void @llvm.nvvm.barrier.cta.sync.aligned(i32 %id, i32 %n)
-  declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %id)
-  declare void @llvm.nvvm.barrier.cta.arrive.aligned(i32 %id, i32 %n)
+  declare void @llvm.nvvm.barrier0()
 
 Overview:
 """""""""
 
-The '``@llvm.nvvm.barrier.cta.*``' family of intrinsics perform barrier
-synchronization and communication within a CTA. They can be used by the threads
-within the CTA for synchronization and communication.
-
-Semantics:
-""""""""""
-
-Operand %id specifies a logical barrier resource and must fall within the range
-0 through 15. When present, operand %n specifies the number of threads
-participating in the barrier. When specifying a thread count, the value must be
-a multiple of the warp size. With the '``@llvm.nvvm.barrier.cta.sync.*``'
-variants, the '``.all``' suffix indicates that all threads in the CTA should
-participate in the barrier and the %n operand is not present.
-
-All forms of the '``@llvm.nvvm.barrier.cta.*``' intrinsic cause the executing
-thread to wait for all non-exited threads from its warp and then marks the
-warp's arrival at the barrier. In addition to signaling its arrival at the 
-barrier, the '``@llvm.nvvm.barrier.cta.sync.*``' intrinsics cause the executing
-thread to wait for non-exited threads of all other warps participating in the
-barrier to arrive. On the other hand, the '``@llvm.nvvm.barrier.cta.arrive.*``'
-intrinsic does not cause the executing thread to wait for threads of other
-participating warps.
-
-When a barrier completes, the waiting threads are restarted without delay,
-and the barrier is reinitialized so that it can be immediately reused.
-
-The '``@llvm.nvvm.barrier.cta.*``' intrinsic has an optional '``.aligned``'
-modifier to indicate textual alignment of the barrier. When specified, it
-indicates that all threads in the CTA will execute the same
-'``@llvm.nvvm.barrier.cta.*``' instruction. In conditionally executed code, an
-aligned '``@llvm.nvvm.barrier.cta.*``' instruction should only be used if it is
-known that all threads in the CTA evaluate the condition identically, otherwise
-behavior is undefined.
+The '``@llvm.nvvm.barrier0()``' intrinsic emits a PTX ``bar.sync 0``
+instruction, equivalent to the ``__syncthreads()`` call in CUDA.
 
 Electing a thread
 -----------------
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index a0a00677bc5b7..3aa9b0303c63d 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -128,12 +128,6 @@
 //   * llvm.nvvm.swap.lo.hi.b64      --> llvm.fshl(x, x, 32)
 //   * llvm.nvvm.atomic.load.inc.32  --> atomicrmw uinc_wrap
 //   * llvm.nvvm.atomic.load.dec.32  --> atomicrmw udec_wrap
-// * llvm.nvvm.barrier0              --> llvm.nvvm.barrier.cta.sync.aligned.all(0)
-// * llvm.nvvm.barrier.n             --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
-// * llvm.nvvm.bar.sync              --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
-// * llvm.nvvm.barrier               --> llvm.nvvm.barrier.cta.sync.aligned(x, y)
-// * llvm.nvvm.barrier.sync          --> llvm.nvvm.barrier.cta.sync.all(x)
-// * llvm.nvvm.barrier.sync.cnt      --> llvm.nvvm.barrier.cta.sync(x, y)
 
 def llvm_global_ptr_ty  : LLVMQualPointerType<1>;         // (global)ptr
 def llvm_shared_ptr_ty  : LLVMQualPointerType<3>;         // (shared)ptr
@@ -1269,6 +1263,18 @@ let TargetPrefix = "nvvm" in {
   defm int_nvvm_atomic_cas_gen_i  : PTXAtomicWithScope3<llvm_anyint_ty>;
 
 // Bar.Sync
+
+  // The builtin for "bar.sync 0" is called __syncthreads.  Unlike most of the
+  // intrinsics in this file, this one is a user-facing API.
+  def int_nvvm_barrier0 : ClangBuiltin<"__syncthreads">,
+      Intrinsic<[], [], [IntrConvergent, IntrNoCallback]>;
+  // Synchronize all threads in the CTA at barrier 'n'.
+  def int_nvvm_barrier_n : ClangBuiltin<"__nvvm_bar_n">,
+      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
+  // Synchronize 'm', a multiple of warp size, (arg 2) threads in
+  // the CTA at barrier 'n' (arg 1).
+  def int_nvvm_barrier : ClangBuiltin<"__nvvm_bar">,
+      Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_barrier0_popc : ClangBuiltin<"__nvvm_bar0_popc">,
       Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_barrier0_and : ClangBuiltin<"__nvvm_bar0_and">,
@@ -1276,21 +1282,16 @@ let TargetPrefix = "nvvm" in {
   def int_nvvm_barrier0_or : ClangBuiltin<"__nvvm_bar0_or">,
       Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
 
+  def int_nvvm_bar_sync : NVVMBuiltin,
+      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_bar_warp_sync : NVVMBuiltin,
       Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
 
-  // barrier{.cta}.sync{.aligned}      a{, b};
-  // barrier{.cta}.arrive{.aligned}    a, b;
-  let IntrProperties = [IntrConvergent, IntrNoCallback] in {
-    foreach align = ["", "_aligned"] in {
-      def int_nvvm_barrier_cta_sync # align # _all :
-          Intrinsic<[], [llvm_i32_ty]>;
-      def int_nvvm_barrier_cta_sync # align :
-          Intrinsic<[], [llvm_i32_ty, llvm_i32_ty]>;
-      def int_nvvm_barrier_cta_arrive # align :
-          Intrinsic<[], [llvm_i32_ty, llvm_i32_ty]>;
-    }
-  }
+  // barrier.sync id[, cnt]
+  def int_nvvm_barrier_sync : NVVMBuiltin,
+      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
+  def int_nvvm_barrier_sync_cnt : NVVMBuiltin,
+      Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
 
   // barrier.cluster.[wait, arrive, arrive.relaxed]
   def int_nvvm_barrier_cluster_arrive :
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 94ac22f047429..7157baf394e3f 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1343,9 +1343,12 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
         // nvvm.abs.{i,ii}
         Expand =
             Name == "i" || Name == "ll" || Name == "bf16" || Name == "bf16x2";
-      else if (Name.consume_front("fabs."))
+      else if (Name == "fabs.f" || Name == "fabs.ftz.f" || Name == "fabs.d")
         // nvvm.fabs.{f,ftz.f,d}
-        Expand = Name == "f" || Name == "ftz.f" || Name == "d";
+        Expand = true;
+      else if (Name == "clz.ll" || Name == "popc.ll" || Name == "h2f" ||
+               Name == "swap.lo.hi.b64")
+        Expand = true;
       else if (Name.consume_front("max.") || Name.consume_front("min."))
         // nvvm.{min,max}.{i,ii,ui,ull}
         Expand = Name == "s" || Name == "i" || Name == "ll" || Name == "us" ||
@@ -1377,18 +1380,7 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
         Expand = (Name.starts_with("i.") || Name.starts_with("f.") ||
                   Name.starts_with("p."));
       else
-        Expand = StringSwitch<bool>(Name)
-                     .Case("barrier0", true)
-                     .Case("barrier.n", true)
-                     .Case("barrier.sync.cnt", true)
-                     .Case("barrier.sync", true)
-                     .Case("barrier", true)
-                     .Case("bar.sync", true)
-                     .Case("clz.ll", true)
-                     .Case("popc.ll", true)
-                     .Case("h2f", true)
-                     .Case("swap.lo.hi.b64", true)
-                     .Default(false);
+        Expand = false;
 
       if (Expand) {
         NewFn = nullptr;
@@ -2486,20 +2478,6 @@ static Value *upgradeNVVMIntrinsicCall(StringRef Name, CallBase *CI,
     MDNode *MD = MDNode::get(Builder.getContext(), {});
     LD->setMetadata(LLVMContext::MD_invariant_load, MD);
     return LD;
-  } else if (Name == "barrier0" || Name == "barrier.n" || Name == "bar.sync") {
-    Value *Arg =
-        Name.ends_with('0') ? Builder.getInt32(0) : CI->getArgOperand(0);
-    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all,
-                                  {}, {Arg});
-  } else if (Name == "barrier") {
-    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned, {},
-                                  {CI->getArgOperand(0), CI->getArgOperand(1)});
-  } else if (Name == "barrier.sync") {
-    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_all, {},
-                                  {CI->getArgOperand(0)});
-  } else if (Name == "barrier.sync.cnt") {
-    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync, {},
-                                  {CI->getArgOperand(0), CI->getArgOperand(1)});
   } else {
     Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
     if (IID != Intrinsic::not_intrinsic &&
diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index 5234fb0806189..444d35b3115ba 100644
--- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -237,47 +237,6 @@ def BF16RT   : RegTyInfo<bf16, Int16Regs, bf16imm, fpimm, supports_imm = 0>;
 def F16X2RT  : RegTyInfo<v2f16, Int32Regs, ?, ?, supports_imm = 0>;
 def BF16X2RT : RegTyInfo<v2bf16, Int32Regs, ?, ?, supports_imm = 0>;
 
-// This class provides a basic wrapper around an NVPTXInst that abstracts the
-// specific syntax of most PTX instructions. It automatically handles the
-// construction of the asm string based on the provided dag arguments.
-// For example, the following asm-strings would be computed:
-//
-//   * BasicFlagsNVPTXInst<(outs Int32Regs:$dst),
-//                         (ins Int32Regs:$a, Int32Regs:$b), (ins),
-//                         "add.s32">;
-//         ---> "add.s32 \t$dst, $a, $b;"
-//
-//   * BasicFlagsNVPTXInst<(outs Int32Regs:$d),
-//                         (ins Int32Regs:$a, Int32Regs:$b, Hexu32imm:$c),
-//                         (ins PrmtMode:$mode),
-//                         "prmt.b32${mode}">;
-//         ---> "prmt.b32${mode} \t$d, $a, $b, $c;"
-//
-class BasicFlagsNVPTXInst<dag outs_dag, dag ins_dag, dag flags_dag, string asmstr,
-                          list<dag> pattern = []>
-  : NVPTXInst<
-      outs_dag,
-      !con(ins_dag, flags_dag),
-      !strconcat(
-        asmstr,
-        !if(!and(!empty(ins_dag), !empty(outs_dag)), "",
-          !strconcat(
-            " \t",
-            !interleave(
-              !foreach(i, !range(!size(outs_dag)),
-                "$" # !getdagname(outs_dag, i)),
-              "|"),
-            !if(!or(!empty(ins_dag), !empty(outs_dag)), "", ", "),
-            !interleave(
-              !foreach(i, !range(!size(ins_dag)),
-                "$" # !getdagname(ins_dag, i)),
-              ", "))),
-        ";"),
-      pattern>;
-
-class BasicNVPTXInst<dag outs, dag insv, string asmstr, list<dag> pattern = []>
-  : BasicFlagsNVPTXInst<outs, insv, (ins), asmstr, pattern>;
-
 
 multiclass I3Inst<string op_str, SDPatternOperator op_node, RegTyInfo t,
                   bit commutative, list<Predicate> requires = []> {
diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index f7b8aca0f77d8..193418ca391e5 100644
--- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -67,6 +67,15 @@ class THREADMASK_INFO<bit sync> {
 // Synchronization and shuffle functions
 //-----------------------------------
 let isConvergent = true in {
+def INT_BARRIER0 : NVPTXInst<(outs), (ins),
+                  "bar.sync \t0;",
+      [(int_nvvm_barrier0)]>;
+def INT_BARRIERN : NVPTXInst<(outs), (ins Int32Regs:$src1),
+                  "bar.sync \t$src1;",
+      [(int_nvvm_barrier_n i32:$src1)]>;
+def INT_BARRIER : NVPTXInst<(outs), (ins Int32Regs:$src1, Int32Regs:$src2),
+                  "bar.sync \t$src1, $src2;",
+      [(int_nvvm_barrier i32:$src1, i32:$src2)]>;
 def INT_BARRIER0_POPC : NVPTXInst<(outs Int32Regs:$dst), (ins Int32Regs:$pred),
   !strconcat("{{ \n\t",
              ".reg .pred \t%p1; \n\t",
@@ -93,6 +102,9 @@ def INT_BARRIER0_OR : NVPTXInst<(outs Int32Regs:$dst), (ins Int32Regs:$pred),
              "}}"),
       [(set i32:$dst, (int_nvvm_barrier0_or i32:$pred))]>;
 
+def INT_BAR_SYNC : NVPTXInst<(outs), (ins i32imm:$i), "bar.sync \t$i;",
+                             [(int_nvvm_bar_sync imm:$i)]>;
+
 def INT_BAR_WARP_SYNC_I : NVPTXInst<(outs), (ins i32imm:$i), "bar.warp.sync \t$i;",
                              [(int_nvvm_bar_warp_sync imm:$i)]>,
         Requires<[hasPTX<60>, hasSM<30>]>;
@@ -100,44 +112,29 @@ def INT_BAR_WARP_SYNC_R : NVPTXInst<(outs), (ins Int32Regs:$i), "bar.warp.sync \
                              [(int_nvvm_bar_warp_sync i32:$i)]>,
         Requires<[hasPTX<60>, hasSM<30>]>;
 
-multiclass BARRIER1<string asmstr, Intrinsic intrinsic, list<Predicate> requires = []> {
-  def _i : BasicNVPTXInst<(outs), (ins i32imm:$i), asmstr,
-                          [(intrinsic imm:$i)]>,
-           Requires<requires>;
-
-  def _r : BasicNVPTXInst<(outs), (ins Int32Regs:$i), asmstr,
-                          [(intrinsic i32:$i)]>,
-           Requires<requires>;
-}
-
-multiclass BARRIER2<string asmstr, Intrinsic intrinsic, list<Predicate> requires = []> {
-  def _rr : BasicNVPTXInst<(outs), (ins Int32Regs:$i, Int32Regs:$j), asmstr,
-                          [(intrinsic i32:$i, i32:$j)]>,
-            Requires<requires>;
-
-  def _ri : BasicNVPTXInst<(outs), (ins Int32Regs:$i, i32imm:$j), asmstr,
-                          [(intrinsic i32:$i, imm:$j)]>,
-            Requires<requires>;
-
-  def _ir : BasicNVPTXInst<(outs), (ins i32imm:$i, Int32Regs:$j), asmstr,
-                          [(intrinsic imm:$i, i32:$j)]>,
-            Requires<requires>;
-
-  def _ii : BasicNVPTXInst<(outs), (ins i32imm:$i, i32imm:$j), asmstr,
-                          [(intrinsic imm:$i, imm:$j)]>,
-            Requires<requires>;
-}
-
-// Note the "bar.sync" variants could be renamed to the equivalent corresponding
-// "barrier.*.aligned" variants. We use the older syntax for compatibility with
-// older versions of the PTX ISA.
-defm BARRIER_CTA_SYNC_ALIGNED_ALL : BARRIER1<"bar.sync", int_nvvm_barrier_cta_sync_aligned_all>;
-defm BARRIER_CTA_SYNC_ALIGNED : BARRIER2<"bar.sync", int_nvvm_barrier_cta_sync_aligned>;
-defm BARRIER_CTA_ARRIVE_ALIGNED : BARRIER2<"bar.arrive", int_nvvm_barrier_cta_arrive_aligned>;
+def INT_BARRIER_SYNC_I : NVPTXInst<(outs), (ins i32imm:$i), "barrier.sync \t$i;",
+                                   [(int_nvvm_barrier_sync imm:$i)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
+def INT_BARRIER_SYNC_R : NVPTXInst<(outs), (ins Int32Regs:$i), "barrier.sync \t$i;",
+                                   [(int_nvvm_barrier_sync i32:$i)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
 
-defm BARRIER_CTA_SYNC_ALL : BARRIER1<"barrier.sync", int_nvvm_barrier_cta_sync_all, [hasPTX<60>]>;
-defm BARRIER_CTA_SYNC : BARRIER2<"barrier.sync", int_nvvm_barrier_cta_sync, [hasPTX<60>]>;
-defm BARRIER_CTA_ARRIVE : BARRIER2<"barrier.arrive", int_nvvm_barrier_cta_arrive, [hasPTX<60>]>;
+def INT_BARRIER_SYNC_CNT_RR : NVPTXInst<(outs), (ins Int32Regs:$id, Int32Regs:$cnt),
+                 "barrier.sync \t$id, $cnt;",
+                 [(int_nvvm_barrier_sync_cnt i32:$id, i32:$cnt)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
+def INT_BARRIER_SYNC_CNT_RI : NVPTXInst<(outs), (ins Int32Regs:$id, i32imm:$cnt),
+                 "barrier.sync \t$id, $cnt;",
+                 [(int_nvvm_barrier_sync_cnt i32:$id, imm:$cnt)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
+def INT_BARRIER_SYNC_CNT_IR : NVPTXInst<(outs), (ins i32imm:$id, Int32Regs:$cnt),
+                 "barrier.sync \t$id, $cnt;",
+                 [(int_nvvm_barrier_sync_cnt imm:$id, i32:$cnt)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
+def INT_BARRIER_SYNC_CNT_II : NVPTXInst<(outs), (ins i32imm:$id, i32imm:$cnt),
+                 "barrier.sync \t$id, $cnt;",
+                 [(int_nvvm_barrier_sync_cnt imm:$id, imm:$cnt)]>,
+        Requires<[hasPTX<60>, hasSM<30>]>;
 
 class INT_BARRIER_CLUSTER<string variant, Intrinsic Intr,
                           list<Predicate> Preds = [hasPTX<78>, hasSM<90>]>:
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 79d9b3da054b5..8b843634600be 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -2150,8 +2150,7 @@ struct AANoUnwindCallSite final
 
 bool AANoSync::isAlignedBarrier(const CallBase &CB, bool ExecutedAligned) {
   switch (CB.getIntrinsicID()) {
-  case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
-  case Intrinsic::nvvm_barrier_cta_sync_aligned:
+  case Intrinsic::nvvm_barrier0:
   case Intrinsic::nvvm_barrier0_and:
   case Intrinsic::nvvm_barrier0_or:
   case Intrinsic::nvvm_barrier0_popc:
diff --git a/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll b/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
index 7019694439bb8..e92a45807ed9c 100644
--- a/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
+++ b/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
@@ -11,15 +11,28 @@ target triple = "nvptx64-nvidia-cuda"
 
 ; CHECK-LABEL: @bar_sync
 ; CHECK: store
-; CHECK: tail call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK: tail call void @llvm.nvvm.bar.sync(i32 0)
 ; CHECK: load
 define dso_local i32 @bar_sync(i32 %0) local_unnamed_addr {
   store i32 %0, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
-  tail call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  tail call void @llvm.nvvm.bar.sync(i32 0)
   %2 = load i32, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
   ret i32 %2
 }
 
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #0
+declare void @llvm.nvvm.bar.sync(i32) #0
+
+; CHECK-LABEL: @barrier0
+; CHECK: store
+; CHECK: tail call void @llvm.nvvm.barrier0()
+; CHECK: load
+define dso_local i32 @barrier0(i32 %0) local_unnamed_addr  {
+  store i32 %0, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
+  tail call void @llvm.nvvm.barrier0()
+  %2 = load i32, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
+  ret i32 %2
+}
+
+declare void @llvm.nvvm.barrier0() #0
 
 attributes #0 = { convergent nounwind }
diff --git a/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll b/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
index e362ad88a8c0d..2bfa1c2dfba7a 100644
--- a/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
+++ b/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
@@ -78,13 +78,6 @@ declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.3d(ptr addrspace(3) %d,
 declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.4d(ptr addrspace(3) %d, ptr addrspace(3) %bar, ptr %tm, i32 %d0, i32 %d1, i32 %d2, i32 %d3, i16 %im2col0, i16 %im2col1, i16 %mc, i64 %ch, i1 %f1, i1 %f2);
 declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.5d(ptr addrspace(3) %d, ptr addrspace(3) %bar, ptr %tm, i32 %d0, i32 %d1, i32 %d2, i32 %d3, i32 %d4, i16 %im2col0, i16 %im2col1, i16 %im2col2, i16 %mc, i64 %ch, i1 %f1, i1 %f2);
 
-declare void @llvm.nvvm.barrier0()
-declare void @llvm.nvvm.barrier.n(i32)
-declare void @llvm.nvvm.bar.sync(i32)
-declare void @llvm.nvvm.barrier(i32, i32)
-declare void @llvm.nvvm.barrier.sync(i32)
-declare void @llvm.nvvm.barrier.sync.cnt(i32, i32)
-
 ; CHECK-LABEL: @simple_upgrade
 define void @simple_upgrade(i32 %a, i64 %b, i16 %c) {
 ; CHECK: call i32 @llvm.bitreverse.i32(i32 %a)
@@ -331,18 +324,3 @@ define void @nvvm_cp_async_bulk_tensor_g2s_tile(ptr addrspace(3) %d, ptr addrspa
   ret void
 }
 
-define void @cta_barriers(i32 %x, i32 %y) {
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %x)
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %x)
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned(i32 %x, i32 %y)
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.all(i32 %x)
-; CHECK: call void @llvm.nvvm.barrier.cta.sync(i32 %x, i32 %y)
-  call void @llvm.nvvm.barrier0()
-  call void @llvm.nvvm.barrier.n(i32 %x)
-  call void @llvm.nvvm.bar.sync(i32 %x)
-  call void @llvm.nvvm.barrier(i32 %x, i32 %y)
-  call void @llvm.nvvm.barrier.sync(i32 %x)
-  call void @llvm.nvvm.barrier.sync.cnt(i32 %x, i32 %y)
-  ret void
-}
diff --git a/llvm/test/CodeGen/NVPTX/barrier.ll b/llvm/test/CodeGen/NVPTX/barrier.ll
index 75db99b7f49dd..05bdc9087f572 100644
--- a/llvm/test/CodeGen/NVPTX/barrier.ll
+++ b/llvm/test/CodeGen/NVPTX/barrier.ll
@@ -1,136 +1,33 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_30 -mattr=+ptx60 | FileCheck %s
 ; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_30 -mattr=+ptx60 | %ptxas-verify %}
 
 declare void @llvm.nvvm.bar.warp.sync(i32)
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
-declare void @llvm.nvvm.barrier.cta.sync.aligned(i32, i32)
-declare void @llvm.nvvm.barrier.cta.sync.all(i32)
-declare void @llvm.nvvm.barrier.cta.sync(i32, i32)
-declare void @llvm.nvvm.barrier.cta.arrive(i32, i32)
-declare void @llvm.nvvm.barrier.cta.arrive.aligned(i32, i32)
-
-define void @barrier_warp_sync(i32 %id) {
-; CHECK-LABEL: barrier_warp_sync(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<2>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_warp_sync_param_0];
-; CHECK-NEXT:    bar.warp.sync %r1;
-; CHECK-NEXT:    bar.warp.sync 6;
-; CHECK-NEXT:    ret;
+declare void @llvm.nvvm.barrier.sync(i32)
+declare void @llvm.nvvm.barrier.sync.cnt(i32, i32)
+
+; CHECK-LABEL: .func{{.*}}barrier_sync
+define void @barrier_sync(i32 %id, i32 %cnt) {
+  ; CHECK: ld.param.b32 	[[ID:%r[0-9]+]], [barrier_sync_param_0];
+  ; CHECK: ld.param.b32 	[[CNT:%r[0-9]+]], [barrier_sync_param_1];
+
+  ; CHECK:  barrier.sync [[ID]], [[CNT]];
+  call void @llvm.nvvm.barrier.sync.cnt(i32 %id, i32 %cnt)
+  ; CHECK:  barrier.sync [[ID]], 32;
+  call void @llvm.nvvm.barrier.sync.cnt(i32 %id, i32 32)
+  ; CHECK:  barrier.sync 3, [[CNT]];
+  call void @llvm.nvvm.barrier.sync.cnt(i32 3, i32 %cnt)
+  ; CHECK:  barrier.sync 4, 64;
+  call void @llvm.nvvm.barrier.sync.cnt(i32 4, i32 64)
+
+  ; CHECK: barrier.sync [[ID]];
+  call void @llvm.nvvm.barrier.sync(i32 %id)
+  ; CHECK: barrier.sync 1;
+  call void @llvm.nvvm.barrier.sync(i32 1)
+
+  ; CHECK: bar.warp.sync [[ID]];
   call void @llvm.nvvm.bar.warp.sync(i32 %id)
+  ; CHECK: bar.warp.sync 6;
   call void @llvm.nvvm.bar.warp.sync(i32 6)
-  ret void
-}
-
-define void @barrier_cta_sync_aligned_all(i32 %id) {
-; CHECK-LABEL: barrier_cta_sync_aligned_all(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<2>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_aligned_all_param_0];
-; CHECK-NEXT:    bar.sync %r1;
-; CHECK-NEXT:    bar.sync 3;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %id)
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 3)
-  ret void
-}
-
-define void @barrier_cta_sync_aligned(i32 %id, i32 %cnt) {
-; CHECK-LABEL: barrier_cta_sync_aligned(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<3>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_aligned_param_0];
-; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_sync_aligned_param_1];
-; CHECK-NEXT:    bar.sync %r1, %r2;
-; CHECK-NEXT:    bar.sync 3, %r2;
-; CHECK-NEXT:    bar.sync %r1, 64;
-; CHECK-NEXT:    bar.sync 4, 64;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.sync.aligned(i32 %id, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.sync.aligned(i32 3, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.sync.aligned(i32 %id, i32 64)
-  call void @llvm.nvvm.barrier.cta.sync.aligned(i32 4, i32 64)
-  ret void
-}
-
-define void @barrier_cta_arrive_aligned(i32 %id, i32 %cnt) {
-; CHECK-LABEL: barrier_cta_arrive_aligned(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<3>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_arrive_aligned_param_0];
-; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_arrive_aligned_param_1];
-; CHECK-NEXT:    bar.arrive %r1, %r2;
-; CHECK-NEXT:    bar.arrive 3, %r2;
-; CHECK-NEXT:    bar.arrive %r1, 64;
-; CHECK-NEXT:    bar.arrive 4, 64;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.arrive.aligned(i32 %id, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.arrive.aligned(i32 3, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.arrive.aligned(i32 %id, i32 64)
-  call void @llvm.nvvm.barrier.cta.arrive.aligned(i32 4, i32 64)
-  ret void
-}
-
-define void @barrier_cta_sync_all(i32 %id) {
-; CHECK-LABEL: barrier_cta_sync_all(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<2>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_all_param_0];
-; CHECK-NEXT:    barrier.sync %r1;
-; CHECK-NEXT:    barrier.sync 3;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.sync.all(i32 %id)
-  call void @llvm.nvvm.barrier.cta.sync.all(i32 3)
-  ret void
+  ret void;
 }
 
-define void @barrier_cta_sync(i32 %id, i32 %cnt) {
-; CHECK-LABEL: barrier_cta_sync(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<3>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_param_0];
-; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_sync_param_1];
-; CHECK-NEXT:    barrier.sync %r1, %r2;
-; CHECK-NEXT:    barrier.sync 3, %r2;
-; CHECK-NEXT:    barrier.sync %r1, 64;
-; CHECK-NEXT:    barrier.sync 4, 64;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.sync(i32 %id, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.sync(i32 3, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.sync(i32 %id, i32 64)
-  call void @llvm.nvvm.barrier.cta.sync(i32 4, i32 64)
-  ret void
-}
-
-define void @barrier_cta_arrive(i32 %id, i32 %cnt) {
-; CHECK-LABEL: barrier_cta_arrive(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<3>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_arrive_param_0];
-; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_arrive_param_1];
-; CHECK-NEXT:    barrier.arrive %r1, %r2;
-; CHECK-NEXT:    barrier.arrive 3, %r2;
-; CHECK-NEXT:    barrier.arrive %r1, 64;
-; CHECK-NEXT:    barrier.arrive 4, 64;
-; CHECK-NEXT:    ret;
-  call void @llvm.nvvm.barrier.cta.arrive(i32 %id, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.arrive(i32 3, i32 %cnt)
-  call void @llvm.nvvm.barrier.cta.arrive(i32 %id, i32 64)
-  call void @llvm.nvvm.barrier.cta.arrive(i32 4, i32 64)
-  ret void
-}
diff --git a/llvm/test/CodeGen/NVPTX/named-barriers.ll b/llvm/test/CodeGen/NVPTX/named-barriers.ll
new file mode 100644
index 0000000000000..34e93cef6aaa4
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/named-barriers.ll
@@ -0,0 +1,42 @@
+; RUN: llc < %s -mtriple=nvptx -mcpu=sm_20 | FileCheck %s
+; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 | FileCheck %s
+; RUN: %if ptxas && !ptxas-12.0 %{ llc < %s -mtriple=nvptx -mcpu=sm_20 | %ptxas-verify %}
+; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 | %ptxas-verify %}
+
+; Use bar.sync to arrive at a pre-computed barrier number and
+; wait for all threads in CTA to also arrive:
+define ptx_device void @test_barrier_named_cta() {
+; CHECK: mov.b32  %r[[REG0:[0-9]+]], 0;
+; CHECK: bar.sync %r[[REG0]];
+; CHECK: mov.b32  %r[[REG1:[0-9]+]], 10;
+; CHECK: bar.sync %r[[REG1]];
+; CHECK: mov.b32  %r[[REG2:[0-9]+]], 15;
+; CHECK: bar.sync %r[[REG2]];
+; CHECK: ret;
+  call void @llvm.nvvm.barrier.n(i32 0)
+  call void @llvm.nvvm.barrier.n(i32 10)
+  call void @llvm.nvvm.barrier.n(i32 15)
+  ret void
+}
+
+; Use bar.sync to arrive at a pre-computed barrier number and
+; wait for fixed number of cooperating threads to arrive:
+define ptx_device void @test_barrier_named() {
+; CHECK: mov.b32  %r[[REG0A:[0-9]+]], 32;
+; CHECK: mov.b32  %r[[REG0B:[0-9]+]], 0;
+; CHECK: bar.sync %r[[REG0B]], %r[[REG0A]];
+; CHECK: mov.b32  %r[[REG1A:[0-9]+]], 352;
+; CHECK: mov.b32  %r[[REG1B:[0-9]+]], 10;
+; CHECK: bar.sync %r[[REG1B]], %r[[REG1A]];
+; CHECK: mov.b32  %r[[REG2A:[0-9]+]], 992;
+; CHECK: mov.b32  %r[[REG2B:[0-9]+]], 15;
+; CHECK: bar.sync %r[[REG2B]], %r[[REG2A]];
+; CHECK: ret;
+  call void @llvm.nvvm.barrier(i32 0, i32 32)
+  call void @llvm.nvvm.barrier(i32 10, i32 352)
+  call void @llvm.nvvm.barrier(i32 15, i32 992)
+  ret void
+}
+
+declare void @llvm.nvvm.barrier(i32, i32)
+declare void @llvm.nvvm.barrier.n(i32)
diff --git a/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll b/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
index 02abae0c8f9c5..2a0c5ab7299ba 100644
--- a/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
+++ b/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
@@ -3,8 +3,8 @@
 ; Make sure the call to syncthreads is not duplicate here by the LLVM
 ; optimizations, because it has the noduplicate attribute set.
 
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all
-; CHECK-NOT: call void @llvm.nvvm.barrier.cta.sync.aligned.all
+; CHECK: call void @llvm.nvvm.barrier0
+; CHECK-NOT: call void @llvm.nvvm.barrier0
 
 ; Function Attrs: nounwind
 define void @foo(ptr %output) #1 {
@@ -36,7 +36,7 @@ if.else:                                          ; preds = %entry
   br label %if.end
 
 if.end:                                           ; preds = %if.else, %if.then
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   %6 = load ptr, ptr %output.addr, align 8
   %7 = load float, ptr %6, align 4
   %conv7 = fpext float %7 to double
diff --git a/llvm/test/Feature/intrinsic-noduplicate.ll b/llvm/test/Feature/intrinsic-noduplicate.ll
index 42264ef909e8a..ecdb381b7920b 100644
--- a/llvm/test/Feature/intrinsic-noduplicate.ll
+++ b/llvm/test/Feature/intrinsic-noduplicate.ll
@@ -2,9 +2,9 @@
 ; REQUIRES: nvptx-registered-target
 
 ; Make sure LLVM knows about the convergent attribute on the
-; llvm.nvvm.barrier.cta.sync.aligned.all intrinsic.
+; llvm.nvvm.barrier0 intrinsic.
 
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
+declare void @llvm.nvvm.barrier0()
 
-; CHECK: declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #[[ATTRNUM:[0-9]+]]
+; CHECK: declare void @llvm.nvvm.barrier0() #[[ATTRNUM:[0-9]+]]
 ; CHECK: attributes #[[ATTRNUM]] = { convergent nocallback nounwind }
diff --git a/llvm/test/Transforms/FunctionAttrs/convergent.ll b/llvm/test/Transforms/FunctionAttrs/convergent.ll
index e2581b2b418fe..49c357bd6bc86 100644
--- a/llvm/test/Transforms/FunctionAttrs/convergent.ll
+++ b/llvm/test/Transforms/FunctionAttrs/convergent.ll
@@ -70,17 +70,17 @@ define i32 @indirect_non_convergent_call(ptr %f) convergent norecurse {
   ret i32 %a
 }
 
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) convergent
+declare void @llvm.nvvm.barrier0() convergent
 
 define i32 @intrinsic() convergent {
   ; Implicitly convergent, because the intrinsic is convergent.
 ; CHECK: Function Attrs: convergent norecurse nounwind
 ; CHECK-LABEL: define {{[^@]+}}@intrinsic
 ; CHECK-SAME: () #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK-NEXT:    call void @llvm.nvvm.barrier0()
 ; CHECK-NEXT:    ret i32 0
 ;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   ret i32 0
 }
 
diff --git a/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll b/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
index 1671baaaa0876..8a9e6f728936f 100644
--- a/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
+++ b/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
@@ -12,7 +12,7 @@ define i32 @wrapped_tid() #0 comdat align 32 {
   ret i32 %1
 }
 
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #1
+declare void @llvm.nvvm.barrier0() #1
 
 ; We had a bug where we duplicated basic blocks containing convergent
 ; functions like @llvm.nvvm.barrier0 below.  Verify that we don't do
@@ -32,9 +32,9 @@ define void @foo() local_unnamed_addr #2 comdat align 32 {
   br label %6
 
 6:
-; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
-; CHECK-NOT: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK: call void @llvm.nvvm.barrier0()
+; CHECK-NOT: call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier0()
   %7 = icmp eq i32 %2, 0
   br i1 %7, label %11, label %8
 
diff --git a/llvm/test/Transforms/OpenMP/barrier_removal.ll b/llvm/test/Transforms/OpenMP/barrier_removal.ll
index f662d5dd85b2b..5b7544b1a7961 100644
--- a/llvm/test/Transforms/OpenMP/barrier_removal.ll
+++ b/llvm/test/Transforms/OpenMP/barrier_removal.ll
@@ -8,7 +8,7 @@ target triple = "amdgcn-amd-amdhsa"
 declare void @useI32(i32)
 declare void @unknown()
 declare void @aligned_barrier() "llvm.assume"="ompx_aligned_barrier"
-declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
+declare void @llvm.nvvm.barrier0()
 declare i32 @llvm.nvvm.barrier0.and(i32)
 declare i32 @llvm.nvvm.barrier0.or(i32)
 declare i32 @llvm.nvvm.barrier0.popc(i32)
@@ -58,7 +58,7 @@ define amdgpu_kernel void @pos_empty_3() "kernel" {
 ; CHECK-SAME: () #[[ATTR4]] {
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   ret void
 }
 define amdgpu_kernel void @pos_empty_4() "kernel" {
@@ -393,12 +393,12 @@ define amdgpu_kernel void @pos_multiple() "kernel" {
 ; CHECK-SAME: () #[[ATTR4]] {
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   call void @aligned_barrier()
   call void @aligned_barrier()
   call void @llvm.amdgcn.s.barrier()
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   call void @aligned_barrier()
   call void @aligned_barrier()
   ret void
@@ -422,7 +422,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_1(i1 %c0, i1 %c1) "kernel" {
 ; CHECK-NEXT:    ret void
 ;
   fence acquire
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   fence release
   call void @aligned_barrier()
   fence seq_cst
@@ -441,7 +441,7 @@ f0:
   fence release
   call void @aligned_barrier()
   fence acquire
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   fence acquire
   br i1 %c1, label %t1, label %f1
 t1:
@@ -473,7 +473,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_2(i1 %c0, i1 %c1, ptr %p) "ker
 ; CHECK-NEXT:    br label [[M:%.*]]
 ; CHECK:       f0:
 ; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
-; CHECK-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK-NEXT:    call void @llvm.nvvm.barrier0()
 ; CHECK-NEXT:    br i1 [[C1]], label [[T1:%.*]], label [[F1:%.*]]
 ; CHECK:       t1:
 ; CHECK-NEXT:    br label [[M]]
@@ -483,7 +483,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_2(i1 %c0, i1 %c1, ptr %p) "ker
 ; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   store i32 4, ptr %p
   call void @aligned_barrier()
   br i1 %c0, label %t0, label %f0
@@ -496,7 +496,7 @@ t0b:
 f0:
   call void @aligned_barrier()
   store i32 4, ptr %p
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -527,7 +527,7 @@ define void @multiple_blocks_non_kernel_1(i1 %c0, i1 %c1) "kernel" {
 ; CHECK:       m:
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   call void @aligned_barrier()
   br i1 %c0, label %t0, label %f0
 t0:
@@ -538,7 +538,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -577,7 +577,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -614,7 +614,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -665,7 +665,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier0()
   store i32 2, ptr %p
   br i1 %c1, label %t1, label %f1
 t1:
diff --git a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
index 0c5c87cfe002f..e4a44f698b622 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
@@ -535,13 +535,8 @@ def NVVM_MBarrierTestWaitSharedOp : NVVM_Op<"mbarrier.test.wait.shared">,
 // NVVM synchronization op definitions
 //===----------------------------------------------------------------------===//
 
-def NVVM_Barrier0Op : NVVM_Op<"barrier0"> {
+def NVVM_Barrier0Op : NVVM_IntrOp<"barrier0"> {
   let assemblyFormat = "attr-dict";
-  string llvmBuilder = [{
-      createIntrinsicCall(
-          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_all,
-          {builder.getInt32(0)});
-  }];
 }
 
 def NVVM_BarrierOp : NVVM_Op<"barrier", [AttrSizedOperandSegments]> {
@@ -549,14 +544,15 @@ def NVVM_BarrierOp : NVVM_Op<"barrier", [AttrSizedOperandSegments]> {
     Optional<I32>:$barrierId,
     Optional<I32>:$numberOfThreads);
   string llvmBuilder = [{
-    llvm::Value *id = $barrierId ? $barrierId : builder.getInt32(0);
-    if ($numberOfThreads)
-      createIntrinsicCall(
-          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned,
-          {id, $numberOfThreads});
-    else
-      createIntrinsicCall(
-          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_all, {id});
+    if ($numberOfThreads && $barrierId) {
+      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier,
+                {$barrierId, $numberOfThreads});
+    } else if($barrierId) {
+      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier_n,
+                {$barrierId});   
+    } else {
+      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier0);
+    }
   }];
   let hasVerifier = 1;
 
diff --git a/mlir/test/Target/LLVMIR/Import/nvvmir.ll b/mlir/test/Target/LLVMIR/Import/nvvmir.ll
index 2da0b0ceb2cfe..c8b7b82f47fd9 100644
--- a/mlir/test/Target/LLVMIR/Import/nvvmir.ll
+++ b/mlir/test/Target/LLVMIR/Import/nvvmir.ll
@@ -73,11 +73,12 @@ define float @nvvm_rcp(float %0) {
 
 ; CHECK-LABEL: @llvm_nvvm_barrier0()
 define void @llvm_nvvm_barrier0() {
-  ; CHECK: llvm.nvvm.barrier.cta.sync.aligned.all
+  ; CHECK: nvvm.barrier0
   call void @llvm.nvvm.barrier0()
   ret void
 }
 
+
 ; TODO: Support the intrinsics below once they derive from NVVM_IntrOp rather than from NVVM_Op.
 ;
 ; define i32 @nvvm_shfl(i32 %0, i32 %1, i32 %2, i32 %3, float %4) {
diff --git a/mlir/test/Target/LLVMIR/nvvmir.mlir b/mlir/test/Target/LLVMIR/nvvmir.mlir
index 90519a9402621..894b72733a46a 100644
--- a/mlir/test/Target/LLVMIR/nvvmir.mlir
+++ b/mlir/test/Target/LLVMIR/nvvmir.mlir
@@ -162,7 +162,7 @@ llvm.func @nvvm_rcp(%0: f32) -> f32 {
 
 // CHECK-LABEL: @llvm_nvvm_barrier0
 llvm.func @llvm_nvvm_barrier0() {
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  // CHECK: call void @llvm.nvvm.barrier0()
   nvvm.barrier0
   llvm.return
 }
@@ -170,11 +170,11 @@ llvm.func @llvm_nvvm_barrier0() {
 // CHECK-LABEL: @llvm_nvvm_barrier(
 // CHECK-SAME: i32 %[[barId:.*]], i32 %[[numThreads:.*]])
 llvm.func @llvm_nvvm_barrier(%barID : i32, %numberOfThreads : i32) {
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
-  nvvm.barrier
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %[[barId]])
+  // CHECK: call void @llvm.nvvm.barrier0()
+  nvvm.barrier 
+  // CHECK: call void @llvm.nvvm.barrier.n(i32 %[[barId]])
   nvvm.barrier id = %barID
-  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned(i32 %[[barId]], i32 %[[numThreads]])
+  // CHECK: call void @llvm.nvvm.barrier(i32 %[[barId]], i32 %[[numThreads]])
   nvvm.barrier id = %barID number_of_threads = %numberOfThreads
   llvm.return
 }

>From 8e3f44d68bf2f5318406dac73e86333d7c34976d Mon Sep 17 00:00:00 2001
From: jimingham <jingham at apple.com>
Date: Thu, 22 May 2025 10:35:35 -0700
Subject: [PATCH 027/105] Fix a bug where using "thread backtrace unique" would
 switch you to (#140993)

always using the "frame-format-unique" even when you weren't doing the
unique backtrace mode.
---
 .../Commands/CommandObjectThreadUtil.cpp      |  2 ++
 .../thread/num_threads/TestNumThreads.py      | 24 ++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Commands/CommandObjectThreadUtil.cpp b/lldb/source/Commands/CommandObjectThreadUtil.cpp
index cdc5946547f47..a451de137d702 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.cpp
+++ b/lldb/source/Commands/CommandObjectThreadUtil.cpp
@@ -37,6 +37,8 @@ void CommandObjectIterateOverThreads::DoExecute(Args &command,
   result.SetStatus(m_success_return);
 
   bool all_threads = false;
+  m_unique_stacks = false;
+
   if (command.GetArgumentCount() == 0) {
     Thread *thread = m_exe_ctx.GetThreadPtr();
     if (thread)
diff --git a/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py b/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
index ee9b14f15b6e9..2f7d64bacfea9 100644
--- a/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
+++ b/lldb/test/API/functionalities/thread/num_threads/TestNumThreads.py
@@ -132,10 +132,32 @@ def is_thread3(thread):
         # Construct our expected back trace string
         expect_string = "10 thread(s)%s" % (expect_threads)
 
+        # There was a bug where if you used 'thread backtrace unique'
+        # we would switch all future backtraces to use the
+        # "frame-format-unique" not the "frame-format".  Make
+        # sure we don't do that...
+        setting_data = self.dbg.GetSetting("frame-format-unique")
+        setting_str = setting_data.GetStringValue(1000)
+        setting_str = "UNIQUE: " + setting_str
+        lldb.SBDebugger.SetInternalVariable(
+            "frame-format-unique", setting_str, self.dbg.GetInstanceName()
+        )
         # Now that we are stopped, we should have 10 threads waiting in the
         # thread3 function. All of these threads should show as one stack.
         self.expect(
             "thread backtrace unique",
             "Backtrace with unique stack shown correctly",
-            substrs=[expect_string, "main.cpp:%d" % self.thread3_before_lock_line],
+            substrs=[
+                expect_string,
+                "UNIQUE:",
+                "main.cpp:%d" % self.thread3_before_lock_line,
+            ],
+        )
+        # Make sure setting the unique flag in the command isn't
+        # persistent:
+        self.expect(
+            "thread backtrace",
+            "Backtrace unique is not sticky",
+            substrs=["UNIQUE:"],
+            matching=False,
         )

>From a40762cd78d5d254d2298d74ead839732f4c8b7f Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Thu, 22 May 2025 13:37:05 -0400
Subject: [PATCH 028/105] [PowerPC][NFC] clean up if-else block in
 PPCRegisterInfo.cpp (#140084)

Move all if-else conditions into a switch stmt for handling spills.
---
 llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp | 75 ++++++++++++---------
 1 file changed, 42 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
index e1d9db0e3daa7..51902ad218d1c 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp
@@ -1610,62 +1610,71 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
   // Get the instruction opcode.
   unsigned OpC = MI.getOpcode();
 
-  if ((OpC == PPC::DYNAREAOFFSET || OpC == PPC::DYNAREAOFFSET8)) {
+  switch (OpC) {
+  default:
+    break;
+  case PPC::DYNAREAOFFSET:
+  case PPC::DYNAREAOFFSET8:
     lowerDynamicAreaOffset(II);
     // lowerDynamicAreaOffset erases II
     return true;
+  case PPC::DYNALLOC:
+  case PPC::DYNALLOC8: {
+    // Special case for dynamic alloca.
+    if (FPSI && FrameIndex == FPSI) {
+      lowerDynamicAlloc(II); // lowerDynamicAlloc erases II
+      return true;
+    }
+    break;
   }
-
-  // Special case for dynamic alloca.
-  if (FPSI && FrameIndex == FPSI &&
-      (OpC == PPC::DYNALLOC || OpC == PPC::DYNALLOC8)) {
-    lowerDynamicAlloc(II);
-    // lowerDynamicAlloc erases II
-    return true;
-  }
-
-  if (FPSI && FrameIndex == FPSI &&
-      (OpC == PPC::PREPARE_PROBED_ALLOCA_64 ||
-       OpC == PPC::PREPARE_PROBED_ALLOCA_32 ||
-       OpC == PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64 ||
-       OpC == PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32)) {
-    lowerPrepareProbedAlloca(II);
-    // lowerPrepareProbedAlloca erases II
-    return true;
+  case PPC::PREPARE_PROBED_ALLOCA_64:
+  case PPC::PREPARE_PROBED_ALLOCA_32:
+  case PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_64:
+  case PPC::PREPARE_PROBED_ALLOCA_NEGSIZE_SAME_REG_32: {
+    if (FPSI && FrameIndex == FPSI) {
+      lowerPrepareProbedAlloca(II); // lowerPrepareProbedAlloca erases II
+      return true;
+    }
+    break;
   }
-
-  // Special case for pseudo-ops SPILL_CR and RESTORE_CR, etc.
-  if (OpC == PPC::SPILL_CR) {
+  case PPC::SPILL_CR:
+    // Special case for pseudo-ops SPILL_CR and RESTORE_CR, etc.
     lowerCRSpilling(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::RESTORE_CR) {
+  case PPC::RESTORE_CR:
     lowerCRRestore(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::SPILL_CRBIT) {
+  case PPC::SPILL_CRBIT:
     lowerCRBitSpilling(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::RESTORE_CRBIT) {
+  case PPC::RESTORE_CRBIT:
     lowerCRBitRestore(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::SPILL_ACC || OpC == PPC::SPILL_UACC) {
+  case PPC::SPILL_ACC:
+  case PPC::SPILL_UACC:
     lowerACCSpilling(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::RESTORE_ACC || OpC == PPC::RESTORE_UACC) {
+  case PPC::RESTORE_ACC:
+  case PPC::RESTORE_UACC:
     lowerACCRestore(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::STXVP && DisableAutoPairedVecSt) {
-    lowerOctWordSpilling(II, FrameIndex);
-    return true;
-  } else if (OpC == PPC::SPILL_WACC) {
+  case PPC::STXVP: {
+    if (DisableAutoPairedVecSt) {
+      lowerOctWordSpilling(II, FrameIndex);
+      return true;
+    }
+    break;
+  }
+  case PPC::SPILL_WACC:
     lowerWACCSpilling(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::RESTORE_WACC) {
+  case PPC::RESTORE_WACC:
     lowerWACCRestore(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::SPILL_QUADWORD) {
+  case PPC::SPILL_QUADWORD:
     lowerQuadwordSpilling(II, FrameIndex);
     return true;
-  } else if (OpC == PPC::RESTORE_QUADWORD) {
+  case PPC::RESTORE_QUADWORD:
     lowerQuadwordRestore(II, FrameIndex);
     return true;
   }

>From 827027b3a39d5c43f6fa74cf8761f974bf125611 Mon Sep 17 00:00:00 2001
From: Timm Baeder <tbaeder at redhat.com>
Date: Thu, 22 May 2025 19:44:17 +0200
Subject: [PATCH 029/105] [clang] Move Diags.isIgnored() check below faster
 checks (#141084)

Because this check is relatively slow and the others aren't as much.


http://llvm-compile-time-tracker.com/compare.php?from=4a158f675be7fd1b3763bf39980d801db89744f8&to=886a8fab041ff7574d54cccddbc1a9b968c1bb58&stat=instructions:u
---
 clang/lib/Sema/SemaChecking.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index a960b9931ddfd..0b2a74e272339 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11745,10 +11745,6 @@ static void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
 
 static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
                                    SourceLocation CC) {
-  if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
-                        E->getExprLoc()))
-    return;
-
   // Don't warn on functions which have return type nullptr_t.
   if (isa<CallExpr>(E))
     return;
@@ -11765,6 +11761,10 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
       T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType())
     return;
 
+  if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
+                        E->getExprLoc()))
+    return;
+
   SourceLocation Loc = E->getSourceRange().getBegin();
 
   // Venture through the macro stacks to get to the source of macro arguments.

>From f07fc38a4ce306bce59371f36957f516b6d4e614 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 19:17:22 +0100
Subject: [PATCH 030/105] [IndVars] Improve code; use SCEVPatternMatch (NFC)
 (#139533)

---
 llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 70610f7c020c8..e774e5fd99cbb 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -38,6 +38,7 @@
 #include "llvm/Analysis/MemorySSAUpdater.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Analysis/ScalarEvolutionPatternMatch.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -53,7 +54,6 @@
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/IR/PatternMatch.h"
@@ -79,6 +79,7 @@
 
 using namespace llvm;
 using namespace PatternMatch;
+using namespace SCEVPatternMatch;
 
 #define DEBUG_TYPE "indvars"
 
@@ -806,12 +807,9 @@ static bool isLoopCounter(PHINode* Phi, Loop *L,
   if (!SE->isSCEVable(Phi->getType()))
     return false;
 
-  const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(Phi));
-  if (!AR || AR->getLoop() != L || !AR->isAffine())
-    return false;
-
-  const SCEV *Step = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*SE));
-  if (!Step || !Step->isOne())
+  const SCEV *S = SE->getSCEV(Phi);
+  if (!match(S, m_scev_AffineAddRec(m_SCEV(), m_scev_One())) ||
+      cast<SCEVAddRecExpr>(S)->getLoop() != L)
     return false;
 
   int LatchIdx = Phi->getBasicBlockIndex(L->getLoopLatch());

>From 00f40e3c1ac3163dd92ed7f5a0779775ed190596 Mon Sep 17 00:00:00 2001
From: "Oleksandr T." <oleksandr.tarasiuk at outlook.com>
Date: Thu, 22 May 2025 21:24:12 +0300
Subject: [PATCH 031/105] [Clang] Add missing macro undefs in
 AttributeSpellingList emitter (#141090)

Fixes
https://github.com/llvm/llvm-project/pull/140629#issuecomment-2901568992

---

This patch adds `#undef ATTR_NAME` and `#undef ATTR_SCOPE_NAME` to the
end of the generated `AttributeSpellingList.inc` file to prevent macro
redefinition warnings
---
 clang/lib/Basic/Attributes.cpp            |  4 +---
 clang/utils/TableGen/ClangAttrEmitter.cpp | 10 +++++++---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index c2f3120aed5d0..ebc86a5adf7a7 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -233,13 +233,11 @@ unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
 static constexpr const char *AttrSpellingList[] = {
 #include "clang/Basic/AttributeSpellingList.inc"
 };
-#undef ATTR_NAME
 
-#define ATTR_SCOPE_SCOPE(SCOPE_NAME) SCOPE_NAME,
+#define ATTR_SCOPE_NAME(SCOPE_NAME) SCOPE_NAME,
 static constexpr const char *AttrScopeSpellingList[] = {
 #include "clang/Basic/AttributeSpellingList.inc"
 };
-#undef ATTR_SCOPE_SCOPE
 
 std::optional<std::string>
 AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target,
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index f6c5c84602762..21d76c12a3cce 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -4146,14 +4146,18 @@ void EmitAttributeSpellingList(const RecordKeeper &Records, raw_ostream &OS) {
     OS << "ATTR_NAME(\"" << AttrName << "\")\n";
   }
   OS << "\n";
+  OS << "#undef ATTR_NAME" << "\n";
+  OS << "\n";
 
-  OS << "#ifndef ATTR_SCOPE_SCOPE" << "\n";
-  OS << "#define ATTR_SCOPE_SCOPE(SCOPE_NAME) SCOPE_NAME" << "\n";
+  OS << "#ifndef ATTR_SCOPE_NAME" << "\n";
+  OS << "#define ATTR_SCOPE_NAME(SCOPE_NAME) SCOPE_NAME" << "\n";
   OS << "#endif" << "\n" << "\n";
   for (const auto &AttrScopeName : AttrScopeSpellingList) {
-    OS << "ATTR_SCOPE_SCOPE(\"" << AttrScopeName << "\")\n";
+    OS << "ATTR_SCOPE_NAME(\"" << AttrScopeName << "\")\n";
   }
   OS << "\n";
+  OS << "#undef ATTR_SCOPE_NAME" << "\n";
+  OS << "\n";
 }
 
 static bool isArgVariadic(const Record &R, StringRef AttrName) {

>From eaf911bb98509e47b35376ffbc800dca6c803793 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Thu, 22 May 2025 14:28:45 -0400
Subject: [PATCH 032/105] [InstCombine] Fix comment typo that incorrectly
 described fold (NFC) (#141105)

icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X != -1, not X != 0 && X
== -1, which would go to X == -1 anyway.
---
 llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 00b0f05f18f03..bdc7a49700cfc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7078,7 +7078,7 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
         // icmp eq X, (zext (icmp ne X, 0)) --> X == 0 || X == 1
         // icmp ne X, (zext (icmp ne X, 0)) --> X != 0 && X != 1
         // icmp eq X, (sext (icmp ne X, 0)) --> X == 0 || X == -1
-        // icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X == -1
+        // icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X != -1
         return CreateRangeCheck();
       }
     } else if (IsSExt ? C->isAllOnes() : C->isOne()) {

>From ced6076dfc39aa54f6d703982e6752e4be8370f5 Mon Sep 17 00:00:00 2001
From: Viktoria Maximova <viktoria.maksimova at intel.com>
Date: Thu, 22 May 2025 20:56:54 +0200
Subject: [PATCH 033/105] [SPIR-V] Support `SPV_INTEL_int4` extension (#141031)

Adds support for native 4-bit type.

Spec:

https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/INTEL/SPV_INTEL_int4.asciidoc
---
 llvm/docs/SPIRVUsage.rst                      |  2 ++
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |  3 +-
 llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 21 +++++++++++---
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |  3 +-
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   |  3 +-
 .../lib/Target/SPIRV/SPIRVSymbolicOperands.td |  3 ++
 .../SPV_INTEL_int4/cooperative_matrix.ll      | 20 +++++++++++++
 .../extensions/SPV_INTEL_int4/negative.ll     | 29 +++++++++++++++++++
 .../extensions/SPV_INTEL_int4/trivial.ll      | 25 ++++++++++++++++
 9 files changed, 102 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/cooperative_matrix.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/negative.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/trivial.ll

diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 4d8b7996dec01..373dd1e3856d8 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -215,6 +215,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
      - Adds a bitwise instruction on three operands and a look-up table index for specifying the bitwise operation to perform. 
    * - ``SPV_INTEL_subgroup_matrix_multiply_accumulate``
      - Adds an instruction to compute the matrix product of an M x K matrix with a K x N matrix and then add an M x N matrix. 
+   * - ``SPV_INTEL_int4``
+     - Adds support for 4-bit integer type, and allow this type to be used in cooperative matrices.
 
 To enable multiple extensions, list them separated by comma. For example, to enable support for atomic operations on floating-point numbers and arbitrary precision integers, use:
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index e6cb8cee66a60..fbaca4e0e4d81 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -99,7 +99,8 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
         {"SPV_INTEL_ternary_bitwise_function",
          SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function},
         {"SPV_INTEL_2d_block_io",
-         SPIRV::Extension::Extension::SPV_INTEL_2d_block_io}};
+         SPIRV::Extension::Extension::SPV_INTEL_2d_block_io},
+        {"SPV_INTEL_int4", SPIRV::Extension::Extension::SPV_INTEL_int4}};
 
 bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
                                   StringRef ArgValue,
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index ac397fc486e19..d9fcb5623b220 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -154,7 +154,8 @@ unsigned SPIRVGlobalRegistry::adjustOpTypeIntWidth(unsigned Width) const {
     report_fatal_error("Unsupported integer width!");
   const SPIRVSubtarget &ST = cast<SPIRVSubtarget>(CurMF->getSubtarget());
   if (ST.canUseExtension(
-          SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers))
+          SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers) ||
+      ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4))
     return Width;
   if (Width <= 8)
     Width = 8;
@@ -174,9 +175,14 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeInt(unsigned Width,
   const SPIRVSubtarget &ST =
       cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
   return createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
-    if ((!isPowerOf2_32(Width) || Width < 8) &&
-        ST.canUseExtension(
-            SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers)) {
+    if (Width == 4 && ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
+      MIRBuilder.buildInstr(SPIRV::OpExtension)
+          .addImm(SPIRV::Extension::SPV_INTEL_int4);
+      MIRBuilder.buildInstr(SPIRV::OpCapability)
+          .addImm(SPIRV::Capability::Int4TypeINTEL);
+    } else if ((!isPowerOf2_32(Width) || Width < 8) &&
+               ST.canUseExtension(
+                   SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers)) {
       MIRBuilder.buildInstr(SPIRV::OpExtension)
           .addImm(SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers);
       MIRBuilder.buildInstr(SPIRV::OpCapability)
@@ -1563,6 +1569,13 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateOpTypeCoopMatr(
   const MachineInstr *NewMI =
       createOpType(MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
         SPIRVType *SpvTypeInt32 = getOrCreateSPIRVIntegerType(32, MIRBuilder);
+        const Type *ET = getTypeForSPIRVType(ElemType);
+        if (ET->isIntegerTy() && ET->getIntegerBitWidth() == 4 &&
+            cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget())
+                .canUseExtension(SPIRV::Extension::SPV_INTEL_int4)) {
+          MIRBuilder.buildInstr(SPIRV::OpCapability)
+              .addImm(SPIRV::Capability::Int4CooperativeMatrixINTEL);
+        }
         return MIRBuilder.buildInstr(SPIRV::OpTypeCooperativeMatrixKHR)
             .addDef(createTypeVReg(MIRBuilder))
             .addUse(getSPIRVTypeID(ElemType))
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 578e82881f6e8..29ec90d2ae8df 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -128,7 +128,8 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
   bool IsExtendedInts =
       ST.canUseExtension(
           SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers) ||
-      ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
+      ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
+      ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
   auto extendedScalarsAndVectors =
       [IsExtendedInts](const LegalityQuery &Query) {
         const LLT Ty = Query.Types[0];
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index b6a2da6e2045d..2d6d0e37c8a1c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -492,7 +492,8 @@ generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
   bool IsExtendedInts =
       ST->canUseExtension(
           SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers) ||
-      ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
+      ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
+      ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
 
   for (MachineBasicBlock *MBB : post_order(&MF)) {
     if (MBB->empty())
diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
index b49507cd8a1c9..ca8a9a9997a8b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
+++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td
@@ -317,6 +317,7 @@ defm SPV_INTEL_fp_max_error : ExtensionOperand<119>;
 defm SPV_INTEL_ternary_bitwise_function : ExtensionOperand<120>;
 defm SPV_INTEL_subgroup_matrix_multiply_accumulate : ExtensionOperand<121>;
 defm SPV_INTEL_2d_block_io : ExtensionOperand<122>;
+defm SPV_INTEL_int4 : ExtensionOperand<123>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define Capabilities enum values and at the same time
@@ -522,6 +523,8 @@ defm SubgroupMatrixMultiplyAccumulateINTEL : CapabilityOperand<6236, 0, 0, [SPV_
 defm Subgroup2DBlockIOINTEL : CapabilityOperand<6228, 0, 0, [SPV_INTEL_2d_block_io], []>;
 defm Subgroup2DBlockTransformINTEL : CapabilityOperand<6229, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>;
 defm Subgroup2DBlockTransposeINTEL : CapabilityOperand<6230, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>;
+defm Int4TypeINTEL : CapabilityOperand<5112, 0, 0, [SPV_INTEL_int4], []>;
+defm Int4CooperativeMatrixINTEL : CapabilityOperand<5114, 0, 0, [SPV_INTEL_int4], [Int4TypeINTEL, CooperativeMatrixKHR]>;
 
 //===----------------------------------------------------------------------===//
 // Multiclass used to define SourceLanguage enum values and at the same time
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/cooperative_matrix.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/cooperative_matrix.ll
new file mode 100644
index 0000000000000..02f023276bf5d
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/cooperative_matrix.ll
@@ -0,0 +1,20 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_int4,+SPV_KHR_cooperative_matrix %s -o - | FileCheck %s
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_int4,+SPV_KHR_cooperative_matrix %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability Int4TypeINTEL
+; CHECK-DAG: Capability CooperativeMatrixKHR
+; CHECK-DAG: Extension "SPV_INTEL_int4"
+; CHECK-DAG: Capability Int4CooperativeMatrixINTEL
+; CHECK-DAG: Extension "SPV_KHR_cooperative_matrix"
+
+; CHECK: %[[#Int4Ty:]] = OpTypeInt 4 0
+; CHECK: %[[#CoopMatTy:]] = OpTypeCooperativeMatrixKHR %[[#Int4Ty]]
+; CHECK: CompositeConstruct %[[#CoopMatTy]]
+
+define spir_kernel void @foo() {
+entry:
+  %call.i.i = tail call spir_func noundef target("spirv.CooperativeMatrixKHR", i4, 3, 12, 12, 2) @_Z26__spirv_CompositeConstruct(i4 noundef 0)
+  ret void
+}
+
+declare dso_local spir_func noundef target("spirv.CooperativeMatrixKHR", i4, 3, 12, 12, 2) @_Z26__spirv_CompositeConstruct(i4 noundef)
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/negative.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/negative.ll
new file mode 100644
index 0000000000000..17202ab243e8f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/negative.ll
@@ -0,0 +1,29 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_arbitrary_precision_integers %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INT-4
+
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-INT-8
+; No error would be reported in comparison to Khronos llvm-spirv, because type adjustments to integer size are made 
+; in case no appropriate extension is enabled. Here we expect that the type is adjusted to 8 bits.
+
+; CHECK-SPIRV: Capability ArbitraryPrecisionIntegersINTEL
+; CHECK-SPIRV: Extension "SPV_INTEL_arbitrary_precision_integers"
+; CHECK-INT-4: %[[#Int4:]] = OpTypeInt 4 0
+; CHECK-INT-8: %[[#Int4:]] = OpTypeInt 8 0
+; CHECK: OpTypeFunction %[[#]] %[[#Int4]]
+; CHECK: %[[#Int4PtrTy:]] = OpTypePointer Function %[[#Int4]]
+; CHECK: %[[#Const:]] = OpConstant %[[#Int4]]  1
+
+; CHECK: %[[#Int4Ptr:]] = OpVariable %[[#Int4PtrTy]] Function
+; CHECK: OpStore %[[#Int4Ptr]] %[[#Const]]
+; CHECK: %[[#Load:]] = OpLoad %[[#Int4]] %[[#Int4Ptr]]
+; CHECK: OpFunctionCall %[[#]] %[[#]] %[[#Load]]
+
+define spir_kernel void @foo() {
+entry:
+  %0 = alloca i4
+  store i4 1, ptr %0
+  %1 = load i4, ptr %0
+  call spir_func void @boo(i4 %1)
+  ret void
+}
+
+declare spir_func void @boo(i4)
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/trivial.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/trivial.ll
new file mode 100644
index 0000000000000..f1bee0b963613
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_int4/trivial.ll
@@ -0,0 +1,25 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_int4 %s -o - | FileCheck %s
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_int4 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK: Capability Int4TypeINTEL
+; CHECK: Extension "SPV_INTEL_int4"
+; CHECK: %[[#Int4:]] = OpTypeInt  4 0
+; CHECK: OpTypeFunction %[[#]] %[[#Int4]]
+; CHECK: %[[#Int4PtrTy:]] = OpTypePointer Function %[[#Int4]]
+; CHECK: %[[#Const:]] = OpConstant %[[#Int4]]  1
+
+; CHECK: %[[#Int4Ptr:]] = OpVariable %[[#Int4PtrTy]] Function
+; CHECK: OpStore %[[#Int4Ptr]] %[[#Const]]
+; CHECK: %[[#Load:]] = OpLoad %[[#Int4]] %[[#Int4Ptr]]
+; CHECK: OpFunctionCall %[[#]] %[[#]] %[[#Load]]
+
+define spir_kernel void @foo() {
+entry:
+  %0 = alloca i4
+  store i4 1, ptr %0
+  %1 = load i4, ptr %0
+  call spir_func void @boo(i4 %1)
+  ret void
+}
+
+declare spir_func void @boo(i4)

>From 57e9097ad28916f43a7d9ee07c66a7cffd02b0d5 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 22 May 2025 21:01:49 +0200
Subject: [PATCH 034/105] AMDGPU: Add baseline v_med3_f32 tests from
 minimumnum/maximumnum (#141047)

---
 llvm/test/CodeGen/AMDGPU/clamp-modifier.ll | 595 ++++++++++++++++++++
 llvm/test/CodeGen/AMDGPU/clamp.ll          | 605 +++++++++++++++++++++
 llvm/test/CodeGen/AMDGPU/fmed3.bf16.ll     | 242 +++++++++
 llvm/test/CodeGen/AMDGPU/fmed3.ll          | 557 ++++++++++++++++++-
 llvm/test/CodeGen/AMDGPU/minmax.ll         |  26 +
 llvm/test/CodeGen/AMDGPU/omod.ll           |  29 +
 6 files changed, 2052 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/AMDGPU/fmed3.bf16.ll

diff --git a/llvm/test/CodeGen/AMDGPU/clamp-modifier.ll b/llvm/test/CodeGen/AMDGPU/clamp-modifier.ll
index f7c58ca9599b4..7407fc60a1bcf 100644
--- a/llvm/test/CodeGen/AMDGPU/clamp-modifier.ll
+++ b/llvm/test/CodeGen/AMDGPU/clamp-modifier.ll
@@ -1637,6 +1637,601 @@ define <2 x half> @v_clamp_cvt_pkrtz_src_v2f16_denorm(float %a, float %b) #0 {
   ret <2 x half> %clamp
 }
 
+define amdgpu_kernel void @v_clamp_add_src_f32_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_src_f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dword v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    buffer_store_dword v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_f32_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 2, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dword v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f32_e64 v2, v3, 1.0 clamp
+; GFX8-NEXT:    flat_store_dword v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dword v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX9-NEXT:    global_store_dword v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_src_f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b32 v1, v0, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX11-NEXT:    global_store_b32 v0, v1, s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr float, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr float, ptr addrspace(1) %out, i32 %tid
+  %a = load float, ptr addrspace(1) %gep0
+  %add = fadd float %a, 1.0
+  %max = call float @llvm.maximumnum.f32(float %add, float 0.0)
+  %clamp = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  store float %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_neg_src_f32_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_neg_src_f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dword v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_floor_f32_e32 v2, v2
+; SI-NEXT:    v_max_f32_e64 v2, -v2, -v2 clamp
+; SI-NEXT:    buffer_store_dword v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_neg_src_f32_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 2, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dword v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_floor_f32_e32 v2, v3
+; GFX8-NEXT:    v_max_f32_e64 v2, -v2, -v2 clamp
+; GFX8-NEXT:    flat_store_dword v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_neg_src_f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dword v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_floor_f32_e32 v1, v1
+; GFX9-NEXT:    v_max_f32_e64 v1, -v1, -v1 clamp
+; GFX9-NEXT:    global_store_dword v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_neg_src_f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_4) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b32 v1, v0, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_floor_f32_e32 v1, v1
+; GFX11-NEXT:    v_max_f32_e64 v1, -v1, -v1 clamp
+; GFX11-NEXT:    global_store_b32 v0, v1, s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr float, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr float, ptr addrspace(1) %out, i32 %tid
+  %a = load float, ptr addrspace(1) %gep0
+  %floor = call float @llvm.floor.f32(float %a)
+  %neg.floor = fneg float %floor
+  %max = call float @llvm.maximumnum.f32(float %neg.floor, float 0.0)
+  %clamp = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  store float %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+
+define amdgpu_kernel void @v_clamp_add_src_f64_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_src_f64_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 3, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dwordx2 v[2:3], v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_add_f64 v[2:3], v[2:3], 1.0 clamp
+; SI-NEXT:    buffer_store_dwordx2 v[2:3], v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_f64_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dwordx2 v[0:1], v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v3, s1
+; GFX8-NEXT:    v_add_u32_e32 v2, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v3, vcc, 0, v3, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0 clamp
+; GFX8-NEXT:    flat_store_dwordx2 v[2:3], v[0:1]
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_f64_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dwordx2 v[0:1], v2, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0 clamp
+; GFX9-NEXT:    global_store_dwordx2 v2, v[0:1], s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_src_f64_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b64 v[0:1], v2, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0 clamp
+; GFX11-NEXT:    global_store_b64 v2, v[0:1], s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr double, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr double, ptr addrspace(1) %out, i32 %tid
+  %a = load double, ptr addrspace(1) %gep0
+  %add = fadd double %a, 1.0
+  %max = call double @llvm.maximumnum.f64(double %add, double 0.0)
+  %clamp = call double @llvm.minimumnum.f64(double %max, double 1.0)
+  store double %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_src_f32_denormals_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #2 {
+; SI-LABEL: v_clamp_add_src_f32_denormals_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dword v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    buffer_store_dword v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_f32_denormals_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 2, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dword v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f32_e64 v2, v3, 1.0 clamp
+; GFX8-NEXT:    flat_store_dword v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_f32_denormals_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dword v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX9-NEXT:    global_store_dword v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_src_f32_denormals_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b32 v1, v0, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX11-NEXT:    global_store_b32 v0, v1, s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr float, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr float, ptr addrspace(1) %out, i32 %tid
+  %a = load float, ptr addrspace(1) %gep0
+  %add = fadd float %a, 1.0
+  %max = call float @llvm.maximumnum.f32(float %add, float 0.0)
+  %clamp = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  store float %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_src_f16_denorm_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_src_f16_denorm_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_ushort v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_cvt_f32_f16_e32 v2, v2
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    v_cvt_f16_f32_e32 v2, v2
+; SI-NEXT:    buffer_store_short v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_f16_denorm_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 1, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_ushort v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f16_e64 v2, v3, 1.0 clamp
+; GFX8-NEXT:    flat_store_short v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_f16_denorm_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_ushort v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f16_e64 v1, v1, 1.0 clamp
+; GFX9-NEXT:    global_store_short v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-TRUE16-LABEL: v_clamp_add_src_f16_denorm_minimumnum_maximumnum:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-TRUE16-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-TRUE16-NEXT:    v_lshlrev_b32_e32 v1, 1, v0
+; GFX11-TRUE16-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    global_load_d16_b16 v0, v1, s[2:3]
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, 1.0 clamp
+; GFX11-TRUE16-NEXT:    global_store_b16 v1, v0, s[0:1]
+; GFX11-TRUE16-NEXT:    s_endpgm
+;
+; GFX11-FAKE16-LABEL: v_clamp_add_src_f16_denorm_minimumnum_maximumnum:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-FAKE16-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-FAKE16-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; GFX11-FAKE16-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    global_load_u16 v1, v0, s[2:3]
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-FAKE16-NEXT:    v_add_f16_e64 v1, v1, 1.0 clamp
+; GFX11-FAKE16-NEXT:    global_store_b16 v0, v1, s[0:1]
+; GFX11-FAKE16-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr half, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr half, ptr addrspace(1) %out, i32 %tid
+  %a = load half, ptr addrspace(1) %gep0
+  %add = fadd half %a, 1.0
+  %max = call half @llvm.maximumnum.f16(half %add, half 0.0)
+  %clamp = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  store half %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #3 {
+; SI-LABEL: v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_ushort v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_cvt_f32_f16_e32 v2, v2
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    v_cvt_f16_f32_e32 v2, v2
+; SI-NEXT:    buffer_store_short v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 1, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_ushort v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f16_e64 v2, v3, 1.0 clamp
+; GFX8-NEXT:    flat_store_short v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_ushort v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f16_e64 v1, v1, 1.0 clamp
+; GFX9-NEXT:    global_store_short v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-TRUE16-LABEL: v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-TRUE16-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-TRUE16-NEXT:    v_lshlrev_b32_e32 v1, 1, v0
+; GFX11-TRUE16-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    global_load_d16_b16 v0, v1, s[2:3]
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, 1.0 clamp
+; GFX11-TRUE16-NEXT:    global_store_b16 v1, v0, s[0:1]
+; GFX11-TRUE16-NEXT:    s_endpgm
+;
+; GFX11-FAKE16-LABEL: v_clamp_add_src_f16_no_denormals_minimumnum_maximumnum:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-FAKE16-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-FAKE16-NEXT:    v_lshlrev_b32_e32 v0, 1, v0
+; GFX11-FAKE16-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    global_load_u16 v1, v0, s[2:3]
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-FAKE16-NEXT:    v_add_f16_e64 v1, v1, 1.0 clamp
+; GFX11-FAKE16-NEXT:    global_store_b16 v0, v1, s[0:1]
+; GFX11-FAKE16-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr half, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr half, ptr addrspace(1) %out, i32 %tid
+  %a = load half, ptr addrspace(1) %gep0
+  %add = fadd half %a, 1.0
+  %max = call half @llvm.maximumnum.f16(half %add, half 0.0)
+  %clamp = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  store half %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_src_v2f32_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_src_v2f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 3, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dwordx2 v[2:3], v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    v_add_f32_e64 v3, v3, 1.0 clamp
+; SI-NEXT:    buffer_store_dwordx2 v[2:3], v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_v2f32_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dwordx2 v[0:1], v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v3, s1
+; GFX8-NEXT:    v_add_u32_e32 v2, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v3, vcc, 0, v3, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp
+; GFX8-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX8-NEXT:    flat_store_dwordx2 v[2:3], v[0:1]
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_v2f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dwordx2 v[0:1], v2, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp
+; GFX9-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX9-NEXT:    global_store_dwordx2 v2, v[0:1], s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_src_v2f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v2, 3, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b64 v[0:1], v2, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp
+; GFX11-NEXT:    v_add_f32_e64 v1, v1, 1.0 clamp
+; GFX11-NEXT:    global_store_b64 v2, v[0:1], s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr <2 x float>, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr <2 x float>, ptr addrspace(1) %out, i32 %tid
+  %a = load <2 x float>, ptr addrspace(1) %gep0
+  %add = fadd <2 x float> %a, <float 1.0, float 1.0>
+  %max = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %add, <2 x float> zeroinitializer)
+  %clamp = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %max, <2 x float> <float 1.0, float 1.0>)
+  store <2 x float> %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
+define amdgpu_kernel void @v_clamp_add_src_v2f16_denorm_minimumnum_maximumnum(ptr addrspace(1) %out, ptr addrspace(1) %aptr) #0 {
+; SI-LABEL: v_clamp_add_src_v2f16_denorm_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x9
+; SI-NEXT:    s_mov_b32 s7, 0xf000
+; SI-NEXT:    s_mov_b32 s6, 0
+; SI-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; SI-NEXT:    v_mov_b32_e32 v1, 0
+; SI-NEXT:    s_waitcnt lgkmcnt(0)
+; SI-NEXT:    s_mov_b64 s[4:5], s[2:3]
+; SI-NEXT:    buffer_load_dword v2, v[0:1], s[4:7], 0 addr64
+; SI-NEXT:    s_mov_b64 s[2:3], s[6:7]
+; SI-NEXT:    s_waitcnt vmcnt(0)
+; SI-NEXT:    v_lshrrev_b32_e32 v3, 16, v2
+; SI-NEXT:    v_cvt_f32_f16_e32 v3, v3
+; SI-NEXT:    v_cvt_f32_f16_e32 v2, v2
+; SI-NEXT:    v_add_f32_e64 v3, v3, 1.0 clamp
+; SI-NEXT:    v_add_f32_e64 v2, v2, 1.0 clamp
+; SI-NEXT:    v_cvt_f16_f32_e32 v3, v3
+; SI-NEXT:    v_cvt_f16_f32_e32 v2, v2
+; SI-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; SI-NEXT:    v_or_b32_e32 v2, v2, v3
+; SI-NEXT:    buffer_store_dword v2, v[0:1], s[0:3], 0 addr64
+; SI-NEXT:    s_endpgm
+;
+; GFX8-LABEL: v_clamp_add_src_v2f16_denorm_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX8-NEXT:    v_lshlrev_b32_e32 v2, 2, v0
+; GFX8-NEXT:    v_mov_b32_e32 v4, 0x3c00
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    flat_load_dword v3, v[0:1]
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v2
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_add_f16_e64 v2, v3, 1.0 clamp
+; GFX8-NEXT:    v_add_f16_sdwa v3, v3, v4 clamp dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
+; GFX8-NEXT:    v_or_b32_e32 v2, v2, v3
+; GFX8-NEXT:    flat_store_dword v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_clamp_add_src_v2f16_denorm_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx4 s[0:3], s[4:5], 0x24
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dword v1, v0, s[2:3]
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_pk_add_f16 v1, v1, 1.0 op_sel_hi:[1,0] clamp
+; GFX9-NEXT:    global_store_dword v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+;
+; GFX11-LABEL: v_clamp_add_src_v2f16_denorm_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_load_b128 s[0:3], s[4:5], 0x24
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x3ff, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX11-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX11-NEXT:    global_load_b32 v1, v0, s[2:3]
+; GFX11-NEXT:    s_waitcnt vmcnt(0)
+; GFX11-NEXT:    v_pk_add_f16 v1, v1, 1.0 op_sel_hi:[1,0] clamp
+; GFX11-NEXT:    global_store_b32 v0, v1, s[0:1]
+; GFX11-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr <2 x half>, ptr addrspace(1) %aptr, i32 %tid
+  %out.gep = getelementptr <2 x half>, ptr addrspace(1) %out, i32 %tid
+  %a = load <2 x half>, ptr addrspace(1) %gep0
+  %add = fadd <2 x half> %a, <half 1.0, half 1.0>
+  %max = call <2 x half> @llvm.maximumnum.v2f16(<2 x half> %add, <2 x half> zeroinitializer)
+  %clamp = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %max, <2 x half> <half 1.0, half 1.0>)
+  store <2 x half> %clamp, ptr addrspace(1) %out.gep
+  ret void
+}
+
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 declare float @llvm.fabs.f32(float) #1
 declare float @llvm.floor.f32(float) #1
diff --git a/llvm/test/CodeGen/AMDGPU/clamp.ll b/llvm/test/CodeGen/AMDGPU/clamp.ll
index 3e0837b58aafc..01681e7d8b8ed 100644
--- a/llvm/test/CodeGen/AMDGPU/clamp.ll
+++ b/llvm/test/CodeGen/AMDGPU/clamp.ll
@@ -4111,6 +4111,609 @@ define amdgpu_kernel void @v_clamp_diff_source_f32(ptr addrspace(1) %out, ptr ad
   ret void
 }
 
+define float @v_clamp_f32_daz_minimumnum_maximumnum(float %a) #0 {
+; GFX6-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_minimumnum_maximumnum(float %a) #1 {
+; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_minimumnum_maximumnum:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_neg_minimumnum_maximumnum(float %a) #1 {
+; GFX6-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e64 v0, -1.0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e64 v0, -1.0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e64 v0, -v0, -v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e64 v0, -v0, -v0 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, -v0, -v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %neg.a = fneg float %a
+  %max = call float @llvm.maximumnum.f32(float %neg.a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_minimumnum_maximumnum_no_ieee(float %a) #5 {
+; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_minimumnum_maximumnum_foldable_source(float %a, float %b) #1 {
+; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum_foldable_source:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum_foldable_source:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum_foldable_source:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_minimumnum_maximumnum_foldable_source:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_minimumnum_maximumnum_foldable_source:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %add = fadd float %a, %b
+  %max = call float @llvm.maximumnum.f32(float %add, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source(float %a, float %b) #5 {
+; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %add = fadd float %a, %b
+  %max = call float @llvm.maximumnum.f32(float %add, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define half @v_clamp_f16_minimumnum_maximumnum(half %a) #1 {
+; GFX6-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_f32_f16_e64 v0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    v_max_f16_e64 v0.l, v0.l, v0.l clamp
+; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX12-TRUE16:       ; %bb.0:
+; GFX12-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-TRUE16-NEXT:    v_max_num_f16_e64 v0.l, v0.l, v0.l clamp
+; GFX12-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum:
+; GFX12-FAKE16:       ; %bb.0:
+; GFX12-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-FAKE16-NEXT:    v_max_num_f16_e64 v0, v0, v0 clamp
+; GFX12-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %max = call half @llvm.maximumnum.f16(half %a, half 0.0)
+  %med = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  ret half %med
+}
+
+define half @v_clamp_f16_minimumnum_maximumnum_no_ieee(half %a) #5 {
+; GFX6-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_f32_f16_e64 v0, v0 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    v_max_f16_e64 v0.l, v0.l, v0.l clamp
+; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    v_max_f16_e64 v0, v0, v0 clamp
+; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX12-TRUE16:       ; %bb.0:
+; GFX12-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-TRUE16-NEXT:    v_max_num_f16_e64 v0.l, v0.l, v0.l clamp
+; GFX12-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee:
+; GFX12-FAKE16:       ; %bb.0:
+; GFX12-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-FAKE16-NEXT:    v_max_num_f16_e64 v0, v0, v0 clamp
+; GFX12-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %max = call half @llvm.maximumnum.f16(half %a, half 0.0)
+  %med = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  ret half %med
+}
+
+define half @v_clamp_f16_minimumnum_maximumnum_foldable_source(half %a, half %b) #1 {
+; GFX6-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v1, v1
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_f32_f16_e32 v1, v1
+; GFX6-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; GFX6-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, v1.l clamp
+; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX12-TRUE16:       ; %bb.0:
+; GFX12-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, v1.l clamp
+; GFX12-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_foldable_source:
+; GFX12-FAKE16:       ; %bb.0:
+; GFX12-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-FAKE16-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX12-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %add = fadd half %a, %b
+  %max = call half @llvm.maximumnum.f16(half %add, half 0.0)
+  %med = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  ret half %med
+}
+
+define half @v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source(half %a, half %b) #5 {
+; GFX6-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v1, v1
+; GFX6-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; GFX6-NEXT:    v_cvt_f32_f16_e32 v1, v1
+; GFX6-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; GFX6-NEXT:    v_add_f32_e64 v0, v0, v1 clamp
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, v1.l clamp
+; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-TRUE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX12-TRUE16:       ; %bb.0:
+; GFX12-TRUE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-TRUE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-TRUE16-NEXT:    v_add_f16_e64 v0.l, v0.l, v1.l clamp
+; GFX12-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-FAKE16-LABEL: v_clamp_f16_minimumnum_maximumnum_no_ieee_foldable_source:
+; GFX12-FAKE16:       ; %bb.0:
+; GFX12-FAKE16-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_expcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_samplecnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-FAKE16-NEXT:    s_wait_kmcnt 0x0
+; GFX12-FAKE16-NEXT:    v_add_f16_e64 v0, v0, v1 clamp
+; GFX12-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %add = fadd half %a, %b
+  %max = call half @llvm.maximumnum.f16(half %add, half 0.0)
+  %med = call half @llvm.minimumnum.f16(half %max, half 1.0)
+  ret half %med
+}
+
+define float @v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp(float %a) #6 {
+; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; GFX6-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_minimumnum_maximumnum_no_dx10_clamp:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp(float %a) #4 {
+; GFX6-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; GFX6-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_max_num_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+define float @v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src(float %a) #4 {
+; GFX6-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX6-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, v0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: v_clamp_f32_daz_minimumnum_maximumnum_daz_no_dx10clamp_nnan_src:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_add_f32_e64 v0, v0, v0 clamp
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %nnan.src = fadd nnan float %a, %a
+  %max = call float @llvm.maximumnum.f32(float %nnan.src, float 0.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  ret float %med
+}
+
+
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 declare float @llvm.fabs.f32(float) #1
 declare float @llvm.minnum.f32(float, float) #1
@@ -4131,3 +4734,5 @@ attributes #1 = { nounwind readnone }
 attributes #2 = { nounwind "amdgpu-dx10-clamp"="false" "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-nans-fp-math"="false" }
 attributes #3 = { nounwind "amdgpu-dx10-clamp"="true" "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-nans-fp-math"="false" }
 attributes #4 = { nounwind "amdgpu-dx10-clamp"="false" "denormal-fp-math-f32"="preserve-sign,preserve-sign" "no-nans-fp-math"="false" }
+attributes #5 = { nounwind readnone "amdgpu-ieee"="false" }
+attributes #6 = { nounwind "amdgpu-dx10-clamp"="false" }
diff --git a/llvm/test/CodeGen/AMDGPU/fmed3.bf16.ll b/llvm/test/CodeGen/AMDGPU/fmed3.bf16.ll
new file mode 100644
index 0000000000000..0742ac7b425a6
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/fmed3.bf16.ll
@@ -0,0 +1,242 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=amdgcn < %s | FileCheck -enable-var-scope -check-prefixes=SI,SI-SDAG %s
+; RUN: llc -mtriple=amdgcn -mcpu=tonga < %s | FileCheck -enable-var-scope -check-prefixes=VI-SDAG %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -enable-var-scope -check-prefixes=GFX9,GFX9-SDAG %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -mattr=-real-true16 < %s | FileCheck -enable-var-scope -check-prefixes=GFX11,GFX11-SDAG,GFX11-SDAG-FAKE16 %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -mattr=+real-true16 < %s | FileCheck -enable-var-scope -check-prefixes=GFX11,GFX11-SDAG,GFX11-SDAG-TRUE16 %s
+
+define bfloat @v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum(bfloat %a) #1 {
+; SI-LABEL: v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    v_min_f32_e32 v0, 4.0, v0
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; VI-SDAG-NEXT:    v_mov_b32_e32 v2, 0x4000
+; VI-SDAG-NEXT:    v_cmp_o_f32_e32 vcc, v1, v1
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; VI-SDAG-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v1
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; VI-SDAG-NEXT:    v_mov_b32_e32 v2, 0x4080
+; VI-SDAG-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v1
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX9-NEXT:    v_mov_b32_e32 v2, 0x4000
+; GFX9-NEXT:    v_cmp_o_f32_e32 vcc, v1, v1
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; GFX9-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX9-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v1
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; GFX9-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX9-NEXT:    v_mov_b32_e32 v2, 0x4080
+; GFX9-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v1
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-FAKE16-LABEL: v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum:
+; GFX11-SDAG-FAKE16:       ; %bb.0:
+; GFX11-SDAG-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_o_f32_e32 vcc_lo, v1, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4000, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_lt_f32_e32 vcc_lo, 2.0, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4000, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_gt_f32_e32 vcc_lo, 4.0, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4080, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-TRUE16-LABEL: v_test_fmed3_r_i_i_bf16_minimumnum_maximumnum:
+; GFX11-SDAG-TRUE16:       ; %bb.0:
+; GFX11-SDAG-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v0
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_o_f32_e32 vcc_lo, v1, v1
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4000, v0.l, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v1.l, v0.l
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_lt_f32_e32 vcc_lo, 2.0, v1
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4000, v0.l, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v1.l, v0.l
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v1, 16, v1
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_gt_f32_e32 vcc_lo, 4.0, v1
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4080, v0.l, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+  %max = call bfloat @llvm.maximumnum.bf16(bfloat %a, bfloat 2.0)
+  %med = call bfloat @llvm.minimumnum.bf16(bfloat %max, bfloat 4.0)
+  ret bfloat %med
+}
+
+define <2 x bfloat> @v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum(<2 x bfloat> %a) #1 {
+; SI-LABEL: v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; SI-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    v_and_b32_e32 v1, 0xffff0000, v1
+; SI-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; SI-NEXT:    v_max_f32_e32 v1, 2.0, v1
+; SI-NEXT:    v_and_b32_e32 v1, 0xffff0000, v1
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    v_min_f32_e32 v1, 4.0, v1
+; SI-NEXT:    v_min_f32_e32 v0, 4.0, v0
+; SI-NEXT:    v_and_b32_e32 v0, 0xffff0000, v0
+; SI-NEXT:    v_and_b32_e32 v1, 0xffff0000, v1
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_and_b32_e32 v1, 0xffff0000, v0
+; VI-SDAG-NEXT:    v_cmp_o_f32_e32 vcc, v1, v1
+; VI-SDAG-NEXT:    v_mov_b32_e32 v1, 0x4000
+; VI-SDAG-NEXT:    v_cndmask_b32_sdwa v2, v1, v0, vcc dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:WORD_1
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v3, 16, v2
+; VI-SDAG-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v3
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v2, v1, v2, vcc
+; VI-SDAG-NEXT:    v_cmp_o_f32_e32 vcc, v3, v3
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; VI-SDAG-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v3
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v1, 16, v2
+; VI-SDAG-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v1
+; VI-SDAG-NEXT:    v_mov_b32_e32 v1, 0x4080
+; VI-SDAG-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; VI-SDAG-NEXT:    v_cndmask_b32_sdwa v2, v1, v2, vcc dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:DWORD
+; VI-SDAG-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v3
+; VI-SDAG-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
+; VI-SDAG-NEXT:    v_or_b32_sdwa v0, v0, v2 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_0 src1_sel:DWORD
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_and_b32_e32 v1, 0xffff0000, v0
+; GFX9-NEXT:    v_cmp_o_f32_e32 vcc, v1, v1
+; GFX9-NEXT:    v_mov_b32_e32 v1, 0x4000
+; GFX9-NEXT:    v_cndmask_b32_sdwa v2, v1, v0, vcc dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:WORD_1
+; GFX9-NEXT:    v_lshlrev_b32_e32 v3, 16, v2
+; GFX9-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v3
+; GFX9-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; GFX9-NEXT:    v_cndmask_b32_e32 v2, v1, v2, vcc
+; GFX9-NEXT:    v_cmp_o_f32_e32 vcc, v3, v3
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX9-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; GFX9-NEXT:    v_cmp_lt_f32_e32 vcc, 2.0, v3
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
+; GFX9-NEXT:    v_lshlrev_b32_e32 v1, 16, v2
+; GFX9-NEXT:    v_mov_b32_e32 v3, 0x4080
+; GFX9-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v1
+; GFX9-NEXT:    v_cndmask_b32_e32 v1, v3, v2, vcc
+; GFX9-NEXT:    v_lshlrev_b32_e32 v2, 16, v0
+; GFX9-NEXT:    v_cmp_gt_f32_e32 vcc, 4.0, v2
+; GFX9-NEXT:    v_cndmask_b32_e32 v0, v3, v0, vcc
+; GFX9-NEXT:    s_mov_b32 s4, 0x5040100
+; GFX9-NEXT:    v_perm_b32 v0, v1, v0, s4
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-FAKE16-LABEL: v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum:
+; GFX11-SDAG-FAKE16:       ; %bb.0:
+; GFX11-SDAG-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-FAKE16-NEXT:    v_and_b32_e32 v1, 0xffff0000, v0
+; GFX11-SDAG-FAKE16-NEXT:    v_lshrrev_b32_e32 v2, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_o_f32_e32 vcc_lo, v1, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v1, 0x4000, v2, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_o_f32_e32 vcc_lo, v3, v3
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v2, 16, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4000, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_lt_f32_e32 vcc_lo, 2.0, v2
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v1, 0x4000, v1, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_lt_f32_e32 vcc_lo, 2.0, v3
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v2, 16, v1
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4000, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_gt_f32_e32 vcc_lo, 4.0, v2
+; GFX11-SDAG-FAKE16-NEXT:    v_lshlrev_b32_e32 v3, 16, v0
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v1, 0x4080, v1, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_1) | instid1(VALU_DEP_1)
+; GFX11-SDAG-FAKE16-NEXT:    v_cmp_gt_f32_e32 vcc_lo, 4.0, v3
+; GFX11-SDAG-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x4080, v0, vcc_lo
+; GFX11-SDAG-FAKE16-NEXT:    v_perm_b32 v0, v1, v0, 0x5040100
+; GFX11-SDAG-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-TRUE16-LABEL: v_test_fmed3_r_i_i_v2bf16_minimumnum_maximumnum:
+; GFX11-SDAG-TRUE16:       ; %bb.0:
+; GFX11-SDAG-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-TRUE16-NEXT:    v_and_b32_e32 v1, 0xffff0000, v0
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v2, 16, v0
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_o_f32_e32 vcc_lo, v1, v1
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_o_f32_e64 s0, v2, v2
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v1.l, 0x4000, v0.h, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4000, v0.l, s0
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v2.l, v1.l
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v3.l, v0.l
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_lt_f32_e32 vcc_lo, 2.0, v2
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(SKIP_1) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_lt_f32_e64 s0, 2.0, v3
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v1.l, 0x4000, v1.l, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4000, v0.l, s0
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v2.l, v1.l
+; GFX11-SDAG-TRUE16-NEXT:    v_mov_b16_e32 v3.l, v0.l
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v2, 16, v2
+; GFX11-SDAG-TRUE16-NEXT:    v_lshlrev_b32_e32 v3, 16, v3
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_gt_f32_e32 vcc_lo, 4.0, v2
+; GFX11-SDAG-TRUE16-NEXT:    v_cmp_gt_f32_e64 s0, 4.0, v3
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.h, 0x4080, v1.l, vcc_lo
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2)
+; GFX11-SDAG-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x4080, v0.l, s0
+; GFX11-SDAG-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+  %max = call <2 x bfloat> @llvm.maximumnum.v2bf16(<2 x bfloat> %a, <2 x bfloat> splat (bfloat 2.0))
+  %med = call <2 x bfloat> @llvm.minimumnum.v2bf16(<2 x bfloat> %max, <2 x bfloat> splat (bfloat 4.0))
+  ret <2 x bfloat> %med
+}
+
+attributes #0 = { nounwind readnone }
+attributes #1 = { nounwind "unsafe-fp-math"="false" "no-nans-fp-math"="false" }
+attributes #2 = { nounwind "unsafe-fp-math"="false" "no-nans-fp-math"="true" }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; GFX11: {{.*}}
+; GFX11-SDAG: {{.*}}
+; GFX9-SDAG: {{.*}}
+; SI-SDAG: {{.*}}
diff --git a/llvm/test/CodeGen/AMDGPU/fmed3.ll b/llvm/test/CodeGen/AMDGPU/fmed3.ll
index db0c5362bdc5f..f9a1472b4596f 100644
--- a/llvm/test/CodeGen/AMDGPU/fmed3.ll
+++ b/llvm/test/CodeGen/AMDGPU/fmed3.ll
@@ -8349,6 +8349,561 @@ define amdgpu_kernel void @two_non_inline_constant_multi_use(ptr addrspace(1) %o
   ret void
 }
 
+define float @v_test_fmed3_r_i_i_f32_minimumnum_maximumnum(float %a) #1 {
+; SI-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 2.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define <2 x float> @v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum(<2 x float> %a) #1 {
+; SI-SDAG-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; SI-SDAG:       ; %bb.0:
+; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-SDAG-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; SI-SDAG-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-SDAG-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-GISEL-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; SI-GISEL:       ; %bb.0:
+; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-GISEL-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-GISEL-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; SI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-GISEL-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; VI-SDAG-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-SDAG-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; GFX9-SDAG:       ; %bb.0:
+; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-SDAG-NEXT:    v_max_f32_e32 v1, v1, v1
+; GFX9-SDAG-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-SDAG-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-GISEL-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; GFX9-GISEL:       ; %bb.0:
+; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-GISEL-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-GISEL-NEXT:    v_max_f32_e32 v1, v1, v1
+; GFX9-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-GISEL-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_fmed3_r_i_i_v2f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_dual_max_f32 v0, v0, v0 :: v_dual_max_f32 v1, v1, v1
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %max = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %a, <2 x float> splat (float 2.0))
+  %med = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %max, <2 x float> splat (float 4.0))
+  ret <2 x float> %med
+}
+
+define { float, float } @v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use(float %a) #1 {
+; SI-SDAG-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; SI-SDAG:       ; %bb.0:
+; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-SDAG-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-SDAG-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; SI-SDAG-NEXT:    v_min_f32_e32 v0, 4.0, v1
+; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-GISEL-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; SI-GISEL:       ; %bb.0:
+; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-GISEL-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; SI-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; SI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; VI-SDAG-NEXT:    v_min_f32_e32 v0, 4.0, v1
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-SDAG-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; GFX9-SDAG:       ; %bb.0:
+; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-SDAG-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-SDAG-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; GFX9-SDAG-NEXT:    v_min_f32_e32 v0, 4.0, v1
+; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-GISEL-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; GFX9-GISEL:       ; %bb.0:
+; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-GISEL-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; GFX9-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; GFX11-SDAG:       ; %bb.0:
+; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-SDAG-NEXT:    v_max_f32_e32 v1, 2.0, v0
+; GFX11-SDAG-NEXT:    v_min_f32_e32 v0, 4.0, v1
+; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-GISEL-LABEL: v_test_fmed3_r_i_i_f32_minimumnum_maximumnum_multi_use:
+; GFX11-GISEL:       ; %bb.0:
+; GFX11-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-GISEL-NEXT:    v_max_f32_e32 v1, v0, v0
+; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-NEXT:    v_med3_f32 v0, v1, 2.0, 4.0
+; GFX11-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v1
+; GFX11-GISEL-NEXT:    s_setpc_b64 s[30:31]
+  %max = call float @llvm.maximumnum.f32(float %a, float 2.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 4.0)
+  %ins.0 = insertvalue { float, float } poison, float %med, 0
+  %ins.1 = insertvalue { float, float } %ins.0, float %max, 1
+  ret { float, float } %ins.1
+}
+
+define float @v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum(float %a) #1 {
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %a.add = fadd nnan float %a, 1.0
+  %max = call float @llvm.maximumnum.f32(float %a.add, float 2.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define float @v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum(float %a) #1 {
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minimumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %a.add = fadd nnan float %a, 1.0
+  %max = call float @llvm.maximumnum.f32(float %a.add, float 2.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define float @v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum(float %a) #1 {
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maxnum_minimumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %a.add = fadd nnan float %a, 1.0
+  %max = call float @llvm.maxnum.f32(float %a.add, float 2.0)
+  %med = call float @llvm.minimumnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define float @v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum(float %a) #1 {
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximumnum_minnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %a.add = fadd nnan float %a, 1.0
+  %max = call float @llvm.maximumnum.f32(float %a.add, float 2.0)
+  %med = call float @llvm.minnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define half @v_test_fmed3_r_i_i_f16_minimumnum_maximumnum(half %a) #1 {
+; SI-SDAG-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; SI-SDAG:       ; %bb.0:
+; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-SDAG-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-SDAG-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-GISEL-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; SI-GISEL:       ; %bb.0:
+; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v1, 2.0
+; SI-GISEL-NEXT:    v_max_f32_e32 v0, v0, v1
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v1, 4.0
+; SI-GISEL-NEXT:    v_min_f32_e32 v0, v0, v1
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_max_f16_e32 v0, v0, v0
+; VI-SDAG-NEXT:    v_max_f16_e32 v0, 2.0, v0
+; VI-SDAG-NEXT:    v_min_f16_e32 v0, 4.0, v0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_max_f16_e32 v0, v0, v0
+; VI-GISEL-NEXT:    v_max_f16_e32 v0, 2.0, v0
+; VI-GISEL-NEXT:    v_min_f16_e32 v0, 4.0, v0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f16_e32 v0, v0, v0
+; GFX9-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-FAKE16-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; GFX11-SDAG-FAKE16:       ; %bb.0:
+; GFX11-SDAG-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-FAKE16-NEXT:    v_max_f16_e32 v0, v0, v0
+; GFX11-SDAG-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-FAKE16-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
+; GFX11-SDAG-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-GISEL-FAKE16-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; GFX11-GISEL-FAKE16:       ; %bb.0:
+; GFX11-GISEL-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-GISEL-FAKE16-NEXT:    v_max_f16_e32 v0, v0, v0
+; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-FAKE16-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
+; GFX11-GISEL-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-SDAG-TRUE16-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; GFX11-SDAG-TRUE16:       ; %bb.0:
+; GFX11-SDAG-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-SDAG-TRUE16-NEXT:    v_max_f16_e32 v0.l, v0.l, v0.l
+; GFX11-SDAG-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-SDAG-TRUE16-NEXT:    v_med3_f16 v0.l, v0.l, 2.0, 4.0
+; GFX11-SDAG-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-GISEL-TRUE16-LABEL: v_test_fmed3_r_i_i_f16_minimumnum_maximumnum:
+; GFX11-GISEL-TRUE16:       ; %bb.0:
+; GFX11-GISEL-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-GISEL-TRUE16-NEXT:    v_max_f16_e32 v0.l, v0.l, v0.l
+; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-GISEL-TRUE16-NEXT:    v_med3_f16 v0.l, v0.l, 2.0, 4.0
+; GFX11-GISEL-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+  %max = call half @llvm.maximumnum.f16(half %a, half 2.0)
+  %med = call half @llvm.minimumnum.f16(half %max, half 4.0)
+  ret half %med
+}
+
+define <2 x half> @v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum(<2 x half> %a) #1 {
+; SI-SDAG-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; SI-SDAG:       ; %bb.0:
+; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-SDAG-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-SDAG-NEXT:    v_cvt_f16_f32_e32 v1, v1
+; SI-SDAG-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-SDAG-NEXT:    v_cvt_f32_f16_e32 v1, v1
+; SI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-SDAG-NEXT:    v_med3_f32 v1, v1, 2.0, 4.0
+; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-GISEL-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; SI-GISEL:       ; %bb.0:
+; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v2, 2.0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v1, v1
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v3, 4.0
+; SI-GISEL-NEXT:    v_max_f32_e32 v0, v0, v2
+; SI-GISEL-NEXT:    v_max_f32_e32 v1, v1, v2
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v1
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v1, v1
+; SI-GISEL-NEXT:    v_min_f32_e32 v0, v0, v3
+; SI-GISEL-NEXT:    v_min_f32_e32 v1, v1, v3
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
+; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v1, v1
+; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_max_f16_sdwa v1, v0, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
+; VI-SDAG-NEXT:    v_max_f16_e32 v0, v0, v0
+; VI-SDAG-NEXT:    v_max_f16_e32 v1, 2.0, v1
+; VI-SDAG-NEXT:    v_max_f16_e32 v0, 2.0, v0
+; VI-SDAG-NEXT:    v_mov_b32_e32 v2, 0x4400
+; VI-SDAG-NEXT:    v_min_f16_e32 v0, 4.0, v0
+; VI-SDAG-NEXT:    v_min_f16_sdwa v1, v1, v2 dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:DWORD
+; VI-SDAG-NEXT:    v_or_b32_e32 v0, v0, v1
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_max_f16_e32 v1, v0, v0
+; VI-GISEL-NEXT:    v_max_f16_sdwa v0, v0, v0 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
+; VI-GISEL-NEXT:    v_max_f16_e32 v1, 2.0, v1
+; VI-GISEL-NEXT:    v_max_f16_e32 v0, 2.0, v0
+; VI-GISEL-NEXT:    v_mov_b32_e32 v2, 0x4400
+; VI-GISEL-NEXT:    v_min_f16_e32 v1, 4.0, v1
+; VI-GISEL-NEXT:    v_min_f16_sdwa v0, v0, v2 dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:DWORD
+; VI-GISEL-NEXT:    v_or_b32_e32 v0, v1, v0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX9-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
+; GFX9-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_fmed3_r_i_i_v2f16_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_pk_max_f16 v0, v0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
+; GFX11-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %max = call <2 x half> @llvm.maximumnum.v2f16(<2 x half> %a, <2 x half> splat (half 2.0))
+  %med = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %max, <2 x half> splat (half 4.0))
+  ret <2 x half> %med
+}
+
+define double @v_test_fmed3_r_i_i_f64_minimumnum_maximumnum(double %a) #1 {
+; SI-LABEL: v_test_fmed3_r_i_i_f64_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_max_f64 v[0:1], v[0:1], v[0:1]
+; SI-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; SI-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-SDAG-LABEL: v_test_fmed3_r_i_i_f64_minimumnum_maximumnum:
+; VI-SDAG:       ; %bb.0:
+; VI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-SDAG-NEXT:    v_max_f64 v[0:1], v[0:1], v[0:1]
+; VI-SDAG-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; VI-SDAG-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; VI-SDAG-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-GISEL-LABEL: v_test_fmed3_r_i_i_f64_minimumnum_maximumnum:
+; VI-GISEL:       ; %bb.0:
+; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], v[0:1]
+; VI-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; VI-GISEL-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_test_fmed3_r_i_i_f64_minimumnum_maximumnum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX9-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; GFX9-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_test_fmed3_r_i_i_f64_minimumnum_maximumnum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_max_f64 v[0:1], v[0:1], v[0:1]
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; GFX11-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %max = call double @llvm.maximumnum.f64(double %a, double 2.0)
+  %med = call double @llvm.minimumnum.f64(double %max, double 4.0)
+  ret double %med
+}
+
 declare i32 @llvm.amdgcn.workitem.id.x() #0
 declare float @llvm.fabs.f32(float) #0
 declare float @llvm.minnum.f32(float, float) #0
@@ -8362,5 +8917,3 @@ declare half @llvm.maxnum.f16(half, half) #0
 attributes #0 = { nounwind readnone }
 attributes #1 = { nounwind "unsafe-fp-math"="false" "no-nans-fp-math"="false" }
 attributes #2 = { nounwind "unsafe-fp-math"="false" "no-nans-fp-math"="true" }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; SI: {{.*}}
diff --git a/llvm/test/CodeGen/AMDGPU/minmax.ll b/llvm/test/CodeGen/AMDGPU/minmax.ll
index e8e1837c58bbb..bdd8935d0df5e 100644
--- a/llvm/test/CodeGen/AMDGPU/minmax.ll
+++ b/llvm/test/CodeGen/AMDGPU/minmax.ll
@@ -470,6 +470,32 @@ define void @test_med3_f32(ptr addrspace(1) %arg, float %x, float %y, float %z)
   ret void
 }
 
+define void @test_med3_minimumnum_maximumnum_f32(ptr addrspace(1) %arg, float %x, float %y, float %z) #0 {
+; GFX11-LABEL: test_med3_minimumnum_maximumnum_f32:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_med3_f32 v2, v2, v3, v4
+; GFX11-NEXT:    global_store_b32 v[0:1], v2, off
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: test_med3_minimumnum_maximumnum_f32:
+; GFX12:       ; %bb.0:
+; GFX12-NEXT:    s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT:    s_wait_expcnt 0x0
+; GFX12-NEXT:    s_wait_samplecnt 0x0
+; GFX12-NEXT:    s_wait_bvhcnt 0x0
+; GFX12-NEXT:    s_wait_kmcnt 0x0
+; GFX12-NEXT:    v_med3_num_f32 v2, v2, v3, v4
+; GFX12-NEXT:    global_store_b32 v[0:1], v2, off
+; GFX12-NEXT:    s_setpc_b64 s[30:31]
+  %tmp0 = call float @llvm.minimumnum.f32(float %x, float %y)
+  %tmp1 = call float @llvm.maximumnum.f32(float %x, float %y)
+  %tmp2 = call float @llvm.minimumnum.f32(float %tmp1, float %z)
+  %tmp3 = call float @llvm.maximumnum.f32(float %tmp0, float %tmp2)
+  store float %tmp3, ptr addrspace(1) %arg
+  ret void
+}
+
 define amdgpu_ps half @test_minmax_f16_ieee_false(half %a, half %b, half %c) {
 ; SDAG-GFX11-TRUE16-LABEL: test_minmax_f16_ieee_false:
 ; SDAG-GFX11-TRUE16:       ; %bb.0:
diff --git a/llvm/test/CodeGen/AMDGPU/omod.ll b/llvm/test/CodeGen/AMDGPU/omod.ll
index e34f51e6daf8c..c1ae6818d34df 100644
--- a/llvm/test/CodeGen/AMDGPU/omod.ll
+++ b/llvm/test/CodeGen/AMDGPU/omod.ll
@@ -1273,6 +1273,35 @@ define amdgpu_ps void @v_omod_mac_to_mad(float %b, float %a) #0 {
   ret void
 }
 
+define amdgpu_ps void @v_clamp_omod_div2_f32_minimumnum_maximumnum(float %a) #0 {
+; SI-LABEL: v_clamp_omod_div2_f32_minimumnum_maximumnum:
+; SI:       ; %bb.0:
+; SI-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp div:2
+; SI-NEXT:    s_mov_b32 s3, 0xf000
+; SI-NEXT:    s_mov_b32 s2, -1
+; SI-NEXT:    buffer_store_dword v0, off, s[0:3], 0
+; SI-NEXT:    s_endpgm
+;
+; VI-LABEL: v_clamp_omod_div2_f32_minimumnum_maximumnum:
+; VI:       ; %bb.0:
+; VI-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp div:2
+; VI-NEXT:    flat_store_dword v[0:1], v0
+; VI-NEXT:    s_endpgm
+;
+; GFX11PLUS-LABEL: v_clamp_omod_div2_f32_minimumnum_maximumnum:
+; GFX11PLUS:       ; %bb.0:
+; GFX11PLUS-NEXT:    v_add_f32_e64 v0, v0, 1.0 clamp div:2
+; GFX11PLUS-NEXT:    global_store_b32 v[0:1], v0, off
+; GFX11PLUS-NEXT:    s_endpgm
+  %add = fadd float %a, 1.0
+  %div2 = fmul float %add, 0.5
+
+  %max = call float @llvm.maximumnum.f32(float %div2, float 0.0)
+  %clamp = call float @llvm.minimumnum.f32(float %max, float 1.0)
+  store float %clamp, ptr addrspace(1) poison
+  ret void
+}
+
 declare i32 @llvm.amdgcn.workitem.id.x() #1
 declare float @llvm.fabs.f32(float) #1
 declare float @llvm.floor.f32(float) #1

>From db0bac0ef2de92cf478977fbb5f48a0eabd8e9c2 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 22 May 2025 21:04:47 +0200
Subject: [PATCH 035/105] AMDGPU: Form v_med_f32 from minimumnum/maximumnum
 immediate pattern (#141048)

This makes little difference in the final output, as we manage to form this
after these are lowered to the _ieee operations. This does result in fewer steps
in the DAG, and helps prepare for changing the handling of minnum/maxnum.
---
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp | 33 +++++++++++++++++++++--
 llvm/test/CodeGen/AMDGPU/clamp.ll         | 16 +++++------
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 2d337fafe6dc2..ade88a16193b8 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -13593,10 +13593,34 @@ SDValue SITargetLowering::performFPMed3ImmCombine(SelectionDAG &DAG,
   if (K0->getValueAPF() > K1->getValueAPF())
     return SDValue();
 
+  // med3 with a nan input acts like
+  // v_min_f32(v_min_f32(S0.f32, S1.f32), S2.f32)
+  //
+  // So the result depends on whether the IEEE mode bit is enabled or not with a
+  // signaling nan input.
+  // ieee=1
+  // s0 snan: yields s2
+  // s1 snan: yields s2
+  // s2 snan: qnan
+
+  // s0 qnan: min(s1, s2)
+  // s1 qnan: min(s0, s2)
+  // s2 qnan: min(s0, s1)
+
+  // ieee=0
+  // s0 snan: min(s1, s2)
+  // s1 snan: min(s0, s2)
+  // s2 snan: qnan
+
+  // s0 qnan: min(s1, s2)
+  // s1 qnan: min(s0, s2)
+  // s2 qnan: min(s0, s1)
   const MachineFunction &MF = DAG.getMachineFunction();
   const SIMachineFunctionInfo *Info = MF.getInfo<SIMachineFunctionInfo>();
 
-  // TODO: Check IEEE bit enabled?
+  // TODO: Check IEEE bit enabled. We can form fmed3 with IEEE=0 regardless of
+  // whether the input is a signaling nan if op0 is fmaximum or fmaximumnum. We
+  // can only form if op0 is fmaxnum_ieee if IEEE=1.
   EVT VT = Op0.getValueType();
   if (Info->getMode().DX10Clamp) {
     // If dx10_clamp is enabled, NaNs clamp to 0.0. This is the same as the
@@ -13714,9 +13738,14 @@ SDValue SITargetLowering::performMinMaxCombine(SDNode *N,
       return Med3;
   }
 
-  // fminnum(fmaxnum(x, K0), K1), K0 < K1 && !is_snan(x) -> fmed3(x, K0, K1)
+  // if !is_snan(x):
+  //   fminnum(fmaxnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)
+  //   fminnum_ieee(fmaxnum_ieee(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)
+  //   fminnumnum(fmaxnumnum(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)
+  //   fmin_legacy(fmax_legacy(x, K0), K1), K0 < K1 -> fmed3(x, K0, K1)
   if (((Opc == ISD::FMINNUM && Op0.getOpcode() == ISD::FMAXNUM) ||
        (Opc == ISD::FMINNUM_IEEE && Op0.getOpcode() == ISD::FMAXNUM_IEEE) ||
+       (Opc == ISD::FMINIMUMNUM && Op0.getOpcode() == ISD::FMAXIMUMNUM) ||
        (Opc == AMDGPUISD::FMIN_LEGACY &&
         Op0.getOpcode() == AMDGPUISD::FMAX_LEGACY)) &&
       (VT == MVT::f32 || VT == MVT::f64 ||
diff --git a/llvm/test/CodeGen/AMDGPU/clamp.ll b/llvm/test/CodeGen/AMDGPU/clamp.ll
index 01681e7d8b8ed..6274b38a63fe0 100644
--- a/llvm/test/CodeGen/AMDGPU/clamp.ll
+++ b/llvm/test/CodeGen/AMDGPU/clamp.ll
@@ -4115,13 +4115,13 @@ define float @v_clamp_f32_daz_minimumnum_maximumnum(float %a) #0 {
 ; GFX6-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
 ; GFX6:       ; %bb.0:
 ; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX6-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX8-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_clamp_f32_daz_minimumnum_maximumnum:
@@ -4154,13 +4154,13 @@ define float @v_clamp_f32_minimumnum_maximumnum(float %a) #1 {
 ; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum:
 ; GFX6:       ; %bb.0:
 ; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX6-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum:
@@ -4193,13 +4193,13 @@ define float @v_clamp_f32_neg_minimumnum_maximumnum(float %a) #1 {
 ; GFX6-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
 ; GFX6:       ; %bb.0:
 ; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX6-NEXT:    v_mul_f32_e64 v0, -1.0, v0 clamp
+; GFX6-NEXT:    v_max_f32_e64 v0, -v0, -v0 clamp
 ; GFX6-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX8-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_mul_f32_e64 v0, -1.0, v0 clamp
+; GFX8-NEXT:    v_max_f32_e64 v0, -v0, -v0 clamp
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_clamp_f32_neg_minimumnum_maximumnum:
@@ -4233,13 +4233,13 @@ define float @v_clamp_f32_minimumnum_maximumnum_no_ieee(float %a) #5 {
 ; GFX6-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
 ; GFX6:       ; %bb.0:
 ; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX6-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX6-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX6-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX8-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_mul_f32_e64 v0, 1.0, v0 clamp
+; GFX8-NEXT:    v_max_f32_e64 v0, v0, v0 clamp
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_clamp_f32_minimumnum_maximumnum_no_ieee:

>From 4a6b1fb9dac5bb3a065b1e6e5192c4c7964af7e0 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 22 May 2025 20:05:35 +0100
Subject: [PATCH 036/105] [LAA] Remove dead SE arg from canCheckPtrAtRT (NFC).

---
 llvm/lib/Analysis/LoopAccessAnalysis.cpp | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 389c3c7932859..6f05d2ac1a8d5 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -693,8 +693,7 @@ class AccessAnalysis {
   ///
   /// Returns true if we need no check or if we do and we can generate them
   /// (i.e. the pointers have computable bounds).
-  bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, ScalarEvolution *SE,
-                       Loop *TheLoop,
+  bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, Loop *TheLoop,
                        const DenseMap<Value *, const SCEV *> &Strides,
                        Value *&UncomputablePtr);
 
@@ -1188,7 +1187,7 @@ bool AccessAnalysis::createCheckForAccess(
 }
 
 bool AccessAnalysis::canCheckPtrAtRT(
-    RuntimePointerChecking &RtCheck, ScalarEvolution *SE, Loop *TheLoop,
+    RuntimePointerChecking &RtCheck, Loop *TheLoop,
     const DenseMap<Value *, const SCEV *> &StridesMap,
     Value *&UncomputablePtr) {
   // Find pointers with computable bounds. We are going to use this information
@@ -2651,7 +2650,7 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI,
   // to place a runtime bound check.
   Value *UncomputablePtr = nullptr;
   bool CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(
-      *PtrRtChecking, PSE->getSE(), TheLoop, SymbolicStrides, UncomputablePtr);
+      *PtrRtChecking, TheLoop, SymbolicStrides, UncomputablePtr);
   if (!CanDoRTIfNeeded) {
     const auto *I = dyn_cast_or_null<Instruction>(UncomputablePtr);
     recordAnalysis("CantIdentifyArrayBounds", I)
@@ -2679,10 +2678,9 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI,
       PtrRtChecking->reset();
       PtrRtChecking->Need = true;
 
-      auto *SE = PSE->getSE();
       UncomputablePtr = nullptr;
       CanDoRTIfNeeded = Accesses.canCheckPtrAtRT(
-          *PtrRtChecking, SE, TheLoop, SymbolicStrides, UncomputablePtr);
+          *PtrRtChecking, TheLoop, SymbolicStrides, UncomputablePtr);
 
       // Check that we found the bounds for the pointer.
       if (!CanDoRTIfNeeded) {

>From 6a8dde04a07287f837bbabeb93e23e47af366d3d Mon Sep 17 00:00:00 2001
From: William Moses <gh at wsmoses.com>
Date: Thu, 22 May 2025 14:13:32 -0500
Subject: [PATCH 037/105] [MLIR] Change getBackwardSlice to return a
 logicalresult rather than crash (#140961)

The current implementation of getBackwardSlice will crash if an
operation in the dependency chain is defined by an operation with
multiple regions or blocks. Crashing is bad (and forbids many analyses
from using getBackwardSlice, as well as causing existing users of
getBackwardSlice to fail for IR with this property).

This PR instead causes the analysis to return a failure, rather than
crash in the cases it cannot compute the full slice

---------

Co-authored-by: Oleksandr "Alex" Zinenko <git at ozinenko.com>
---
 mlir/include/mlir/Analysis/SliceAnalysis.h    | 12 ++--
 .../mlir/Query/Matcher/SliceMatchers.h        |  3 +-
 mlir/lib/Analysis/SliceAnalysis.cpp           | 58 +++++++++++--------
 .../Conversion/VectorToGPU/VectorToGPU.cpp    |  4 +-
 .../Linalg/Transforms/HoistPadding.cpp        |  7 ++-
 .../NVGPU/TransformOps/NVGPUTransformOps.cpp  |  6 +-
 .../SCF/Transforms/TileUsingInterface.cpp     |  3 +-
 mlir/lib/Transforms/Utils/RegionUtils.cpp     |  6 +-
 .../Dialect/Affine/TestVectorizationUtils.cpp |  4 +-
 mlir/test/lib/IR/TestSlicing.cpp              |  3 +-
 10 files changed, 67 insertions(+), 39 deletions(-)

diff --git a/mlir/include/mlir/Analysis/SliceAnalysis.h b/mlir/include/mlir/Analysis/SliceAnalysis.h
index 3b731e8bb1c22..d082d2d9f758b 100644
--- a/mlir/include/mlir/Analysis/SliceAnalysis.h
+++ b/mlir/include/mlir/Analysis/SliceAnalysis.h
@@ -138,13 +138,17 @@ void getForwardSlice(Value root, SetVector<Operation *> *forwardSlice,
 /// Assuming all local orders match the numbering order:
 ///    {1, 2, 5, 3, 4, 6}
 ///
-void getBackwardSlice(Operation *op, SetVector<Operation *> *backwardSlice,
-                      const BackwardSliceOptions &options = {});
+/// This function returns whether the backwards slice was able to be
+/// successfully computed, and failure if it was unable to determine the slice.
+LogicalResult getBackwardSlice(Operation *op,
+                               SetVector<Operation *> *backwardSlice,
+                               const BackwardSliceOptions &options = {});
 
 /// Value-rooted version of `getBackwardSlice`. Return the union of all backward
 /// slices for the op defining or owning the value `root`.
-void getBackwardSlice(Value root, SetVector<Operation *> *backwardSlice,
-                      const BackwardSliceOptions &options = {});
+LogicalResult getBackwardSlice(Value root,
+                               SetVector<Operation *> *backwardSlice,
+                               const BackwardSliceOptions &options = {});
 
 /// Iteratively computes backward slices and forward slices until
 /// a fixed point is reached. Returns an `SetVector<Operation *>` which
diff --git a/mlir/include/mlir/Query/Matcher/SliceMatchers.h b/mlir/include/mlir/Query/Matcher/SliceMatchers.h
index 1b0e4c32dbe94..40a39d23ca695 100644
--- a/mlir/include/mlir/Query/Matcher/SliceMatchers.h
+++ b/mlir/include/mlir/Query/Matcher/SliceMatchers.h
@@ -112,7 +112,8 @@ bool BackwardSliceMatcher<Matcher>::matches(
     }
     return true;
   };
-  getBackwardSlice(rootOp, &backwardSlice, options);
+  LogicalResult result = getBackwardSlice(rootOp, &backwardSlice, options);
+  assert(result.succeeded() && "expected backward slice to succeed");
   return options.inclusive ? backwardSlice.size() > 1
                            : backwardSlice.size() >= 1;
 }
diff --git a/mlir/lib/Analysis/SliceAnalysis.cpp b/mlir/lib/Analysis/SliceAnalysis.cpp
index 5aebb19e3a86e..12b9d3adb49fa 100644
--- a/mlir/lib/Analysis/SliceAnalysis.cpp
+++ b/mlir/lib/Analysis/SliceAnalysis.cpp
@@ -80,25 +80,25 @@ void mlir::getForwardSlice(Value root, SetVector<Operation *> *forwardSlice,
   forwardSlice->insert(v.rbegin(), v.rend());
 }
 
-static void getBackwardSliceImpl(Operation *op,
-                                 SetVector<Operation *> *backwardSlice,
-                                 const BackwardSliceOptions &options) {
+static LogicalResult getBackwardSliceImpl(Operation *op,
+                                          SetVector<Operation *> *backwardSlice,
+                                          const BackwardSliceOptions &options) {
   if (!op || op->hasTrait<OpTrait::IsIsolatedFromAbove>())
-    return;
+    return success();
 
   // Evaluate whether we should keep this def.
   // This is useful in particular to implement scoping; i.e. return the
   // transitive backwardSlice in the current scope.
   if (options.filter && !options.filter(op))
-    return;
+    return success();
 
   auto processValue = [&](Value value) {
     if (auto *definingOp = value.getDefiningOp()) {
       if (backwardSlice->count(definingOp) == 0)
-        getBackwardSliceImpl(definingOp, backwardSlice, options);
+        return getBackwardSliceImpl(definingOp, backwardSlice, options);
     } else if (auto blockArg = dyn_cast<BlockArgument>(value)) {
       if (options.omitBlockArguments)
-        return;
+        return success();
 
       Block *block = blockArg.getOwner();
       Operation *parentOp = block->getParentOp();
@@ -106,15 +106,17 @@ static void getBackwardSliceImpl(Operation *op,
       // blocks of parentOp, which are not technically backward unless they flow
       // into us. For now, just bail.
       if (parentOp && backwardSlice->count(parentOp) == 0) {
-        assert(parentOp->getNumRegions() == 1 &&
-               llvm::hasSingleElement(parentOp->getRegion(0).getBlocks()));
-        getBackwardSliceImpl(parentOp, backwardSlice, options);
+        if (parentOp->getNumRegions() == 1 &&
+            llvm::hasSingleElement(parentOp->getRegion(0).getBlocks())) {
+          return getBackwardSliceImpl(parentOp, backwardSlice, options);
+        }
       }
-    } else {
-      llvm_unreachable("No definingOp and not a block argument.");
     }
+    return failure();
   };
 
+  bool succeeded = true;
+
   if (!options.omitUsesFromAbove) {
     llvm::for_each(op->getRegions(), [&](Region &region) {
       // Walk this region recursively to collect the regions that descend from
@@ -125,36 +127,41 @@ static void getBackwardSliceImpl(Operation *op,
       region.walk([&](Operation *op) {
         for (OpOperand &operand : op->getOpOperands()) {
           if (!descendents.contains(operand.get().getParentRegion()))
-            processValue(operand.get());
+            if (!processValue(operand.get()).succeeded()) {
+              return WalkResult::interrupt();
+            }
         }
+        return WalkResult::advance();
       });
     });
   }
   llvm::for_each(op->getOperands(), processValue);
 
   backwardSlice->insert(op);
+  return success(succeeded);
 }
 
-void mlir::getBackwardSlice(Operation *op,
-                            SetVector<Operation *> *backwardSlice,
-                            const BackwardSliceOptions &options) {
-  getBackwardSliceImpl(op, backwardSlice, options);
+LogicalResult mlir::getBackwardSlice(Operation *op,
+                                     SetVector<Operation *> *backwardSlice,
+                                     const BackwardSliceOptions &options) {
+  LogicalResult result = getBackwardSliceImpl(op, backwardSlice, options);
 
   if (!options.inclusive) {
     // Don't insert the top level operation, we just queried on it and don't
     // want it in the results.
     backwardSlice->remove(op);
   }
+  return result;
 }
 
-void mlir::getBackwardSlice(Value root, SetVector<Operation *> *backwardSlice,
-                            const BackwardSliceOptions &options) {
+LogicalResult mlir::getBackwardSlice(Value root,
+                                     SetVector<Operation *> *backwardSlice,
+                                     const BackwardSliceOptions &options) {
   if (Operation *definingOp = root.getDefiningOp()) {
-    getBackwardSlice(definingOp, backwardSlice, options);
-    return;
+    return getBackwardSlice(definingOp, backwardSlice, options);
   }
   Operation *bbAargOwner = cast<BlockArgument>(root).getOwner()->getParentOp();
-  getBackwardSlice(bbAargOwner, backwardSlice, options);
+  return getBackwardSlice(bbAargOwner, backwardSlice, options);
 }
 
 SetVector<Operation *>
@@ -170,7 +177,9 @@ mlir::getSlice(Operation *op, const BackwardSliceOptions &backwardSliceOptions,
     auto *currentOp = (slice)[currentIndex];
     // Compute and insert the backwardSlice starting from currentOp.
     backwardSlice.clear();
-    getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
+    LogicalResult result =
+        getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
+    assert(result.succeeded());
     slice.insert_range(backwardSlice);
 
     // Compute and insert the forwardSlice starting from currentOp.
@@ -193,7 +202,8 @@ static bool dependsOnCarriedVals(Value value,
   sliceOptions.filter = [&](Operation *op) {
     return !ancestorOp->isAncestor(op);
   };
-  getBackwardSlice(value, &slice, sliceOptions);
+  LogicalResult result = getBackwardSlice(value, &slice, sliceOptions);
+  assert(result.succeeded());
 
   // Check that none of the operands of the operations in the backward slice are
   // loop iteration arguments, and neither is the value itself.
diff --git a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
index 8b16da387457d..0ec9ddc25ff8d 100644
--- a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
+++ b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
@@ -317,7 +317,9 @@ getSliceContract(Operation *op,
     auto *currentOp = (slice)[currentIndex];
     // Compute and insert the backwardSlice starting from currentOp.
     backwardSlice.clear();
-    getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
+    LogicalResult result =
+        getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
+    assert(result.succeeded() && "expected a backward slice");
     slice.insert_range(backwardSlice);
 
     // Compute and insert the forwardSlice starting from currentOp.
diff --git a/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp b/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
index d33a17af63459..2c98bd3ba93af 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
@@ -124,10 +124,13 @@ static void computeBackwardSlice(tensor::PadOp padOp,
   getUsedValuesDefinedAbove(padOp.getRegion(), padOp.getRegion(),
                             valuesDefinedAbove);
   for (Value v : valuesDefinedAbove) {
-    getBackwardSlice(v, &backwardSlice, sliceOptions);
+    LogicalResult result = getBackwardSlice(v, &backwardSlice, sliceOptions);
+    assert(result.succeeded() && "expected a backward slice");
   }
   // Then, add the backward slice from padOp itself.
-  getBackwardSlice(padOp.getOperation(), &backwardSlice, sliceOptions);
+  LogicalResult result =
+      getBackwardSlice(padOp.getOperation(), &backwardSlice, sliceOptions);
+  assert(result.succeeded() && "expected a backward slice");
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
index 75dbe0becf80d..1046f5798ecd4 100644
--- a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
+++ b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
@@ -290,8 +290,10 @@ static void getPipelineStages(
   });
   options.inclusive = true;
   for (Operation &op : forOp.getBody()->getOperations()) {
-    if (stage0Ops.contains(&op))
-      getBackwardSlice(&op, &dependencies, options);
+    if (stage0Ops.contains(&op)) {
+      LogicalResult result = getBackwardSlice(&op, &dependencies, options);
+      assert(result.succeeded() && "expected a backward slice");
+    }
   }
 
   for (Operation &op : forOp.getBody()->getOperations()) {
diff --git a/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp b/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
index 719e2c6fa459e..9e3d3f8b10a13 100644
--- a/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
@@ -1772,7 +1772,8 @@ checkAssumptionForLoop(Operation *loopOp, Operation *consumerOp,
   };
   llvm::SetVector<Operation *> slice;
   for (auto operand : consumerOp->getOperands()) {
-    getBackwardSlice(operand, &slice, options);
+    LogicalResult result = getBackwardSlice(operand, &slice, options);
+    assert(result.succeeded() && "expected a backward slice");
   }
 
   if (!slice.empty()) {
diff --git a/mlir/lib/Transforms/Utils/RegionUtils.cpp b/mlir/lib/Transforms/Utils/RegionUtils.cpp
index 4985d718c1780..c136ff92255cd 100644
--- a/mlir/lib/Transforms/Utils/RegionUtils.cpp
+++ b/mlir/lib/Transforms/Utils/RegionUtils.cpp
@@ -1094,7 +1094,8 @@ LogicalResult mlir::moveOperationDependencies(RewriterBase &rewriter,
     return !dominance.properlyDominates(sliceBoundaryOp, insertionPoint);
   };
   llvm::SetVector<Operation *> slice;
-  getBackwardSlice(op, &slice, options);
+  LogicalResult result = getBackwardSlice(op, &slice, options);
+  assert(result.succeeded() && "expected a backward slice");
 
   // If the slice contains `insertionPoint` cannot move the dependencies.
   if (slice.contains(insertionPoint)) {
@@ -1159,7 +1160,8 @@ LogicalResult mlir::moveValueDefinitions(RewriterBase &rewriter,
   };
   llvm::SetVector<Operation *> slice;
   for (auto value : prunedValues) {
-    getBackwardSlice(value, &slice, options);
+    LogicalResult result = getBackwardSlice(value, &slice, options);
+    assert(result.succeeded() && "expected a backward slice");
   }
 
   // If the slice contains `insertionPoint` cannot move the dependencies.
diff --git a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
index f26058f30ad7b..145acd99e6616 100644
--- a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
+++ b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
@@ -154,7 +154,9 @@ void VectorizerTestPass::testBackwardSlicing(llvm::raw_ostream &outs) {
   patternTestSlicingOps().match(f, &matches);
   for (auto m : matches) {
     SetVector<Operation *> backwardSlice;
-    getBackwardSlice(m.getMatchedOperation(), &backwardSlice);
+    LogicalResult result =
+        getBackwardSlice(m.getMatchedOperation(), &backwardSlice);
+    assert(result.succeeded() && "expected a backward slice");
     outs << "\nmatched: " << *m.getMatchedOperation()
          << " backward static slice: ";
     for (auto *op : backwardSlice)
diff --git a/mlir/test/lib/IR/TestSlicing.cpp b/mlir/test/lib/IR/TestSlicing.cpp
index e99d5976d6d9d..ad99be2b9d0c9 100644
--- a/mlir/test/lib/IR/TestSlicing.cpp
+++ b/mlir/test/lib/IR/TestSlicing.cpp
@@ -41,7 +41,8 @@ static LogicalResult createBackwardSliceFunction(Operation *op,
   options.omitBlockArguments = omitBlockArguments;
   // TODO: Make this default.
   options.omitUsesFromAbove = false;
-  getBackwardSlice(op, &slice, options);
+  LogicalResult result = getBackwardSlice(op, &slice, options);
+  assert(result.succeeded() && "expected a backward slice");
   for (Operation *slicedOp : slice)
     builder.clone(*slicedOp, mapper);
   builder.create<func::ReturnOp>(loc);

>From 2b8bff6f66fd90ac658d0ae0d7f9a83ffadfd77f Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Thu, 22 May 2025 12:28:32 -0700
Subject: [PATCH 038/105] [doc][mlgo] Document the logger (serialization) and
 expose the doc (#141094)

---
 llvm/docs/MLGO.rst      | 92 ++++++++++++++++++++++++++++++++++++++---
 llvm/docs/Reference.rst |  6 ++-
 2 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/llvm/docs/MLGO.rst b/llvm/docs/MLGO.rst
index 49efea3519c5a..43b45d505ea3a 100644
--- a/llvm/docs/MLGO.rst
+++ b/llvm/docs/MLGO.rst
@@ -314,7 +314,7 @@ features.
 ``MLModelRunner`` implementations
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-We currently feature 3 implementations:
+We currently feature 4 implementations:
 
 - ``ModelUnderTrainingRunner``. This requires the compiler be built with TFLite
   support. It allows loading a TFLite model dynamically and is primarily
@@ -338,15 +338,97 @@ requiring no out of tree build-time dependencies.
   presumably a python training algorithm. We do not envision using this in a
   production environment.
 
+- ``NoInferenceModelRunner``. This serves as a store for feature values, and its
+  ``evaluate`` should never be called. It's used for training scenarios, when we
+  want to capture the behavior of the default (non-ML) heuristic.
+
 Note that training leaves it to the training infrastructure to handle
 distributed computing. The assumed architecture has python processes
 communicating remotely between themselves, but managing local communication with
 clang.
 
-..
-    TODO(mtrofin): 
-        - logging, and the use in interactive mode.
-        - discuss an example (like the inliner)
+Logging Facility
+----------------
+
+When training models, we need to expose the features we will want to use during
+inference, as well as outcomes, to guide reward-based learning techniques. This
+can happen in 2 forms:
+
+- when running the compiler on some input, as a capture of the features and
+  actions taken by some policy or a model currently being used.
+  For example, see ``DevelopmentModeInlineAdvisor`` or ``DevelopmentModeEvictAdvisor``
+  in ``MLRegallocEvictAdvisor.cpp``. In more detail, in the former case, if
+  ``-training-log`` is specified, the features and actions (inline/no inline)
+  from each inlining decision are saved to the specified file. Since
+  ``MLModelRunner`` implementations hold on to feature values (they don't get
+  cleared by ``evaluate``), logging is easily supported by just looping over the
+  model runner's features and passing the tensor buffers to the logger. Note how
+  we use the ``NoInferenceModelRunner`` to capture the features observed when
+  using the default policy.
+
+- as a serialization mechanism for the ``InteractiveModelRunner``. Here, we need
+  to pass the observed features over IPC (a file descriptor, likely a named
+  pipe).
+
+Both cases require serializing the same kind of data and we support both with
+``Analysis/Utils/TrainingLogger``.
+
+The goal of the logger design was avoiding any new dependency, and optimizing
+for the tensor scenario - i.e. exchanging potentially large buffers of fixed
+size, containing scalars. We explicitly assume the reader of the format has the
+same endianness as the compiler host, and we further expect the reader and the
+compiler run on the same host. This is because we expect the training scenarios
+have a (typically python) process managing the compiler process, and we leave to
+the training side to handle remoting.
+
+The logger produces the following sequence:
+
+- a header describing the structure of the log. This is a one-line textual JSON
+  dictionary with the following elements:
+  
+  - ``features``: a list of JSON-serialized ``TensorSpec`` values. The position
+    in the list matters, as it will be the order in which values will be
+    subsequently recorded. If we are just logging (i.e. not using the
+    ``InteractiveModelRunner``), the last feature should be that of the action
+    (e.g. "inline/no inline", or "index of evicted live range")
+  - (optional) ``score``: a ``TensorSpec`` describing a value we will include to
+    help formulate a reward. This could be a size estimate or a latency estimate.
+  - (optional) ``advice``: a ``TensorSpec`` describing the action. This is used
+    for the ``InteractiveModelRunner``, in which case it shouldn't be in the 
+    ``features`` list.
+- a sequence of ``contexts``. Contexts are independent traces of the optimization
+  problem. For module passes, there is only one context, for function passes,
+  there is a context per function. The start of a context is marked with a
+  one-line JSON dictionary of the form ``{"context": <context name, a string>}``
+  
+  Each context has a sequence of:
+
+  - ``observations``. An observation is:
+    
+    - one-line JSON ``{"observation": <observation number. 0-indexed>}``
+    - a binary dump of the tensor buffers, in the order in which they were
+      specified in the header.
+    - a new line character
+    - if ``score`` was specified in the header:
+    
+      - a one-line JSON object ``{"outcome": <value>}``, where the ``value``
+        conforms to the ``TensorSpec`` in defined for the ``score`` in the header.
+      - the outcome value, as a binary dump
+      - a new line character.
+
+The format uses a mix of textual JSON (for headers) and binary dumps (for tensors)
+because the headers are not expected to dominate the payload - the tensor values
+are. We wanted to avoid overburdening the log reader - likely python - from
+additional dependencies; and the one-line JSON makes it rudimentarily possible
+to inspect a log without additional tooling.
+
+A python utility for reading logs, used for tests, is available at
+``Analysis/models/log_reader.py``. A utility showcasing the ``InteractiveModelRunner``,
+which uses this reader as well, is at ``Analysis/models/interactive_host.py``.
+The latter is also used in tests.
+
+There is no C++ implementation of a log reader. We do not have a scenario
+motivating one.
 
 IR2Vec Embeddings
 =================
diff --git a/llvm/docs/Reference.rst b/llvm/docs/Reference.rst
index 565d5c6876d66..cb9576b15d701 100644
--- a/llvm/docs/Reference.rst
+++ b/llvm/docs/Reference.rst
@@ -40,8 +40,8 @@ LLVM and API reference documentation.
    PCSectionsMetadata
    PDB/index
    PointerAuth
-   ScudoHardenedAllocator
    MLGO
+   ScudoHardenedAllocator
    MemoryModelRelaxationAnnotations
    MemTagSanitizer
    Security
@@ -239,3 +239,7 @@ Additional Topics
 :doc:`ConvergenceAndUniformity`
    A description of uniformity analysis in the presence of irreducible
    control flow, and its implementation.
+
+:doc:`MLGO`
+   Facilities for ML-Guided Optimization, such as collecting IR corpora from a
+   build, interfacing with ML models, an exposing features for training.

>From 9e306ad4600c4d3392c194a8be88919ee758425c Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 12:33:52 -0700
Subject: [PATCH 039/105] [clang] Remove intrusive reference count from
 `DiagnosticOptions` (#139584)

The `DiagnosticOptions` class is currently intrusively
reference-counted, which makes reasoning about its lifetime very
difficult in some cases. For example, `CompilerInvocation` owns the
`DiagnosticOptions` instance (wrapped in `llvm::IntrusiveRefCntPtr`) and
only exposes an accessor returning `DiagnosticOptions &`. One would
think this gives `CompilerInvocation` exclusive ownership of the object,
but that's not the case:

```c++
void shareOwnership(CompilerInvocation &CI) {
  llvm::IntrusiveRefCntPtr<DiagnosticOptions> CoOwner = &CI.getDiagnosticOptions();
  // ...
}
```

This is a perfectly valid pattern that is being actually used in the
codebase.

I would like to ensure the ownership of `DiagnosticOptions` by
`CompilerInvocation` is guaranteed to be exclusive. This can be
leveraged for a copy-on-write optimization later on. This PR changes
usages of `DiagnosticOptions` across `clang`, `clang-tools-extra` and
`lldb` to not be intrusively reference-counted.
---
 .../tool/ClangApplyReplacementsMain.cpp       |  4 +-
 .../tool/ClangChangeNamespace.cpp             |  6 +-
 .../tool/ClangIncludeFixer.cpp                |  6 +-
 .../clang-move/tool/ClangMove.cpp             |  6 +-
 clang-tools-extra/clang-query/Query.cpp       |  2 +-
 .../tool/ClangReorderFields.cpp               |  6 +-
 clang-tools-extra/clang-tidy/ClangTidy.cpp    | 24 +++---
 .../ClangTidyDiagnosticConsumer.cpp           |  4 +-
 .../clang-tidy/ClangTidyDiagnosticConsumer.h  |  5 +-
 .../ExpandModularHeadersPPCallbacks.cpp       |  2 +-
 .../ExpandModularHeadersPPCallbacks.h         |  1 +
 clang-tools-extra/clangd/Compiler.cpp         |  5 +-
 clang-tools-extra/clangd/ModulesBuilder.cpp   |  4 +-
 clang-tools-extra/clangd/ParsedAST.cpp        |  3 +-
 clang-tools-extra/clangd/Preamble.cpp         |  2 +-
 .../clangd/SystemIncludeExtractor.cpp         |  3 +-
 .../clangd/unittests/ConfigCompileTests.cpp   |  3 +-
 .../clangd/unittests/tweaks/TweakTests.cpp    |  3 +-
 .../include-cleaner/unittests/RecordTest.cpp  |  4 +-
 .../include-cleaner/unittests/WalkASTTest.cpp |  6 +-
 .../modularize/ModularizeUtilities.cpp        |  6 +-
 .../modularize/ModularizeUtilities.h          |  2 +-
 .../ApplyReplacementsTest.cpp                 |  4 +-
 .../clang-tidy/ClangTidyOptionsTest.cpp       | 18 ++---
 .../unittests/clang-tidy/ClangTidyTest.h      |  6 +-
 clang/include/clang/Basic/Diagnostic.h        |  6 +-
 clang/include/clang/Basic/DiagnosticOptions.h |  4 +-
 clang/include/clang/Basic/SourceManager.h     |  1 +
 clang/include/clang/Frontend/ASTUnit.h        | 12 ++-
 .../include/clang/Frontend/CompilerInstance.h |  2 +-
 .../clang/Frontend/CompilerInvocation.h       |  2 +-
 .../clang/Frontend/DiagnosticRenderer.h       |  7 +-
 .../clang/Frontend/LogDiagnosticPrinter.h     |  4 +-
 .../include/clang/Frontend/SARIFDiagnostic.h  |  2 +-
 .../clang/Frontend/SARIFDiagnosticPrinter.h   |  4 +-
 .../Frontend/SerializedDiagnosticPrinter.h    |  2 +-
 clang/include/clang/Frontend/TextDiagnostic.h |  2 +-
 .../clang/Frontend/TextDiagnosticPrinter.h    |  4 +-
 clang/include/clang/Serialization/ASTReader.h |  9 +--
 clang/lib/Basic/Diagnostic.cpp                | 10 +--
 clang/lib/Basic/SourceManager.cpp             |  4 +-
 clang/lib/CrossTU/CrossTranslationUnit.cpp    | 20 ++---
 clang/lib/Frontend/ASTMerge.cpp               | 13 ++-
 clang/lib/Frontend/ASTUnit.cpp                | 14 +++-
 clang/lib/Frontend/ChainedIncludesSource.cpp  |  4 +-
 clang/lib/Frontend/CompilerInstance.cpp       | 27 +++----
 clang/lib/Frontend/CompilerInvocation.cpp     | 27 ++-----
 .../CreateInvocationFromCommandLine.cpp       | 14 ++--
 clang/lib/Frontend/DiagnosticRenderer.cpp     | 17 ++--
 clang/lib/Frontend/FrontendAction.cpp         | 12 +--
 clang/lib/Frontend/FrontendActions.cpp        | 16 ++--
 clang/lib/Frontend/LogDiagnosticPrinter.cpp   |  4 +-
 clang/lib/Frontend/SARIFDiagnostic.cpp        |  4 +-
 clang/lib/Frontend/SARIFDiagnosticPrinter.cpp |  7 +-
 .../Frontend/SerializedDiagnosticPrinter.cpp  | 29 +++----
 clang/lib/Frontend/TextDiagnostic.cpp         | 79 +++++++++----------
 clang/lib/Frontend/TextDiagnosticPrinter.cpp  | 15 ++--
 clang/lib/Interpreter/CodeCompletion.cpp      |  3 +-
 clang/lib/Interpreter/Interpreter.cpp         |  8 +-
 clang/lib/Rewrite/HTMLRewrite.cpp             |  4 +-
 clang/lib/Serialization/ASTReader.cpp         | 25 +++---
 clang/lib/Testing/TestAST.cpp                 |  2 +-
 clang/lib/Tooling/CompilationDatabase.cpp     |  8 +-
 clang/lib/Tooling/Core/Replacement.cpp        |  4 +-
 .../DependencyScanningWorker.cpp              |  6 +-
 clang/lib/Tooling/Refactoring.cpp             |  8 +-
 clang/lib/Tooling/Tooling.cpp                 | 10 +--
 clang/tools/c-index-test/core_main.cpp        | 20 ++---
 .../ClangExtDefMapGen.cpp                     | 14 ++--
 clang/tools/clang-format/ClangFormat.cpp      |  8 +-
 .../clang-import-test/clang-import-test.cpp   |  4 +-
 .../clang-installapi/ClangInstallAPI.cpp      |  8 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  9 ++-
 clang/tools/diagtool/ShowEnabledWarnings.cpp  |  6 +-
 clang/tools/diagtool/TreeView.cpp             |  4 +-
 clang/tools/driver/cc1_main.cpp               |  4 +-
 clang/tools/driver/cc1as_main.cpp             |  8 +-
 clang/tools/driver/cc1gen_reproducer_main.cpp |  6 +-
 clang/tools/driver/driver.cpp                 | 11 ++-
 clang/tools/libclang/CIndex.cpp               | 11 +--
 clang/tools/libclang/CIndexCodeCompletion.cpp | 10 +--
 clang/tools/libclang/CIndexDiagnostic.cpp     | 17 ++--
 clang/tools/libclang/Indexing.cpp             |  7 +-
 clang/unittests/AST/ASTVectorTest.cpp         |  3 +-
 clang/unittests/AST/CommentLexer.cpp          | 10 +--
 clang/unittests/AST/CommentParser.cpp         | 10 +--
 clang/unittests/AST/CommentTextTest.cpp       |  3 +-
 clang/unittests/AST/ExternalASTSourceTest.cpp |  4 +-
 .../UncheckedOptionalAccessModelTest.cpp      |  5 +-
 .../Analysis/MacroExpansionContextTest.cpp    |  6 +-
 .../Analysis/UnsafeBufferUsageTest.cpp        |  3 +-
 clang/unittests/Basic/DiagnosticTest.cpp      | 23 +++---
 clang/unittests/Basic/SarifTest.cpp           |  6 +-
 clang/unittests/Basic/SourceManagerTest.cpp   |  9 +--
 clang/unittests/Driver/DXCModeTest.cpp        | 12 +--
 clang/unittests/Driver/SanitizerArgsTest.cpp  |  7 +-
 .../Driver/SimpleDiagnosticConsumer.h         |  5 +-
 clang/unittests/Driver/ToolChainTest.cpp      | 71 +++++++++--------
 clang/unittests/Frontend/ASTUnitTest.cpp      | 37 ++++-----
 .../Frontend/CompilerInstanceTest.cpp         | 11 +--
 .../Frontend/CompilerInvocationTest.cpp       |  3 +-
 clang/unittests/Frontend/OutputStreamTest.cpp | 12 +--
 clang/unittests/Frontend/PCHPreambleTest.cpp  |  7 +-
 .../Frontend/ReparseWorkingDirTest.cpp        |  6 +-
 clang/unittests/Frontend/SearchPathTest.cpp   |  4 +-
 .../unittests/Frontend/TextDiagnosticTest.cpp |  8 +-
 clang/unittests/Frontend/UtilsTest.cpp        |  9 ++-
 .../unittests/Interpreter/InterpreterTest.cpp | 15 ++--
 clang/unittests/Lex/HeaderSearchTest.cpp      |  3 +-
 clang/unittests/Lex/LexerTest.cpp             | 10 +--
 clang/unittests/Lex/ModuleDeclStateTest.cpp   |  3 +-
 clang/unittests/Lex/PPCallbacksTest.cpp       |  8 +-
 .../Lex/PPConditionalDirectiveRecordTest.cpp  | 10 +--
 .../Lex/PPDependencyDirectivesTest.cpp        |  3 +-
 .../unittests/Lex/PPMemoryAllocationsTest.cpp |  3 +-
 .../Parse/ParseHLSLRootSignatureTest.cpp      |  4 +-
 clang/unittests/Sema/SemaNoloadLookupTest.cpp |  4 +-
 .../Serialization/ForceCheckFileInputTest.cpp |  8 +-
 .../Serialization/LoadSpecLazilyTest.cpp      |  3 +-
 .../Serialization/ModuleCacheTest.cpp         |  6 +-
 .../Serialization/NoCommentsTest.cpp          |  3 +-
 .../PreambleInNamedModulesTest.cpp            |  3 +-
 .../Serialization/VarDeclConstantInitTest.cpp |  3 +-
 clang/unittests/Support/TimeProfilerTest.cpp  |  4 +-
 clang/unittests/Tooling/RewriterTestContext.h |  9 +--
 clang/unittests/Tooling/Syntax/TokensTest.cpp |  3 +-
 .../unittests/Tooling/Syntax/TreeTestBase.cpp |  2 +-
 clang/unittests/Tooling/Syntax/TreeTestBase.h |  4 +-
 clang/unittests/Tooling/ToolingTest.cpp       |  8 +-
 .../Clang/ClangExpressionParser.cpp           | 10 +--
 .../Clang/ClangExpressionSourceCode.cpp       |  3 +-
 .../Clang/ClangModulesDeclVendor.cpp          | 21 +++--
 .../Language/ClangCommon/ClangHighlighter.cpp |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.h        |  1 +
 135 files changed, 603 insertions(+), 568 deletions(-)

diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 68b5743c6540f..062e236d3e51f 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -96,9 +96,9 @@ int main(int argc, char **argv) {
   cl::SetVersionPrinter(printVersion);
   cl::ParseCommandLineOptions(argc, argv);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 22d26db0c11bc..2a8fe2d06d185 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -126,10 +126,10 @@ int main(int argc, const char **argv) {
   if (int Result = Tool.run(Factory.get()))
     return Result;
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager Sources(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 6e51f25a66407..746ba7bcea015 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) {
   }
 
   // Set up a new source manager for applying the resulting replacements.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
-  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
-  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts);
   SourceManager SM(Diagnostics, tool.getFiles());
   Diagnostics.setClient(&DiagnosticPrinter, false);
 
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 655ea81ee37d4..750eb952714f7 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -176,10 +176,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager SM(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
index 382aa5d6fe25e..574b64ee0f759 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
           clang::SourceRange R = BI->second.getSourceRange();
           if (R.isValid()) {
             TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
-                              &AST->getDiagnostics().getDiagnosticOptions());
+                              AST->getDiagnostics().getDiagnosticOptions());
             TD.emitDiagnostic(
                 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
                 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
index 5b77ee7b5738c..03502525417b2 100644
--- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
+++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -72,10 +72,10 @@ int main(int argc, const char **argv) {
 
   int ExitCode = Tool.run(Factory.get());
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
 
   auto &FileMgr = Tool.getFiles();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 733a53a0f5dcc..26f9afbc0880e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -97,15 +97,14 @@ class ErrorReporter {
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagOpts(new DiagnosticOptions()),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
-        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
+        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
               DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
-    DiagOpts->ShowColors = Context.getOptions().UseColor.value_or(
+    DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
         llvm::sys::Process::StandardOutHasColors());
     DiagPrinter->BeginSourceFile(LangOpts);
-    if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
+    if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
       llvm::sys::Process::UseANSIEscapeCodes(true);
     }
   }
@@ -308,7 +307,7 @@ class ErrorReporter {
 
   FileManager Files;
   LangOptions LangOpts; // FIXME: use langopts from each original file
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticConsumer *DiagPrinter;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
@@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options,
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(),
-                       llvm::makeIntrusiveRefCnt<DiagnosticOptions>(),
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
                        &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
   ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
-                       &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
+                       /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   Tool.setDiagnosticConsumer(&DiagConsumer);
 
   class ActionFactory : public FrontendActionFactory {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index b216970bfbd8c..a0253a5fd1a48 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -49,7 +49,7 @@ namespace {
 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
 public:
   ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
-                              DiagnosticOptions *DiagOpts,
+                              DiagnosticOptions &DiagOpts,
                               ClangTidyError &Error)
       : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
 
@@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
     forwardDiagnostic(Info);
   } else {
     ClangTidyDiagnosticRenderer Converter(
-        Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
+        Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
         Errors.back());
     SmallString<100> Message;
     Info.FormatDiagnostic(Message);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index d6cf6a2b2731e..bd7a1bf2c11c7 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -75,7 +75,9 @@ class ClangTidyContext {
   /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
   // FIXME: this is required initialization, and should be a constructor param.
   // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
+  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
+                            DiagnosticsEngine *DiagEngine) {
+    this->DiagOpts = std::move(DiagOpts);
     this->DiagEngine = DiagEngine;
   }
 
@@ -231,6 +233,7 @@ class ClangTidyContext {
   // Writes to Stats.
   friend class ClangTidyDiagnosticConsumer;
 
+  std::unique_ptr<DiagnosticOptions> DiagOpts = nullptr;
   DiagnosticsEngine *DiagEngine = nullptr;
   std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
 
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 03a3e8404e069..6a84704434c33 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
       InMemoryFs(new llvm::vfs::InMemoryFileSystem),
       Sources(Compiler.getSourceManager()),
       // Forward the new diagnostics to the original DiagnosticConsumer.
-      Diags(new DiagnosticIDs, new DiagnosticOptions,
+      Diags(new DiagnosticIDs, DiagOpts,
             new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
       LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
   // Add a FileSystem containing the extra files needed in place of modular
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
index a263681b3c633..c3478917ef498 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs;
 
   SourceManager &Sources;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   LangOptions LangOpts;
   HeaderSearchOptions HSOpts;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 9be0152afd2f7..8b3865c8a8e5c 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
   CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   CIOpts.CC1Args = CC1Args;
   CIOpts.RecoverOnError = true;
-  CIOpts.Diags = CompilerInstance::createDiagnostics(
-      *CIOpts.VFS, new DiagnosticOptions, &D, false);
+  DiagnosticOptions DiagOpts;
+  CIOpts.Diags =
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);
   CIOpts.ProbePrecompiled = false;
   std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
   if (!CI)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..bf77f43bd28bb 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   HSOpts.ValidateASTInputFilesContent = true;
 
   clang::clangd::IgnoreDiagnostics IgnoreDiags;
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
-                                          &IgnoreDiags,
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
                                           /*ShouldOwnClient=*/false);
 
   LangOptions LangOpts;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 3f63daaf400db..9e1f6bb977226 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
         *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
         tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
-    CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+    // The lifetime of DiagnosticOptions is managed by \c Clang.
+    CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index ba9a53db8a0dc..7b4d63ff197e7 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       });
   auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
-      CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(),
+      CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
                                           &PreambleDiagnostics,
                                           /*ShouldOwnClient=*/false);
   const Config &Cfg = Config::current();
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index 6417bf8765622..0b067e8b0b2b2 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -253,7 +253,8 @@ namespace {
 bool isValidTarget(llvm::StringRef Triple) {
   std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions);
   TargetOpts->Triple = Triple.str();
-  DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
                           new IgnoringDiagConsumer);
   llvm::IntrusiveRefCntPtr<TargetInfo> Target =
       TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index c3e484a1a79c4..75d0ff244038d 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
                                    "unreachable-code", "unused-variable",
                                    "typecheck_bool_condition",
                                    "unexpected_friend", "warn_alloca"));
-  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts,
                                       new clang::IgnoringDiagConsumer);
 
   using Diag = clang::Diagnostic;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
index 8bd40c1429012..e39b70224d97c 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
@@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) {
   for (const auto *Path : RelPaths)
     MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path));
   FileManager FM(FileSystemOptions(), MemFS);
-  DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts);
   SourceManager SM(DE, FM);
 
   for (const auto *Path : RelPaths) {
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index a10c0d5a54a95..91d2697712b6e 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) {
                  llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(),
                                                       /*BufferName=*/""));
 
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get());
+  DiagnosticOptions DiagOpts;
+  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts);
   auto Invocation = std::make_unique<CompilerInvocation>();
   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()},
                                                  *Diags, "clang"));
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 0de0b77f33daf..3487f24f2af8f 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -85,9 +85,9 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
   // For each difference, show the target point in context, like a diagnostic.
   std::string DiagBuf;
   llvm::raw_string_ostream DiagOS(DiagBuf);
-  auto *DiagOpts = new DiagnosticOptions();
-  DiagOpts->ShowLevel = 0;
-  DiagOpts->ShowNoteIncludeStack = 0;
+  DiagnosticOptions DiagOpts;
+  DiagOpts.ShowLevel = 0;
+  DiagOpts.ShowNoteIncludeStack = 0;
   TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
   auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) {
     Diag.emitDiagnostic(
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index a8f1ddf64d34b..9ad1731915a8b 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
       MissingHeaderCount(0),
       // Init clang stuff needed for loading the module map and preprocessing.
       LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
-      DiagnosticOpts(new DiagnosticOptions()),
-      DC(llvm::errs(), DiagnosticOpts.get()),
-      Diagnostics(
-          new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
+      DC(llvm::errs(), DiagnosticOpts),
+      Diagnostics(new DiagnosticsEngine(DiagIDs, DiagnosticOpts, &DC, false)),
       TargetOpts(new ModuleMapTargetOptions()),
       Target(TargetInfo::CreateTargetInfo(*Diagnostics, *TargetOpts)),
       FileMgr(new FileManager(FileSystemOpts)),
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.h b/clang-tools-extra/modularize/ModularizeUtilities.h
index 7b4c16a492b89..3242ea0c4b97e 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.h
+++ b/clang-tools-extra/modularize/ModularizeUtilities.h
@@ -198,7 +198,7 @@ class ModularizeUtilities {
   /// Diagnostic IDs.
   const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs;
   /// Options controlling the diagnostic engine.
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagnosticOpts;
+  clang::DiagnosticOptions DiagnosticOpts;
   /// Diagnostic consumer.
   clang::TextDiagnosticPrinter DC;
   /// Diagnostic engine.
diff --git a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
index 4fe57e618004d..87b0d69f4654a 100644
--- a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
+++ b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
@@ -32,9 +32,9 @@ makeTUDiagnostics(const std::string &MainSourceFile, StringRef DiagnosticName,
 // Test to ensure diagnostics with no fixes, will be merged correctly
 // before applying.
 TEST(ApplyReplacementsTest, mergeDiagnosticsWithNoFixes) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
   FileManager Files((FileSystemOptions()));
   SourceManager SM(Diagnostics, Files);
   TUReplacements TURs;
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index aaec0e6b50bbf..d3ca26a19dd63 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -317,9 +317,9 @@ TEST(CheckOptionsValidation, MissingOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
   EXPECT_FALSE(TestCheck.getLocal("Opt"));
   EXPECT_EQ(TestCheck.getLocal("Opt", "Unknown"), "Unknown");
@@ -347,9 +347,9 @@ TEST(CheckOptionsValidation, ValidIntOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal("IntExpected"), 1);
@@ -409,9 +409,9 @@ TEST(ValidConfiguration, ValidEnumOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal<Colours>("Valid"), Colours::Red);
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
index e511eb6e49e8d..789cc2afb4f0c 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -96,9 +96,9 @@ runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
 
   std::vector<std::string> Args(1, "clang-tidy");
   Args.push_back("-fsyntax-only");
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 49ef22d4e4eb6..e9c54c3c487c9 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -330,7 +330,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   unsigned ConstexprBacktraceLimit = 0;
 
   IntrusiveRefCntPtr<DiagnosticIDs> Diags;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
   DiagnosticConsumer *Client = nullptr;
   std::unique_ptr<DiagnosticConsumer> Owner;
   SourceManager *SourceMgr = nullptr;
@@ -566,7 +566,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
 
 public:
   explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
-                             IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+                             DiagnosticOptions &DiagOpts,
                              DiagnosticConsumer *client = nullptr,
                              bool ShouldOwnClient = true);
   DiagnosticsEngine(const DiagnosticsEngine &) = delete;
@@ -582,7 +582,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   }
 
   /// Retrieve the diagnostic options.
-  DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
+  DiagnosticOptions &getDiagnosticOptions() const { return DiagOpts; }
 
   using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>;
 
diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h
index 29146532f9524..a230022224de5 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.h
+++ b/clang/include/clang/Basic/DiagnosticOptions.h
@@ -10,7 +10,6 @@
 #define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
 
 #include "clang/Basic/LLVM.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -67,8 +66,7 @@ inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS,
 raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M);
 
 /// Options for controlling the compiler diagnostics engine.
-class DiagnosticOptions
-    : public llvm::ThreadSafeRefCountedBase<DiagnosticOptions> {
+class DiagnosticOptions {
   friend bool ParseDiagnosticArgs(DiagnosticOptions &, llvm::opt::ArgList &,
                                   clang::DiagnosticsEngine *, bool);
 
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 3762dbc2ccee8..cd3dac9133223 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -2041,6 +2041,7 @@ class SourceManagerForFile {
   // as they are created in `createSourceManagerForFile` so that they can be
   // deleted in the reverse order as they are created.
   std::unique_ptr<FileManager> FileMgr;
+  std::unique_ptr<DiagnosticOptions> DiagOpts;
   std::unique_ptr<DiagnosticsEngine> Diagnostics;
   std::unique_ptr<SourceManager> SourceMgr;
 };
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index ac99f0fb2b471..1485192e8f1e3 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -107,6 +107,11 @@ class ASTUnit {
 
 private:
   std::unique_ptr<LangOptions> LangOpts;
+  // FIXME: The documentation on \c LoadFrom* member functions states that the
+  // DiagnosticsEngine (and therefore DiagnosticOptions) must outlive the
+  // returned ASTUnit. This is not the case. Enfore it by storing non-owning
+  // pointers here.
+  std::shared_ptr<DiagnosticOptions> DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
   IntrusiveRefCntPtr<FileManager>         FileMgr;
   IntrusiveRefCntPtr<SourceManager>       SourceMgr;
@@ -674,6 +679,7 @@ class ASTUnit {
   /// Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
   static std::unique_ptr<ASTUnit>
   create(std::shared_ptr<CompilerInvocation> CI,
+         std::shared_ptr<DiagnosticOptions> DiagOpts,
          IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
          CaptureDiagsKind CaptureDiagnostics, bool UserFilesAreVolatile);
 
@@ -700,7 +706,8 @@ class ASTUnit {
   /// \returns - The initialized ASTUnit or null if the AST failed to load.
   static std::unique_ptr<ASTUnit> LoadFromASTFile(
       StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-      WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+      WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       const FileSystemOptions &FileSystemOpts,
       const HeaderSearchOptions &HSOpts, const LangOptions *LangOpts = nullptr,
       bool OnlyLocalDecls = false,
@@ -762,6 +769,7 @@ class ASTUnit {
   static ASTUnit *LoadFromCompilerInvocationAction(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       FrontendAction *Action = nullptr, ASTUnit *Unit = nullptr,
       bool Persistent = true, StringRef ResourceFilesPath = StringRef(),
@@ -789,6 +797,7 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
       bool OnlyLocalDecls = false,
       CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
@@ -837,6 +846,7 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCommandLine(
       const char **ArgBegin, const char **ArgEnd,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
       bool StorePreamblesInMemory = false,
       StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false,
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 5f25a932c5052..0ae490f0e8073 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -674,7 +674,7 @@ class CompilerInstance : public ModuleLoader {
   ///
   /// \return The new object on success, or null on failure.
   static IntrusiveRefCntPtr<DiagnosticsEngine>
-  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
+  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
                     DiagnosticConsumer *Client = nullptr,
                     bool ShouldOwnClient = true,
                     const CodeGenOptions *CodeGenOpts = nullptr);
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 3ca900729b4a8..e147d2ba6087e 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -80,7 +80,7 @@ class CompilerInvocationBase {
   std::shared_ptr<TargetOptions> TargetOpts;
 
   /// Options controlling the diagnostic engine.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
+  std::shared_ptr<DiagnosticOptions> DiagnosticOpts;
 
   /// Options controlling the \#include directive.
   std::shared_ptr<HeaderSearchOptions> HSOpts;
diff --git a/clang/include/clang/Frontend/DiagnosticRenderer.h b/clang/include/clang/Frontend/DiagnosticRenderer.h
index b939ebe979e71..3f03a6e02da4b 100644
--- a/clang/include/clang/Frontend/DiagnosticRenderer.h
+++ b/clang/include/clang/Frontend/DiagnosticRenderer.h
@@ -47,7 +47,7 @@ using DiagOrStoredDiag =
 class DiagnosticRenderer {
 protected:
   const LangOptions &LangOpts;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// The location of the previous diagnostic if known.
   ///
@@ -68,8 +68,7 @@ class DiagnosticRenderer {
   /// which change the amount of information displayed.
   DiagnosticsEngine::Level LastLevel = DiagnosticsEngine::Ignored;
 
-  DiagnosticRenderer(const LangOptions &LangOpts,
-                     DiagnosticOptions *DiagOpts);
+  DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts);
 
   virtual ~DiagnosticRenderer();
 
@@ -142,7 +141,7 @@ class DiagnosticRenderer {
 class DiagnosticNoteRenderer : public DiagnosticRenderer {
 public:
   DiagnosticNoteRenderer(const LangOptions &LangOpts,
-                         DiagnosticOptions *DiagOpts)
+                         DiagnosticOptions &DiagOpts)
       : DiagnosticRenderer(LangOpts, DiagOpts) {}
 
   ~DiagnosticNoteRenderer() override;
diff --git a/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
index ec22a8b6cc5fb..b43b0da13967a 100644
--- a/clang/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -51,7 +51,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
   std::unique_ptr<raw_ostream> StreamOwner;
   const LangOptions *LangOpts;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   SourceLocation LastWarningLoc;
   FullSourceLoc LastLoc;
@@ -62,7 +62,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   std::string DwarfDebugFlags;
 
 public:
-  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
+  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts,
                        std::unique_ptr<raw_ostream> StreamOwner);
 
   void setDwarfDebugFlags(StringRef Value) {
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index ec1d0b8e6a7c9..780f36c874109 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -23,7 +23,7 @@ namespace clang {
 class SARIFDiagnostic : public DiagnosticRenderer {
 public:
   SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                  DiagnosticOptions *DiagOpts, SarifDocumentWriter *Writer);
+                  DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer);
 
   ~SARIFDiagnostic() = default;
 
diff --git a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
index f2652833b3c18..3406ed16c2fba 100644
--- a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
@@ -29,7 +29,7 @@ class SarifDocumentWriter;
 
 class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 public:
-  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags);
+  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts);
   ~SARIFDiagnosticPrinter() = default;
 
   SARIFDiagnosticPrinter &operator=(const SARIFDiagnosticPrinter &&) = delete;
@@ -60,7 +60,7 @@ class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 
 private:
   raw_ostream &OS;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// Handle to the currently active SARIF diagnostic emitter.
   std::unique_ptr<SARIFDiagnostic> SARIFDiag;
diff --git a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
index 5586ef65e393f..2b6d2e4477d58 100644
--- a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -32,7 +32,7 @@ namespace serialized_diags {
 /// (via libclang) without needing to parse Clang's command line output.
 ///
 std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
-                                           DiagnosticOptions *Diags,
+                                           DiagnosticOptions &DiagOpts,
                                            bool MergeChildRecords = false);
 
 } // end serialized_diags namespace
diff --git a/clang/include/clang/Frontend/TextDiagnostic.h b/clang/include/clang/Frontend/TextDiagnostic.h
index a2fe8ae995423..e2e88d4d648a2 100644
--- a/clang/include/clang/Frontend/TextDiagnostic.h
+++ b/clang/include/clang/Frontend/TextDiagnostic.h
@@ -38,7 +38,7 @@ class TextDiagnostic : public DiagnosticRenderer {
 
 public:
   TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                 DiagnosticOptions *DiagOpts, const Preprocessor *PP = nullptr);
+                 DiagnosticOptions &DiagOpts, const Preprocessor *PP = nullptr);
 
   ~TextDiagnostic() override;
 
diff --git a/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
index 2610bde7513a1..dd1ca6b2248b7 100644
--- a/clang/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -26,7 +26,7 @@ class TextDiagnostic;
 
 class TextDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// Handle to the currently active text diagnostic emitter.
   std::unique_ptr<TextDiagnostic> TextDiag;
@@ -38,7 +38,7 @@ class TextDiagnosticPrinter : public DiagnosticConsumer {
   unsigned OwnsOutputStream : 1;
 
 public:
-  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
+  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions &DiagOpts,
                         bool OwnsOutputStream = false);
   ~TextDiagnosticPrinter() override;
 
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 57b0266af26bb..6963611c6a815 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -151,9 +151,8 @@ class ASTReaderListener {
   ///
   /// \returns true to indicate the diagnostic options are invalid, or false
   /// otherwise.
-  virtual bool
-  ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
-                        StringRef ModuleFilename, bool Complain) {
+  virtual bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+                                     StringRef ModuleFilename, bool Complain) {
     return false;
   }
 
@@ -285,7 +284,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadFileSystemOptions(const FileSystemOptions &FSOpts,
                              bool Complain) override;
@@ -326,7 +325,7 @@ class PCHValidator : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
                                StringRef ModuleFilename, bool ReadMacros,
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index b48eed8650672..22821418c7078 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -77,11 +77,11 @@ DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
   Output.append(Str.begin(), Str.end());
 }
 
-DiagnosticsEngine::DiagnosticsEngine(
-    IntrusiveRefCntPtr<DiagnosticIDs> diags,
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
-    bool ShouldOwnClient)
-    : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
+DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
+                                     DiagnosticOptions &DiagOpts,
+                                     DiagnosticConsumer *client,
+                                     bool ShouldOwnClient)
+    : Diags(std::move(diags)), DiagOpts(DiagOpts) {
   setClient(client, ShouldOwnClient);
   ArgToStringFn = DummyArgToStringFn;
 
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 4028bbf060364..09e5c6547fb51 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2391,11 +2391,11 @@ SourceManagerForFile::SourceManagerForFile(StringRef FileName,
   // in `Environment` so that `FileMgr` can out-live this function scope.
   FileMgr =
       std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
+  DiagOpts = std::make_unique<DiagnosticOptions>();
   // This is passed to `SM` as reference, so the pointer has to be referenced
   // by `Environment` due to the same reason above.
   Diagnostics = std::make_unique<DiagnosticsEngine>(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), *DiagOpts);
   SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr);
   FileEntryRef FE = llvm::cantFail(FileMgr->getFileRef(FileName));
   FileID ID =
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index ef395f497216c..6d0f042d5accd 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -560,15 +560,15 @@ CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
 
 CrossTranslationUnitContext::LoadResultTy
 CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, *DiagOpts, DiagClient));
   return ASTUnit::LoadFromASTFile(
       ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
+      ASTUnit::LoadEverything, DiagOpts, Diags, CI.getFileSystemOpts(),
       CI.getHeaderSearchOpts());
 }
 
@@ -603,17 +603,17 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource(
                  CommandLineArgs.begin(),
                  [](auto &&CmdPart) { return CmdPart.c_str(); });
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
+  auto DiagOpts = std::make_shared<DiagnosticOptions>(CI.getDiagnosticOpts());
   auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
       CI.getDiagnostics().getDiagnosticIDs()};
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
+      new DiagnosticsEngine{DiagID, *DiagOpts, DiagClient});
 
-  return ASTUnit::LoadFromCommandLine(CommandLineArgs.begin(),
-                                      (CommandLineArgs.end()),
-                                      CI.getPCHContainerOperations(), Diags,
-                                      CI.getHeaderSearchOpts().ResourceDir);
+  return ASTUnit::LoadFromCommandLine(
+      CommandLineArgs.begin(), (CommandLineArgs.end()),
+      CI.getPCHContainerOperations(), DiagOpts, Diags,
+      CI.getHeaderSearchOpts().ResourceDir);
 }
 
 llvm::Expected<InvocationListTy>
diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp
index b6b06440bc3f8..a4ce88351e28e 100644
--- a/clang/lib/Frontend/ASTMerge.cpp
+++ b/clang/lib/Frontend/ASTMerge.cpp
@@ -41,14 +41,13 @@ void ASTMergeAction::ExecuteAction() {
   auto SharedState = std::make_shared<ASTImporterSharedState>(
       *CI.getASTContext().getTranslationUnitDecl());
   for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
-    IntrusiveRefCntPtr<DiagnosticsEngine>
-        Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(),
-                                    new ForwardingDiagnosticConsumer(
-                                          *CI.getDiagnostics().getClient()),
-                                    /*ShouldOwnClient=*/true));
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+        DiagIDs, CI.getDiagnosticOpts(),
+        new ForwardingDiagnosticConsumer(*CI.getDiagnostics().getClient()),
+        /*ShouldOwnClient=*/true));
     std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
-        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
-        CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything,
+        nullptr, Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
 
     if (!Unit)
       continue;
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 5a79fe070c384..457043c6bd7ce 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -803,7 +803,8 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
 
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
     StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-    WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+    WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
     const FileSystemOptions &FileSystemOpts, const HeaderSearchOptions &HSOpts,
     const LangOptions *LangOpts, bool OnlyLocalDecls,
     CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors,
@@ -823,6 +824,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
                            : std::make_unique<LangOptions>();
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileMgr = new FileManager(FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
@@ -1534,6 +1536,7 @@ StringRef ASTUnit::getASTFileName() const {
 
 std::unique_ptr<ASTUnit>
 ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
+                std::shared_ptr<DiagnosticOptions> DiagOpts,
                 IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
                 CaptureDiagsKind CaptureDiagnostics,
                 bool UserFilesAreVolatile) {
@@ -1541,6 +1544,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       createVFSFromCompilerInvocation(*CI, *Diags);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   AST->Invocation = std::move(CI);
@@ -1556,6 +1560,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
 ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FrontendAction *Action,
     ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1567,7 +1572,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
   ASTUnit *AST = Unit;
   if (!AST) {
     // Create the AST unit.
-    OwnAST = create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile);
+    OwnAST =
+        create(CI, DiagOpts, Diags, CaptureDiagnostics, UserFilesAreVolatile);
     AST = OwnAST.get();
     if (!AST)
       return nullptr;
@@ -1729,6 +1735,7 @@ bool ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
     unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
@@ -1737,6 +1744,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1766,6 +1774,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
     const char **ArgBegin, const char **ArgEnd,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
     bool StorePreamblesInMemory, StringRef PreambleStoragePath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1828,6 +1837,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
   AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
   AST->StoredDiagnostics.swap(StoredDiagnostics);
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 95b0ed248d545..f9a398dbfb90f 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -117,10 +117,10 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
 
     TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
+        new TextDiagnosticPrinter(llvm::errs(), CI.getDiagnosticOpts());
     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
+        new DiagnosticsEngine(DiagID, CI.getDiagnosticOpts(), DiagClient));
 
     auto Clang = std::make_unique<CompilerInstance>(
         std::move(CInvok), CI.getPCHContainerOperations());
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 503d36467653e..cc39049167687 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -280,20 +280,20 @@ static void collectVFSEntries(CompilerInstance &CI,
 }
 
 // Diagnostics
-static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
+static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts,
                                const CodeGenOptions *CodeGenOpts,
                                DiagnosticsEngine &Diags) {
   std::error_code EC;
   std::unique_ptr<raw_ostream> StreamOwner;
   raw_ostream *OS = &llvm::errs();
-  if (DiagOpts->DiagnosticLogFile != "-") {
+  if (DiagOpts.DiagnosticLogFile != "-") {
     // Create the output stream.
     auto FileOS = std::make_unique<llvm::raw_fd_ostream>(
-        DiagOpts->DiagnosticLogFile, EC,
+        DiagOpts.DiagnosticLogFile, EC,
         llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
     if (EC) {
       Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
-          << DiagOpts->DiagnosticLogFile << EC.message();
+          << DiagOpts.DiagnosticLogFile << EC.message();
     } else {
       FileOS->SetUnbuffered();
       OS = FileOS.get();
@@ -315,7 +315,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
   }
 }
 
-static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
+static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts,
                                        DiagnosticsEngine &Diags,
                                        StringRef OutputFile) {
   auto SerializedConsumer =
@@ -333,12 +333,12 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
 void CompilerInstance::createDiagnostics(llvm::vfs::FileSystem &VFS,
                                          DiagnosticConsumer *Client,
                                          bool ShouldOwnClient) {
-  Diagnostics = createDiagnostics(VFS, &getDiagnosticOpts(), Client,
+  Diagnostics = createDiagnostics(VFS, getDiagnosticOpts(), Client,
                                   ShouldOwnClient, &getCodeGenOpts());
 }
 
 IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
-    llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
+    llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
     DiagnosticConsumer *Client, bool ShouldOwnClient,
     const CodeGenOptions *CodeGenOpts) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -349,25 +349,24 @@ IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
   // implementing -verify.
   if (Client) {
     Diags->setClient(Client, ShouldOwnClient);
-  } else if (Opts->getFormat() == DiagnosticOptions::SARIF) {
+  } else if (Opts.getFormat() == DiagnosticOptions::SARIF) {
     Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts));
   } else
     Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
 
   // Chain in -verify checker, if requested.
-  if (Opts->VerifyDiagnostics)
+  if (Opts.VerifyDiagnostics)
     Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
 
   // Chain in -diagnostic-log-file dumper, if requested.
-  if (!Opts->DiagnosticLogFile.empty())
+  if (!Opts.DiagnosticLogFile.empty())
     SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
 
-  if (!Opts->DiagnosticSerializationFile.empty())
-    SetupSerializedDiagnostics(Opts, *Diags,
-                               Opts->DiagnosticSerializationFile);
+  if (!Opts.DiagnosticSerializationFile.empty())
+    SetupSerializedDiagnostics(Opts, *Diags, Opts.DiagnosticSerializationFile);
 
   // Configure our handling of diagnostics.
-  ProcessWarningOptions(*Diags, *Opts, VFS);
+  ProcessWarningOptions(*Diags, Opts, VFS);
 
   return Diags;
 }
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 3c23073fc6a8c..9c33910eff57e 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -125,21 +125,14 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
 // Initialization.
 //===----------------------------------------------------------------------===//
 
-namespace {
 template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
   return std::make_shared<T>(X);
 }
 
-template <class T>
-llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
-  return llvm::makeIntrusiveRefCnt<T>(X);
-}
-} // namespace
-
 CompilerInvocationBase::CompilerInvocationBase()
     : LangOpts(std::make_shared<LangOptions>()),
       TargetOpts(std::make_shared<TargetOptions>()),
-      DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
+      DiagnosticOpts(std::make_shared<DiagnosticOptions>()),
       HSOpts(std::make_shared<HeaderSearchOptions>()),
       PPOpts(std::make_shared<PreprocessorOptions>()),
       AnalyzerOpts(std::make_shared<AnalyzerOptions>()),
@@ -156,7 +149,7 @@ CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
   if (this != &X) {
     LangOpts = make_shared_copy(X.getLangOpts());
     TargetOpts = make_shared_copy(X.getTargetOpts());
-    DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
+    DiagnosticOpts = make_shared_copy(X.getDiagnosticOpts());
     HSOpts = make_shared_copy(X.getHeaderSearchOpts());
     PPOpts = make_shared_copy(X.getPreprocessorOpts());
     AnalyzerOpts = make_shared_copy(X.getAnalyzerOpts());
@@ -202,7 +195,6 @@ CompilerInvocation::operator=(const CowCompilerInvocation &X) {
   return *this;
 }
 
-namespace {
 template <typename T>
 T &ensureOwned(std::shared_ptr<T> &Storage) {
   if (Storage.use_count() > 1)
@@ -210,14 +202,6 @@ T &ensureOwned(std::shared_ptr<T> &Storage) {
   return *Storage;
 }
 
-template <typename T>
-T &ensureOwned(llvm::IntrusiveRefCntPtr<T> &Storage) {
-  if (Storage.useCount() > 1)
-    Storage = llvm::makeIntrusiveRefCnt<T>(*Storage);
-  return *Storage;
-}
-} // namespace
-
 LangOptions &CowCompilerInvocation::getMutLangOpts() {
   return ensureOwned(LangOpts);
 }
@@ -844,7 +828,8 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate,
   };
 
   // Setup a dummy DiagnosticsEngine.
-  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), new DiagnosticOptions());
+  DiagnosticOptions DummyDiagOpts;
+  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), DummyDiagOpts);
   DummyDiags.setClient(new TextDiagnosticBuffer());
 
   // Run the first parse on the original arguments with the dummy invocation and
@@ -2663,9 +2648,11 @@ clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) {
 bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                 DiagnosticsEngine *Diags,
                                 bool DefaultDiagColor) {
+  std::optional<DiagnosticOptions> IgnoringDiagOpts;
   std::optional<DiagnosticsEngine> IgnoringDiags;
   if (!Diags) {
-    IgnoringDiags.emplace(new DiagnosticIDs(), new DiagnosticOptions(),
+    IgnoringDiagOpts.emplace();
+    IgnoringDiags.emplace(new DiagnosticIDs(), *IgnoringDiagOpts,
                           new IgnoringDiagConsumer());
     Diags = &*IgnoringDiags;
   }
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index d0b855fff2534..99212b81fe064 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,11 +31,15 @@ std::unique_ptr<CompilerInvocation>
 clang::createInvocation(ArrayRef<const char *> ArgList,
                         CreateInvocationOptions Opts) {
   assert(!ArgList.empty());
-  auto Diags = Opts.Diags
-                   ? std::move(Opts.Diags)
-                   : CompilerInstance::createDiagnostics(
-                         Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(),
-                         new DiagnosticOptions);
+  std::optional<DiagnosticOptions> LocalDiagOpts;
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+  if (Opts.Diags) {
+    Diags = std::move(Opts.Diags);
+  } else {
+    LocalDiagOpts.emplace();
+    Diags = CompilerInstance::createDiagnostics(
+        Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(), *LocalDiagOpts);
+  }
 
   SmallVector<const char *, 16> Args(ArgList);
 
diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp
index 3b120abbc3a7a..1396b2bfbd151 100644
--- a/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -30,7 +30,7 @@
 using namespace clang;
 
 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
-                                       DiagnosticOptions *DiagOpts)
+                                       DiagnosticOptions &DiagOpts)
     : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
 
 DiagnosticRenderer::~DiagnosticRenderer() = default;
@@ -115,7 +115,7 @@ void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
     // Find the ultimate expansion location for the diagnostic.
     Loc = Loc.getFileLoc();
 
-    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
 
     // First, if this diagnostic is not in the main file, print out the
     // "included from" lines.
@@ -172,7 +172,7 @@ void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
 
   LastIncludeLoc = IncludeLoc;
 
-  if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+  if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
     return;
 
   if (IncludeLoc.isValid())
@@ -191,7 +191,7 @@ void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
   if (PLoc.isInvalid())
     return;
 
@@ -232,7 +232,7 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
 
   // Emit the other import frames first.
   std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
@@ -247,9 +247,8 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
   ModuleBuildStack Stack = SM.getModuleBuildStack();
   for (const auto &I : Stack) {
-    emitBuildingModuleLocation(I.second, I.second.getPresumedLoc(
-                                              DiagOpts->ShowPresumedLoc),
-                               I.first);
+    emitBuildingModuleLocation(
+        I.second, I.second.getPresumedLoc(DiagOpts.ShowPresumedLoc), I.first);
   }
 }
 
@@ -539,7 +538,7 @@ void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
                       LocationStack.begin() + IgnoredEnd);
 
   unsigned MacroDepth = LocationStack.size();
-  unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
+  unsigned MacroLimit = DiagOpts.MacroBacktraceLimit;
   if (MacroDepth <= MacroLimit || MacroLimit == 0) {
     for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
          I != E; ++I)
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 54a2e3eb297f5..af9d18ab66108 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -766,9 +766,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
 
     // The AST unit populates its own diagnostics engine rather than ours.
-    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
-        new DiagnosticsEngine(Diags->getDiagnosticIDs(),
-                              &Diags->getDiagnosticOptions()));
+    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine(
+        Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions()));
     ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
 
     // FIXME: What if the input is a memory buffer?
@@ -776,7 +775,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
         InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
-        ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        nullptr, ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
     if (!AST)
       return false;
 
@@ -842,8 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     StringRef InputFile = Input.getFile();
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
-        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
-        CI.getFileSystemOpts(), CI.getHeaderSearchOpts(), &CI.getLangOpts());
+        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, nullptr,
+        Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts(),
+        &CI.getLangOpts());
 
     if (!AST)
       return false;
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 8c75e1a46da54..d14d091e3fe38 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -685,21 +685,21 @@ namespace {
       return false;
     }
 
-    bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+    bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                                StringRef ModuleFilename,
                                bool Complain) override {
       Out.indent(2) << "Diagnostic options:\n";
-#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
-      Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
-#define VALUE_DIAGOPT(Name, Bits, Default) \
-      Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
+#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts.Name, #Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default)                              \
+    Out.indent(4) << #Name << ": " << DiagOpts.get##Name() << "\n";
+#define VALUE_DIAGOPT(Name, Bits, Default)                                   \
+    Out.indent(4) << #Name << ": " << DiagOpts.Name << "\n";
 #include "clang/Basic/DiagnosticOptions.def"
 
       Out.indent(4) << "Diagnostic flags:\n";
-      for (const std::string &Warning : DiagOpts->Warnings)
+      for (const std::string &Warning : DiagOpts.Warnings)
         Out.indent(6) << "-W" << Warning << "\n";
-      for (const std::string &Remark : DiagOpts->Remarks)
+      for (const std::string &Remark : DiagOpts.Remarks)
         Out.indent(6) << "-R" << Remark << "\n";
 
       return false;
diff --git a/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 4e963af837f01..2d188931e4f8a 100644
--- a/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -18,10 +18,10 @@ using namespace clang;
 using namespace markup;
 
 LogDiagnosticPrinter::LogDiagnosticPrinter(
-    raw_ostream &os, DiagnosticOptions *diags,
+    raw_ostream &os, DiagnosticOptions &DiagOpts,
     std::unique_ptr<raw_ostream> StreamOwner)
     : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
-      DiagOpts(diags) {}
+      DiagOpts(DiagOpts) {}
 
 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
   switch (Level) {
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 4e36153ed5391..e2aec7f677f12 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -31,7 +31,7 @@
 namespace clang {
 
 SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                                 DiagnosticOptions *DiagOpts,
+                                 DiagnosticOptions &DiagOpts,
                                  SarifDocumentWriter *Writer)
     : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
@@ -163,7 +163,7 @@ SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
 
 llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
                                               const SourceManager &SM) {
-  if (DiagOpts->AbsolutePath) {
+  if (DiagOpts.AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
index 73928d19a031a..23fbc3e4fa92b 100644
--- a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -26,15 +26,15 @@
 namespace clang {
 
 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
-                                               DiagnosticOptions *Diags)
-    : OS(OS), DiagOpts(Diags) {}
+                                               DiagnosticOptions &DiagOpts)
+    : OS(OS), DiagOpts(DiagOpts) {}
 
 void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                              const Preprocessor *PP) {
   // Build the SARIFDiagnostic utility.
   assert(hasSarifWriter() && "Writer not set!");
   assert(!SARIFDiag && "SARIFDiagnostic already set.");
-  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, &*DiagOpts, &*Writer);
+  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, DiagOpts, &*Writer);
   // Initialize the SARIF object.
   Writer->createRun("clang", Prefix);
 }
@@ -72,7 +72,6 @@ void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   }
 
   // Assert that the rest of our infrastructure is setup properly.
-  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
 
diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 02aa3e8e4d984..ee49cdd84e79e 100644
--- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -57,8 +57,8 @@ class SDiagsRenderer : public DiagnosticNoteRenderer {
   SDiagsWriter &Writer;
 public:
   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
-                 DiagnosticOptions *DiagOpts)
-    : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+                 DiagnosticOptions &DiagOpts)
+      : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
   ~SDiagsRenderer() override {}
 
@@ -140,7 +140,7 @@ class SDiagsWriter : public DiagnosticConsumer {
         State(std::move(State)) {}
 
 public:
-  SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
+  SDiagsWriter(StringRef File, DiagnosticOptions &Diags, bool MergeChildRecords)
       : LangOpts(nullptr), OriginalInstance(true),
         MergeChildRecords(MergeChildRecords),
         State(std::make_shared<SharedState>(File, Diags)) {
@@ -242,12 +242,12 @@ class SDiagsWriter : public DiagnosticConsumer {
   /// State that is shared among the various clones of this diagnostic
   /// consumer.
   struct SharedState {
-    SharedState(StringRef File, DiagnosticOptions *Diags)
-        : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
+    SharedState(StringRef File, DiagnosticOptions &DiagOpts)
+        : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(File.str()),
           EmittedAnyDiagBlocks(false) {}
 
     /// Diagnostic options.
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+    DiagnosticOptions DiagOpts;
 
     /// The byte buffer for the serialized content.
     SmallString<1024> Buffer;
@@ -295,9 +295,11 @@ class SDiagsWriter : public DiagnosticConsumer {
 
 namespace clang {
 namespace serialized_diags {
-std::unique_ptr<DiagnosticConsumer>
-create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
-  return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
+std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
+                                           DiagnosticOptions &DiagOpts,
+                                           bool MergeChildRecords) {
+  return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
+                                        MergeChildRecords);
 }
 
 } // end namespace serialized_diags
@@ -617,7 +619,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 
   assert(Info.hasSourceManager() && LangOpts &&
          "Unexpected diagnostic with valid location outside of a source file");
-  SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
+  SDiagsRenderer Renderer(*this, *LangOpts, State->DiagOpts);
   Renderer.emitDiagnostic(
       FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
       State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
@@ -755,10 +757,9 @@ DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
   //    normally not be used.
   if (!State->MetaDiagnostics) {
     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
-    auto Client =
-        new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
-    State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
-        IDs, State->DiagOpts.get(), Client);
+    auto Client = new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
+    State->MetaDiagnostics =
+        std::make_unique<DiagnosticsEngine>(IDs, State->DiagOpts, Client);
   }
   return State->MetaDiagnostics.get();
 }
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 4119ce6048d45..25ab13b7ae6c2 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -654,7 +654,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns,
 }
 
 TextDiagnostic::TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                               DiagnosticOptions *DiagOpts,
+                               DiagnosticOptions &DiagOpts,
                                const Preprocessor *PP)
     : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS), PP(PP) {}
 
@@ -670,15 +670,15 @@ void TextDiagnostic::emitDiagnosticMessage(
   if (Loc.isValid())
     emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.resetColor();
 
-  if (DiagOpts->ShowLevel)
-    printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+  if (DiagOpts.ShowLevel)
+    printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
   printDiagnosticMessage(OS,
                          /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
                          Message, OS.tell() - StartOfLocationInfo,
-                         DiagOpts->MessageLength, DiagOpts->ShowColors);
+                         DiagOpts.MessageLength, DiagOpts.ShowColors);
 }
 
 /*static*/ void
@@ -743,7 +743,7 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
 #ifdef _WIN32
   SmallString<4096> TmpFilename;
 #endif
-  if (DiagOpts->AbsolutePath) {
+  if (DiagOpts.AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
@@ -796,27 +796,27 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
   }
   unsigned LineNo = PLoc.getLine();
 
-  if (!DiagOpts->ShowLocation)
+  if (!DiagOpts.ShowLocation)
     return;
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.changeColor(savedColor, true);
 
   emitFilename(PLoc.getFilename(), Loc.getManager());
-  switch (DiagOpts->getFormat()) {
+  switch (DiagOpts.getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
-    if (DiagOpts->ShowLine)
+    if (DiagOpts.ShowLine)
       OS << ':' << LineNo;
     break;
   case DiagnosticOptions::MSVC:  OS << '('  << LineNo; break;
   case DiagnosticOptions::Vi:    OS << " +" << LineNo; break;
   }
 
-  if (DiagOpts->ShowColumn)
+  if (DiagOpts.ShowColumn)
     // Compute the column number.
     if (unsigned ColNo = PLoc.getColumn()) {
-      if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
+      if (DiagOpts.getFormat() == DiagnosticOptions::MSVC) {
         OS << ',';
         // Visual Studio 2010 or earlier expects column number to be off by one
         if (LangOpts.MSCompatibilityVersion &&
@@ -826,7 +826,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
         OS << ':';
       OS << ColNo;
     }
-  switch (DiagOpts->getFormat()) {
+  switch (DiagOpts.getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
   case DiagnosticOptions::Vi:    OS << ':';    break;
@@ -841,7 +841,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
     break;
   }
 
-  if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
+  if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
     FileID CaretFileID = Loc.getExpansionLoc().getFileID();
     bool PrintedRange = false;
     const SourceManager &SM = Loc.getManager();
@@ -881,7 +881,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
 }
 
 void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
-  if (DiagOpts->ShowLocation && PLoc.isValid()) {
+  if (DiagOpts.ShowLocation && PLoc.isValid()) {
     OS << "In file included from ";
     emitFilename(PLoc.getFilename(), Loc.getManager());
     OS << ':' << PLoc.getLine() << ":\n";
@@ -891,7 +891,7 @@ void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
 
 void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                         StringRef ModuleName) {
-  if (DiagOpts->ShowLocation && PLoc.isValid())
+  if (DiagOpts.ShowLocation && PLoc.isValid())
     OS << "In module '" << ModuleName << "' imported from "
        << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -901,7 +901,7 @@ void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
 void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
                                                 PresumedLoc PLoc,
                                                 StringRef ModuleName) {
-  if (DiagOpts->ShowLocation && PLoc.isValid())
+  if (DiagOpts.ShowLocation && PLoc.isValid())
     OS << "While building module '" << ModuleName << "' imported from "
       << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -998,14 +998,13 @@ static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
   std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo, '~');
 }
 
-static std::string buildFixItInsertionLine(FileID FID,
-                                           unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
                                            const SourceColumnMap &map,
                                            ArrayRef<FixItHint> Hints,
                                            const SourceManager &SM,
-                                           const DiagnosticOptions *DiagOpts) {
+                                           const DiagnosticOptions &DiagOpts) {
   std::string FixItInsertionLine;
-  if (Hints.empty() || !DiagOpts->ShowFixits)
+  if (Hints.empty() || !DiagOpts.ShowFixits)
     return FixItInsertionLine;
   unsigned PrevHintEndCol = 0;
 
@@ -1057,7 +1056,7 @@ static std::string buildFixItInsertionLine(FileID FID,
     }
   }
 
-  expandTabs(FixItInsertionLine, DiagOpts->TabStop);
+  expandTabs(FixItInsertionLine, DiagOpts.TabStop);
 
   return FixItInsertionLine;
 }
@@ -1296,7 +1295,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // was part of a different warning or error diagnostic, or if the
   // diagnostic has ranges.  We don't want to emit the same caret
   // multiple times if one loc has multiple diagnostics.
-  if (!DiagOpts->ShowCarets)
+  if (!DiagOpts.ShowCarets)
     return;
   if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
       (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
@@ -1322,7 +1321,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     return;
 
   // Find the set of lines to include.
-  const unsigned MaxLines = DiagOpts->SnippetLineLimit;
+  const unsigned MaxLines = DiagOpts.SnippetLineLimit;
   std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
   unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
   for (const auto &I : Ranges) {
@@ -1338,7 +1337,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // Where [number] is MaxLineNoDisplayWidth columns
   // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
   unsigned MaxLineNoDisplayWidth =
-      DiagOpts->ShowLineNumbers
+      DiagOpts.ShowLineNumbers
           ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
           : 0;
   auto indentForLineNumbers = [&] {
@@ -1350,7 +1349,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // emit, starting from the first line.
   std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
       highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
-                     DiagOpts->ShowColors, FID, SM);
+                     DiagOpts.ShowColors, FID, SM);
 
   SmallVector<LineRange> LineRanges =
       prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
@@ -1382,7 +1381,7 @@ void TextDiagnostic::emitSnippetAndCaret(
       SourceLine.pop_back();
 
     // Build the byte to column map.
-    const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+    const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
 
     std::string CaretLine;
     // Highlight all of the characters covered by Ranges with ~ characters.
@@ -1398,12 +1397,12 @@ void TextDiagnostic::emitSnippetAndCaret(
       CaretLine[Col] = '^';
     }
 
-    std::string FixItInsertionLine = buildFixItInsertionLine(
-        FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
+    std::string FixItInsertionLine =
+        buildFixItInsertionLine(FID, LineNo, sourceColMap, Hints, SM, DiagOpts);
 
     // If the source line is too long for our terminal, select only the
     // "interesting" source region within that line.
-    unsigned Columns = DiagOpts->MessageLength;
+    unsigned Columns = DiagOpts.MessageLength;
     if (Columns)
       selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
                                     Columns, sourceColMap);
@@ -1412,7 +1411,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     // to produce easily machine parsable output.  Add a space before the
     // source line and the caret to make it trivial to tell the main diagnostic
     // line from what the user is intended to see.
-    if (DiagOpts->ShowSourceRanges && !SourceLine.empty()) {
+    if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
       SourceLine = ' ' + SourceLine;
       CaretLine = ' ' + CaretLine;
     }
@@ -1423,22 +1422,22 @@ void TextDiagnostic::emitSnippetAndCaret(
 
     if (!CaretLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.changeColor(caretColor, true);
       OS << CaretLine << '\n';
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.resetColor();
     }
 
     if (!FixItInsertionLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         // Print fixit line in color
         OS.changeColor(fixitColor, false);
-      if (DiagOpts->ShowSourceRanges)
+      if (DiagOpts.ShowSourceRanges)
         OS << ' ';
       OS << FixItInsertionLine << '\n';
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.resetColor();
     }
   }
@@ -1464,10 +1463,10 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
   size_t I = 0;
   while (I < SourceLine.size()) {
     auto [Str, WasPrintable] =
-        printableTextForNextCharacter(SourceLine, &I, DiagOpts->TabStop);
+        printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
 
     // Toggle inverted colors on or off for this character.
-    if (DiagOpts->ShowColors) {
+    if (DiagOpts.ShowColors) {
       if (WasPrintable == PrintReversed) {
         PrintReversed = !PrintReversed;
         if (PrintReversed)
@@ -1498,7 +1497,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
     OS << Str;
   }
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.resetColor();
 
   OS << '\n';
@@ -1506,7 +1505,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
 
 void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
                                          const SourceManager &SM) {
-  if (!DiagOpts->ShowParseableFixits)
+  if (!DiagOpts.ShowParseableFixits)
     return;
 
   // We follow FixItRewriter's example in not (yet) handling
diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 28f7218dc23f5..e878c630fa01d 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -22,11 +22,9 @@
 using namespace clang;
 
 TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
-                                             DiagnosticOptions *diags,
+                                             DiagnosticOptions &DiagOpts,
                                              bool _OwnsOutputStream)
-  : OS(os), DiagOpts(diags),
-    OwnsOutputStream(_OwnsOutputStream) {
-}
+    : OS(os), DiagOpts(DiagOpts), OwnsOutputStream(_OwnsOutputStream) {}
 
 TextDiagnosticPrinter::~TextDiagnosticPrinter() {
   if (OwnsOutputStream)
@@ -36,7 +34,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
 void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                             const Preprocessor *PP) {
   // Build the TextDiagnostic utility.
-  TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts, PP));
+  TextDiag.reset(new TextDiagnostic(OS, LO, DiagOpts, PP));
 }
 
 void TextDiagnosticPrinter::EndSourceFile() {
@@ -121,7 +119,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   Info.FormatDiagnostic(OutStr);
 
   llvm::raw_svector_ostream DiagMessageStream(OutStr);
-  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
+  printDiagnosticOptions(DiagMessageStream, Level, Info, DiagOpts);
 
   // Keeps track of the starting position of the location
   // information (e.g., "foo.c:10:4:") that precedes the error
@@ -137,17 +135,16 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   // diagnostics in a context that lacks language options, a source manager, or
   // other infrastructure necessary when emitting more rich diagnostics.
   if (!Info.getLocation().isValid()) {
-    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
     TextDiagnostic::printDiagnosticMessage(
         OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note,
         DiagMessageStream.str(), OS.tell() - StartOfLocationInfo,
-        DiagOpts->MessageLength, DiagOpts->ShowColors);
+        DiagOpts.MessageLength, DiagOpts.ShowColors);
     OS.flush();
     return;
   }
 
   // Assert that the rest of our infrastructure is setup properly.
-  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
   assert(TextDiag && "Unexpected diagnostic outside source file processing");
diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp
index aa90663538128..dac38887cd0a1 100644
--- a/clang/lib/Interpreter/CodeCompletion.cpp
+++ b/clang/lib/Interpreter/CodeCompletion.cpp
@@ -359,13 +359,12 @@ void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI,
                                      unsigned Col,
                                      const CompilerInstance *ParentCI,
                                      std::vector<std::string> &CCResults) {
-  auto DiagOpts = DiagnosticOptions();
   auto consumer = ReplCompletionConsumer(CCResults, *this);
 
   auto diag = InterpCI->getDiagnosticsPtr();
   std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
       InterpCI->getInvocationPtr(), std::make_shared<PCHContainerOperations>(),
-      diag));
+      nullptr, diag));
   llvm::SmallVector<clang::StoredDiagnostic, 8> sd = {};
   llvm::SmallVector<const llvm::MemoryBuffer *, 1> tb = {};
   InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile(
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 4b407a0172adb..84feff82c63a7 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -95,9 +95,9 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
 
   // Buffer diagnostics from argument parsing so that we can output them using
   // a well formed diagnostic object.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
   bool Success = CompilerInvocation::CreateFromArgs(
       Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
 
@@ -173,10 +173,10 @@ IncrementalCompilerBuilder::create(std::string TT,
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+  std::unique_ptr<DiagnosticOptions> DiagOpts =
       CreateAndPopulateDiagOpts(ClangArgv);
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagsBuffer);
 
   driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
   Driver.setCheckInputsExist(false); // the input comes from mem buffers
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index c75835df2c98e..1829a4ff3504a 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -636,8 +636,8 @@ static void HighlightMacrosImpl(
   // Temporarily change the diagnostics object so that we ignore any generated
   // diagnostics from this pass.
   DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
-                             &PP.getDiagnostics().getDiagnosticOptions(),
-                      new IgnoringDiagConsumer);
+                             PP.getDiagnostics().getDiagnosticOptions(),
+                             new IgnoringDiagConsumer);
 
   // FIXME: This is a huge hack; we reuse the input preprocessor because we want
   // its state, but we aren't actually changing it (we hope). This should really
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d068f5e163176..c113fd7cbb911 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -193,8 +193,7 @@ bool ChainedASTReaderListener::ReadTargetOptions(
 }
 
 bool ChainedASTReaderListener::ReadDiagnosticOptions(
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
-    bool Complain) {
+    DiagnosticOptions &DiagOpts, StringRef ModuleFilename, bool Complain) {
   return First->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain) ||
          Second->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
@@ -595,16 +594,16 @@ static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr,
   return M;
 }
 
-bool PCHValidator::ReadDiagnosticOptions(
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
-    bool Complain) {
+bool PCHValidator::ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+                                         StringRef ModuleFilename,
+                                         bool Complain) {
   DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
+      new DiagnosticsEngine(DiagIDs, DiagOpts));
   // This should never fail, because we would have processed these options
   // before writing them to an ASTFile.
-  ProcessWarningOptions(*Diags, *DiagOpts,
+  ProcessWarningOptions(*Diags, DiagOpts,
                         PP.getFileManager().getVirtualFileSystem(),
                         /*Report*/ false);
 
@@ -6422,17 +6421,17 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
 bool ASTReader::ParseDiagnosticOptions(const RecordData &Record,
                                        StringRef ModuleFilename, bool Complain,
                                        ASTReaderListener &Listener) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
   unsigned Idx = 0;
-#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
-  DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
+#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default)                                \
+  DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
 #include "clang/Basic/DiagnosticOptions.def"
 
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts->Warnings.push_back(ReadString(Record, Idx));
+    DiagOpts.Warnings.push_back(ReadString(Record, Idx));
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts->Remarks.push_back(ReadString(Record, Idx));
+    DiagOpts.Remarks.push_back(ReadString(Record, Idx));
 
   return Listener.ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index 748f59b856e83..b59a8d55129de 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -44,7 +44,7 @@ class StoreDiagnostics : public DiagnosticConsumer {
       std::string Text;
       llvm::raw_string_ostream OS(Text);
       TextDiagnostic Renderer(OS, LangOpts,
-                              &Info.getDiags()->getDiagnosticOptions());
+                              Info.getDiags()->getDiagnosticOptions());
       Renderer.emitStoredDiagnostic(Out.back());
       ADD_FAILURE() << Text;
     }
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index af18194ae0fe4..09596b9799833 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -243,13 +243,13 @@ std::string GetClangToolCommand() {
 static bool stripPositionalArgs(std::vector<const char *> Args,
                                 std::vector<std::string> &Result,
                                 std::string &ErrorMsg) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   llvm::raw_string_ostream Output(ErrorMsg);
-  TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(Output, DiagOpts);
   UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagClient, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      &DiagClient, false);
 
   // The clang executable path isn't required since the jobs the driver builds
   // will not be executed.
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index 92e9859ca206e..9e2582ee53c59 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -585,9 +585,9 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
   SourceManager SourceMgr(Diagnostics, Files);
   Rewriter Rewrite(SourceMgr, LangOptions());
   InMemoryFileSystem->addFile(
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 21eea72b198b3..207b0a96aaf27 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -642,7 +642,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, TUBuffer))
@@ -660,7 +660,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, ModuleName))
@@ -744,7 +744,7 @@ bool DependencyScanningWorker::scanDependencies(
   sanitizeDiagOpts(*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(FileMgr->getVirtualFileSystem(),
-                                          DiagOpts.release(), &DC,
+                                          *DiagOpts, &DC,
                                           /*ShouldOwnClient=*/false);
 
   // Although `Diagnostics` are used only for command-line parsing, the
diff --git a/clang/lib/Tooling/Refactoring.cpp b/clang/lib/Tooling/Refactoring.cpp
index 961fc1c180154..874d44ff6731c 100644
--- a/clang/lib/Tooling/Refactoring.cpp
+++ b/clang/lib/Tooling/Refactoring.cpp
@@ -39,11 +39,11 @@ int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
   }
 
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagnosticPrinter, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      &DiagnosticPrinter, false);
   SourceManager Sources(Diagnostics, getFiles());
   Rewriter Rewrite(Sources, DefaultLangOptions);
 
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 3c72f52040142..1abd7c7adb127 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -377,17 +377,17 @@ bool ToolInvocation::run() {
 
   // Parse diagnostic options from the driver command-line only if none were
   // explicitly set.
-  IntrusiveRefCntPtr<DiagnosticOptions> ParsedDiagOpts;
+  std::unique_ptr<DiagnosticOptions> ParsedDiagOpts;
   DiagnosticOptions *DiagOpts = this->DiagOpts;
   if (!DiagOpts) {
     ParsedDiagOpts = CreateAndPopulateDiagOpts(Argv);
     DiagOpts = &*ParsedDiagOpts;
   }
 
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), *DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics =
       CompilerInstance::createDiagnostics(
-          Files->getVirtualFileSystem(), &*DiagOpts,
+          Files->getVirtualFileSystem(), *DiagOpts,
           DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
   // Although `Diagnostics` are used only for command-line parsing, the custom
   // `DiagConsumer` might expect a `SourceManager` to be present.
@@ -652,9 +652,9 @@ class ASTBuilderAction : public ToolAction {
                      std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                      DiagnosticConsumer *DiagConsumer) override {
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        Invocation, std::move(PCHContainerOps),
+        Invocation, std::move(PCHContainerOps), nullptr,
         CompilerInstance::createDiagnostics(Files->getVirtualFileSystem(),
-                                            &Invocation->getDiagnosticOpts(),
+                                            Invocation->getDiagnosticOpts(),
                                             DiagConsumer,
                                             /*ShouldOwnClient=*/false),
         Files);
diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp
index 8d023a0b22121..25104304322d4 100644
--- a/clang/tools/c-index-test/core_main.cpp
+++ b/clang/tools/c-index-test/core_main.cpp
@@ -220,9 +220,10 @@ static bool printSourceSymbols(const char *Executable,
   SmallVector<const char *, 4> ArgsWithProgName;
   ArgsWithProgName.push_back(Executable);
   ArgsWithProgName.append(Args.begin(), Args.end());
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions));
+                                          *DiagOpts));
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
@@ -241,7 +242,7 @@ static bool printSourceSymbols(const char *Executable,
 
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
+      std::move(CInvok), PCHContainerOps, DiagOpts, Diags, IndexAction.get()));
 
   if (!Unit)
     return true;
@@ -274,15 +275,16 @@ static bool printSourceSymbolsFromModule(StringRef modulePath,
 
   HeaderSearchOptions HSOpts;
 
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
-  std::unique_ptr<ASTUnit> AU =
-      ASTUnit::LoadFromASTFile(modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
-                               FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
-                               /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
-                               /*AllowASTWithCompilerErrors=*/true,
-                               /*UserFilesAreVolatile=*/false);
+                                          *DiagOpts);
+  std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+      modulePath, *pchRdr, ASTUnit::LoadASTOnly, DiagOpts, Diags,
+      FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
+      /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
+      /*AllowASTWithCompilerErrors=*/true,
+      /*UserFilesAreVolatile=*/false);
   if (!AU) {
     errs() << "failed to create TU for: " << modulePath << '\n';
     return true;
diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index ff684d20c150c..0b621b849e92f 100644
--- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -123,21 +123,21 @@ static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
 
 static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
 
-IntrusiveRefCntPtr<DiagnosticsEngine> GetDiagnosticsEngine() {
+IntrusiveRefCntPtr<DiagnosticsEngine>
+GetDiagnosticsEngine(DiagnosticOptions &DiagOpts) {
   if (Diags) {
     // Call reset to make sure we don't mix errors
     Diags->Reset(false);
     return Diags;
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
   DiagClient->setPrefix("clang-extdef-mappping");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
   IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
-      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, DiagOpts, DiagClient));
   Diags.swap(DiagEngine);
 
   // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile
@@ -152,11 +152,13 @@ static bool HandleAST(StringRef AstPath) {
   if (!CI)
     CI = new CompilerInstance();
 
-  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine = GetDiagnosticsEngine();
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
+  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine =
+      GetDiagnosticsEngine(*DiagOpts);
 
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
       AstPath, CI->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts(),
+      ASTUnit::LoadASTOnly, DiagOpts, DiagEngine, CI->getFileSystemOpts(),
       CI->getHeaderSearchOpts());
 
   if (!Unit)
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index e40e04eac5472..b22d3aaf3183b 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -240,9 +240,9 @@ static bool fillRanges(MemoryBuffer *Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
   SourceManager Sources(Diagnostics, Files);
   FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
                                  InMemoryFileSystem.get());
@@ -519,10 +519,10 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
         new llvm::vfs::InMemoryFileSystem);
     FileManager Files(FileSystemOptions(), InMemoryFileSystem);
 
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+    DiagnosticOptions DiagOpts;
     ClangFormatDiagConsumer IgnoreDiagnostics;
     DiagnosticsEngine Diagnostics(
-        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
         &IgnoreDiagnostics, false);
     SourceManager Sources(Diagnostics, Files);
     FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 765f342947046..aefc2f5728eda 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -162,10 +162,10 @@ class TestDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions DiagOpts;
   auto DC = std::make_unique<TestDiagnosticConsumer>();
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), DiagOpts.get(), DC.get(),
+      *llvm::vfs::getRealFileSystem(), DiagOpts, DC.get(),
       /*ShouldOwnClient=*/false);
 
   auto Inv = std::make_unique<CompilerInvocation>();
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index 14e7b53d74b09..f68236abaa6c9 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -70,16 +70,16 @@ static bool runFrontend(StringRef ProgName, Twine Label, bool Verbose,
 
 static bool run(ArrayRef<const char *> Args, const char *ProgName) {
   // Setup Diagnostics engine.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   const llvm::opt::OptTable &ClangOpts = clang::driver::getDriverOptTable();
   unsigned MissingArgIndex, MissingArgCount;
   llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(
       ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);
-  ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
+  ParseDiagnosticArgs(DiagOpts, ParsedArgs);
 
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag = new clang::DiagnosticsEngine(
-      new clang::DiagnosticIDs(), DiagOpts.get(),
-      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
+      new clang::DiagnosticIDs(), DiagOpts,
+      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts));
 
   // Create file manager for all file operations and holding in-memory generated
   // inputs.
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 3b42267f4d5f4..c17eb9dcadfd7 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -452,11 +452,11 @@ class FullDeps {
   // Returns \c true if any command lines fail to round-trip. We expect
   // commands already be canonical when output by the scanner.
   bool roundTripCommands(raw_ostream &ErrOS) {
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions{};
-    TextDiagnosticPrinter DiagConsumer(ErrOS, &*DiagOpts);
+    DiagnosticOptions DiagOpts;
+    TextDiagnosticPrinter DiagConsumer(ErrOS, DiagOpts);
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
         CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                            &*DiagOpts, &DiagConsumer,
+                                            DiagOpts, &DiagConsumer,
                                             /*ShouldOwnClient=*/false);
 
     for (auto &&M : Modules)
@@ -779,9 +779,10 @@ getCompilationDatabase(int argc, char **argv, std::string &ErrorMessage) {
         CompilationDB, ErrorMessage,
         tooling::JSONCommandLineSyntax::AutoDetect);
 
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions);
+                                          DiagOpts);
   driver::Driver TheDriver(CommandLine[0], llvm::sys::getDefaultTargetTriple(),
                            *Diags);
   TheDriver.setCheckInputsExist(false);
diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp
index 1f32f791de082..0d1455d270436 100644
--- a/clang/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp
@@ -56,6 +56,7 @@ static char getCharForLevel(DiagnosticsEngine::Level Level) {
 static IntrusiveRefCntPtr<DiagnosticsEngine>
 createDiagnostics(unsigned int argc, char **argv) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+  DiagnosticOptions DiagOpts;
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
@@ -66,8 +67,7 @@ createDiagnostics(unsigned int argc, char **argv) {
   Args.push_back("diagtool");
   Args.append(argv, argv + argc);
   CreateInvocationOptions CIOpts;
-  CIOpts.Diags =
-      new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer);
+  CIOpts.Diags = new DiagnosticsEngine(DiagIDs, DiagOpts, DiagsBuffer);
   std::unique_ptr<CompilerInvocation> Invocation =
       createInvocation(Args, CIOpts);
   if (!Invocation)
@@ -76,7 +76,7 @@ createDiagnostics(unsigned int argc, char **argv) {
   // Build the diagnostics parser
   IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          &Invocation->getDiagnosticOpts());
+                                          Invocation->getDiagnosticOpts());
   if (!FinalDiags)
     return nullptr;
 
diff --git a/clang/tools/diagtool/TreeView.cpp b/clang/tools/diagtool/TreeView.cpp
index 8d1ce14b0f520..7e47c748af959 100644
--- a/clang/tools/diagtool/TreeView.cpp
+++ b/clang/tools/diagtool/TreeView.cpp
@@ -31,8 +31,8 @@ class TreePrinter {
 
   static bool isIgnored(unsigned DiagID) {
     // FIXME: This feels like a hack.
-    static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
-                                          new DiagnosticOptions);
+    static DiagnosticOptions DiagOpts;
+    static clang::DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
     return Diags.isIgnored(DiagID, SourceLocation());
   }
 
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 6638a15ff7e12..2c17f28621f5f 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -232,9 +232,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
 
   // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs.
   if (find(Argv, StringRef("-Rround-trip-cc1-args")) != Argv.end())
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index ab7ba238bcc57..f938e7e4041e8 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -658,12 +658,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   InitializeAllAsmParsers();
 
   // Construct our diagnostic client.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(errs(), DiagOpts);
   DiagClient->setPrefix("clang -cc1as");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient);
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
diff --git a/clang/tools/driver/cc1gen_reproducer_main.cpp b/clang/tools/driver/cc1gen_reproducer_main.cpp
index df59b53f9ef18..8d7171eb2e5e0 100644
--- a/clang/tools/driver/cc1gen_reproducer_main.cpp
+++ b/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -117,12 +117,12 @@ generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
   using namespace driver;
   auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new IgnoringDiagConsumer());
   auto VFS = llvm::vfs::getRealFileSystem();
-  ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
+  ProcessWarningOptions(Diags, DiagOpts, *VFS, /*ReportDiags=*/false);
   Driver TheDriver(ToolContext.Path, llvm::sys::getDefaultTargetTriple(), Diags,
                    /*Title=*/"clang LLVM compiler", VFS);
   TheDriver.setTargetAndMode(TargetAndMode);
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 82f47ab973064..d21a34e961394 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -321,25 +321,24 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
                            .Case("-fintegrated-cc1", false)
                            .Default(UseNewCC1Process);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
-      CreateAndPopulateDiagOpts(Args);
+  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Args);
   // Driver's diagnostics don't use suppression mappings, so don't bother
   // parsing them. CC1 still receives full args, so this doesn't impact other
   // actions.
   DiagOpts->DiagnosticSuppressionMappingsFile.clear();
 
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
   FixupDiagPrefixExeName(DiagClient, ProgName);
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagClient);
 
   if (!DiagOpts->DiagnosticSerializationFile.empty()) {
     auto SerializedConsumer =
         clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
-                                        &*DiagOpts, /*MergeChildRecords=*/true);
+                                        *DiagOpts, /*MergeChildRecords=*/true);
     Diags.setClient(new ChainedDiagnosticConsumer(
         Diags.takeClient(), std::move(SerializedConsumer)));
   }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 06a17006fdee9..1d9d1027521bc 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -4227,12 +4227,13 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx,
   FileSystemOptions FileSystemOpts;
   HeaderSearchOptions HSOpts;
 
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
+                                          *DiagOpts);
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, Diags, FileSystemOpts, HSOpts,
+      ASTUnit::LoadEverything, DiagOpts, Diags, FileSystemOpts, HSOpts,
       /*LangOpts=*/nullptr, CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All,
       /*AllowASTWithCompilerErrors=*/true,
       /*UserFilesAreVolatile=*/true);
@@ -4299,11 +4300,11 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
   }
 
   // Configure the diagnostics.
-  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
+  std::shared_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
       llvm::ArrayRef(command_line_args, num_command_line_args));
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          DiagOpts.release()));
+                                          *DiagOpts));
 
   if (options & CXTranslationUnit_KeepGoing)
     Diags->setFatalsAsError(true);
@@ -4387,7 +4388,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
       options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files);
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromCommandLine(
       Args->data(), Args->data() + Args->size(),
-      CXXIdx->getPCHContainerOperations(), Diags,
+      CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
       CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(),
       CXXIdx->getPreambleStoragePath(), CXXIdx->getOnlyLocalDecls(),
       CaptureDiagnostics, *RemappedFiles,
diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp
index 850c004680fd9..8f6729b83ffa0 100644
--- a/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -256,8 +256,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
   /// Allocated API-exposed wrappters for Diagnostics.
   SmallVector<std::unique_ptr<CXStoredDiagnostic>, 8> DiagnosticsWrappers;
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
-  
+  DiagnosticOptions DiagOpts;
+
   /// Diag object
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
   
@@ -356,9 +356,9 @@ static std::atomic<unsigned> CodeCompletionResultObjects;
 
 AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     IntrusiveRefCntPtr<FileManager> FileMgr)
-    : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions),
+    : CXCodeCompleteResults(),
       Diag(new DiagnosticsEngine(
-          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
+          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts)),
       FileMgr(std::move(FileMgr)),
       SourceMgr(new SourceManager(*Diag, *this->FileMgr)),
       CodeCompletionAllocator(
@@ -369,7 +369,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     fprintf(stderr, "+++ %u completion results\n",
             ++CodeCompletionResultObjects);
 }
-  
+
 AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
   delete [] Results;
 
diff --git a/clang/tools/libclang/CIndexDiagnostic.cpp b/clang/tools/libclang/CIndexDiagnostic.cpp
index 92271d9c37f86..d37597e747a84 100644
--- a/clang/tools/libclang/CIndexDiagnostic.cpp
+++ b/clang/tools/libclang/CIndexDiagnostic.cpp
@@ -80,12 +80,11 @@ class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
 };    
     
 class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
-public:  
-  CXDiagnosticRenderer(const LangOptions &LangOpts,
-                       DiagnosticOptions *DiagOpts,
+public:
+  CXDiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts,
                        CXDiagnosticSetImpl *mainSet)
-  : DiagnosticNoteRenderer(LangOpts, DiagOpts),
-    CurrentSet(mainSet), MainSet(mainSet) {}
+      : DiagnosticNoteRenderer(LangOpts, DiagOpts), CurrentSet(mainSet),
+        MainSet(mainSet) {}
 
   ~CXDiagnosticRenderer() override {}
 
@@ -182,10 +181,10 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
   if (!TU->Diagnostics) {
     CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
     TU->Diagnostics = Set;
-    IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
-    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
-                                  &*DOpts, Set);
-    
+    DiagnosticOptions DOpts;
+    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(), DOpts,
+                                  Set);
+
     for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
          ei = AU->stored_diag_end(); it != ei; ++it) {
       Renderer.emitStoredDiagnostic(*it);
diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index e1441bce15f88..3cd49bf90235b 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -480,9 +480,10 @@ static CXErrorCode clang_indexSourceFile_Impl(
     CaptureDiag = new CaptureDiagnosticConsumer();
 
   // Configure the diagnostics.
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions, CaptureDiag,
+                                          *DiagOpts, CaptureDiag,
                                           /*ShouldOwnClient=*/true));
 
   // Recover resources if we crash before exiting this function.
@@ -554,7 +555,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
   CInvok->getHeaderSearchOpts().ModuleFormat = std::string(
       CXXIdx->getPCHContainerOperations()->getRawReader().getFormats().front());
 
-  auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics,
+  auto Unit = ASTUnit::create(CInvok, DiagOpts, Diags, CaptureDiagnostics,
                               /*UserFilesAreVolatile=*/true);
   if (!Unit)
     return CXError_InvalidArguments;
@@ -617,7 +618,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
       !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
   DiagnosticErrorTrap DiagTrap(*Diags);
   bool Success = ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags,
+      std::move(CInvok), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
       IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(),
       OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
       CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true);
diff --git a/clang/unittests/AST/ASTVectorTest.cpp b/clang/unittests/AST/ASTVectorTest.cpp
index 1c17eb9210ac3..66003b49eccb2 100644
--- a/clang/unittests/AST/ASTVectorTest.cpp
+++ b/clang/unittests/AST/ASTVectorTest.cpp
@@ -27,13 +27,14 @@ class ASTVectorTest : public ::testing::Test {
 protected:
   ASTVectorTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
         Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins, TU_Complete) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp
index 22866f0eb23ed..dc10dae7a2f8f 100644
--- a/clang/unittests/AST/CommentLexer.cpp
+++ b/clang/unittests/AST/CommentLexer.cpp
@@ -27,16 +27,14 @@ namespace {
 class CommentLexerTest : public ::testing::Test {
 protected:
   CommentLexerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      Traits(Allocator, CommentOptions()) {
-  }
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentParser.cpp b/clang/unittests/AST/CommentParser.cpp
index aa08b6718e506..67fabe5181798 100644
--- a/clang/unittests/AST/CommentParser.cpp
+++ b/clang/unittests/AST/CommentParser.cpp
@@ -33,16 +33,14 @@ const bool MY_DEBUG = true;
 class CommentParserTest : public ::testing::Test {
 protected:
   CommentParserTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      Traits(Allocator, CommentOptions()) {
-  }
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentTextTest.cpp b/clang/unittests/AST/CommentTextTest.cpp
index b697828698d85..84ec51a308360 100644
--- a/clang/unittests/AST/CommentTextTest.cpp
+++ b/clang/unittests/AST/CommentTextTest.cpp
@@ -43,7 +43,8 @@ class CommentTextTest : public ::testing::Test {
     // FIXME: technically, merged that we set here is incorrect, but that
     // shouldn't matter.
     RawComment Comment(SourceMgr, CommentRange, EmptyOpts, /*Merged=*/true);
-    DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions);
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
     return Comment.getFormattedText(SourceMgr, Diags);
   }
 };
diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp b/clang/unittests/AST/ExternalASTSourceTest.cpp
index 807bab1b3dd81..11715bb8ce7cd 100644
--- a/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -51,9 +51,9 @@ bool testExternalASTSource(ExternalASTSource *Source, StringRef FileContents) {
       "test.cc", MemoryBuffer::getMemBuffer(FileContents).release());
   const char *Args[] = { "test.cc" };
 
-  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions InvocationDiagOpts;
   auto InvocationDiags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts.get());
+      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts);
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index 6f69ccbd36552..1dd07834bfd7e 100644
--- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -1388,10 +1388,9 @@ class UncheckedOptionalAccessTest
             unsigned Line = SrcMgr.getPresumedLineNumber(Diag.Range.getBegin());
             DiagnosticLines.insert(Line);
             if (!AnnotationLines.contains(Line)) {
-              IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
-                  new DiagnosticOptions());
+              DiagnosticOptions DiagOpts;
               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
-                                DiagOpts.get());
+                                DiagOpts);
               TD.emitDiagnostic(FullSourceLoc(Diag.Range.getBegin(), SrcMgr),
                                 DiagnosticsEngine::Error,
                                 "unexpected diagnostic", {Diag.Range}, {});
diff --git a/clang/unittests/Analysis/MacroExpansionContextTest.cpp b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
index 929d4122cdec7..9874ea687f3ed 100644
--- a/clang/unittests/Analysis/MacroExpansionContextTest.cpp
+++ b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
@@ -35,8 +35,8 @@ class MacroExpansionContextTest : public ::testing::Test {
   MacroExpansionContextTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-pc-linux-unknown";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -46,7 +46,7 @@ class MacroExpansionContextTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
index e48f39bf13f44..9da2c58970b84 100644
--- a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
@@ -13,12 +13,13 @@ class UnsafeBufferUsageTest : public ::testing::Test {
 protected:
   UnsafeBufferUsageTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
 };
diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp
index 88fa1800f0ff2..b0a034e9af1cd 100644
--- a/clang/unittests/Basic/DiagnosticTest.cpp
+++ b/clang/unittests/Basic/DiagnosticTest.cpp
@@ -46,8 +46,8 @@ using testing::IsEmpty;
 
 // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
 TEST(DiagnosticTest, suppressAndTrap) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(),
-                          new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   Diags.setSuppressAllDiagnostics(true);
 
@@ -77,8 +77,8 @@ TEST(DiagnosticTest, suppressAndTrap) {
 // Check that FatalsAsError works as intended
 TEST(DiagnosticTest, fatalsAsError) {
   for (unsigned FatalsAsError = 0; FatalsAsError != 2; ++FatalsAsError) {
-    DiagnosticsEngine Diags(new DiagnosticIDs(),
-                            new DiagnosticOptions,
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                             new IgnoringDiagConsumer());
     Diags.setFatalsAsError(FatalsAsError);
 
@@ -101,7 +101,8 @@ TEST(DiagnosticTest, fatalsAsError) {
 }
 
 TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   Diags.setFatalsAsError(true);
 
@@ -117,7 +118,8 @@ TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
 
 // Check that soft RESET works as intended
 TEST(DiagnosticTest, softReset) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
 
   unsigned numWarnings = 0U, numErrors = 0U;
@@ -140,7 +142,8 @@ TEST(DiagnosticTest, softReset) {
 }
 
 TEST(DiagnosticTest, diagnosticError) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   PartialDiagnostic::DiagStorageAllocator Alloc;
   llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create(
@@ -162,7 +165,8 @@ TEST(DiagnosticTest, diagnosticError) {
 }
 
 TEST(DiagnosticTest, storedDiagEmptyWarning) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts);
 
   class CaptureDiagnosticConsumer : public DiagnosticConsumer {
   public:
@@ -192,7 +196,8 @@ class SuppressionMappingTest : public testing::Test {
 protected:
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  DiagnosticsEngine Diags{new DiagnosticIDs(), new DiagnosticOptions};
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags{new DiagnosticIDs(), DiagOpts};
 
   llvm::ArrayRef<StoredDiagnostic> diags() {
     return CaptureConsumer.StoredDiags;
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index febfbabe8695e..ad9f8ecc208a4 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -43,14 +43,14 @@ class SarifDocumentWriterTest : public ::testing::Test {
   SarifDocumentWriterTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp
index 1f0986f61dfa9..cbe047b5e599a 100644
--- a/clang/unittests/Basic/SourceManagerTest.cpp
+++ b/clang/unittests/Basic/SourceManagerTest.cpp
@@ -40,11 +40,9 @@ namespace {
 class SourceManagerTest : public ::testing::Test {
 protected:
   SourceManagerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions) {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -52,6 +50,7 @@ class SourceManagerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp
index 616c07c0d389d..f6845939d04b4 100644
--- a/clang/unittests/Driver/DXCModeTest.cpp
+++ b/clang/unittests/Driver/DXCModeTest.cpp
@@ -64,8 +64,8 @@ TEST(DxcModeTest, TargetProfileValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
 
   validateTargetProfile("-Tvs_6_0", "dxilv1.0--shadermodel6.0-vertex",
                         InMemoryFileSystem, Diags);
@@ -114,8 +114,8 @@ TEST(DxcModeTest, ValidatorVersionValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
   Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
@@ -218,9 +218,9 @@ TEST(DxcModeTest, DefaultEntry) {
 
   const char *Args[] = {"clang", "--driver-mode=dxc", "-Tcs_6_7", "foo.hlsl"};
 
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*InMemoryFileSystem,
-                                          new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*InMemoryFileSystem, DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Driver/SanitizerArgsTest.cpp b/clang/unittests/Driver/SanitizerArgsTest.cpp
index 5a4221023c950..b8bfc6806da6d 100644
--- a/clang/unittests/Driver/SanitizerArgsTest.cpp
+++ b/clang/unittests/Driver/SanitizerArgsTest.cpp
@@ -52,10 +52,9 @@ class SanitizerArgsTest : public ::testing::Test {
                                           std::vector<std::string> ExtraFiles) {
     assert(!DriverInstance && "Running twice is not allowed");
 
-    llvm::IntrusiveRefCntPtr<DiagnosticOptions> Opts = new DiagnosticOptions;
-    DiagnosticsEngine Diags(
-        new DiagnosticIDs, Opts,
-        new TextDiagnosticPrinter(llvm::errs(), Opts.get()));
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
+                            new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
     DriverInstance.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,
                            "clang LLVM compiler", prepareFS(ExtraFiles));
 
diff --git a/clang/unittests/Driver/SimpleDiagnosticConsumer.h b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
index 6515bdedb3d5d..c3772baade566 100644
--- a/clang/unittests/Driver/SimpleDiagnosticConsumer.h
+++ b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
@@ -47,9 +47,8 @@ inline clang::driver::Driver diagnostic_test_driver() {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
-      new clang::DiagnosticOptions();
-  clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
   return clang::driver::Driver("/bin/clang", "", Diags, "", InMemoryFileSystem);
 }
 
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index c1ffe4a82ce4b..670090a01b0d3 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -38,7 +38,7 @@ using namespace clang::driver;
 namespace {
 
 TEST(ToolChainTest, VFSGCCInstallation) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -84,7 +84,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -107,7 +107,8 @@ TEST(ToolChainTest, VFSGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -134,11 +135,11 @@ TEST(ToolChainTest, VFSGCCInstallation) {
 }
 
 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -173,7 +174,7 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
 }
 
 TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -201,7 +202,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "i386-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -225,7 +226,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "amd64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -249,7 +250,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -273,7 +274,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparc-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -296,7 +297,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
               S);
   }
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparcv9-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -337,7 +338,7 @@ MATCHER_P(jobHasArgs, Substr, "") {
 }
 
 TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -355,7 +356,7 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-unknown-linux-gnu", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -368,11 +369,11 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
 }
 
 TEST(ToolChainTest, DefaultDriverMode) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -403,8 +404,8 @@ TEST(ToolChainTest, DefaultDriverMode) {
 TEST(ToolChainTest, InvalidArgument) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
@@ -514,11 +515,11 @@ TEST(ToolChainTest, GetTargetAndMode) {
 }
 
 TEST(ToolChainTest, CommandOutput) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -543,10 +544,10 @@ TEST(ToolChainTest, CommandOutput) {
 }
 
 TEST(ToolChainTest, PostCallback) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -596,10 +597,10 @@ TEST(ToolChainTest, UEFICallingConventionTest) {
 }
 
 TEST(ToolChainTest, UEFIDefaultDebugFormatTest) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver CCDriver("/home/test/bin/clang", "x86_64-unknown-uefi", Diags,
@@ -638,10 +639,10 @@ struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 TEST(ToolChainTest, ConfigFileSearch) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -715,11 +716,11 @@ struct FileSystemWithError : public llvm::vfs::FileSystem {
 };
 
 TEST(ToolChainTest, ConfigFileError) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
 
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -736,11 +737,11 @@ TEST(ToolChainTest, ConfigFileError) {
 }
 
 TEST(ToolChainTest, BadConfigFile) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -810,11 +811,11 @@ TEST(ToolChainTest, BadConfigFile) {
 }
 
 TEST(ToolChainTest, ConfigInexistentInclude) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -851,11 +852,11 @@ TEST(ToolChainTest, ConfigInexistentInclude) {
 }
 
 TEST(ToolChainTest, ConfigRecursiveInclude) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -897,10 +898,10 @@ TEST(ToolChainTest, ConfigRecursiveInclude) {
 }
 
 TEST(ToolChainTest, NestedConfigFile) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp
index 08daca9111e64..afa64b5e90a6d 100644
--- a/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -30,6 +30,8 @@ class ASTUnitTest : public ::testing::Test {
   int FD;
   llvm::SmallString<256> InputFileName;
   std::unique_ptr<ToolOutputFile> input_file;
+  std::shared_ptr<DiagnosticOptions> DiagOpts =
+      std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   std::shared_ptr<CompilerInvocation> CInvok;
   std::shared_ptr<PCHContainerOperations> PCHContainerOps;
@@ -43,7 +45,7 @@ class ASTUnitTest : public ::testing::Test {
     const char *Args[] = {"clang", "-xc++", InputFileName.c_str()};
 
     auto VFS = llvm::vfs::getRealFileSystem();
-    Diags = CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+    Diags = CompilerInstance::createDiagnostics(*VFS, *DiagOpts);
 
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
@@ -57,8 +59,8 @@ class ASTUnitTest : public ::testing::Test {
     PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
     return ASTUnit::LoadFromCompilerInvocation(
-        CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None,
-        0, TU_Complete, false, false, isVolatile);
+        CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None, 0, TU_Complete, false, false, isVolatile);
   }
 };
 
@@ -95,7 +97,7 @@ TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) {
 
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything,
-      Diags, FileSystemOptions(), HSOpts);
+      DiagOpts, Diags, FileSystemOptions(), HSOpts);
 
   if (!AU)
     FAIL() << "failed to load ASTUnit";
@@ -136,8 +138,7 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
 
   const char *Args[] = {"clang", "test.cpp", "-fmodule-map-file=m.modulemap",
                         "-fmodule-name=M"};
-  Diags =
-      CompilerInstance::createDiagnostics(*InMemoryFs, new DiagnosticOptions());
+  Diags = CompilerInstance::createDiagnostics(*InMemoryFs, *DiagOpts);
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CInvok = createInvocation(Args, std::move(CIOpts));
@@ -147,8 +148,8 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
   PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
   auto AU = ASTUnit::LoadFromCompilerInvocation(
-      CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, 1,
-      TU_Complete, false, false, false);
+      CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
+      CaptureDiagsKind::None, 1, TU_Complete, false, false, false);
   ASSERT_TRUE(AU);
   auto File = AU->getFileManager().getFileRef("Textual.h", false, false);
   ASSERT_TRUE(bool(File));
@@ -166,15 +167,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) {
   const char *Args[] = {"clang", "-target", "foobar", InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
+      *llvm::vfs::getRealFileSystem(), *DiagOpts);
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
-      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
-      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
-      &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
+      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
+      false, SkipFunctionBodiesScope::None, false, true, false, false,
+      std::nullopt, &ErrUnit, nullptr);
 
   ASSERT_EQ(AST, nullptr);
   ASSERT_NE(ErrUnit, nullptr);
@@ -194,15 +195,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) {
                         InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
+      *llvm::vfs::getRealFileSystem(), *DiagOpts);
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
-      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
-      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
-      &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
+      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
+      false, SkipFunctionBodiesScope::None, false, true, false, false,
+      std::nullopt, &ErrUnit, nullptr);
 
   ASSERT_NE(AST, nullptr);
   ASSERT_FALSE(Diags->hasErrorOccurred());
diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp
index 6e9a6f5f728a5..a7b258d5e537e 100644
--- a/clang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -53,9 +53,10 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
   const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
   const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};
 
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
+                                          DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
@@ -76,17 +77,17 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
 }
 
 TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
-  auto DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
   // ensures that a chained diagnostic consumer is created so that the test can
   // exercise the unowned diagnostic consumer in a chained consumer.
-  DiagOpts->DiagnosticLogFile = "-";
+  DiagOpts.DiagnosticLogFile = "-";
 
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
   CompilerInstance Instance;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       Instance.createDiagnostics(*llvm::vfs::getRealFileSystem(), DiagOpts,
diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp
index 94ab9fe8451e0..75390aa42d00e 100644
--- a/clang/unittests/Frontend/CompilerInvocationTest.cpp
+++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp
@@ -29,6 +29,7 @@ using ::testing::StartsWith;
 namespace {
 class CommandLineTest : public ::testing::Test {
 public:
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   SmallVector<const char *, 32> GeneratedArgs;
   BumpPtrAllocator Alloc;
@@ -41,7 +42,7 @@ class CommandLineTest : public ::testing::Test {
 
   CommandLineTest()
       : Diags(CompilerInstance::createDiagnostics(
-            *llvm::vfs::getRealFileSystem(), new DiagnosticOptions(),
+            *llvm::vfs::getRealFileSystem(), DiagOpts,
             new TextDiagnosticBuffer())),
         StringPool(Alloc) {}
 };
diff --git a/clang/unittests/Frontend/OutputStreamTest.cpp b/clang/unittests/Frontend/OutputStreamTest.cpp
index 0eda3a1dab403..dfb5a544cb88a 100644
--- a/clang/unittests/Frontend/OutputStreamTest.cpp
+++ b/clang/unittests/Frontend/OutputStreamTest.cpp
@@ -61,10 +61,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamShared) {
   raw_string_ostream VerboseStream(VerboseBuffer);
 
   Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  Compiler.createDiagnostics(
-      *llvm::vfs::getRealFileSystem(),
-      new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+  DiagnosticOptions DiagOpts;
+  Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem(),
+                             new TextDiagnosticPrinter(llvm::nulls(), DiagOpts),
+                             true);
   Compiler.setVerboseOutputStream(VerboseStream);
 
   bool Success = ExecuteCompilerInvocation(&Compiler);
@@ -91,10 +91,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) {
         std::make_unique<raw_string_ostream>(VerboseBuffer);
 
     Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+    DiagnosticOptions DiagOpts;
     Compiler.createDiagnostics(
         *llvm::vfs::getRealFileSystem(),
-        new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+        new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), true);
     Compiler.setVerboseOutputStream(std::move(VerboseStream));
 
     Success = ExecuteCompilerInvocation(&Compiler);
diff --git a/clang/unittests/Frontend/PCHPreambleTest.cpp b/clang/unittests/Frontend/PCHPreambleTest.cpp
index 58ec2e2ce7058..faad408193f62 100644
--- a/clang/unittests/Frontend/PCHPreambleTest.cpp
+++ b/clang/unittests/Frontend/PCHPreambleTest.cpp
@@ -53,6 +53,8 @@ class PCHPreambleTest : public ::testing::Test {
   IntrusiveRefCntPtr<ReadCountingInMemoryFileSystem> VFS;
   StringMap<std::string> RemappedFiles;
   std::shared_ptr<PCHContainerOperations> PCHContainerOpts;
+  std::shared_ptr<DiagnosticOptions> DiagOpts =
+      std::make_shared<DiagnosticOptions>();
   FileSystemOptions FSOpts;
 
 public:
@@ -95,13 +97,14 @@ class PCHPreambleTest : public ::testing::Test {
     PPOpts.RemappedFilesKeepOriginalName = true;
 
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
+        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(FSOpts, VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
+        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
index b0f2d51b80b9e..1b8051f80e9b8 100644
--- a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
+++ b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
@@ -57,14 +57,16 @@ class ReparseWorkingDirTest : public ::testing::Test {
     CI->getFileSystemOpts().WorkingDir = *VFS->getCurrentWorkingDirectory();
     CI->getTargetOpts().Triple = "i386-unknown-linux-gnu";
 
+    auto DiagOpts = std::make_shared<DiagnosticOptions>();
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
+        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
+        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/SearchPathTest.cpp b/clang/unittests/Frontend/SearchPathTest.cpp
index 2ebe74d47eb02..c74a5c75fada5 100644
--- a/clang/unittests/Frontend/SearchPathTest.cpp
+++ b/clang/unittests/Frontend/SearchPathTest.cpp
@@ -40,12 +40,12 @@ namespace {
 class SearchPathTest : public ::testing::Test {
 protected:
   SearchPathTest()
-      : Diags(new DiagnosticIDs(), new DiagnosticOptions,
-              new IgnoringDiagConsumer()),
+      : Diags(new DiagnosticIDs(), DiagOpts, new IgnoringDiagConsumer()),
         VFS(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), VFS), SourceMgr(Diags, FileMgr),
         Invocation(std::make_unique<CompilerInvocation>()) {}
 
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
   FileManager FileMgr;
diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp
index fef5726f053f1..8fd8187134b63 100644
--- a/clang/unittests/Frontend/TextDiagnosticTest.cpp
+++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp
@@ -20,13 +20,12 @@ namespace {
 
 /// Prints a diagnostic with the given DiagnosticOptions and the given
 /// SourceLocation and returns the printed diagnostic text.
-static std::string PrintDiag(const DiagnosticOptions &Opts, FullSourceLoc Loc) {
+static std::string PrintDiag(DiagnosticOptions &Opts, FullSourceLoc Loc) {
   std::string Out;
   llvm::raw_string_ostream OS(Out);
   clang::LangOptions LangOpts;
   // Owned by TextDiagnostic.
-  DiagnosticOptions *DiagOpts = new DiagnosticOptions(Opts);
-  TextDiagnostic Diag(OS, LangOpts, DiagOpts);
+  TextDiagnostic Diag(OS, LangOpts, Opts);
   // Emit a dummy diagnostic that is just 'message'.
   Diag.emitDiagnostic(Loc, DiagnosticsEngine::Level::Warning, "message",
                       /*Ranges=*/{}, /*FixItHints=*/{});
@@ -38,7 +37,8 @@ TEST(TextDiagnostic, ShowLine) {
   FileSystemOptions FSOpts;
   FileManager FileMgr(FSOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
-  DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions,
+  DiagnosticOptions DiagEngineOpts;
+  DiagnosticsEngine DiagEngine(DiagID, DiagEngineOpts,
                                new IgnoringDiagConsumer());
   SourceManager SrcMgr(DiagEngine, FileMgr);
 
diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp
index 47ca3210ab596..cf385a5323c61 100644
--- a/clang/unittests/Frontend/UtilsTest.cpp
+++ b/clang/unittests/Frontend/UtilsTest.cpp
@@ -26,11 +26,12 @@ TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
   std::vector<const char *> Args = {"clang", "--target=macho", "-arch",  "i386",
                                     "-arch", "x86_64",         "foo.cpp"};
   clang::IgnoringDiagConsumer D;
+  clang::DiagnosticOptions DiagOpts;
   CreateInvocationOptions Opts;
   Opts.RecoverOnError = true;
   Opts.VFS = new llvm::vfs::InMemoryFileSystem();
-  Opts.Diags = clang::CompilerInstance::createDiagnostics(
-      *Opts.VFS, new DiagnosticOptions, &D, false);
+  Opts.Diags = clang::CompilerInstance::createDiagnostics(*Opts.VFS, DiagOpts,
+                                                          &D, false);
   std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
   ASSERT_TRUE(CI);
   EXPECT_THAT(CI->getTargetOpts().Triple, testing::StartsWith("i386-"));
@@ -45,9 +46,9 @@ TEST(BuildCompilerInvocationTest, ProbePrecompiled) {
   FS->addFile("foo.h.pch", 0, llvm::MemoryBuffer::getMemBuffer(""));
 
   clang::IgnoringDiagConsumer D;
+  clang::DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
-      clang::CompilerInstance::createDiagnostics(*FS, new DiagnosticOptions, &D,
-                                                 false);
+      clang::CompilerInstance::createDiagnostics(*FS, DiagOpts, &D, false);
   // Default: ProbePrecompiled=false
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = CommandLineDiagsEngine;
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index 03b9c33232080..b97f5ae17c9f0 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -95,8 +95,9 @@ TEST_F(InterpreterTest, Errors) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError();
@@ -126,8 +127,9 @@ TEST_F(InterpreterTest, DeclsAndStatements) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto R1 = Interp->Parse(
@@ -148,8 +150,9 @@ TEST_F(InterpreterTest, UndoCommand) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
 
diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp b/clang/unittests/Lex/HeaderSearchTest.cpp
index b8896261703cd..9903c1246d33d 100644
--- a/clang/unittests/Lex/HeaderSearchTest.cpp
+++ b/clang/unittests/Lex/HeaderSearchTest.cpp
@@ -30,7 +30,7 @@ class HeaderSearchTest : public ::testing::Test {
   HeaderSearchTest()
       : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS),
         DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
         Search(HSOpts, SourceMgr, Diags, LangOpts, Target.get()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
@@ -81,6 +81,7 @@ class HeaderSearchTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp
index 9806d4c7bf145..381755d4d1b6f 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -41,12 +41,9 @@ using testing::ElementsAre;
 class LexerTest : public ::testing::Test {
 protected:
   LexerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions)
-  {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -104,6 +101,7 @@ class LexerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/ModuleDeclStateTest.cpp b/clang/unittests/Lex/ModuleDeclStateTest.cpp
index 6fbc6bff12d8a..6ecba4de3187c 100644
--- a/clang/unittests/Lex/ModuleDeclStateTest.cpp
+++ b/clang/unittests/Lex/ModuleDeclStateTest.cpp
@@ -55,7 +55,7 @@ class ModuleDeclStateTest : public ::testing::Test {
 protected:
   ModuleDeclStateTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-unknown-linux-gnu";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -94,6 +94,7 @@ class ModuleDeclStateTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   std::shared_ptr<TargetOptions> TargetOpts;
diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp
index c2a84d974dd39..af86c1888f2c7 100644
--- a/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -135,8 +135,8 @@ class PPCallbacksTest : public ::testing::Test {
   PPCallbacksTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -145,7 +145,7 @@ class PPCallbacksTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
@@ -437,7 +437,7 @@ TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
   HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
 
   DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
-  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer);
+  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts, DiagConsumer);
   Preprocessor PP(PPOpts, FileNotFoundDiags, LangOpts, SourceMgr, HeaderInfo,
                   ModLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
   PP.Initialize(*Target);
diff --git a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 5c3ce6fa33012..54c1d020aa0ea 100644
--- a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -29,12 +29,9 @@ namespace {
 class PPConditionalDirectiveRecordTest : public ::testing::Test {
 protected:
   PPConditionalDirectiveRecordTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions)
-  {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -42,6 +39,7 @@ class PPConditionalDirectiveRecordTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
index 74e3c00b451ba..061cb136a552a 100644
--- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
+++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
@@ -32,7 +32,7 @@ class PPDependencyDirectivesTest : public ::testing::Test {
 protected:
   PPDependencyDirectivesTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-macos12";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -41,6 +41,7 @@ class PPDependencyDirectivesTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
index 304a66ab96caa..4d83003e28b36 100644
--- a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
+++ b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
@@ -28,7 +28,7 @@ class PPMemoryAllocationsTest : public ::testing::Test {
 protected:
   PPMemoryAllocationsTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -37,6 +37,7 @@ class PPMemoryAllocationsTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 7d03dda1f516b..912e96e5700aa 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -67,8 +67,7 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
 protected:
   ParseHLSLRootSignatureTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Consumer(new ExpectedDiagConsumer()),
-        Diags(DiagID, new DiagnosticOptions, Consumer),
+        Consumer(new ExpectedDiagConsumer()), Diags(DiagID, DiagOpts, Consumer),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     // This is an arbitrarily chosen target triple to create the target info.
     TargetOpts->Triple = "dxil";
@@ -95,6 +94,7 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   ExpectedDiagConsumer *Consumer;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
index c68a71ae05d3f..5a04f42697b99 100644
--- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp
+++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
@@ -59,9 +59,9 @@ class NoloadLookupTest : public ::testing::Test {
 
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     std::string CacheBMIPath =
diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
index 16742a6cb01e8..970eeef3c953e 100644
--- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
+++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
@@ -66,9 +66,9 @@ export int aa = 43;
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
 
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     const char *Args[] = {"clang++",       "-std=c++20",
@@ -106,9 +106,9 @@ export int aa = 43;
   {
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str();
diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
index d62d669149f51..631547431ce7c 100644
--- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
+++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
@@ -53,8 +53,9 @@ class LoadSpecLazilyTest : public ::testing::Test {
 
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
         llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*VFS, DiagOpts);
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
     CIOpts.VFS = VFS;
diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp
index 38003e93c5d9d..de6e13a738cb8 100644
--- a/clang/unittests/Serialization/ModuleCacheTest.cpp
+++ b/clang/unittests/Serialization/ModuleCacheTest.cpp
@@ -108,8 +108,9 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
@@ -157,8 +158,9 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp
index 3aaaa548c6eff..05efeef990d43 100644
--- a/clang/unittests/Serialization/NoCommentsTest.cpp
+++ b/clang/unittests/Serialization/NoCommentsTest.cpp
@@ -85,8 +85,9 @@ void foo() {}
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   std::string CacheBMIPath = llvm::Twine(TestDir + "/Comments.pcm").str();
diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
index 7a037d22d5c0d..c43520f79b02c 100644
--- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
+++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
@@ -77,8 +77,9 @@ export using ::E;
 
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
index 33c3c6b5e61fd..5b2988ed26336 100644
--- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
+++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
@@ -92,8 +92,9 @@ export namespace Fibonacci
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   const char *Args[] = {"clang++",       "-std=c++20",
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index a92b0eb11c423..85d36b5d21423 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -58,9 +58,9 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
 
   auto Invocation = std::make_shared<CompilerInvocation>();
   std::vector<const char *> Args = {Standard.data(), File.data()};
-  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions InvocationDiagOpts;
   auto InvocationDiags =
-      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts.get());
+      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts);
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Tooling/RewriterTestContext.h b/clang/unittests/Tooling/RewriterTestContext.h
index b7aa1a133c83e..2d697e276c5e8 100644
--- a/clang/unittests/Tooling/RewriterTestContext.h
+++ b/clang/unittests/Tooling/RewriterTestContext.h
@@ -49,9 +49,8 @@ struct RewriterDiagnosticConsumer : public DiagnosticConsumer {
 class RewriterTestContext {
  public:
    RewriterTestContext()
-       : DiagOpts(new DiagnosticOptions()),
-         Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-                     &*DiagOpts),
+       : Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+                     DiagOpts),
          InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
          OverlayFileSystem(
              new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())),
@@ -61,7 +60,7 @@ class RewriterTestContext {
      // FIXME: To make these tests truly in-memory, we need to overlay the
      // builtin headers.
      OverlayFileSystem->pushOverlay(InMemoryFileSystem);
-  }
+   }
 
   ~RewriterTestContext() {}
 
@@ -124,7 +123,7 @@ class RewriterTestContext {
     return std::string((*FileBuffer)->getBuffer());
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics;
   RewriterDiagnosticConsumer DiagnosticPrinter;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp
index d42273be1858c..b5f44454e862d 100644
--- a/clang/unittests/Tooling/Syntax/TokensTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -248,8 +248,9 @@ class TokenCollectorTest : public ::testing::Test {
   }
 
   // Data fields.
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
+      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
index 7710a9cc5a743..9f22b1d64c913 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
@@ -126,7 +126,7 @@ SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) {
   FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
 
   if (!Diags->getClient())
-    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
+    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
   Diags->setSeverityForGroup(diag::Flavor::WarningOrError, "unused-value",
                              diag::Severity::Ignored, SourceLocation());
 
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.h b/clang/unittests/Tooling/Syntax/TreeTestBase.h
index 1176f457cf8b3..6110cffa708d9 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.h
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.h
@@ -40,9 +40,9 @@ class SyntaxTreeTest : public ::testing::Test,
   syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root);
 
   // Data fields.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts.get());
+      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index cfa021a5ef137..32af4b6b3b359 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -294,8 +294,8 @@ TEST(ToolInvocation, CustomDiagnosticOptionsOverwriteParsedOnes) {
   Invocation.setDiagnosticConsumer(&Consumer);
 
   // Inject custom `DiagnosticOptions` for command-line parsing.
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  Invocation.setDiagnosticOptions(&*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  Invocation.setDiagnosticOptions(&DiagOpts);
 
   EXPECT_TRUE(Invocation.run());
   // Check that the warning was issued during command-line parsing due to the
@@ -392,14 +392,14 @@ overlayRealFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
 
 struct CommandLineExtractorTest : public ::testing::Test {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   driver::Driver Driver;
 
 public:
   CommandLineExtractorTest()
       : InMemoryFS(new llvm::vfs::InMemoryFileSystem),
-        Diags(CompilerInstance::createDiagnostics(*InMemoryFS,
-                                                  new DiagnosticOptions)),
+        Diags(CompilerInstance::createDiagnostics(*InMemoryFS, DiagOpts)),
         Driver("clang", llvm::sys::getDefaultTargetTriple(), *Diags,
                "clang LLVM compiler", overlayRealFS(InMemoryFS)) {}
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 25b4c8b876265..959cbb282b043 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -166,13 +166,12 @@ static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) {
 class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 public:
   ClangDiagnosticManagerAdapter(DiagnosticOptions &opts, StringRef filename)
-      : m_filename(filename) {
-    DiagnosticOptions *options = new DiagnosticOptions(opts);
-    options->ShowPresumedLoc = true;
-    options->ShowLevel = false;
+      : m_options(opts), m_filename(filename) {
+    m_options.ShowPresumedLoc = true;
+    m_options.ShowLevel = false;
     m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
     m_passthrough =
-        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options);
+        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options);
   }
 
   void ResetManager(DiagnosticManager *manager = nullptr) {
@@ -313,6 +312,7 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 
 private:
   DiagnosticManager *m_manager = nullptr;
+  DiagnosticOptions m_options;
   std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
   /// Output stream of m_passthrough.
   std::shared_ptr<llvm::raw_string_ostream> m_os;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 1feeeb64aa9e5..06f3a7efac7a2 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -261,8 +261,7 @@ TokenVerifier::TokenVerifier(std::string body) {
   // Let's build the actual source code Clang needs and setup some utility
   // objects.
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
-      new DiagnosticOptions());
+  DiagnosticOptions diags_opts;
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(body);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index eee6166e43f98..eb62cb618f254 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -66,6 +66,7 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
   typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
       IDAndDiagnostic;
   std::vector<IDAndDiagnostic> m_diagnostics;
+  std::unique_ptr<clang::DiagnosticOptions> m_diag_opts;
   /// The DiagnosticPrinter used for creating the full diagnostic messages
   /// that are stored in m_diagnostics.
   std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
@@ -83,6 +84,7 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
 class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 public:
   ClangModulesDeclVendorImpl(
+      std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
       llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
       std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
       std::unique_ptr<clang::CompilerInstance> compiler_instance,
@@ -115,6 +117,7 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 
   bool m_enabled = false;
 
+  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options;
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
   std::shared_ptr<clang::CompilerInvocation> m_compiler_invocation;
   std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
@@ -134,10 +137,10 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 } // anonymous namespace
 
 StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
-  auto *options = new clang::DiagnosticOptions();
+  m_diag_opts = std::make_unique<clang::DiagnosticOptions>();
   m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
   m_diag_printer =
-      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options);
+      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, *m_diag_opts);
 }
 
 void StoringDiagnosticConsumer::HandleDiagnostic(
@@ -228,11 +231,13 @@ ClangModulesDeclVendor::ClangModulesDeclVendor()
 ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
 
 ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(
+    std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
     llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
     std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
     std::unique_ptr<clang::CompilerInstance> compiler_instance,
     std::unique_ptr<clang::Parser> parser)
-    : m_diagnostics_engine(std::move(diagnostics_engine)),
+    : m_diagnostic_options(std::move(diagnostic_options)),
+      m_diagnostics_engine(std::move(diagnostics_engine)),
       m_compiler_invocation(std::move(compiler_invocation)),
       m_compiler_instance(std::move(compiler_instance)),
       m_parser(std::move(parser)) {
@@ -706,8 +711,8 @@ ClangModulesDeclVendor::Create(Target &target) {
       clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
       clang::CompilerInstance::createDiagnostics(
-          *FileSystem::Instance().GetVirtualFileSystem(),
-          diag_options_up.release(), new StoringDiagnosticConsumer);
+          *FileSystem::Instance().GetVirtualFileSystem(), *diag_options_up,
+          new StoringDiagnosticConsumer);
 
   Log *log = GetLog(LLDBLog::Expressions);
   LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
@@ -767,7 +772,7 @@ ClangModulesDeclVendor::Create(Target &target) {
   while (!parser->ParseTopLevelDecl(parsed, ImportState))
     ;
 
-  return new ClangModulesDeclVendorImpl(std::move(diagnostics_engine),
-                                        std::move(invocation),
-                                        std::move(instance), std::move(parser));
+  return new ClangModulesDeclVendorImpl(
+      std::move(diag_options_up), std::move(diagnostics_engine),
+      std::move(invocation), std::move(instance), std::move(parser));
 }
diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
index 6e56e29f8c31c..8cc5714d0f0fc 100644
--- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
+++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
@@ -163,8 +163,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options,
   // objects.
   std::string full_source = previous_lines.str() + line.str();
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
-      new DiagnosticOptions());
+  DiagnosticOptions diags_opts;
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(full_source);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index bc9a41b58c0d7..150c08ff353ea 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -680,8 +680,9 @@ void TypeSystemClang::CreateASTContext() {
       file_system_options, FileSystem::Instance().GetVirtualFileSystem());
 
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
+  m_diagnostic_options_up = std::make_unique<DiagnosticOptions>();
   m_diagnostics_engine_up =
-      std::make_unique<DiagnosticsEngine>(diag_id_sp, new DiagnosticOptions());
+      std::make_unique<DiagnosticsEngine>(diag_id_sp, *m_diagnostic_options_up);
 
   m_source_manager_up = std::make_unique<clang::SourceManager>(
       *m_diagnostics_engine_up, *m_file_manager_up);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index f918cb017f51b..285748719390c 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1204,6 +1204,7 @@ class TypeSystemClang : public TypeSystem {
   std::unique_ptr<clang::LangOptions> m_language_options_up;
   std::unique_ptr<clang::FileManager> m_file_manager_up;
   std::unique_ptr<clang::SourceManager> m_source_manager_up;
+  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options_up;
   std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up;
   std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up;
   std::shared_ptr<clang::TargetOptions> m_target_options_rp;

>From 4bcea4e9ed4770ed181294c8850c9ce573e58fbd Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 12:37:28 -0700
Subject: [PATCH 040/105] [mlir] Fix unused-variable warnings

This patch fixes warnings of the form:

  mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp:320:19: error:
  unused variable 'result' [-Werror,-Wunused-variable]
---
 mlir/include/mlir/Query/Matcher/SliceMatchers.h           | 1 +
 mlir/lib/Analysis/SliceAnalysis.cpp                       | 2 ++
 mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp           | 1 +
 mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp       | 2 ++
 mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp | 1 +
 mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp    | 1 +
 mlir/lib/Transforms/Utils/RegionUtils.cpp                 | 2 ++
 mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp   | 1 +
 mlir/test/lib/IR/TestSlicing.cpp                          | 1 +
 9 files changed, 12 insertions(+)

diff --git a/mlir/include/mlir/Query/Matcher/SliceMatchers.h b/mlir/include/mlir/Query/Matcher/SliceMatchers.h
index 40a39d23ca695..441205b3a9615 100644
--- a/mlir/include/mlir/Query/Matcher/SliceMatchers.h
+++ b/mlir/include/mlir/Query/Matcher/SliceMatchers.h
@@ -114,6 +114,7 @@ bool BackwardSliceMatcher<Matcher>::matches(
   };
   LogicalResult result = getBackwardSlice(rootOp, &backwardSlice, options);
   assert(result.succeeded() && "expected backward slice to succeed");
+  (void)result;
   return options.inclusive ? backwardSlice.size() > 1
                            : backwardSlice.size() >= 1;
 }
diff --git a/mlir/lib/Analysis/SliceAnalysis.cpp b/mlir/lib/Analysis/SliceAnalysis.cpp
index 12b9d3adb49fa..c4eda71c42f3e 100644
--- a/mlir/lib/Analysis/SliceAnalysis.cpp
+++ b/mlir/lib/Analysis/SliceAnalysis.cpp
@@ -180,6 +180,7 @@ mlir::getSlice(Operation *op, const BackwardSliceOptions &backwardSliceOptions,
     LogicalResult result =
         getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
     assert(result.succeeded());
+    (void)result;
     slice.insert_range(backwardSlice);
 
     // Compute and insert the forwardSlice starting from currentOp.
@@ -204,6 +205,7 @@ static bool dependsOnCarriedVals(Value value,
   };
   LogicalResult result = getBackwardSlice(value, &slice, sliceOptions);
   assert(result.succeeded());
+  (void)result;
 
   // Check that none of the operands of the operations in the backward slice are
   // loop iteration arguments, and neither is the value itself.
diff --git a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
index 0ec9ddc25ff8d..9017bcb5283c9 100644
--- a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
+++ b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp
@@ -320,6 +320,7 @@ getSliceContract(Operation *op,
     LogicalResult result =
         getBackwardSlice(currentOp, &backwardSlice, backwardSliceOptions);
     assert(result.succeeded() && "expected a backward slice");
+    (void)result;
     slice.insert_range(backwardSlice);
 
     // Compute and insert the forwardSlice starting from currentOp.
diff --git a/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp b/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
index 2c98bd3ba93af..bfeeb7756860d 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp
@@ -126,11 +126,13 @@ static void computeBackwardSlice(tensor::PadOp padOp,
   for (Value v : valuesDefinedAbove) {
     LogicalResult result = getBackwardSlice(v, &backwardSlice, sliceOptions);
     assert(result.succeeded() && "expected a backward slice");
+    (void)result;
   }
   // Then, add the backward slice from padOp itself.
   LogicalResult result =
       getBackwardSlice(padOp.getOperation(), &backwardSlice, sliceOptions);
   assert(result.succeeded() && "expected a backward slice");
+  (void)result;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
index 1046f5798ecd4..d2c94b124cdfb 100644
--- a/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
+++ b/mlir/lib/Dialect/NVGPU/TransformOps/NVGPUTransformOps.cpp
@@ -293,6 +293,7 @@ static void getPipelineStages(
     if (stage0Ops.contains(&op)) {
       LogicalResult result = getBackwardSlice(&op, &dependencies, options);
       assert(result.succeeded() && "expected a backward slice");
+      (void)result;
     }
   }
 
diff --git a/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp b/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
index 9e3d3f8b10a13..57ee0f52e7491 100644
--- a/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/TileUsingInterface.cpp
@@ -1774,6 +1774,7 @@ checkAssumptionForLoop(Operation *loopOp, Operation *consumerOp,
   for (auto operand : consumerOp->getOperands()) {
     LogicalResult result = getBackwardSlice(operand, &slice, options);
     assert(result.succeeded() && "expected a backward slice");
+    (void)result;
   }
 
   if (!slice.empty()) {
diff --git a/mlir/lib/Transforms/Utils/RegionUtils.cpp b/mlir/lib/Transforms/Utils/RegionUtils.cpp
index c136ff92255cd..70a97f26b01f6 100644
--- a/mlir/lib/Transforms/Utils/RegionUtils.cpp
+++ b/mlir/lib/Transforms/Utils/RegionUtils.cpp
@@ -1096,6 +1096,7 @@ LogicalResult mlir::moveOperationDependencies(RewriterBase &rewriter,
   llvm::SetVector<Operation *> slice;
   LogicalResult result = getBackwardSlice(op, &slice, options);
   assert(result.succeeded() && "expected a backward slice");
+  (void)result;
 
   // If the slice contains `insertionPoint` cannot move the dependencies.
   if (slice.contains(insertionPoint)) {
@@ -1162,6 +1163,7 @@ LogicalResult mlir::moveValueDefinitions(RewriterBase &rewriter,
   for (auto value : prunedValues) {
     LogicalResult result = getBackwardSlice(value, &slice, options);
     assert(result.succeeded() && "expected a backward slice");
+    (void)result;
   }
 
   // If the slice contains `insertionPoint` cannot move the dependencies.
diff --git a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
index 145acd99e6616..2c93991386675 100644
--- a/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
+++ b/mlir/test/lib/Dialect/Affine/TestVectorizationUtils.cpp
@@ -157,6 +157,7 @@ void VectorizerTestPass::testBackwardSlicing(llvm::raw_ostream &outs) {
     LogicalResult result =
         getBackwardSlice(m.getMatchedOperation(), &backwardSlice);
     assert(result.succeeded() && "expected a backward slice");
+    (void)result;
     outs << "\nmatched: " << *m.getMatchedOperation()
          << " backward static slice: ";
     for (auto *op : backwardSlice)
diff --git a/mlir/test/lib/IR/TestSlicing.cpp b/mlir/test/lib/IR/TestSlicing.cpp
index ad99be2b9d0c9..92fd6de88ce88 100644
--- a/mlir/test/lib/IR/TestSlicing.cpp
+++ b/mlir/test/lib/IR/TestSlicing.cpp
@@ -43,6 +43,7 @@ static LogicalResult createBackwardSliceFunction(Operation *op,
   options.omitUsesFromAbove = false;
   LogicalResult result = getBackwardSlice(op, &slice, options);
   assert(result.succeeded() && "expected a backward slice");
+  (void)result;
   for (Operation *slicedOp : slice)
     builder.clone(*slicedOp, mapper);
   builder.create<func::ReturnOp>(loc);

>From d25f95fdbc5314f30618912e18f00ad4dd720fa0 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 12:40:03 -0700
Subject: [PATCH 041/105] [clang] Fix handle_cxx.cpp after 9e306ad4

---
 clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp b/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
index 14204021d262b..98925c00260f1 100644
--- a/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
+++ b/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp
@@ -32,9 +32,9 @@ void clang_fuzzer::HandleCXX(const std::string &S,
   llvm::IntrusiveRefCntPtr<FileManager> Files(
       new FileManager(FileSystemOptions()));
   IgnoringDiagConsumer Diags;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &Diags, false);
   std::unique_ptr<clang::CompilerInvocation> Invocation(
       tooling::newInvocation(&Diagnostics, CC1Args, /*BinaryName=*/nullptr));

>From b544853fc335bdba6edbcde33e0c284306cd08eb Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 12:42:35 -0700
Subject: [PATCH 042/105] [clang] Fix VirtualFileHelper.h after 9e306ad4

---
 .../unittests/include/common/VirtualFileHelper.h         | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/unittests/include/common/VirtualFileHelper.h b/clang-tools-extra/unittests/include/common/VirtualFileHelper.h
index abe1067495694..86991bb343d8d 100644
--- a/clang-tools-extra/unittests/include/common/VirtualFileHelper.h
+++ b/clang-tools-extra/unittests/include/common/VirtualFileHelper.h
@@ -32,10 +32,9 @@ class VirtualFileHelper {
 
 public:
   VirtualFileHelper()
-      : DiagOpts(new DiagnosticOptions()),
-        Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-                    &*DiagOpts),
-        DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+      : Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+                    DiagOpts),
+        DiagnosticPrinter(llvm::outs(), DiagOpts),
         Files((FileSystemOptions())) {}
 
   /// Create a virtual file \p FileName, with content \p Code.
@@ -67,7 +66,7 @@ class VirtualFileHelper {
   }
 
 private:
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics;
   TextDiagnosticPrinter DiagnosticPrinter;
   FileManager Files;

>From e23a6921b47d2cfb4d27289149079e9d77aa0560 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 20:43:33 +0100
Subject: [PATCH 043/105] [LoopIdiom] Improve code; use SCEVPatternMatch (NFC)
 (#139540)

---
 .../Transforms/Scalar/LoopIdiomRecognize.cpp  | 108 ++++++++----------
 1 file changed, 45 insertions(+), 63 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index 0eaed2eddcdbb..0d5e0156b22be 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -32,7 +32,6 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
@@ -49,6 +48,7 @@
 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
 #include "llvm/Analysis/ScalarEvolution.h"
 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Analysis/ScalarEvolutionPatternMatch.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -91,6 +91,7 @@
 #include <vector>
 
 using namespace llvm;
+using namespace SCEVPatternMatch;
 
 #define DEBUG_TYPE "loop-idiom"
 
@@ -340,9 +341,8 @@ bool LoopIdiomRecognize::runOnCountableLoop() {
 
   // If this loop executes exactly one time, then it should be peeled, not
   // optimized by this pass.
-  if (const SCEVConstant *BECst = dyn_cast<SCEVConstant>(BECount))
-    if (BECst->getAPInt() == 0)
-      return false;
+  if (BECount->isZero())
+    return false;
 
   SmallVector<BasicBlock *, 8> ExitBlocks;
   CurLoop->getUniqueExitBlocks(ExitBlocks);
@@ -453,13 +453,10 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) {
   // See if the pointer expression is an AddRec like {base,+,1} on the current
   // loop, which indicates a strided store.  If we have something else, it's a
   // random store we can't handle.
-  const SCEVAddRecExpr *StoreEv =
-      dyn_cast<SCEVAddRecExpr>(SE->getSCEV(StorePtr));
-  if (!StoreEv || StoreEv->getLoop() != CurLoop || !StoreEv->isAffine())
-    return LegalStoreKind::None;
-
-  // Check to see if we have a constant stride.
-  if (!isa<SCEVConstant>(StoreEv->getOperand(1)))
+  const SCEV *StoreEv = SE->getSCEV(StorePtr);
+  const SCEVConstant *Stride;
+  if (!match(StoreEv, m_scev_AffineAddRec(m_SCEV(), m_SCEVConstant(Stride))) ||
+      cast<SCEVAddRecExpr>(StoreEv)->getLoop() != CurLoop)
     return LegalStoreKind::None;
 
   // See if the store can be turned into a memset.
@@ -494,9 +491,9 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) {
   if (HasMemcpy && !DisableLIRP::Memcpy) {
     // Check to see if the stride matches the size of the store.  If so, then we
     // know that every byte is touched in the loop.
-    APInt Stride = getStoreStride(StoreEv);
     unsigned StoreSize = DL->getTypeStoreSize(SI->getValueOperand()->getType());
-    if (StoreSize != Stride && StoreSize != -Stride)
+    APInt StrideAP = Stride->getAPInt();
+    if (StoreSize != StrideAP && StoreSize != -StrideAP)
       return LegalStoreKind::None;
 
     // The store must be feeding a non-volatile load.
@@ -512,13 +509,12 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) {
     // See if the pointer expression is an AddRec like {base,+,1} on the current
     // loop, which indicates a strided load.  If we have something else, it's a
     // random load we can't handle.
-    const SCEVAddRecExpr *LoadEv =
-        dyn_cast<SCEVAddRecExpr>(SE->getSCEV(LI->getPointerOperand()));
-    if (!LoadEv || LoadEv->getLoop() != CurLoop || !LoadEv->isAffine())
-      return LegalStoreKind::None;
+    const SCEV *LoadEv = SE->getSCEV(LI->getPointerOperand());
 
     // The store and load must share the same stride.
-    if (StoreEv->getOperand(1) != LoadEv->getOperand(1))
+    if (!match(LoadEv,
+               m_scev_AffineAddRec(m_SCEV(), m_scev_Specific(Stride))) ||
+        cast<SCEVAddRecExpr>(LoadEv)->getLoop() != CurLoop)
       return LegalStoreKind::None;
 
     // Success.  This store can be converted into a memcpy.
@@ -805,20 +801,17 @@ bool LoopIdiomRecognize::processLoopMemCpy(MemCpyInst *MCI,
 
   // Check if the stride matches the size of the memcpy. If so, then we know
   // that every byte is touched in the loop.
-  const SCEVConstant *ConstStoreStride =
-      dyn_cast<SCEVConstant>(StoreEv->getOperand(1));
-  const SCEVConstant *ConstLoadStride =
-      dyn_cast<SCEVConstant>(LoadEv->getOperand(1));
-  if (!ConstStoreStride || !ConstLoadStride)
+  const APInt *StoreStrideValue, *LoadStrideValue;
+  if (!match(StoreEv->getOperand(1), m_scev_APInt(StoreStrideValue)) ||
+      !match(LoadEv->getOperand(1), m_scev_APInt(LoadStrideValue)))
     return false;
 
-  APInt StoreStrideValue = ConstStoreStride->getAPInt();
-  APInt LoadStrideValue = ConstLoadStride->getAPInt();
   // Huge stride value - give up
-  if (StoreStrideValue.getBitWidth() > 64 || LoadStrideValue.getBitWidth() > 64)
+  if (StoreStrideValue->getBitWidth() > 64 ||
+      LoadStrideValue->getBitWidth() > 64)
     return false;
 
-  if (SizeInBytes != StoreStrideValue && SizeInBytes != -StoreStrideValue) {
+  if (SizeInBytes != *StoreStrideValue && SizeInBytes != -*StoreStrideValue) {
     ORE.emit([&]() {
       return OptimizationRemarkMissed(DEBUG_TYPE, "SizeStrideUnequal", MCI)
              << ore::NV("Inst", "memcpy") << " in "
@@ -829,8 +822,8 @@ bool LoopIdiomRecognize::processLoopMemCpy(MemCpyInst *MCI,
     return false;
   }
 
-  int64_t StoreStrideInt = StoreStrideValue.getSExtValue();
-  int64_t LoadStrideInt = LoadStrideValue.getSExtValue();
+  int64_t StoreStrideInt = StoreStrideValue->getSExtValue();
+  int64_t LoadStrideInt = LoadStrideValue->getSExtValue();
   // Check if the load stride matches the store stride.
   if (StoreStrideInt != LoadStrideInt)
     return false;
@@ -857,15 +850,15 @@ bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
   // See if the pointer expression is an AddRec like {base,+,1} on the current
   // loop, which indicates a strided store.  If we have something else, it's a
   // random store we can't handle.
-  const SCEVAddRecExpr *Ev = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(Pointer));
-  if (!Ev || Ev->getLoop() != CurLoop)
-    return false;
-  if (!Ev->isAffine()) {
+  const SCEV *Ev = SE->getSCEV(Pointer);
+  const SCEV *PointerStrideSCEV;
+  if (!match(Ev, m_scev_AffineAddRec(m_SCEV(), m_SCEV(PointerStrideSCEV)))) {
     LLVM_DEBUG(dbgs() << "  Pointer is not affine, abort\n");
     return false;
   }
+  if (cast<SCEVAddRecExpr>(Ev)->getLoop() != CurLoop)
+    return false;
 
-  const SCEV *PointerStrideSCEV = Ev->getOperand(1);
   const SCEV *MemsetSizeSCEV = SE->getSCEV(MSI->getLength());
   if (!PointerStrideSCEV || !MemsetSizeSCEV)
     return false;
@@ -879,15 +872,14 @@ bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
     // we know that every byte is touched in the loop.
     LLVM_DEBUG(dbgs() << "  memset size is constant\n");
     uint64_t SizeInBytes = cast<ConstantInt>(MSI->getLength())->getZExtValue();
-    const SCEVConstant *ConstStride = dyn_cast<SCEVConstant>(Ev->getOperand(1));
-    if (!ConstStride)
+    const APInt *Stride;
+    if (!match(PointerStrideSCEV, m_scev_APInt(Stride)))
       return false;
 
-    APInt Stride = ConstStride->getAPInt();
-    if (SizeInBytes != Stride && SizeInBytes != -Stride)
+    if (SizeInBytes != *Stride && SizeInBytes != -*Stride)
       return false;
 
-    IsNegStride = SizeInBytes == -Stride;
+    IsNegStride = SizeInBytes == -*Stride;
   } else {
     // Memset size is non-constant.
     // Check if the pointer stride matches the memset size.
@@ -944,8 +936,9 @@ bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
   SmallPtrSet<Instruction *, 1> MSIs;
   MSIs.insert(MSI);
   return processLoopStridedStore(Pointer, SE->getSCEV(MSI->getLength()),
-                                 MSI->getDestAlign(), SplatValue, MSI, MSIs, Ev,
-                                 BECount, IsNegStride, /*IsLoopMemset=*/true);
+                                 MSI->getDestAlign(), SplatValue, MSI, MSIs,
+                                 cast<SCEVAddRecExpr>(Ev), BECount, IsNegStride,
+                                 /*IsLoopMemset=*/true);
 }
 
 /// mayLoopAccessLocation - Return true if the specified loop might access the
@@ -963,11 +956,11 @@ mayLoopAccessLocation(Value *Ptr, ModRefInfo Access, Loop *L,
 
   // If the loop iterates a fixed number of times, we can refine the access size
   // to be exactly the size of the memset, which is (BECount+1)*StoreSize
-  const SCEVConstant *BECst = dyn_cast<SCEVConstant>(BECount);
-  const SCEVConstant *ConstSize = dyn_cast<SCEVConstant>(StoreSizeSCEV);
-  if (BECst && ConstSize) {
-    std::optional<uint64_t> BEInt = BECst->getAPInt().tryZExtValue();
-    std::optional<uint64_t> SizeInt = ConstSize->getAPInt().tryZExtValue();
+  const APInt *BECst, *ConstSize;
+  if (match(BECount, m_scev_APInt(BECst)) &&
+      match(StoreSizeSCEV, m_scev_APInt(ConstSize))) {
+    std::optional<uint64_t> BEInt = BECst->tryZExtValue();
+    std::optional<uint64_t> SizeInt = ConstSize->tryZExtValue();
     // FIXME: Should this check for overflow?
     if (BEInt && SizeInt)
       AccessSize = LocationSize::precise((*BEInt + 1) * *SizeInt);
@@ -1579,24 +1572,15 @@ class StrlenVerifier {
     // See if the pointer expression is an AddRec with constant step a of form
     // ({n,+,a}) where a is the width of the char type.
     Value *IncPtr = LoopLoad->getPointerOperand();
-    const SCEVAddRecExpr *LoadEv =
-        dyn_cast<SCEVAddRecExpr>(SE->getSCEV(IncPtr));
-    if (!LoadEv || LoadEv->getLoop() != CurLoop || !LoadEv->isAffine())
+    const SCEV *LoadEv = SE->getSCEV(IncPtr);
+    const APInt *Step;
+    if (!match(LoadEv,
+               m_scev_AffineAddRec(m_SCEV(LoadBaseEv), m_scev_APInt(Step))))
       return false;
-    LoadBaseEv = LoadEv->getStart();
 
     LLVM_DEBUG(dbgs() << "pointer load scev: " << *LoadEv << "\n");
 
-    const SCEVConstant *Step =
-        dyn_cast<SCEVConstant>(LoadEv->getStepRecurrence(*SE));
-    if (!Step)
-      return false;
-
-    unsigned StepSize = 0;
-    StepSizeCI = dyn_cast<ConstantInt>(Step->getValue());
-    if (!StepSizeCI)
-      return false;
-    StepSize = StepSizeCI->getZExtValue();
+    unsigned StepSize = Step->getZExtValue();
 
     // Verify that StepSize is consistent with platform char width.
     OpWidth = OperandType->getIntegerBitWidth();
@@ -3277,9 +3261,7 @@ bool LoopIdiomRecognize::recognizeShiftUntilZero() {
   // Ok, transform appears worthwhile.
   MadeChange = true;
 
-  bool OffsetIsZero = false;
-  if (auto *ExtraOffsetExprC = dyn_cast<SCEVConstant>(ExtraOffsetExpr))
-    OffsetIsZero = ExtraOffsetExprC->isZero();
+  bool OffsetIsZero = ExtraOffsetExpr->isZero();
 
   // Step 1: Compute the loop's final IV value / trip count.
 

>From e2a885537f11f8d9ced1c80c2c90069ab5adeb1d Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 12:44:20 -0700
Subject: [PATCH 044/105] Revert "[clang] Remove intrusive reference count from
 `DiagnosticOptions` (#139584)"

This reverts commit 9e306ad4600c4d3392c194a8be88919ee758425c.

Multiple builtbot failures have been reported:
https://github.com/llvm/llvm-project/pull/139584
---
 .../tool/ClangApplyReplacementsMain.cpp       |  4 +-
 .../tool/ClangChangeNamespace.cpp             |  6 +-
 .../tool/ClangIncludeFixer.cpp                |  6 +-
 .../clang-move/tool/ClangMove.cpp             |  6 +-
 clang-tools-extra/clang-query/Query.cpp       |  2 +-
 .../tool/ClangReorderFields.cpp               |  6 +-
 clang-tools-extra/clang-tidy/ClangTidy.cpp    | 24 +++---
 .../ClangTidyDiagnosticConsumer.cpp           |  4 +-
 .../clang-tidy/ClangTidyDiagnosticConsumer.h  |  5 +-
 .../ExpandModularHeadersPPCallbacks.cpp       |  2 +-
 .../ExpandModularHeadersPPCallbacks.h         |  1 -
 clang-tools-extra/clangd/Compiler.cpp         |  5 +-
 clang-tools-extra/clangd/ModulesBuilder.cpp   |  4 +-
 clang-tools-extra/clangd/ParsedAST.cpp        |  3 +-
 clang-tools-extra/clangd/Preamble.cpp         |  2 +-
 .../clangd/SystemIncludeExtractor.cpp         |  3 +-
 .../clangd/unittests/ConfigCompileTests.cpp   |  3 +-
 .../clangd/unittests/tweaks/TweakTests.cpp    |  3 +-
 .../include-cleaner/unittests/RecordTest.cpp  |  4 +-
 .../include-cleaner/unittests/WalkASTTest.cpp |  6 +-
 .../modularize/ModularizeUtilities.cpp        |  6 +-
 .../modularize/ModularizeUtilities.h          |  2 +-
 .../ApplyReplacementsTest.cpp                 |  4 +-
 .../clang-tidy/ClangTidyOptionsTest.cpp       | 18 ++---
 .../unittests/clang-tidy/ClangTidyTest.h      |  6 +-
 clang/include/clang/Basic/Diagnostic.h        |  6 +-
 clang/include/clang/Basic/DiagnosticOptions.h |  4 +-
 clang/include/clang/Basic/SourceManager.h     |  1 -
 clang/include/clang/Frontend/ASTUnit.h        | 12 +--
 .../include/clang/Frontend/CompilerInstance.h |  2 +-
 .../clang/Frontend/CompilerInvocation.h       |  2 +-
 .../clang/Frontend/DiagnosticRenderer.h       |  7 +-
 .../clang/Frontend/LogDiagnosticPrinter.h     |  4 +-
 .../include/clang/Frontend/SARIFDiagnostic.h  |  2 +-
 .../clang/Frontend/SARIFDiagnosticPrinter.h   |  4 +-
 .../Frontend/SerializedDiagnosticPrinter.h    |  2 +-
 clang/include/clang/Frontend/TextDiagnostic.h |  2 +-
 .../clang/Frontend/TextDiagnosticPrinter.h    |  4 +-
 clang/include/clang/Serialization/ASTReader.h |  9 ++-
 clang/lib/Basic/Diagnostic.cpp                | 10 +--
 clang/lib/Basic/SourceManager.cpp             |  4 +-
 clang/lib/CrossTU/CrossTranslationUnit.cpp    | 20 ++---
 clang/lib/Frontend/ASTMerge.cpp               | 13 +--
 clang/lib/Frontend/ASTUnit.cpp                | 14 +---
 clang/lib/Frontend/ChainedIncludesSource.cpp  |  4 +-
 clang/lib/Frontend/CompilerInstance.cpp       | 27 ++++---
 clang/lib/Frontend/CompilerInvocation.cpp     | 27 +++++--
 .../CreateInvocationFromCommandLine.cpp       | 14 ++--
 clang/lib/Frontend/DiagnosticRenderer.cpp     | 17 ++--
 clang/lib/Frontend/FrontendAction.cpp         | 12 +--
 clang/lib/Frontend/FrontendActions.cpp        | 16 ++--
 clang/lib/Frontend/LogDiagnosticPrinter.cpp   |  4 +-
 clang/lib/Frontend/SARIFDiagnostic.cpp        |  4 +-
 clang/lib/Frontend/SARIFDiagnosticPrinter.cpp |  7 +-
 .../Frontend/SerializedDiagnosticPrinter.cpp  | 29 ++++---
 clang/lib/Frontend/TextDiagnostic.cpp         | 79 ++++++++++---------
 clang/lib/Frontend/TextDiagnosticPrinter.cpp  | 15 ++--
 clang/lib/Interpreter/CodeCompletion.cpp      |  3 +-
 clang/lib/Interpreter/Interpreter.cpp         |  8 +-
 clang/lib/Rewrite/HTMLRewrite.cpp             |  4 +-
 clang/lib/Serialization/ASTReader.cpp         | 25 +++---
 clang/lib/Testing/TestAST.cpp                 |  2 +-
 clang/lib/Tooling/CompilationDatabase.cpp     |  8 +-
 clang/lib/Tooling/Core/Replacement.cpp        |  4 +-
 .../DependencyScanningWorker.cpp              |  6 +-
 clang/lib/Tooling/Refactoring.cpp             |  8 +-
 clang/lib/Tooling/Tooling.cpp                 | 10 +--
 clang/tools/c-index-test/core_main.cpp        | 20 +++--
 .../ClangExtDefMapGen.cpp                     | 14 ++--
 clang/tools/clang-format/ClangFormat.cpp      |  8 +-
 .../clang-import-test/clang-import-test.cpp   |  4 +-
 .../clang-installapi/ClangInstallAPI.cpp      |  8 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  9 +--
 clang/tools/diagtool/ShowEnabledWarnings.cpp  |  6 +-
 clang/tools/diagtool/TreeView.cpp             |  4 +-
 clang/tools/driver/cc1_main.cpp               |  4 +-
 clang/tools/driver/cc1as_main.cpp             |  8 +-
 clang/tools/driver/cc1gen_reproducer_main.cpp |  6 +-
 clang/tools/driver/driver.cpp                 | 11 +--
 clang/tools/libclang/CIndex.cpp               | 11 ++-
 clang/tools/libclang/CIndexCodeCompletion.cpp | 10 +--
 clang/tools/libclang/CIndexDiagnostic.cpp     | 17 ++--
 clang/tools/libclang/Indexing.cpp             |  7 +-
 clang/unittests/AST/ASTVectorTest.cpp         |  3 +-
 clang/unittests/AST/CommentLexer.cpp          | 10 ++-
 clang/unittests/AST/CommentParser.cpp         | 10 ++-
 clang/unittests/AST/CommentTextTest.cpp       |  3 +-
 clang/unittests/AST/ExternalASTSourceTest.cpp |  4 +-
 .../UncheckedOptionalAccessModelTest.cpp      |  5 +-
 .../Analysis/MacroExpansionContextTest.cpp    |  6 +-
 .../Analysis/UnsafeBufferUsageTest.cpp        |  3 +-
 clang/unittests/Basic/DiagnosticTest.cpp      | 23 +++---
 clang/unittests/Basic/SarifTest.cpp           |  6 +-
 clang/unittests/Basic/SourceManagerTest.cpp   |  9 ++-
 clang/unittests/Driver/DXCModeTest.cpp        | 12 +--
 clang/unittests/Driver/SanitizerArgsTest.cpp  |  7 +-
 .../Driver/SimpleDiagnosticConsumer.h         |  5 +-
 clang/unittests/Driver/ToolChainTest.cpp      | 71 ++++++++---------
 clang/unittests/Frontend/ASTUnitTest.cpp      | 37 +++++----
 .../Frontend/CompilerInstanceTest.cpp         | 11 ++-
 .../Frontend/CompilerInvocationTest.cpp       |  3 +-
 clang/unittests/Frontend/OutputStreamTest.cpp | 12 +--
 clang/unittests/Frontend/PCHPreambleTest.cpp  |  7 +-
 .../Frontend/ReparseWorkingDirTest.cpp        |  6 +-
 clang/unittests/Frontend/SearchPathTest.cpp   |  4 +-
 .../unittests/Frontend/TextDiagnosticTest.cpp |  8 +-
 clang/unittests/Frontend/UtilsTest.cpp        |  9 +--
 .../unittests/Interpreter/InterpreterTest.cpp | 15 ++--
 clang/unittests/Lex/HeaderSearchTest.cpp      |  3 +-
 clang/unittests/Lex/LexerTest.cpp             | 10 ++-
 clang/unittests/Lex/ModuleDeclStateTest.cpp   |  3 +-
 clang/unittests/Lex/PPCallbacksTest.cpp       |  8 +-
 .../Lex/PPConditionalDirectiveRecordTest.cpp  | 10 ++-
 .../Lex/PPDependencyDirectivesTest.cpp        |  3 +-
 .../unittests/Lex/PPMemoryAllocationsTest.cpp |  3 +-
 .../Parse/ParseHLSLRootSignatureTest.cpp      |  4 +-
 clang/unittests/Sema/SemaNoloadLookupTest.cpp |  4 +-
 .../Serialization/ForceCheckFileInputTest.cpp |  8 +-
 .../Serialization/LoadSpecLazilyTest.cpp      |  3 +-
 .../Serialization/ModuleCacheTest.cpp         |  6 +-
 .../Serialization/NoCommentsTest.cpp          |  3 +-
 .../PreambleInNamedModulesTest.cpp            |  3 +-
 .../Serialization/VarDeclConstantInitTest.cpp |  3 +-
 clang/unittests/Support/TimeProfilerTest.cpp  |  4 +-
 clang/unittests/Tooling/RewriterTestContext.h |  9 ++-
 clang/unittests/Tooling/Syntax/TokensTest.cpp |  3 +-
 .../unittests/Tooling/Syntax/TreeTestBase.cpp |  2 +-
 clang/unittests/Tooling/Syntax/TreeTestBase.h |  4 +-
 clang/unittests/Tooling/ToolingTest.cpp       |  8 +-
 .../Clang/ClangExpressionParser.cpp           | 10 +--
 .../Clang/ClangExpressionSourceCode.cpp       |  3 +-
 .../Clang/ClangModulesDeclVendor.cpp          | 21 ++---
 .../Language/ClangCommon/ClangHighlighter.cpp |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.h        |  1 -
 135 files changed, 568 insertions(+), 603 deletions(-)

diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 062e236d3e51f..68b5743c6540f 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -96,9 +96,9 @@ int main(int argc, char **argv) {
   cl::SetVersionPrinter(printVersion);
   cl::ParseCommandLineOptions(argc, argv);
 
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 2a8fe2d06d185..22d26db0c11bc 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -126,10 +126,10 @@ int main(int argc, const char **argv) {
   if (int Result = Tool.run(Factory.get()))
     return Result;
   LangOptions DefaultLangOptions;
-  DiagnosticOptions DiagOpts;
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager Sources(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 746ba7bcea015..6e51f25a66407 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) {
   }
 
   // Set up a new source manager for applying the resulting replacements.
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts);
-  TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
   SourceManager SM(Diagnostics, tool.getFiles());
   Diagnostics.setClient(&DiagnosticPrinter, false);
 
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 750eb952714f7..655ea81ee37d4 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -176,10 +176,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  DiagnosticOptions DiagOpts;
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager SM(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
index 574b64ee0f759..382aa5d6fe25e 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
           clang::SourceRange R = BI->second.getSourceRange();
           if (R.isValid()) {
             TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
-                              AST->getDiagnostics().getDiagnosticOptions());
+                              &AST->getDiagnostics().getDiagnosticOptions());
             TD.emitDiagnostic(
                 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
                 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
index 03502525417b2..5b77ee7b5738c 100644
--- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
+++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -72,10 +72,10 @@ int main(int argc, const char **argv) {
 
   int ExitCode = Tool.run(Factory.get());
   LangOptions DefaultLangOptions;
-  DiagnosticOptions DiagOpts;
-  TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
       &DiagnosticPrinter, false);
 
   auto &FileMgr = Tool.getFiles();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 26f9afbc0880e..733a53a0f5dcc 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -97,14 +97,15 @@ class ErrorReporter {
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
-        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
+        DiagOpts(new DiagnosticOptions()),
+        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
+        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
               DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
-    DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
+    DiagOpts->ShowColors = Context.getOptions().UseColor.value_or(
         llvm::sys::Process::StandardOutHasColors());
     DiagPrinter->BeginSourceFile(LangOpts);
-    if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
+    if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
       llvm::sys::Process::UseANSIEscapeCodes(true);
     }
   }
@@ -307,7 +308,7 @@ class ErrorReporter {
 
   FileManager Files;
   LangOptions LangOpts; // FIXME: use langopts from each original file
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticConsumer *DiagPrinter;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
@@ -515,10 +516,10 @@ getCheckOptions(const ClangTidyOptions &Options,
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
+  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(),
+                       llvm::makeIntrusiveRefCnt<DiagnosticOptions>(),
                        &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  Context.setDiagnosticsEngine(&DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -557,10 +558,9 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
   ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
-                       /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
+                       &DiagConsumer, /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(&DE);
   Tool.setDiagnosticConsumer(&DiagConsumer);
 
   class ActionFactory : public FrontendActionFactory {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index a0253a5fd1a48..b216970bfbd8c 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -49,7 +49,7 @@ namespace {
 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
 public:
   ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
-                              DiagnosticOptions &DiagOpts,
+                              DiagnosticOptions *DiagOpts,
                               ClangTidyError &Error)
       : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
 
@@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
     forwardDiagnostic(Info);
   } else {
     ClangTidyDiagnosticRenderer Converter(
-        Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
+        Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
         Errors.back());
     SmallString<100> Message;
     Info.FormatDiagnostic(Message);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index bd7a1bf2c11c7..d6cf6a2b2731e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -75,9 +75,7 @@ class ClangTidyContext {
   /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
   // FIXME: this is required initialization, and should be a constructor param.
   // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
-                            DiagnosticsEngine *DiagEngine) {
-    this->DiagOpts = std::move(DiagOpts);
+  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
     this->DiagEngine = DiagEngine;
   }
 
@@ -233,7 +231,6 @@ class ClangTidyContext {
   // Writes to Stats.
   friend class ClangTidyDiagnosticConsumer;
 
-  std::unique_ptr<DiagnosticOptions> DiagOpts = nullptr;
   DiagnosticsEngine *DiagEngine = nullptr;
   std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
 
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 6a84704434c33..03a3e8404e069 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
       InMemoryFs(new llvm::vfs::InMemoryFileSystem),
       Sources(Compiler.getSourceManager()),
       // Forward the new diagnostics to the original DiagnosticConsumer.
-      Diags(new DiagnosticIDs, DiagOpts,
+      Diags(new DiagnosticIDs, new DiagnosticOptions,
             new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
       LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
   // Add a FileSystem containing the extra files needed in place of modular
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
index c3478917ef498..a263681b3c633 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -128,7 +128,6 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs;
 
   SourceManager &Sources;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   LangOptions LangOpts;
   HeaderSearchOptions HSOpts;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 8b3865c8a8e5c..9be0152afd2f7 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -110,9 +110,8 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
   CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   CIOpts.CC1Args = CC1Args;
   CIOpts.RecoverOnError = true;
-  DiagnosticOptions DiagOpts;
-  CIOpts.Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);
+  CIOpts.Diags = CompilerInstance::createDiagnostics(
+      *CIOpts.VFS, new DiagnosticOptions, &D, false);
   CIOpts.ProbePrecompiled = false;
   std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
   if (!CI)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index bf77f43bd28bb..c1878f91b5e16 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   HSOpts.ValidateASTInputFilesContent = true;
 
   clang::clangd::IgnoreDiagnostics IgnoreDiags;
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
+      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
+                                          &IgnoreDiags,
                                           /*ShouldOwnClient=*/false);
 
   LangOptions LangOpts;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 9e1f6bb977226..3f63daaf400db 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -556,8 +556,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
         *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
         tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
-    // The lifetime of DiagnosticOptions is managed by \c Clang.
-    CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
+    CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index 7b4d63ff197e7..ba9a53db8a0dc 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       });
   auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
-      CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
+      CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(),
                                           &PreambleDiagnostics,
                                           /*ShouldOwnClient=*/false);
   const Config &Cfg = Config::current();
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index 0b067e8b0b2b2..6417bf8765622 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -253,8 +253,7 @@ namespace {
 bool isValidTarget(llvm::StringRef Triple) {
   std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions);
   TargetOpts->Triple = Triple.str();
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
+  DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
                           new IgnoringDiagConsumer);
   llvm::IntrusiveRefCntPtr<TargetInfo> Target =
       TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index 75d0ff244038d..c3e484a1a79c4 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,8 +298,7 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
                                    "unreachable-code", "unused-variable",
                                    "typecheck_bool_condition",
                                    "unexpected_friend", "warn_alloca"));
-  clang::DiagnosticOptions DiagOpts;
-  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts,
+  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
                                       new clang::IgnoringDiagConsumer);
 
   using Diag = clang::Diagnostic;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
index e39b70224d97c..8bd40c1429012 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
@@ -44,8 +44,7 @@ TEST(FileEdits, AbsolutePath) {
   for (const auto *Path : RelPaths)
     MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path));
   FileManager FM(FileSystemOptions(), MemFS);
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts);
+  DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions);
   SourceManager SM(DE, FM);
 
   for (const auto *Path : RelPaths) {
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index 91d2697712b6e..a10c0d5a54a95 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) {
                  llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(),
                                                       /*BufferName=*/""));
 
-  DiagnosticOptions DiagOpts;
-  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts);
+  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get());
   auto Invocation = std::make_unique<CompilerInvocation>();
   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()},
                                                  *Diags, "clang"));
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 3487f24f2af8f..0de0b77f33daf 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -85,9 +85,9 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
   // For each difference, show the target point in context, like a diagnostic.
   std::string DiagBuf;
   llvm::raw_string_ostream DiagOS(DiagBuf);
-  DiagnosticOptions DiagOpts;
-  DiagOpts.ShowLevel = 0;
-  DiagOpts.ShowNoteIncludeStack = 0;
+  auto *DiagOpts = new DiagnosticOptions();
+  DiagOpts->ShowLevel = 0;
+  DiagOpts->ShowNoteIncludeStack = 0;
   TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
   auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) {
     Diag.emitDiagnostic(
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index 9ad1731915a8b..a8f1ddf64d34b 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -48,8 +48,10 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
       MissingHeaderCount(0),
       // Init clang stuff needed for loading the module map and preprocessing.
       LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
-      DC(llvm::errs(), DiagnosticOpts),
-      Diagnostics(new DiagnosticsEngine(DiagIDs, DiagnosticOpts, &DC, false)),
+      DiagnosticOpts(new DiagnosticOptions()),
+      DC(llvm::errs(), DiagnosticOpts.get()),
+      Diagnostics(
+          new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
       TargetOpts(new ModuleMapTargetOptions()),
       Target(TargetInfo::CreateTargetInfo(*Diagnostics, *TargetOpts)),
       FileMgr(new FileManager(FileSystemOpts)),
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.h b/clang-tools-extra/modularize/ModularizeUtilities.h
index 3242ea0c4b97e..7b4c16a492b89 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.h
+++ b/clang-tools-extra/modularize/ModularizeUtilities.h
@@ -198,7 +198,7 @@ class ModularizeUtilities {
   /// Diagnostic IDs.
   const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs;
   /// Options controlling the diagnostic engine.
-  clang::DiagnosticOptions DiagnosticOpts;
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagnosticOpts;
   /// Diagnostic consumer.
   clang::TextDiagnosticPrinter DC;
   /// Diagnostic engine.
diff --git a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
index 87b0d69f4654a..4fe57e618004d 100644
--- a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
+++ b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
@@ -32,9 +32,9 @@ makeTUDiagnostics(const std::string &MainSourceFile, StringRef DiagnosticName,
 // Test to ensure diagnostics with no fixes, will be merged correctly
 // before applying.
 TEST(ApplyReplacementsTest, mergeDiagnosticsWithNoFixes) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
   FileManager Files((FileSystemOptions()));
   SourceManager SM(Diagnostics, Files);
   TUReplacements TURs;
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index d3ca26a19dd63..aaec0e6b50bbf 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -317,9 +317,9 @@ TEST(CheckOptionsValidation, MissingOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
+                       &DiagConsumer, false);
+  Context.setDiagnosticsEngine(&DE);
   TestCheck TestCheck(&Context);
   EXPECT_FALSE(TestCheck.getLocal("Opt"));
   EXPECT_EQ(TestCheck.getLocal("Opt", "Unknown"), "Unknown");
@@ -347,9 +347,9 @@ TEST(CheckOptionsValidation, ValidIntOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
+                       &DiagConsumer, false);
+  Context.setDiagnosticsEngine(&DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal("IntExpected"), 1);
@@ -409,9 +409,9 @@ TEST(ValidConfiguration, ValidEnumOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
+                       &DiagConsumer, false);
+  Context.setDiagnosticsEngine(&DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal<Colours>("Valid"), Colours::Red);
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
index 789cc2afb4f0c..e511eb6e49e8d 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -96,9 +96,9 @@ runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  auto DiagOpts = std::make_unique<DiagnosticOptions>();
-  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
-  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
+  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
+                       &DiagConsumer, false);
+  Context.setDiagnosticsEngine(&DE);
 
   std::vector<std::string> Args(1, "clang-tidy");
   Args.push_back("-fsyntax-only");
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index e9c54c3c487c9..49ef22d4e4eb6 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -330,7 +330,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   unsigned ConstexprBacktraceLimit = 0;
 
   IntrusiveRefCntPtr<DiagnosticIDs> Diags;
-  DiagnosticOptions &DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticConsumer *Client = nullptr;
   std::unique_ptr<DiagnosticConsumer> Owner;
   SourceManager *SourceMgr = nullptr;
@@ -566,7 +566,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
 
 public:
   explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
-                             DiagnosticOptions &DiagOpts,
+                             IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
                              DiagnosticConsumer *client = nullptr,
                              bool ShouldOwnClient = true);
   DiagnosticsEngine(const DiagnosticsEngine &) = delete;
@@ -582,7 +582,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   }
 
   /// Retrieve the diagnostic options.
-  DiagnosticOptions &getDiagnosticOptions() const { return DiagOpts; }
+  DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
 
   using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>;
 
diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h
index a230022224de5..29146532f9524 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.h
+++ b/clang/include/clang/Basic/DiagnosticOptions.h
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -66,7 +67,8 @@ inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS,
 raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M);
 
 /// Options for controlling the compiler diagnostics engine.
-class DiagnosticOptions {
+class DiagnosticOptions
+    : public llvm::ThreadSafeRefCountedBase<DiagnosticOptions> {
   friend bool ParseDiagnosticArgs(DiagnosticOptions &, llvm::opt::ArgList &,
                                   clang::DiagnosticsEngine *, bool);
 
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index cd3dac9133223..3762dbc2ccee8 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -2041,7 +2041,6 @@ class SourceManagerForFile {
   // as they are created in `createSourceManagerForFile` so that they can be
   // deleted in the reverse order as they are created.
   std::unique_ptr<FileManager> FileMgr;
-  std::unique_ptr<DiagnosticOptions> DiagOpts;
   std::unique_ptr<DiagnosticsEngine> Diagnostics;
   std::unique_ptr<SourceManager> SourceMgr;
 };
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index 1485192e8f1e3..ac99f0fb2b471 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -107,11 +107,6 @@ class ASTUnit {
 
 private:
   std::unique_ptr<LangOptions> LangOpts;
-  // FIXME: The documentation on \c LoadFrom* member functions states that the
-  // DiagnosticsEngine (and therefore DiagnosticOptions) must outlive the
-  // returned ASTUnit. This is not the case. Enfore it by storing non-owning
-  // pointers here.
-  std::shared_ptr<DiagnosticOptions> DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
   IntrusiveRefCntPtr<FileManager>         FileMgr;
   IntrusiveRefCntPtr<SourceManager>       SourceMgr;
@@ -679,7 +674,6 @@ class ASTUnit {
   /// Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
   static std::unique_ptr<ASTUnit>
   create(std::shared_ptr<CompilerInvocation> CI,
-         std::shared_ptr<DiagnosticOptions> DiagOpts,
          IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
          CaptureDiagsKind CaptureDiagnostics, bool UserFilesAreVolatile);
 
@@ -706,8 +700,7 @@ class ASTUnit {
   /// \returns - The initialized ASTUnit or null if the AST failed to load.
   static std::unique_ptr<ASTUnit> LoadFromASTFile(
       StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-      WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
-      IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+      WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       const FileSystemOptions &FileSystemOpts,
       const HeaderSearchOptions &HSOpts, const LangOptions *LangOpts = nullptr,
       bool OnlyLocalDecls = false,
@@ -769,7 +762,6 @@ class ASTUnit {
   static ASTUnit *LoadFromCompilerInvocationAction(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       FrontendAction *Action = nullptr, ASTUnit *Unit = nullptr,
       bool Persistent = true, StringRef ResourceFilesPath = StringRef(),
@@ -797,7 +789,6 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
       bool OnlyLocalDecls = false,
       CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
@@ -846,7 +837,6 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCommandLine(
       const char **ArgBegin, const char **ArgEnd,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
       bool StorePreamblesInMemory = false,
       StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false,
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 0ae490f0e8073..5f25a932c5052 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -674,7 +674,7 @@ class CompilerInstance : public ModuleLoader {
   ///
   /// \return The new object on success, or null on failure.
   static IntrusiveRefCntPtr<DiagnosticsEngine>
-  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
+  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
                     DiagnosticConsumer *Client = nullptr,
                     bool ShouldOwnClient = true,
                     const CodeGenOptions *CodeGenOpts = nullptr);
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index e147d2ba6087e..3ca900729b4a8 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -80,7 +80,7 @@ class CompilerInvocationBase {
   std::shared_ptr<TargetOptions> TargetOpts;
 
   /// Options controlling the diagnostic engine.
-  std::shared_ptr<DiagnosticOptions> DiagnosticOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
 
   /// Options controlling the \#include directive.
   std::shared_ptr<HeaderSearchOptions> HSOpts;
diff --git a/clang/include/clang/Frontend/DiagnosticRenderer.h b/clang/include/clang/Frontend/DiagnosticRenderer.h
index 3f03a6e02da4b..b939ebe979e71 100644
--- a/clang/include/clang/Frontend/DiagnosticRenderer.h
+++ b/clang/include/clang/Frontend/DiagnosticRenderer.h
@@ -47,7 +47,7 @@ using DiagOrStoredDiag =
 class DiagnosticRenderer {
 protected:
   const LangOptions &LangOpts;
-  DiagnosticOptions &DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   /// The location of the previous diagnostic if known.
   ///
@@ -68,7 +68,8 @@ class DiagnosticRenderer {
   /// which change the amount of information displayed.
   DiagnosticsEngine::Level LastLevel = DiagnosticsEngine::Ignored;
 
-  DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts);
+  DiagnosticRenderer(const LangOptions &LangOpts,
+                     DiagnosticOptions *DiagOpts);
 
   virtual ~DiagnosticRenderer();
 
@@ -141,7 +142,7 @@ class DiagnosticRenderer {
 class DiagnosticNoteRenderer : public DiagnosticRenderer {
 public:
   DiagnosticNoteRenderer(const LangOptions &LangOpts,
-                         DiagnosticOptions &DiagOpts)
+                         DiagnosticOptions *DiagOpts)
       : DiagnosticRenderer(LangOpts, DiagOpts) {}
 
   ~DiagnosticNoteRenderer() override;
diff --git a/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
index b43b0da13967a..ec22a8b6cc5fb 100644
--- a/clang/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -51,7 +51,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
   std::unique_ptr<raw_ostream> StreamOwner;
   const LangOptions *LangOpts;
-  DiagnosticOptions &DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   SourceLocation LastWarningLoc;
   FullSourceLoc LastLoc;
@@ -62,7 +62,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   std::string DwarfDebugFlags;
 
 public:
-  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts,
+  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
                        std::unique_ptr<raw_ostream> StreamOwner);
 
   void setDwarfDebugFlags(StringRef Value) {
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index 780f36c874109..ec1d0b8e6a7c9 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -23,7 +23,7 @@ namespace clang {
 class SARIFDiagnostic : public DiagnosticRenderer {
 public:
   SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                  DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer);
+                  DiagnosticOptions *DiagOpts, SarifDocumentWriter *Writer);
 
   ~SARIFDiagnostic() = default;
 
diff --git a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
index 3406ed16c2fba..f2652833b3c18 100644
--- a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
@@ -29,7 +29,7 @@ class SarifDocumentWriter;
 
 class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 public:
-  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts);
+  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags);
   ~SARIFDiagnosticPrinter() = default;
 
   SARIFDiagnosticPrinter &operator=(const SARIFDiagnosticPrinter &&) = delete;
@@ -60,7 +60,7 @@ class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 
 private:
   raw_ostream &OS;
-  DiagnosticOptions &DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   /// Handle to the currently active SARIF diagnostic emitter.
   std::unique_ptr<SARIFDiagnostic> SARIFDiag;
diff --git a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
index 2b6d2e4477d58..5586ef65e393f 100644
--- a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -32,7 +32,7 @@ namespace serialized_diags {
 /// (via libclang) without needing to parse Clang's command line output.
 ///
 std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
-                                           DiagnosticOptions &DiagOpts,
+                                           DiagnosticOptions *Diags,
                                            bool MergeChildRecords = false);
 
 } // end serialized_diags namespace
diff --git a/clang/include/clang/Frontend/TextDiagnostic.h b/clang/include/clang/Frontend/TextDiagnostic.h
index e2e88d4d648a2..a2fe8ae995423 100644
--- a/clang/include/clang/Frontend/TextDiagnostic.h
+++ b/clang/include/clang/Frontend/TextDiagnostic.h
@@ -38,7 +38,7 @@ class TextDiagnostic : public DiagnosticRenderer {
 
 public:
   TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                 DiagnosticOptions &DiagOpts, const Preprocessor *PP = nullptr);
+                 DiagnosticOptions *DiagOpts, const Preprocessor *PP = nullptr);
 
   ~TextDiagnostic() override;
 
diff --git a/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
index dd1ca6b2248b7..2610bde7513a1 100644
--- a/clang/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -26,7 +26,7 @@ class TextDiagnostic;
 
 class TextDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
-  DiagnosticOptions &DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
   /// Handle to the currently active text diagnostic emitter.
   std::unique_ptr<TextDiagnostic> TextDiag;
@@ -38,7 +38,7 @@ class TextDiagnosticPrinter : public DiagnosticConsumer {
   unsigned OwnsOutputStream : 1;
 
 public:
-  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions &DiagOpts,
+  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
                         bool OwnsOutputStream = false);
   ~TextDiagnosticPrinter() override;
 
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 6963611c6a815..57b0266af26bb 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -151,8 +151,9 @@ class ASTReaderListener {
   ///
   /// \returns true to indicate the diagnostic options are invalid, or false
   /// otherwise.
-  virtual bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
-                                     StringRef ModuleFilename, bool Complain) {
+  virtual bool
+  ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+                        StringRef ModuleFilename, bool Complain) {
     return false;
   }
 
@@ -284,7 +285,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadFileSystemOptions(const FileSystemOptions &FSOpts,
                              bool Complain) override;
@@ -325,7 +326,7 @@ class PCHValidator : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
                                StringRef ModuleFilename, bool ReadMacros,
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 22821418c7078..b48eed8650672 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -77,11 +77,11 @@ DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
   Output.append(Str.begin(), Str.end());
 }
 
-DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
-                                     DiagnosticOptions &DiagOpts,
-                                     DiagnosticConsumer *client,
-                                     bool ShouldOwnClient)
-    : Diags(std::move(diags)), DiagOpts(DiagOpts) {
+DiagnosticsEngine::DiagnosticsEngine(
+    IntrusiveRefCntPtr<DiagnosticIDs> diags,
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
+    bool ShouldOwnClient)
+    : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
   setClient(client, ShouldOwnClient);
   ArgToStringFn = DummyArgToStringFn;
 
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 09e5c6547fb51..4028bbf060364 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2391,11 +2391,11 @@ SourceManagerForFile::SourceManagerForFile(StringRef FileName,
   // in `Environment` so that `FileMgr` can out-live this function scope.
   FileMgr =
       std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
-  DiagOpts = std::make_unique<DiagnosticOptions>();
   // This is passed to `SM` as reference, so the pointer has to be referenced
   // by `Environment` due to the same reason above.
   Diagnostics = std::make_unique<DiagnosticsEngine>(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), *DiagOpts);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+      new DiagnosticOptions);
   SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr);
   FileEntryRef FE = llvm::cantFail(FileMgr->getFileRef(FileName));
   FileID ID =
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 6d0f042d5accd..ef395f497216c 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -560,15 +560,15 @@ CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
 
 CrossTranslationUnitContext::LoadResultTy
 CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, *DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
   return ASTUnit::LoadFromASTFile(
       ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, DiagOpts, Diags, CI.getFileSystemOpts(),
+      ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
       CI.getHeaderSearchOpts());
 }
 
@@ -603,17 +603,17 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource(
                  CommandLineArgs.begin(),
                  [](auto &&CmdPart) { return CmdPart.c_str(); });
 
-  auto DiagOpts = std::make_shared<DiagnosticOptions>(CI.getDiagnosticOpts());
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
   auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
       CI.getDiagnostics().getDiagnosticIDs()};
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine{DiagID, *DiagOpts, DiagClient});
+      new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
 
-  return ASTUnit::LoadFromCommandLine(
-      CommandLineArgs.begin(), (CommandLineArgs.end()),
-      CI.getPCHContainerOperations(), DiagOpts, Diags,
-      CI.getHeaderSearchOpts().ResourceDir);
+  return ASTUnit::LoadFromCommandLine(CommandLineArgs.begin(),
+                                      (CommandLineArgs.end()),
+                                      CI.getPCHContainerOperations(), Diags,
+                                      CI.getHeaderSearchOpts().ResourceDir);
 }
 
 llvm::Expected<InvocationListTy>
diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp
index a4ce88351e28e..b6b06440bc3f8 100644
--- a/clang/lib/Frontend/ASTMerge.cpp
+++ b/clang/lib/Frontend/ASTMerge.cpp
@@ -41,13 +41,14 @@ void ASTMergeAction::ExecuteAction() {
   auto SharedState = std::make_shared<ASTImporterSharedState>(
       *CI.getASTContext().getTranslationUnitDecl());
   for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
-    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
-        DiagIDs, CI.getDiagnosticOpts(),
-        new ForwardingDiagnosticConsumer(*CI.getDiagnostics().getClient()),
-        /*ShouldOwnClient=*/true));
+    IntrusiveRefCntPtr<DiagnosticsEngine>
+        Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(),
+                                    new ForwardingDiagnosticConsumer(
+                                          *CI.getDiagnostics().getClient()),
+                                    /*ShouldOwnClient=*/true));
     std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
-        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything,
-        nullptr, Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+        CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
 
     if (!Unit)
       continue;
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 457043c6bd7ce..5a79fe070c384 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -803,8 +803,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
 
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
     StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-    WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
-    IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+    WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
     const FileSystemOptions &FileSystemOpts, const HeaderSearchOptions &HSOpts,
     const LangOptions *LangOpts, bool OnlyLocalDecls,
     CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors,
@@ -824,7 +823,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
                            : std::make_unique<LangOptions>();
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
-  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileMgr = new FileManager(FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
@@ -1536,7 +1534,6 @@ StringRef ASTUnit::getASTFileName() const {
 
 std::unique_ptr<ASTUnit>
 ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
-                std::shared_ptr<DiagnosticOptions> DiagOpts,
                 IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
                 CaptureDiagsKind CaptureDiagnostics,
                 bool UserFilesAreVolatile) {
@@ -1544,7 +1541,6 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       createVFSFromCompilerInvocation(*CI, *Diags);
-  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   AST->Invocation = std::move(CI);
@@ -1560,7 +1556,6 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
 ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FrontendAction *Action,
     ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1572,8 +1567,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
   ASTUnit *AST = Unit;
   if (!AST) {
     // Create the AST unit.
-    OwnAST =
-        create(CI, DiagOpts, Diags, CaptureDiagnostics, UserFilesAreVolatile);
+    OwnAST = create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile);
     AST = OwnAST.get();
     if (!AST)
       return nullptr;
@@ -1735,7 +1729,6 @@ bool ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
     unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
@@ -1744,7 +1737,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
-  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1774,7 +1766,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
     const char **ArgBegin, const char **ArgEnd,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
-    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
     bool StorePreamblesInMemory, StringRef PreambleStoragePath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1837,7 +1828,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
   AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
   AST->StoredDiagnostics.swap(StoredDiagnostics);
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
-  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index f9a398dbfb90f..95b0ed248d545 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -117,10 +117,10 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
 
     TextDiagnosticPrinter *DiagClient =
-        new TextDiagnosticPrinter(llvm::errs(), CI.getDiagnosticOpts());
+      new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        new DiagnosticsEngine(DiagID, CI.getDiagnosticOpts(), DiagClient));
+        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
 
     auto Clang = std::make_unique<CompilerInstance>(
         std::move(CInvok), CI.getPCHContainerOperations());
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index cc39049167687..503d36467653e 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -280,20 +280,20 @@ static void collectVFSEntries(CompilerInstance &CI,
 }
 
 // Diagnostics
-static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts,
+static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
                                const CodeGenOptions *CodeGenOpts,
                                DiagnosticsEngine &Diags) {
   std::error_code EC;
   std::unique_ptr<raw_ostream> StreamOwner;
   raw_ostream *OS = &llvm::errs();
-  if (DiagOpts.DiagnosticLogFile != "-") {
+  if (DiagOpts->DiagnosticLogFile != "-") {
     // Create the output stream.
     auto FileOS = std::make_unique<llvm::raw_fd_ostream>(
-        DiagOpts.DiagnosticLogFile, EC,
+        DiagOpts->DiagnosticLogFile, EC,
         llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
     if (EC) {
       Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
-          << DiagOpts.DiagnosticLogFile << EC.message();
+          << DiagOpts->DiagnosticLogFile << EC.message();
     } else {
       FileOS->SetUnbuffered();
       OS = FileOS.get();
@@ -315,7 +315,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts,
   }
 }
 
-static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts,
+static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
                                        DiagnosticsEngine &Diags,
                                        StringRef OutputFile) {
   auto SerializedConsumer =
@@ -333,12 +333,12 @@ static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts,
 void CompilerInstance::createDiagnostics(llvm::vfs::FileSystem &VFS,
                                          DiagnosticConsumer *Client,
                                          bool ShouldOwnClient) {
-  Diagnostics = createDiagnostics(VFS, getDiagnosticOpts(), Client,
+  Diagnostics = createDiagnostics(VFS, &getDiagnosticOpts(), Client,
                                   ShouldOwnClient, &getCodeGenOpts());
 }
 
 IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
-    llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
+    llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
     DiagnosticConsumer *Client, bool ShouldOwnClient,
     const CodeGenOptions *CodeGenOpts) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -349,24 +349,25 @@ IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
   // implementing -verify.
   if (Client) {
     Diags->setClient(Client, ShouldOwnClient);
-  } else if (Opts.getFormat() == DiagnosticOptions::SARIF) {
+  } else if (Opts->getFormat() == DiagnosticOptions::SARIF) {
     Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts));
   } else
     Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
 
   // Chain in -verify checker, if requested.
-  if (Opts.VerifyDiagnostics)
+  if (Opts->VerifyDiagnostics)
     Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
 
   // Chain in -diagnostic-log-file dumper, if requested.
-  if (!Opts.DiagnosticLogFile.empty())
+  if (!Opts->DiagnosticLogFile.empty())
     SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
 
-  if (!Opts.DiagnosticSerializationFile.empty())
-    SetupSerializedDiagnostics(Opts, *Diags, Opts.DiagnosticSerializationFile);
+  if (!Opts->DiagnosticSerializationFile.empty())
+    SetupSerializedDiagnostics(Opts, *Diags,
+                               Opts->DiagnosticSerializationFile);
 
   // Configure our handling of diagnostics.
-  ProcessWarningOptions(*Diags, Opts, VFS);
+  ProcessWarningOptions(*Diags, *Opts, VFS);
 
   return Diags;
 }
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 9c33910eff57e..3c23073fc6a8c 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -125,14 +125,21 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
 // Initialization.
 //===----------------------------------------------------------------------===//
 
+namespace {
 template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
   return std::make_shared<T>(X);
 }
 
+template <class T>
+llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
+  return llvm::makeIntrusiveRefCnt<T>(X);
+}
+} // namespace
+
 CompilerInvocationBase::CompilerInvocationBase()
     : LangOpts(std::make_shared<LangOptions>()),
       TargetOpts(std::make_shared<TargetOptions>()),
-      DiagnosticOpts(std::make_shared<DiagnosticOptions>()),
+      DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
       HSOpts(std::make_shared<HeaderSearchOptions>()),
       PPOpts(std::make_shared<PreprocessorOptions>()),
       AnalyzerOpts(std::make_shared<AnalyzerOptions>()),
@@ -149,7 +156,7 @@ CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
   if (this != &X) {
     LangOpts = make_shared_copy(X.getLangOpts());
     TargetOpts = make_shared_copy(X.getTargetOpts());
-    DiagnosticOpts = make_shared_copy(X.getDiagnosticOpts());
+    DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
     HSOpts = make_shared_copy(X.getHeaderSearchOpts());
     PPOpts = make_shared_copy(X.getPreprocessorOpts());
     AnalyzerOpts = make_shared_copy(X.getAnalyzerOpts());
@@ -195,6 +202,7 @@ CompilerInvocation::operator=(const CowCompilerInvocation &X) {
   return *this;
 }
 
+namespace {
 template <typename T>
 T &ensureOwned(std::shared_ptr<T> &Storage) {
   if (Storage.use_count() > 1)
@@ -202,6 +210,14 @@ T &ensureOwned(std::shared_ptr<T> &Storage) {
   return *Storage;
 }
 
+template <typename T>
+T &ensureOwned(llvm::IntrusiveRefCntPtr<T> &Storage) {
+  if (Storage.useCount() > 1)
+    Storage = llvm::makeIntrusiveRefCnt<T>(*Storage);
+  return *Storage;
+}
+} // namespace
+
 LangOptions &CowCompilerInvocation::getMutLangOpts() {
   return ensureOwned(LangOpts);
 }
@@ -828,8 +844,7 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate,
   };
 
   // Setup a dummy DiagnosticsEngine.
-  DiagnosticOptions DummyDiagOpts;
-  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), DummyDiagOpts);
+  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), new DiagnosticOptions());
   DummyDiags.setClient(new TextDiagnosticBuffer());
 
   // Run the first parse on the original arguments with the dummy invocation and
@@ -2648,11 +2663,9 @@ clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) {
 bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                 DiagnosticsEngine *Diags,
                                 bool DefaultDiagColor) {
-  std::optional<DiagnosticOptions> IgnoringDiagOpts;
   std::optional<DiagnosticsEngine> IgnoringDiags;
   if (!Diags) {
-    IgnoringDiagOpts.emplace();
-    IgnoringDiags.emplace(new DiagnosticIDs(), *IgnoringDiagOpts,
+    IgnoringDiags.emplace(new DiagnosticIDs(), new DiagnosticOptions(),
                           new IgnoringDiagConsumer());
     Diags = &*IgnoringDiags;
   }
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index 99212b81fe064..d0b855fff2534 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,15 +31,11 @@ std::unique_ptr<CompilerInvocation>
 clang::createInvocation(ArrayRef<const char *> ArgList,
                         CreateInvocationOptions Opts) {
   assert(!ArgList.empty());
-  std::optional<DiagnosticOptions> LocalDiagOpts;
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
-  if (Opts.Diags) {
-    Diags = std::move(Opts.Diags);
-  } else {
-    LocalDiagOpts.emplace();
-    Diags = CompilerInstance::createDiagnostics(
-        Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(), *LocalDiagOpts);
-  }
+  auto Diags = Opts.Diags
+                   ? std::move(Opts.Diags)
+                   : CompilerInstance::createDiagnostics(
+                         Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(),
+                         new DiagnosticOptions);
 
   SmallVector<const char *, 16> Args(ArgList);
 
diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp
index 1396b2bfbd151..3b120abbc3a7a 100644
--- a/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -30,7 +30,7 @@
 using namespace clang;
 
 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
-                                       DiagnosticOptions &DiagOpts)
+                                       DiagnosticOptions *DiagOpts)
     : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
 
 DiagnosticRenderer::~DiagnosticRenderer() = default;
@@ -115,7 +115,7 @@ void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
     // Find the ultimate expansion location for the diagnostic.
     Loc = Loc.getFileLoc();
 
-    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
+    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
 
     // First, if this diagnostic is not in the main file, print out the
     // "included from" lines.
@@ -172,7 +172,7 @@ void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
 
   LastIncludeLoc = IncludeLoc;
 
-  if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+  if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
     return;
 
   if (IncludeLoc.isValid())
@@ -191,7 +191,7 @@ void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
   if (PLoc.isInvalid())
     return;
 
@@ -232,7 +232,7 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
 
   // Emit the other import frames first.
   std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
@@ -247,8 +247,9 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
   ModuleBuildStack Stack = SM.getModuleBuildStack();
   for (const auto &I : Stack) {
-    emitBuildingModuleLocation(
-        I.second, I.second.getPresumedLoc(DiagOpts.ShowPresumedLoc), I.first);
+    emitBuildingModuleLocation(I.second, I.second.getPresumedLoc(
+                                              DiagOpts->ShowPresumedLoc),
+                               I.first);
   }
 }
 
@@ -538,7 +539,7 @@ void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
                       LocationStack.begin() + IgnoredEnd);
 
   unsigned MacroDepth = LocationStack.size();
-  unsigned MacroLimit = DiagOpts.MacroBacktraceLimit;
+  unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
   if (MacroDepth <= MacroLimit || MacroLimit == 0) {
     for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
          I != E; ++I)
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index af9d18ab66108..54a2e3eb297f5 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -766,8 +766,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
 
     // The AST unit populates its own diagnostics engine rather than ours.
-    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine(
-        Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions()));
+    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
+        new DiagnosticsEngine(Diags->getDiagnosticIDs(),
+                              &Diags->getDiagnosticOptions()));
     ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
 
     // FIXME: What if the input is a memory buffer?
@@ -775,7 +776,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
         InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
-        nullptr, ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
     if (!AST)
       return false;
 
@@ -841,9 +842,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     StringRef InputFile = Input.getFile();
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
-        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, nullptr,
-        Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts(),
-        &CI.getLangOpts());
+        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
+        CI.getFileSystemOpts(), CI.getHeaderSearchOpts(), &CI.getLangOpts());
 
     if (!AST)
       return false;
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index d14d091e3fe38..8c75e1a46da54 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -685,21 +685,21 @@ namespace {
       return false;
     }
 
-    bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+    bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
                                StringRef ModuleFilename,
                                bool Complain) override {
       Out.indent(2) << "Diagnostic options:\n";
-#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts.Name, #Name);
-#define ENUM_DIAGOPT(Name, Type, Bits, Default)                              \
-    Out.indent(4) << #Name << ": " << DiagOpts.get##Name() << "\n";
-#define VALUE_DIAGOPT(Name, Bits, Default)                                   \
-    Out.indent(4) << #Name << ": " << DiagOpts.Name << "\n";
+#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+      Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
+#define VALUE_DIAGOPT(Name, Bits, Default) \
+      Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
 #include "clang/Basic/DiagnosticOptions.def"
 
       Out.indent(4) << "Diagnostic flags:\n";
-      for (const std::string &Warning : DiagOpts.Warnings)
+      for (const std::string &Warning : DiagOpts->Warnings)
         Out.indent(6) << "-W" << Warning << "\n";
-      for (const std::string &Remark : DiagOpts.Remarks)
+      for (const std::string &Remark : DiagOpts->Remarks)
         Out.indent(6) << "-R" << Remark << "\n";
 
       return false;
diff --git a/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 2d188931e4f8a..4e963af837f01 100644
--- a/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -18,10 +18,10 @@ using namespace clang;
 using namespace markup;
 
 LogDiagnosticPrinter::LogDiagnosticPrinter(
-    raw_ostream &os, DiagnosticOptions &DiagOpts,
+    raw_ostream &os, DiagnosticOptions *diags,
     std::unique_ptr<raw_ostream> StreamOwner)
     : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
-      DiagOpts(DiagOpts) {}
+      DiagOpts(diags) {}
 
 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
   switch (Level) {
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index e2aec7f677f12..4e36153ed5391 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -31,7 +31,7 @@
 namespace clang {
 
 SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                                 DiagnosticOptions &DiagOpts,
+                                 DiagnosticOptions *DiagOpts,
                                  SarifDocumentWriter *Writer)
     : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
@@ -163,7 +163,7 @@ SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
 
 llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
                                               const SourceManager &SM) {
-  if (DiagOpts.AbsolutePath) {
+  if (DiagOpts->AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
index 23fbc3e4fa92b..73928d19a031a 100644
--- a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -26,15 +26,15 @@
 namespace clang {
 
 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
-                                               DiagnosticOptions &DiagOpts)
-    : OS(OS), DiagOpts(DiagOpts) {}
+                                               DiagnosticOptions *Diags)
+    : OS(OS), DiagOpts(Diags) {}
 
 void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                              const Preprocessor *PP) {
   // Build the SARIFDiagnostic utility.
   assert(hasSarifWriter() && "Writer not set!");
   assert(!SARIFDiag && "SARIFDiagnostic already set.");
-  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, DiagOpts, &*Writer);
+  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, &*DiagOpts, &*Writer);
   // Initialize the SARIF object.
   Writer->createRun("clang", Prefix);
 }
@@ -72,6 +72,7 @@ void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   }
 
   // Assert that the rest of our infrastructure is setup properly.
+  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
 
diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index ee49cdd84e79e..02aa3e8e4d984 100644
--- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -57,8 +57,8 @@ class SDiagsRenderer : public DiagnosticNoteRenderer {
   SDiagsWriter &Writer;
 public:
   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
-                 DiagnosticOptions &DiagOpts)
-      : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+                 DiagnosticOptions *DiagOpts)
+    : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
   ~SDiagsRenderer() override {}
 
@@ -140,7 +140,7 @@ class SDiagsWriter : public DiagnosticConsumer {
         State(std::move(State)) {}
 
 public:
-  SDiagsWriter(StringRef File, DiagnosticOptions &Diags, bool MergeChildRecords)
+  SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
       : LangOpts(nullptr), OriginalInstance(true),
         MergeChildRecords(MergeChildRecords),
         State(std::make_shared<SharedState>(File, Diags)) {
@@ -242,12 +242,12 @@ class SDiagsWriter : public DiagnosticConsumer {
   /// State that is shared among the various clones of this diagnostic
   /// consumer.
   struct SharedState {
-    SharedState(StringRef File, DiagnosticOptions &DiagOpts)
-        : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(File.str()),
+    SharedState(StringRef File, DiagnosticOptions *Diags)
+        : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
           EmittedAnyDiagBlocks(false) {}
 
     /// Diagnostic options.
-    DiagnosticOptions DiagOpts;
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
 
     /// The byte buffer for the serialized content.
     SmallString<1024> Buffer;
@@ -295,11 +295,9 @@ class SDiagsWriter : public DiagnosticConsumer {
 
 namespace clang {
 namespace serialized_diags {
-std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
-                                           DiagnosticOptions &DiagOpts,
-                                           bool MergeChildRecords) {
-  return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
-                                        MergeChildRecords);
+std::unique_ptr<DiagnosticConsumer>
+create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
+  return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
 }
 
 } // end namespace serialized_diags
@@ -619,7 +617,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 
   assert(Info.hasSourceManager() && LangOpts &&
          "Unexpected diagnostic with valid location outside of a source file");
-  SDiagsRenderer Renderer(*this, *LangOpts, State->DiagOpts);
+  SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
   Renderer.emitDiagnostic(
       FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
       State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
@@ -757,9 +755,10 @@ DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
   //    normally not be used.
   if (!State->MetaDiagnostics) {
     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
-    auto Client = new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
-    State->MetaDiagnostics =
-        std::make_unique<DiagnosticsEngine>(IDs, State->DiagOpts, Client);
+    auto Client =
+        new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
+    State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
+        IDs, State->DiagOpts.get(), Client);
   }
   return State->MetaDiagnostics.get();
 }
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 25ab13b7ae6c2..4119ce6048d45 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -654,7 +654,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns,
 }
 
 TextDiagnostic::TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                               DiagnosticOptions &DiagOpts,
+                               DiagnosticOptions *DiagOpts,
                                const Preprocessor *PP)
     : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS), PP(PP) {}
 
@@ -670,15 +670,15 @@ void TextDiagnostic::emitDiagnosticMessage(
   if (Loc.isValid())
     emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
 
-  if (DiagOpts.ShowColors)
+  if (DiagOpts->ShowColors)
     OS.resetColor();
 
-  if (DiagOpts.ShowLevel)
-    printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
+  if (DiagOpts->ShowLevel)
+    printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
   printDiagnosticMessage(OS,
                          /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
                          Message, OS.tell() - StartOfLocationInfo,
-                         DiagOpts.MessageLength, DiagOpts.ShowColors);
+                         DiagOpts->MessageLength, DiagOpts->ShowColors);
 }
 
 /*static*/ void
@@ -743,7 +743,7 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
 #ifdef _WIN32
   SmallString<4096> TmpFilename;
 #endif
-  if (DiagOpts.AbsolutePath) {
+  if (DiagOpts->AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
@@ -796,27 +796,27 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
   }
   unsigned LineNo = PLoc.getLine();
 
-  if (!DiagOpts.ShowLocation)
+  if (!DiagOpts->ShowLocation)
     return;
 
-  if (DiagOpts.ShowColors)
+  if (DiagOpts->ShowColors)
     OS.changeColor(savedColor, true);
 
   emitFilename(PLoc.getFilename(), Loc.getManager());
-  switch (DiagOpts.getFormat()) {
+  switch (DiagOpts->getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
-    if (DiagOpts.ShowLine)
+    if (DiagOpts->ShowLine)
       OS << ':' << LineNo;
     break;
   case DiagnosticOptions::MSVC:  OS << '('  << LineNo; break;
   case DiagnosticOptions::Vi:    OS << " +" << LineNo; break;
   }
 
-  if (DiagOpts.ShowColumn)
+  if (DiagOpts->ShowColumn)
     // Compute the column number.
     if (unsigned ColNo = PLoc.getColumn()) {
-      if (DiagOpts.getFormat() == DiagnosticOptions::MSVC) {
+      if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
         OS << ',';
         // Visual Studio 2010 or earlier expects column number to be off by one
         if (LangOpts.MSCompatibilityVersion &&
@@ -826,7 +826,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
         OS << ':';
       OS << ColNo;
     }
-  switch (DiagOpts.getFormat()) {
+  switch (DiagOpts->getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
   case DiagnosticOptions::Vi:    OS << ':';    break;
@@ -841,7 +841,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
     break;
   }
 
-  if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
+  if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
     FileID CaretFileID = Loc.getExpansionLoc().getFileID();
     bool PrintedRange = false;
     const SourceManager &SM = Loc.getManager();
@@ -881,7 +881,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
 }
 
 void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
-  if (DiagOpts.ShowLocation && PLoc.isValid()) {
+  if (DiagOpts->ShowLocation && PLoc.isValid()) {
     OS << "In file included from ";
     emitFilename(PLoc.getFilename(), Loc.getManager());
     OS << ':' << PLoc.getLine() << ":\n";
@@ -891,7 +891,7 @@ void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
 
 void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                         StringRef ModuleName) {
-  if (DiagOpts.ShowLocation && PLoc.isValid())
+  if (DiagOpts->ShowLocation && PLoc.isValid())
     OS << "In module '" << ModuleName << "' imported from "
        << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -901,7 +901,7 @@ void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
 void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
                                                 PresumedLoc PLoc,
                                                 StringRef ModuleName) {
-  if (DiagOpts.ShowLocation && PLoc.isValid())
+  if (DiagOpts->ShowLocation && PLoc.isValid())
     OS << "While building module '" << ModuleName << "' imported from "
       << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -998,13 +998,14 @@ static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
   std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo, '~');
 }
 
-static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID,
+                                           unsigned LineNo,
                                            const SourceColumnMap &map,
                                            ArrayRef<FixItHint> Hints,
                                            const SourceManager &SM,
-                                           const DiagnosticOptions &DiagOpts) {
+                                           const DiagnosticOptions *DiagOpts) {
   std::string FixItInsertionLine;
-  if (Hints.empty() || !DiagOpts.ShowFixits)
+  if (Hints.empty() || !DiagOpts->ShowFixits)
     return FixItInsertionLine;
   unsigned PrevHintEndCol = 0;
 
@@ -1056,7 +1057,7 @@ static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
     }
   }
 
-  expandTabs(FixItInsertionLine, DiagOpts.TabStop);
+  expandTabs(FixItInsertionLine, DiagOpts->TabStop);
 
   return FixItInsertionLine;
 }
@@ -1295,7 +1296,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // was part of a different warning or error diagnostic, or if the
   // diagnostic has ranges.  We don't want to emit the same caret
   // multiple times if one loc has multiple diagnostics.
-  if (!DiagOpts.ShowCarets)
+  if (!DiagOpts->ShowCarets)
     return;
   if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
       (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
@@ -1321,7 +1322,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     return;
 
   // Find the set of lines to include.
-  const unsigned MaxLines = DiagOpts.SnippetLineLimit;
+  const unsigned MaxLines = DiagOpts->SnippetLineLimit;
   std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
   unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
   for (const auto &I : Ranges) {
@@ -1337,7 +1338,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // Where [number] is MaxLineNoDisplayWidth columns
   // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
   unsigned MaxLineNoDisplayWidth =
-      DiagOpts.ShowLineNumbers
+      DiagOpts->ShowLineNumbers
           ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
           : 0;
   auto indentForLineNumbers = [&] {
@@ -1349,7 +1350,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // emit, starting from the first line.
   std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
       highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
-                     DiagOpts.ShowColors, FID, SM);
+                     DiagOpts->ShowColors, FID, SM);
 
   SmallVector<LineRange> LineRanges =
       prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
@@ -1381,7 +1382,7 @@ void TextDiagnostic::emitSnippetAndCaret(
       SourceLine.pop_back();
 
     // Build the byte to column map.
-    const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
+    const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
 
     std::string CaretLine;
     // Highlight all of the characters covered by Ranges with ~ characters.
@@ -1397,12 +1398,12 @@ void TextDiagnostic::emitSnippetAndCaret(
       CaretLine[Col] = '^';
     }
 
-    std::string FixItInsertionLine =
-        buildFixItInsertionLine(FID, LineNo, sourceColMap, Hints, SM, DiagOpts);
+    std::string FixItInsertionLine = buildFixItInsertionLine(
+        FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
 
     // If the source line is too long for our terminal, select only the
     // "interesting" source region within that line.
-    unsigned Columns = DiagOpts.MessageLength;
+    unsigned Columns = DiagOpts->MessageLength;
     if (Columns)
       selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
                                     Columns, sourceColMap);
@@ -1411,7 +1412,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     // to produce easily machine parsable output.  Add a space before the
     // source line and the caret to make it trivial to tell the main diagnostic
     // line from what the user is intended to see.
-    if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
+    if (DiagOpts->ShowSourceRanges && !SourceLine.empty()) {
       SourceLine = ' ' + SourceLine;
       CaretLine = ' ' + CaretLine;
     }
@@ -1422,22 +1423,22 @@ void TextDiagnostic::emitSnippetAndCaret(
 
     if (!CaretLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts.ShowColors)
+      if (DiagOpts->ShowColors)
         OS.changeColor(caretColor, true);
       OS << CaretLine << '\n';
-      if (DiagOpts.ShowColors)
+      if (DiagOpts->ShowColors)
         OS.resetColor();
     }
 
     if (!FixItInsertionLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts.ShowColors)
+      if (DiagOpts->ShowColors)
         // Print fixit line in color
         OS.changeColor(fixitColor, false);
-      if (DiagOpts.ShowSourceRanges)
+      if (DiagOpts->ShowSourceRanges)
         OS << ' ';
       OS << FixItInsertionLine << '\n';
-      if (DiagOpts.ShowColors)
+      if (DiagOpts->ShowColors)
         OS.resetColor();
     }
   }
@@ -1463,10 +1464,10 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
   size_t I = 0;
   while (I < SourceLine.size()) {
     auto [Str, WasPrintable] =
-        printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
+        printableTextForNextCharacter(SourceLine, &I, DiagOpts->TabStop);
 
     // Toggle inverted colors on or off for this character.
-    if (DiagOpts.ShowColors) {
+    if (DiagOpts->ShowColors) {
       if (WasPrintable == PrintReversed) {
         PrintReversed = !PrintReversed;
         if (PrintReversed)
@@ -1497,7 +1498,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
     OS << Str;
   }
 
-  if (DiagOpts.ShowColors)
+  if (DiagOpts->ShowColors)
     OS.resetColor();
 
   OS << '\n';
@@ -1505,7 +1506,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
 
 void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
                                          const SourceManager &SM) {
-  if (!DiagOpts.ShowParseableFixits)
+  if (!DiagOpts->ShowParseableFixits)
     return;
 
   // We follow FixItRewriter's example in not (yet) handling
diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index e878c630fa01d..28f7218dc23f5 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -22,9 +22,11 @@
 using namespace clang;
 
 TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
-                                             DiagnosticOptions &DiagOpts,
+                                             DiagnosticOptions *diags,
                                              bool _OwnsOutputStream)
-    : OS(os), DiagOpts(DiagOpts), OwnsOutputStream(_OwnsOutputStream) {}
+  : OS(os), DiagOpts(diags),
+    OwnsOutputStream(_OwnsOutputStream) {
+}
 
 TextDiagnosticPrinter::~TextDiagnosticPrinter() {
   if (OwnsOutputStream)
@@ -34,7 +36,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
 void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                             const Preprocessor *PP) {
   // Build the TextDiagnostic utility.
-  TextDiag.reset(new TextDiagnostic(OS, LO, DiagOpts, PP));
+  TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts, PP));
 }
 
 void TextDiagnosticPrinter::EndSourceFile() {
@@ -119,7 +121,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   Info.FormatDiagnostic(OutStr);
 
   llvm::raw_svector_ostream DiagMessageStream(OutStr);
-  printDiagnosticOptions(DiagMessageStream, Level, Info, DiagOpts);
+  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
 
   // Keeps track of the starting position of the location
   // information (e.g., "foo.c:10:4:") that precedes the error
@@ -135,16 +137,17 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   // diagnostics in a context that lacks language options, a source manager, or
   // other infrastructure necessary when emitting more rich diagnostics.
   if (!Info.getLocation().isValid()) {
-    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
+    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
     TextDiagnostic::printDiagnosticMessage(
         OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note,
         DiagMessageStream.str(), OS.tell() - StartOfLocationInfo,
-        DiagOpts.MessageLength, DiagOpts.ShowColors);
+        DiagOpts->MessageLength, DiagOpts->ShowColors);
     OS.flush();
     return;
   }
 
   // Assert that the rest of our infrastructure is setup properly.
+  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
   assert(TextDiag && "Unexpected diagnostic outside source file processing");
diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp
index dac38887cd0a1..aa90663538128 100644
--- a/clang/lib/Interpreter/CodeCompletion.cpp
+++ b/clang/lib/Interpreter/CodeCompletion.cpp
@@ -359,12 +359,13 @@ void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI,
                                      unsigned Col,
                                      const CompilerInstance *ParentCI,
                                      std::vector<std::string> &CCResults) {
+  auto DiagOpts = DiagnosticOptions();
   auto consumer = ReplCompletionConsumer(CCResults, *this);
 
   auto diag = InterpCI->getDiagnosticsPtr();
   std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
       InterpCI->getInvocationPtr(), std::make_shared<PCHContainerOperations>(),
-      nullptr, diag));
+      diag));
   llvm::SmallVector<clang::StoredDiagnostic, 8> sd = {};
   llvm::SmallVector<const llvm::MemoryBuffer *, 1> tb = {};
   InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile(
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 84feff82c63a7..4b407a0172adb 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -95,9 +95,9 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
 
   // Buffer diagnostics from argument parsing so that we can output them using
   // a well formed diagnostic object.
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
   bool Success = CompilerInvocation::CreateFromArgs(
       Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
 
@@ -173,10 +173,10 @@ IncrementalCompilerBuilder::create(std::string TT,
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  std::unique_ptr<DiagnosticOptions> DiagOpts =
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
       CreateAndPopulateDiagOpts(ClangArgv);
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
 
   driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
   Driver.setCheckInputsExist(false); // the input comes from mem buffers
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index 1829a4ff3504a..c75835df2c98e 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -636,8 +636,8 @@ static void HighlightMacrosImpl(
   // Temporarily change the diagnostics object so that we ignore any generated
   // diagnostics from this pass.
   DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
-                             PP.getDiagnostics().getDiagnosticOptions(),
-                             new IgnoringDiagConsumer);
+                             &PP.getDiagnostics().getDiagnosticOptions(),
+                      new IgnoringDiagConsumer);
 
   // FIXME: This is a huge hack; we reuse the input preprocessor because we want
   // its state, but we aren't actually changing it (we hope). This should really
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index c113fd7cbb911..d068f5e163176 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -193,7 +193,8 @@ bool ChainedASTReaderListener::ReadTargetOptions(
 }
 
 bool ChainedASTReaderListener::ReadDiagnosticOptions(
-    DiagnosticOptions &DiagOpts, StringRef ModuleFilename, bool Complain) {
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
+    bool Complain) {
   return First->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain) ||
          Second->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
@@ -594,16 +595,16 @@ static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr,
   return M;
 }
 
-bool PCHValidator::ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
-                                         StringRef ModuleFilename,
-                                         bool Complain) {
+bool PCHValidator::ReadDiagnosticOptions(
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
+    bool Complain) {
   DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagIDs, DiagOpts));
+      new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
   // This should never fail, because we would have processed these options
   // before writing them to an ASTFile.
-  ProcessWarningOptions(*Diags, DiagOpts,
+  ProcessWarningOptions(*Diags, *DiagOpts,
                         PP.getFileManager().getVirtualFileSystem(),
                         /*Report*/ false);
 
@@ -6421,17 +6422,17 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
 bool ASTReader::ParseDiagnosticOptions(const RecordData &Record,
                                        StringRef ModuleFilename, bool Complain,
                                        ASTReaderListener &Listener) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
   unsigned Idx = 0;
-#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
-#define ENUM_DIAGOPT(Name, Type, Bits, Default)                                \
-  DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
+#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+  DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
 #include "clang/Basic/DiagnosticOptions.def"
 
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts.Warnings.push_back(ReadString(Record, Idx));
+    DiagOpts->Warnings.push_back(ReadString(Record, Idx));
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts.Remarks.push_back(ReadString(Record, Idx));
+    DiagOpts->Remarks.push_back(ReadString(Record, Idx));
 
   return Listener.ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index b59a8d55129de..748f59b856e83 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -44,7 +44,7 @@ class StoreDiagnostics : public DiagnosticConsumer {
       std::string Text;
       llvm::raw_string_ostream OS(Text);
       TextDiagnostic Renderer(OS, LangOpts,
-                              Info.getDiags()->getDiagnosticOptions());
+                              &Info.getDiags()->getDiagnosticOptions());
       Renderer.emitStoredDiagnostic(Out.back());
       ADD_FAILURE() << Text;
     }
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index 09596b9799833..af18194ae0fe4 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -243,13 +243,13 @@ std::string GetClangToolCommand() {
 static bool stripPositionalArgs(std::vector<const char *> Args,
                                 std::vector<std::string> &Result,
                                 std::string &ErrorMsg) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   llvm::raw_string_ostream Output(ErrorMsg);
-  TextDiagnosticPrinter DiagnosticPrinter(Output, DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
   UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
-      &DiagClient, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+      &*DiagOpts, &DiagClient, false);
 
   // The clang executable path isn't required since the jobs the driver builds
   // will not be executed.
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index 9e2582ee53c59..92e9859ca206e 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -585,9 +585,9 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+      new DiagnosticOptions);
   SourceManager SourceMgr(Diagnostics, Files);
   Rewriter Rewrite(SourceMgr, LangOptions());
   InMemoryFileSystem->addFile(
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 207b0a96aaf27..21eea72b198b3 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -642,7 +642,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, TUBuffer))
@@ -660,7 +660,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, ModuleName))
@@ -744,7 +744,7 @@ bool DependencyScanningWorker::scanDependencies(
   sanitizeDiagOpts(*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(FileMgr->getVirtualFileSystem(),
-                                          *DiagOpts, &DC,
+                                          DiagOpts.release(), &DC,
                                           /*ShouldOwnClient=*/false);
 
   // Although `Diagnostics` are used only for command-line parsing, the
diff --git a/clang/lib/Tooling/Refactoring.cpp b/clang/lib/Tooling/Refactoring.cpp
index 874d44ff6731c..961fc1c180154 100644
--- a/clang/lib/Tooling/Refactoring.cpp
+++ b/clang/lib/Tooling/Refactoring.cpp
@@ -39,11 +39,11 @@ int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
   }
 
   LangOptions DefaultLangOptions;
-  DiagnosticOptions DiagOpts;
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
-      &DiagnosticPrinter, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+      &*DiagOpts, &DiagnosticPrinter, false);
   SourceManager Sources(Diagnostics, getFiles());
   Rewriter Rewrite(Sources, DefaultLangOptions);
 
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 1abd7c7adb127..3c72f52040142 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -377,17 +377,17 @@ bool ToolInvocation::run() {
 
   // Parse diagnostic options from the driver command-line only if none were
   // explicitly set.
-  std::unique_ptr<DiagnosticOptions> ParsedDiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> ParsedDiagOpts;
   DiagnosticOptions *DiagOpts = this->DiagOpts;
   if (!DiagOpts) {
     ParsedDiagOpts = CreateAndPopulateDiagOpts(Argv);
     DiagOpts = &*ParsedDiagOpts;
   }
 
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), *DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics =
       CompilerInstance::createDiagnostics(
-          Files->getVirtualFileSystem(), *DiagOpts,
+          Files->getVirtualFileSystem(), &*DiagOpts,
           DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
   // Although `Diagnostics` are used only for command-line parsing, the custom
   // `DiagConsumer` might expect a `SourceManager` to be present.
@@ -652,9 +652,9 @@ class ASTBuilderAction : public ToolAction {
                      std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                      DiagnosticConsumer *DiagConsumer) override {
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        Invocation, std::move(PCHContainerOps), nullptr,
+        Invocation, std::move(PCHContainerOps),
         CompilerInstance::createDiagnostics(Files->getVirtualFileSystem(),
-                                            Invocation->getDiagnosticOpts(),
+                                            &Invocation->getDiagnosticOpts(),
                                             DiagConsumer,
                                             /*ShouldOwnClient=*/false),
         Files);
diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp
index 25104304322d4..8d023a0b22121 100644
--- a/clang/tools/c-index-test/core_main.cpp
+++ b/clang/tools/c-index-test/core_main.cpp
@@ -220,10 +220,9 @@ static bool printSourceSymbols(const char *Executable,
   SmallVector<const char *, 4> ArgsWithProgName;
   ArgsWithProgName.push_back(Executable);
   ArgsWithProgName.append(Args.begin(), Args.end());
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          *DiagOpts));
+                                          new DiagnosticOptions));
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
@@ -242,7 +241,7 @@ static bool printSourceSymbols(const char *Executable,
 
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), PCHContainerOps, DiagOpts, Diags, IndexAction.get()));
+      std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
 
   if (!Unit)
     return true;
@@ -275,16 +274,15 @@ static bool printSourceSymbolsFromModule(StringRef modulePath,
 
   HeaderSearchOptions HSOpts;
 
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          *DiagOpts);
-  std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
-      modulePath, *pchRdr, ASTUnit::LoadASTOnly, DiagOpts, Diags,
-      FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
-      /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
-      /*AllowASTWithCompilerErrors=*/true,
-      /*UserFilesAreVolatile=*/false);
+                                          new DiagnosticOptions());
+  std::unique_ptr<ASTUnit> AU =
+      ASTUnit::LoadFromASTFile(modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
+                               FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
+                               /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
+                               /*AllowASTWithCompilerErrors=*/true,
+                               /*UserFilesAreVolatile=*/false);
   if (!AU) {
     errs() << "failed to create TU for: " << modulePath << '\n';
     return true;
diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index 0b621b849e92f..ff684d20c150c 100644
--- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -123,21 +123,21 @@ static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
 
 static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
 
-IntrusiveRefCntPtr<DiagnosticsEngine>
-GetDiagnosticsEngine(DiagnosticOptions &DiagOpts) {
+IntrusiveRefCntPtr<DiagnosticsEngine> GetDiagnosticsEngine() {
   if (Diags) {
     // Call reset to make sure we don't mix errors
     Diags->Reset(false);
     return Diags;
   }
 
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
   DiagClient->setPrefix("clang-extdef-mappping");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
   IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
-      new DiagnosticsEngine(DiagID, DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
   Diags.swap(DiagEngine);
 
   // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile
@@ -152,13 +152,11 @@ static bool HandleAST(StringRef AstPath) {
   if (!CI)
     CI = new CompilerInstance();
 
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
-  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine =
-      GetDiagnosticsEngine(*DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine = GetDiagnosticsEngine();
 
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
       AstPath, CI->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadASTOnly, DiagOpts, DiagEngine, CI->getFileSystemOpts(),
+      ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts(),
       CI->getHeaderSearchOpts());
 
   if (!Unit)
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index b22d3aaf3183b..e40e04eac5472 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -240,9 +240,9 @@ static bool fillRanges(MemoryBuffer *Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+      new DiagnosticOptions);
   SourceManager Sources(Diagnostics, Files);
   FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
                                  InMemoryFileSystem.get());
@@ -519,10 +519,10 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
         new llvm::vfs::InMemoryFileSystem);
     FileManager Files(FileSystemOptions(), InMemoryFileSystem);
 
-    DiagnosticOptions DiagOpts;
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
     ClangFormatDiagConsumer IgnoreDiagnostics;
     DiagnosticsEngine Diagnostics(
-        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
+        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
         &IgnoreDiagnostics, false);
     SourceManager Sources(Diagnostics, Files);
     FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index aefc2f5728eda..765f342947046 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -162,10 +162,10 @@ class TestDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
-  DiagnosticOptions DiagOpts;
+  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
   auto DC = std::make_unique<TestDiagnosticConsumer>();
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), DiagOpts, DC.get(),
+      *llvm::vfs::getRealFileSystem(), DiagOpts.get(), DC.get(),
       /*ShouldOwnClient=*/false);
 
   auto Inv = std::make_unique<CompilerInvocation>();
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index f68236abaa6c9..14e7b53d74b09 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -70,16 +70,16 @@ static bool runFrontend(StringRef ProgName, Twine Label, bool Verbose,
 
 static bool run(ArrayRef<const char *> Args, const char *ProgName) {
   // Setup Diagnostics engine.
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   const llvm::opt::OptTable &ClangOpts = clang::driver::getDriverOptTable();
   unsigned MissingArgIndex, MissingArgCount;
   llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(
       ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);
-  ParseDiagnosticArgs(DiagOpts, ParsedArgs);
+  ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
 
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag = new clang::DiagnosticsEngine(
-      new clang::DiagnosticIDs(), DiagOpts,
-      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts));
+      new clang::DiagnosticIDs(), DiagOpts.get(),
+      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
 
   // Create file manager for all file operations and holding in-memory generated
   // inputs.
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index c17eb9dcadfd7..3b42267f4d5f4 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -452,11 +452,11 @@ class FullDeps {
   // Returns \c true if any command lines fail to round-trip. We expect
   // commands already be canonical when output by the scanner.
   bool roundTripCommands(raw_ostream &ErrOS) {
-    DiagnosticOptions DiagOpts;
-    TextDiagnosticPrinter DiagConsumer(ErrOS, DiagOpts);
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions{};
+    TextDiagnosticPrinter DiagConsumer(ErrOS, &*DiagOpts);
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
         CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                            DiagOpts, &DiagConsumer,
+                                            &*DiagOpts, &DiagConsumer,
                                             /*ShouldOwnClient=*/false);
 
     for (auto &&M : Modules)
@@ -779,10 +779,9 @@ getCompilationDatabase(int argc, char **argv, std::string &ErrorMessage) {
         CompilationDB, ErrorMessage,
         tooling::JSONCommandLineSyntax::AutoDetect);
 
-  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          DiagOpts);
+                                          new DiagnosticOptions);
   driver::Driver TheDriver(CommandLine[0], llvm::sys::getDefaultTargetTriple(),
                            *Diags);
   TheDriver.setCheckInputsExist(false);
diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp
index 0d1455d270436..1f32f791de082 100644
--- a/clang/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp
@@ -56,7 +56,6 @@ static char getCharForLevel(DiagnosticsEngine::Level Level) {
 static IntrusiveRefCntPtr<DiagnosticsEngine>
 createDiagnostics(unsigned int argc, char **argv) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
-  DiagnosticOptions DiagOpts;
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
@@ -67,7 +66,8 @@ createDiagnostics(unsigned int argc, char **argv) {
   Args.push_back("diagtool");
   Args.append(argv, argv + argc);
   CreateInvocationOptions CIOpts;
-  CIOpts.Diags = new DiagnosticsEngine(DiagIDs, DiagOpts, DiagsBuffer);
+  CIOpts.Diags =
+      new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer);
   std::unique_ptr<CompilerInvocation> Invocation =
       createInvocation(Args, CIOpts);
   if (!Invocation)
@@ -76,7 +76,7 @@ createDiagnostics(unsigned int argc, char **argv) {
   // Build the diagnostics parser
   IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          Invocation->getDiagnosticOpts());
+                                          &Invocation->getDiagnosticOpts());
   if (!FinalDiags)
     return nullptr;
 
diff --git a/clang/tools/diagtool/TreeView.cpp b/clang/tools/diagtool/TreeView.cpp
index 7e47c748af959..8d1ce14b0f520 100644
--- a/clang/tools/diagtool/TreeView.cpp
+++ b/clang/tools/diagtool/TreeView.cpp
@@ -31,8 +31,8 @@ class TreePrinter {
 
   static bool isIgnored(unsigned DiagID) {
     // FIXME: This feels like a hack.
-    static DiagnosticOptions DiagOpts;
-    static clang::DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
+    static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
+                                          new DiagnosticOptions);
     return Diags.isIgnored(DiagID, SourceLocation());
   }
 
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 2c17f28621f5f..6638a15ff7e12 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -232,9 +232,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
 
   // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs.
   if (find(Argv, StringRef("-Rround-trip-cc1-args")) != Argv.end())
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index f938e7e4041e8..ab7ba238bcc57 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -658,12 +658,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   InitializeAllAsmParsers();
 
   // Construct our diagnostic client.
-  DiagnosticOptions DiagOpts;
-  TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(errs(), DiagOpts);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  TextDiagnosticPrinter *DiagClient
+    = new TextDiagnosticPrinter(errs(), &*DiagOpts);
   DiagClient->setPrefix("clang -cc1as");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
diff --git a/clang/tools/driver/cc1gen_reproducer_main.cpp b/clang/tools/driver/cc1gen_reproducer_main.cpp
index 8d7171eb2e5e0..df59b53f9ef18 100644
--- a/clang/tools/driver/cc1gen_reproducer_main.cpp
+++ b/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -117,12 +117,12 @@ generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
   using namespace driver;
   auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
 
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new IgnoringDiagConsumer());
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
   auto VFS = llvm::vfs::getRealFileSystem();
-  ProcessWarningOptions(Diags, DiagOpts, *VFS, /*ReportDiags=*/false);
+  ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
   Driver TheDriver(ToolContext.Path, llvm::sys::getDefaultTargetTriple(), Diags,
                    /*Title=*/"clang LLVM compiler", VFS);
   TheDriver.setTargetAndMode(TargetAndMode);
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index d21a34e961394..82f47ab973064 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -321,24 +321,25 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
                            .Case("-fintegrated-cc1", false)
                            .Default(UseNewCC1Process);
 
-  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Args);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+      CreateAndPopulateDiagOpts(Args);
   // Driver's diagnostics don't use suppression mappings, so don't bother
   // parsing them. CC1 still receives full args, so this doesn't impact other
   // actions.
   DiagOpts->DiagnosticSuppressionMappingsFile.clear();
 
-  TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
+  TextDiagnosticPrinter *DiagClient
+    = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
   FixupDiagPrefixExeName(DiagClient, ProgName);
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
-  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
 
   if (!DiagOpts->DiagnosticSerializationFile.empty()) {
     auto SerializedConsumer =
         clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
-                                        *DiagOpts, /*MergeChildRecords=*/true);
+                                        &*DiagOpts, /*MergeChildRecords=*/true);
     Diags.setClient(new ChainedDiagnosticConsumer(
         Diags.takeClient(), std::move(SerializedConsumer)));
   }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 1d9d1027521bc..06a17006fdee9 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -4227,13 +4227,12 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx,
   FileSystemOptions FileSystemOpts;
   HeaderSearchOptions HSOpts;
 
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          *DiagOpts);
+                                          new DiagnosticOptions());
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, DiagOpts, Diags, FileSystemOpts, HSOpts,
+      ASTUnit::LoadEverything, Diags, FileSystemOpts, HSOpts,
       /*LangOpts=*/nullptr, CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All,
       /*AllowASTWithCompilerErrors=*/true,
       /*UserFilesAreVolatile=*/true);
@@ -4300,11 +4299,11 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
   }
 
   // Configure the diagnostics.
-  std::shared_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
+  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
       llvm::ArrayRef(command_line_args, num_command_line_args));
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          *DiagOpts));
+                                          DiagOpts.release()));
 
   if (options & CXTranslationUnit_KeepGoing)
     Diags->setFatalsAsError(true);
@@ -4388,7 +4387,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
       options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files);
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromCommandLine(
       Args->data(), Args->data() + Args->size(),
-      CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
+      CXXIdx->getPCHContainerOperations(), Diags,
       CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(),
       CXXIdx->getPreambleStoragePath(), CXXIdx->getOnlyLocalDecls(),
       CaptureDiagnostics, *RemappedFiles,
diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp
index 8f6729b83ffa0..850c004680fd9 100644
--- a/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -256,8 +256,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
   /// Allocated API-exposed wrappters for Diagnostics.
   SmallVector<std::unique_ptr<CXStoredDiagnostic>, 8> DiagnosticsWrappers;
 
-  DiagnosticOptions DiagOpts;
-
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  
   /// Diag object
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
   
@@ -356,9 +356,9 @@ static std::atomic<unsigned> CodeCompletionResultObjects;
 
 AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     IntrusiveRefCntPtr<FileManager> FileMgr)
-    : CXCodeCompleteResults(),
+    : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions),
       Diag(new DiagnosticsEngine(
-          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts)),
+          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
       FileMgr(std::move(FileMgr)),
       SourceMgr(new SourceManager(*Diag, *this->FileMgr)),
       CodeCompletionAllocator(
@@ -369,7 +369,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     fprintf(stderr, "+++ %u completion results\n",
             ++CodeCompletionResultObjects);
 }
-
+  
 AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
   delete [] Results;
 
diff --git a/clang/tools/libclang/CIndexDiagnostic.cpp b/clang/tools/libclang/CIndexDiagnostic.cpp
index d37597e747a84..92271d9c37f86 100644
--- a/clang/tools/libclang/CIndexDiagnostic.cpp
+++ b/clang/tools/libclang/CIndexDiagnostic.cpp
@@ -80,11 +80,12 @@ class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
 };    
     
 class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
-public:
-  CXDiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts,
+public:  
+  CXDiagnosticRenderer(const LangOptions &LangOpts,
+                       DiagnosticOptions *DiagOpts,
                        CXDiagnosticSetImpl *mainSet)
-      : DiagnosticNoteRenderer(LangOpts, DiagOpts), CurrentSet(mainSet),
-        MainSet(mainSet) {}
+  : DiagnosticNoteRenderer(LangOpts, DiagOpts),
+    CurrentSet(mainSet), MainSet(mainSet) {}
 
   ~CXDiagnosticRenderer() override {}
 
@@ -181,10 +182,10 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
   if (!TU->Diagnostics) {
     CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
     TU->Diagnostics = Set;
-    DiagnosticOptions DOpts;
-    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(), DOpts,
-                                  Set);
-
+    IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
+    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
+                                  &*DOpts, Set);
+    
     for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
          ei = AU->stored_diag_end(); it != ei; ++it) {
       Renderer.emitStoredDiagnostic(*it);
diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index 3cd49bf90235b..e1441bce15f88 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -480,10 +480,9 @@ static CXErrorCode clang_indexSourceFile_Impl(
     CaptureDiag = new CaptureDiagnosticConsumer();
 
   // Configure the diagnostics.
-  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          *DiagOpts, CaptureDiag,
+                                          new DiagnosticOptions, CaptureDiag,
                                           /*ShouldOwnClient=*/true));
 
   // Recover resources if we crash before exiting this function.
@@ -555,7 +554,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
   CInvok->getHeaderSearchOpts().ModuleFormat = std::string(
       CXXIdx->getPCHContainerOperations()->getRawReader().getFormats().front());
 
-  auto Unit = ASTUnit::create(CInvok, DiagOpts, Diags, CaptureDiagnostics,
+  auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics,
                               /*UserFilesAreVolatile=*/true);
   if (!Unit)
     return CXError_InvalidArguments;
@@ -618,7 +617,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
       !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
   DiagnosticErrorTrap DiagTrap(*Diags);
   bool Success = ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
+      std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags,
       IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(),
       OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
       CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true);
diff --git a/clang/unittests/AST/ASTVectorTest.cpp b/clang/unittests/AST/ASTVectorTest.cpp
index 66003b49eccb2..1c17eb9210ac3 100644
--- a/clang/unittests/AST/ASTVectorTest.cpp
+++ b/clang/unittests/AST/ASTVectorTest.cpp
@@ -27,14 +27,13 @@ class ASTVectorTest : public ::testing::Test {
 protected:
   ASTVectorTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
         Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins, TU_Complete) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp
index dc10dae7a2f8f..22866f0eb23ed 100644
--- a/clang/unittests/AST/CommentLexer.cpp
+++ b/clang/unittests/AST/CommentLexer.cpp
@@ -27,14 +27,16 @@ namespace {
 class CommentLexerTest : public ::testing::Test {
 protected:
   CommentLexerTest()
-      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
-        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
+    : FileMgr(FileMgrOpts),
+      DiagID(new DiagnosticIDs()),
+      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+      SourceMgr(Diags, FileMgr),
+      Traits(Allocator, CommentOptions()) {
+  }
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentParser.cpp b/clang/unittests/AST/CommentParser.cpp
index 67fabe5181798..aa08b6718e506 100644
--- a/clang/unittests/AST/CommentParser.cpp
+++ b/clang/unittests/AST/CommentParser.cpp
@@ -33,14 +33,16 @@ const bool MY_DEBUG = true;
 class CommentParserTest : public ::testing::Test {
 protected:
   CommentParserTest()
-      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
-        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
+    : FileMgr(FileMgrOpts),
+      DiagID(new DiagnosticIDs()),
+      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+      SourceMgr(Diags, FileMgr),
+      Traits(Allocator, CommentOptions()) {
+  }
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentTextTest.cpp b/clang/unittests/AST/CommentTextTest.cpp
index 84ec51a308360..b697828698d85 100644
--- a/clang/unittests/AST/CommentTextTest.cpp
+++ b/clang/unittests/AST/CommentTextTest.cpp
@@ -43,8 +43,7 @@ class CommentTextTest : public ::testing::Test {
     // FIXME: technically, merged that we set here is incorrect, but that
     // shouldn't matter.
     RawComment Comment(SourceMgr, CommentRange, EmptyOpts, /*Merged=*/true);
-    DiagnosticOptions DiagOpts;
-    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
+    DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions);
     return Comment.getFormattedText(SourceMgr, Diags);
   }
 };
diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp b/clang/unittests/AST/ExternalASTSourceTest.cpp
index 11715bb8ce7cd..807bab1b3dd81 100644
--- a/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -51,9 +51,9 @@ bool testExternalASTSource(ExternalASTSource *Source, StringRef FileContents) {
       "test.cc", MemoryBuffer::getMemBuffer(FileContents).release());
   const char *Args[] = { "test.cc" };
 
-  DiagnosticOptions InvocationDiagOpts;
+  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
   auto InvocationDiags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts);
+      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts.get());
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index 1dd07834bfd7e..6f69ccbd36552 100644
--- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -1388,9 +1388,10 @@ class UncheckedOptionalAccessTest
             unsigned Line = SrcMgr.getPresumedLineNumber(Diag.Range.getBegin());
             DiagnosticLines.insert(Line);
             if (!AnnotationLines.contains(Line)) {
-              DiagnosticOptions DiagOpts;
+              IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
+                  new DiagnosticOptions());
               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
-                                DiagOpts);
+                                DiagOpts.get());
               TD.emitDiagnostic(FullSourceLoc(Diag.Range.getBegin(), SrcMgr),
                                 DiagnosticsEngine::Error,
                                 "unexpected diagnostic", {Diag.Range}, {});
diff --git a/clang/unittests/Analysis/MacroExpansionContextTest.cpp b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
index 9874ea687f3ed..929d4122cdec7 100644
--- a/clang/unittests/Analysis/MacroExpansionContextTest.cpp
+++ b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
@@ -35,8 +35,8 @@ class MacroExpansionContextTest : public ::testing::Test {
   MacroExpansionContextTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
+        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-pc-linux-unknown";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -46,7 +46,7 @@ class MacroExpansionContextTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
index 9da2c58970b84..e48f39bf13f44 100644
--- a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
@@ -13,13 +13,12 @@ class UnsafeBufferUsageTest : public ::testing::Test {
 protected:
   UnsafeBufferUsageTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
 };
diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp
index b0a034e9af1cd..88fa1800f0ff2 100644
--- a/clang/unittests/Basic/DiagnosticTest.cpp
+++ b/clang/unittests/Basic/DiagnosticTest.cpp
@@ -46,8 +46,8 @@ using testing::IsEmpty;
 
 // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
 TEST(DiagnosticTest, suppressAndTrap) {
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
+  DiagnosticsEngine Diags(new DiagnosticIDs(),
+                          new DiagnosticOptions,
                           new IgnoringDiagConsumer());
   Diags.setSuppressAllDiagnostics(true);
 
@@ -77,8 +77,8 @@ TEST(DiagnosticTest, suppressAndTrap) {
 // Check that FatalsAsError works as intended
 TEST(DiagnosticTest, fatalsAsError) {
   for (unsigned FatalsAsError = 0; FatalsAsError != 2; ++FatalsAsError) {
-    DiagnosticOptions DiagOpts;
-    DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
+    DiagnosticsEngine Diags(new DiagnosticIDs(),
+                            new DiagnosticOptions,
                             new IgnoringDiagConsumer());
     Diags.setFatalsAsError(FatalsAsError);
 
@@ -101,8 +101,7 @@ TEST(DiagnosticTest, fatalsAsError) {
 }
 
 TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
+  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
                           new IgnoringDiagConsumer());
   Diags.setFatalsAsError(true);
 
@@ -118,8 +117,7 @@ TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
 
 // Check that soft RESET works as intended
 TEST(DiagnosticTest, softReset) {
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
+  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
                           new IgnoringDiagConsumer());
 
   unsigned numWarnings = 0U, numErrors = 0U;
@@ -142,8 +140,7 @@ TEST(DiagnosticTest, softReset) {
 }
 
 TEST(DiagnosticTest, diagnosticError) {
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
+  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
                           new IgnoringDiagConsumer());
   PartialDiagnostic::DiagStorageAllocator Alloc;
   llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create(
@@ -165,8 +162,7 @@ TEST(DiagnosticTest, diagnosticError) {
 }
 
 TEST(DiagnosticTest, storedDiagEmptyWarning) {
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts);
+  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions);
 
   class CaptureDiagnosticConsumer : public DiagnosticConsumer {
   public:
@@ -196,8 +192,7 @@ class SuppressionMappingTest : public testing::Test {
 protected:
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags{new DiagnosticIDs(), DiagOpts};
+  DiagnosticsEngine Diags{new DiagnosticIDs(), new DiagnosticOptions};
 
   llvm::ArrayRef<StoredDiagnostic> diags() {
     return CaptureConsumer.StoredDiags;
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index ad9f8ecc208a4..febfbabe8695e 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -43,14 +43,14 @@ class SarifDocumentWriterTest : public ::testing::Test {
   SarifDocumentWriterTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
+        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp
index cbe047b5e599a..1f0986f61dfa9 100644
--- a/clang/unittests/Basic/SourceManagerTest.cpp
+++ b/clang/unittests/Basic/SourceManagerTest.cpp
@@ -40,9 +40,11 @@ namespace {
 class SourceManagerTest : public ::testing::Test {
 protected:
   SourceManagerTest()
-      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
-        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
+    : FileMgr(FileMgrOpts),
+      DiagID(new DiagnosticIDs()),
+      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+      SourceMgr(Diags, FileMgr),
+      TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -50,7 +52,6 @@ class SourceManagerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp
index f6845939d04b4..616c07c0d389d 100644
--- a/clang/unittests/Driver/DXCModeTest.cpp
+++ b/clang/unittests/Driver/DXCModeTest.cpp
@@ -64,8 +64,8 @@ TEST(DxcModeTest, TargetProfileValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
 
   validateTargetProfile("-Tvs_6_0", "dxilv1.0--shadermodel6.0-vertex",
                         InMemoryFileSystem, Diags);
@@ -114,8 +114,8 @@ TEST(DxcModeTest, ValidatorVersionValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
   Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
@@ -218,9 +218,9 @@ TEST(DxcModeTest, DefaultEntry) {
 
   const char *Args[] = {"clang", "--driver-mode=dxc", "-Tcs_6_7", "foo.hlsl"};
 
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*InMemoryFileSystem, DiagOpts);
+      CompilerInstance::createDiagnostics(*InMemoryFileSystem,
+                                          new DiagnosticOptions());
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Driver/SanitizerArgsTest.cpp b/clang/unittests/Driver/SanitizerArgsTest.cpp
index b8bfc6806da6d..5a4221023c950 100644
--- a/clang/unittests/Driver/SanitizerArgsTest.cpp
+++ b/clang/unittests/Driver/SanitizerArgsTest.cpp
@@ -52,9 +52,10 @@ class SanitizerArgsTest : public ::testing::Test {
                                           std::vector<std::string> ExtraFiles) {
     assert(!DriverInstance && "Running twice is not allowed");
 
-    DiagnosticOptions DiagOpts;
-    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
-                            new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
+    llvm::IntrusiveRefCntPtr<DiagnosticOptions> Opts = new DiagnosticOptions;
+    DiagnosticsEngine Diags(
+        new DiagnosticIDs, Opts,
+        new TextDiagnosticPrinter(llvm::errs(), Opts.get()));
     DriverInstance.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,
                            "clang LLVM compiler", prepareFS(ExtraFiles));
 
diff --git a/clang/unittests/Driver/SimpleDiagnosticConsumer.h b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
index c3772baade566..6515bdedb3d5d 100644
--- a/clang/unittests/Driver/SimpleDiagnosticConsumer.h
+++ b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
@@ -47,8 +47,9 @@ inline clang::driver::Driver diagnostic_test_driver() {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  clang::DiagnosticOptions DiagOpts;
-  clang::DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
+      new clang::DiagnosticOptions();
+  clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
   return clang::driver::Driver("/bin/clang", "", Diags, "", InMemoryFileSystem);
 }
 
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index 670090a01b0d3..c1ffe4a82ce4b 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -38,7 +38,7 @@ using namespace clang::driver;
 namespace {
 
 TEST(ToolChainTest, VFSGCCInstallation) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -84,7 +84,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -107,8 +107,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
   }
 
   {
-    DiagnosticOptions DiagOpts;
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -135,11 +134,11 @@ TEST(ToolChainTest, VFSGCCInstallation) {
 }
 
 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -174,7 +173,7 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
 }
 
 TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -202,7 +201,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "i386-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -226,7 +225,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "amd64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -250,7 +249,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -274,7 +273,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparc-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -297,7 +296,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
               S);
   }
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparcv9-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -338,7 +337,7 @@ MATCHER_P(jobHasArgs, Substr, "") {
 }
 
 TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -356,7 +355,7 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-unknown-linux-gnu", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -369,11 +368,11 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
 }
 
 TEST(ToolChainTest, DefaultDriverMode) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -404,8 +403,8 @@ TEST(ToolChainTest, DefaultDriverMode) {
 TEST(ToolChainTest, InvalidArgument) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
@@ -515,11 +514,11 @@ TEST(ToolChainTest, GetTargetAndMode) {
 }
 
 TEST(ToolChainTest, CommandOutput) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -544,10 +543,10 @@ TEST(ToolChainTest, CommandOutput) {
 }
 
 TEST(ToolChainTest, PostCallback) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -597,10 +596,10 @@ TEST(ToolChainTest, UEFICallingConventionTest) {
 }
 
 TEST(ToolChainTest, UEFIDefaultDebugFormatTest) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver CCDriver("/home/test/bin/clang", "x86_64-unknown-uefi", Diags,
@@ -639,10 +638,10 @@ struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 TEST(ToolChainTest, ConfigFileSearch) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -716,11 +715,11 @@ struct FileSystemWithError : public llvm::vfs::FileSystem {
 };
 
 TEST(ToolChainTest, ConfigFileError) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
 
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -737,11 +736,11 @@ TEST(ToolChainTest, ConfigFileError) {
 }
 
 TEST(ToolChainTest, BadConfigFile) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -811,11 +810,11 @@ TEST(ToolChainTest, BadConfigFile) {
 }
 
 TEST(ToolChainTest, ConfigInexistentInclude) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -852,11 +851,11 @@ TEST(ToolChainTest, ConfigInexistentInclude) {
 }
 
 TEST(ToolChainTest, ConfigRecursiveInclude) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -898,10 +897,10 @@ TEST(ToolChainTest, ConfigRecursiveInclude) {
 }
 
 TEST(ToolChainTest, NestedConfigFile) {
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp
index afa64b5e90a6d..08daca9111e64 100644
--- a/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -30,8 +30,6 @@ class ASTUnitTest : public ::testing::Test {
   int FD;
   llvm::SmallString<256> InputFileName;
   std::unique_ptr<ToolOutputFile> input_file;
-  std::shared_ptr<DiagnosticOptions> DiagOpts =
-      std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   std::shared_ptr<CompilerInvocation> CInvok;
   std::shared_ptr<PCHContainerOperations> PCHContainerOps;
@@ -45,7 +43,7 @@ class ASTUnitTest : public ::testing::Test {
     const char *Args[] = {"clang", "-xc++", InputFileName.c_str()};
 
     auto VFS = llvm::vfs::getRealFileSystem();
-    Diags = CompilerInstance::createDiagnostics(*VFS, *DiagOpts);
+    Diags = CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
 
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
@@ -59,8 +57,8 @@ class ASTUnitTest : public ::testing::Test {
     PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
     return ASTUnit::LoadFromCompilerInvocation(
-        CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
-        CaptureDiagsKind::None, 0, TU_Complete, false, false, isVolatile);
+        CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None,
+        0, TU_Complete, false, false, isVolatile);
   }
 };
 
@@ -97,7 +95,7 @@ TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) {
 
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything,
-      DiagOpts, Diags, FileSystemOptions(), HSOpts);
+      Diags, FileSystemOptions(), HSOpts);
 
   if (!AU)
     FAIL() << "failed to load ASTUnit";
@@ -138,7 +136,8 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
 
   const char *Args[] = {"clang", "test.cpp", "-fmodule-map-file=m.modulemap",
                         "-fmodule-name=M"};
-  Diags = CompilerInstance::createDiagnostics(*InMemoryFs, *DiagOpts);
+  Diags =
+      CompilerInstance::createDiagnostics(*InMemoryFs, new DiagnosticOptions());
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CInvok = createInvocation(Args, std::move(CIOpts));
@@ -148,8 +147,8 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
   PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
   auto AU = ASTUnit::LoadFromCompilerInvocation(
-      CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
-      CaptureDiagsKind::None, 1, TU_Complete, false, false, false);
+      CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, 1,
+      TU_Complete, false, false, false);
   ASSERT_TRUE(AU);
   auto File = AU->getFileManager().getFileRef("Textual.h", false, false);
   ASSERT_TRUE(bool(File));
@@ -167,15 +166,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) {
   const char *Args[] = {"clang", "-target", "foobar", InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), *DiagOpts);
+      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
-      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
-      false, SkipFunctionBodiesScope::None, false, true, false, false,
-      std::nullopt, &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
+      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
+      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
+      &ErrUnit, nullptr);
 
   ASSERT_EQ(AST, nullptr);
   ASSERT_NE(ErrUnit, nullptr);
@@ -195,15 +194,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) {
                         InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), *DiagOpts);
+      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
-      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
-      false, SkipFunctionBodiesScope::None, false, true, false, false,
-      std::nullopt, &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
+      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
+      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
+      &ErrUnit, nullptr);
 
   ASSERT_NE(AST, nullptr);
   ASSERT_FALSE(Diags->hasErrorOccurred());
diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp
index a7b258d5e537e..6e9a6f5f728a5 100644
--- a/clang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -53,10 +53,9 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
   const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
   const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};
 
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          DiagOpts);
+                                          new DiagnosticOptions());
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
@@ -77,17 +76,17 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
 }
 
 TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
-  DiagnosticOptions DiagOpts;
+  auto DiagOpts = new DiagnosticOptions();
   // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
   // ensures that a chained diagnostic consumer is created so that the test can
   // exercise the unowned diagnostic consumer in a chained consumer.
-  DiagOpts.DiagnosticLogFile = "-";
+  DiagOpts->DiagnosticLogFile = "-";
 
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter =
-      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
+  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
+      DiagnosticsOS, new DiagnosticOptions());
   CompilerInstance Instance;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       Instance.createDiagnostics(*llvm::vfs::getRealFileSystem(), DiagOpts,
diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp
index 75390aa42d00e..94ab9fe8451e0 100644
--- a/clang/unittests/Frontend/CompilerInvocationTest.cpp
+++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp
@@ -29,7 +29,6 @@ using ::testing::StartsWith;
 namespace {
 class CommandLineTest : public ::testing::Test {
 public:
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   SmallVector<const char *, 32> GeneratedArgs;
   BumpPtrAllocator Alloc;
@@ -42,7 +41,7 @@ class CommandLineTest : public ::testing::Test {
 
   CommandLineTest()
       : Diags(CompilerInstance::createDiagnostics(
-            *llvm::vfs::getRealFileSystem(), DiagOpts,
+            *llvm::vfs::getRealFileSystem(), new DiagnosticOptions(),
             new TextDiagnosticBuffer())),
         StringPool(Alloc) {}
 };
diff --git a/clang/unittests/Frontend/OutputStreamTest.cpp b/clang/unittests/Frontend/OutputStreamTest.cpp
index dfb5a544cb88a..0eda3a1dab403 100644
--- a/clang/unittests/Frontend/OutputStreamTest.cpp
+++ b/clang/unittests/Frontend/OutputStreamTest.cpp
@@ -61,10 +61,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamShared) {
   raw_string_ostream VerboseStream(VerboseBuffer);
 
   Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-  DiagnosticOptions DiagOpts;
-  Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                             new TextDiagnosticPrinter(llvm::nulls(), DiagOpts),
-                             true);
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  Compiler.createDiagnostics(
+      *llvm::vfs::getRealFileSystem(),
+      new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
   Compiler.setVerboseOutputStream(VerboseStream);
 
   bool Success = ExecuteCompilerInvocation(&Compiler);
@@ -91,10 +91,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) {
         std::make_unique<raw_string_ostream>(VerboseBuffer);
 
     Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-    DiagnosticOptions DiagOpts;
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
     Compiler.createDiagnostics(
         *llvm::vfs::getRealFileSystem(),
-        new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), true);
+        new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
     Compiler.setVerboseOutputStream(std::move(VerboseStream));
 
     Success = ExecuteCompilerInvocation(&Compiler);
diff --git a/clang/unittests/Frontend/PCHPreambleTest.cpp b/clang/unittests/Frontend/PCHPreambleTest.cpp
index faad408193f62..58ec2e2ce7058 100644
--- a/clang/unittests/Frontend/PCHPreambleTest.cpp
+++ b/clang/unittests/Frontend/PCHPreambleTest.cpp
@@ -53,8 +53,6 @@ class PCHPreambleTest : public ::testing::Test {
   IntrusiveRefCntPtr<ReadCountingInMemoryFileSystem> VFS;
   StringMap<std::string> RemappedFiles;
   std::shared_ptr<PCHContainerOperations> PCHContainerOpts;
-  std::shared_ptr<DiagnosticOptions> DiagOpts =
-      std::make_shared<DiagnosticOptions>();
   FileSystemOptions FSOpts;
 
 public:
@@ -97,14 +95,13 @@ class PCHPreambleTest : public ::testing::Test {
     PPOpts.RemappedFilesKeepOriginalName = true;
 
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
+        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(FSOpts, VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
-        CaptureDiagsKind::None,
+        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
index 1b8051f80e9b8..b0f2d51b80b9e 100644
--- a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
+++ b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
@@ -57,16 +57,14 @@ class ReparseWorkingDirTest : public ::testing::Test {
     CI->getFileSystemOpts().WorkingDir = *VFS->getCurrentWorkingDirectory();
     CI->getTargetOpts().Triple = "i386-unknown-linux-gnu";
 
-    auto DiagOpts = std::make_shared<DiagnosticOptions>();
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
+        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
-        CaptureDiagsKind::None,
+        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/SearchPathTest.cpp b/clang/unittests/Frontend/SearchPathTest.cpp
index c74a5c75fada5..2ebe74d47eb02 100644
--- a/clang/unittests/Frontend/SearchPathTest.cpp
+++ b/clang/unittests/Frontend/SearchPathTest.cpp
@@ -40,12 +40,12 @@ namespace {
 class SearchPathTest : public ::testing::Test {
 protected:
   SearchPathTest()
-      : Diags(new DiagnosticIDs(), DiagOpts, new IgnoringDiagConsumer()),
+      : Diags(new DiagnosticIDs(), new DiagnosticOptions,
+              new IgnoringDiagConsumer()),
         VFS(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), VFS), SourceMgr(Diags, FileMgr),
         Invocation(std::make_unique<CompilerInvocation>()) {}
 
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
   FileManager FileMgr;
diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp
index 8fd8187134b63..fef5726f053f1 100644
--- a/clang/unittests/Frontend/TextDiagnosticTest.cpp
+++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp
@@ -20,12 +20,13 @@ namespace {
 
 /// Prints a diagnostic with the given DiagnosticOptions and the given
 /// SourceLocation and returns the printed diagnostic text.
-static std::string PrintDiag(DiagnosticOptions &Opts, FullSourceLoc Loc) {
+static std::string PrintDiag(const DiagnosticOptions &Opts, FullSourceLoc Loc) {
   std::string Out;
   llvm::raw_string_ostream OS(Out);
   clang::LangOptions LangOpts;
   // Owned by TextDiagnostic.
-  TextDiagnostic Diag(OS, LangOpts, Opts);
+  DiagnosticOptions *DiagOpts = new DiagnosticOptions(Opts);
+  TextDiagnostic Diag(OS, LangOpts, DiagOpts);
   // Emit a dummy diagnostic that is just 'message'.
   Diag.emitDiagnostic(Loc, DiagnosticsEngine::Level::Warning, "message",
                       /*Ranges=*/{}, /*FixItHints=*/{});
@@ -37,8 +38,7 @@ TEST(TextDiagnostic, ShowLine) {
   FileSystemOptions FSOpts;
   FileManager FileMgr(FSOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
-  DiagnosticOptions DiagEngineOpts;
-  DiagnosticsEngine DiagEngine(DiagID, DiagEngineOpts,
+  DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions,
                                new IgnoringDiagConsumer());
   SourceManager SrcMgr(DiagEngine, FileMgr);
 
diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp
index cf385a5323c61..47ca3210ab596 100644
--- a/clang/unittests/Frontend/UtilsTest.cpp
+++ b/clang/unittests/Frontend/UtilsTest.cpp
@@ -26,12 +26,11 @@ TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
   std::vector<const char *> Args = {"clang", "--target=macho", "-arch",  "i386",
                                     "-arch", "x86_64",         "foo.cpp"};
   clang::IgnoringDiagConsumer D;
-  clang::DiagnosticOptions DiagOpts;
   CreateInvocationOptions Opts;
   Opts.RecoverOnError = true;
   Opts.VFS = new llvm::vfs::InMemoryFileSystem();
-  Opts.Diags = clang::CompilerInstance::createDiagnostics(*Opts.VFS, DiagOpts,
-                                                          &D, false);
+  Opts.Diags = clang::CompilerInstance::createDiagnostics(
+      *Opts.VFS, new DiagnosticOptions, &D, false);
   std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
   ASSERT_TRUE(CI);
   EXPECT_THAT(CI->getTargetOpts().Triple, testing::StartsWith("i386-"));
@@ -46,9 +45,9 @@ TEST(BuildCompilerInvocationTest, ProbePrecompiled) {
   FS->addFile("foo.h.pch", 0, llvm::MemoryBuffer::getMemBuffer(""));
 
   clang::IgnoringDiagConsumer D;
-  clang::DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
-      clang::CompilerInstance::createDiagnostics(*FS, DiagOpts, &D, false);
+      clang::CompilerInstance::createDiagnostics(*FS, new DiagnosticOptions, &D,
+                                                 false);
   // Default: ProbePrecompiled=false
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = CommandLineDiagsEngine;
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index b97f5ae17c9f0..03b9c33232080 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -95,9 +95,8 @@ TEST_F(InterpreterTest, Errors) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  DiagnosticOptions DiagOpts;
-  auto DiagPrinter =
-      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
+  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
+      DiagnosticsOS, new DiagnosticOptions());
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError();
@@ -127,9 +126,8 @@ TEST_F(InterpreterTest, DeclsAndStatements) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  DiagnosticOptions DiagOpts;
-  auto DiagPrinter =
-      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
+  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
+      DiagnosticsOS, new DiagnosticOptions());
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto R1 = Interp->Parse(
@@ -150,9 +148,8 @@ TEST_F(InterpreterTest, UndoCommand) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  DiagnosticOptions DiagOpts;
-  auto DiagPrinter =
-      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
+  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
+      DiagnosticsOS, new DiagnosticOptions());
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
 
diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp b/clang/unittests/Lex/HeaderSearchTest.cpp
index 9903c1246d33d..b8896261703cd 100644
--- a/clang/unittests/Lex/HeaderSearchTest.cpp
+++ b/clang/unittests/Lex/HeaderSearchTest.cpp
@@ -30,7 +30,7 @@ class HeaderSearchTest : public ::testing::Test {
   HeaderSearchTest()
       : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS),
         DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
         Search(HSOpts, SourceMgr, Diags, LangOpts, Target.get()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
@@ -81,7 +81,6 @@ class HeaderSearchTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp
index 381755d4d1b6f..9806d4c7bf145 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -41,9 +41,12 @@ using testing::ElementsAre;
 class LexerTest : public ::testing::Test {
 protected:
   LexerTest()
-      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
-        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
+    : FileMgr(FileMgrOpts),
+      DiagID(new DiagnosticIDs()),
+      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+      SourceMgr(Diags, FileMgr),
+      TargetOpts(new TargetOptions)
+  {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -101,7 +104,6 @@ class LexerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/ModuleDeclStateTest.cpp b/clang/unittests/Lex/ModuleDeclStateTest.cpp
index 6ecba4de3187c..6fbc6bff12d8a 100644
--- a/clang/unittests/Lex/ModuleDeclStateTest.cpp
+++ b/clang/unittests/Lex/ModuleDeclStateTest.cpp
@@ -55,7 +55,7 @@ class ModuleDeclStateTest : public ::testing::Test {
 protected:
   ModuleDeclStateTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-unknown-linux-gnu";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -94,7 +94,6 @@ class ModuleDeclStateTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   std::shared_ptr<TargetOptions> TargetOpts;
diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp
index af86c1888f2c7..c2a84d974dd39 100644
--- a/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -135,8 +135,8 @@ class PPCallbacksTest : public ::testing::Test {
   PPCallbacksTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
+        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -145,7 +145,7 @@ class PPCallbacksTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
@@ -437,7 +437,7 @@ TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
   HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
 
   DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
-  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts, DiagConsumer);
+  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer);
   Preprocessor PP(PPOpts, FileNotFoundDiags, LangOpts, SourceMgr, HeaderInfo,
                   ModLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
   PP.Initialize(*Target);
diff --git a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 54c1d020aa0ea..5c3ce6fa33012 100644
--- a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -29,9 +29,12 @@ namespace {
 class PPConditionalDirectiveRecordTest : public ::testing::Test {
 protected:
   PPConditionalDirectiveRecordTest()
-      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
-        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
+    : FileMgr(FileMgrOpts),
+      DiagID(new DiagnosticIDs()),
+      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+      SourceMgr(Diags, FileMgr),
+      TargetOpts(new TargetOptions)
+  {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -39,7 +42,6 @@ class PPConditionalDirectiveRecordTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
index 061cb136a552a..74e3c00b451ba 100644
--- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
+++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
@@ -32,7 +32,7 @@ class PPDependencyDirectivesTest : public ::testing::Test {
 protected:
   PPDependencyDirectivesTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-macos12";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -41,7 +41,6 @@ class PPDependencyDirectivesTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
index 4d83003e28b36..304a66ab96caa 100644
--- a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
+++ b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
@@ -28,7 +28,7 @@ class PPMemoryAllocationsTest : public ::testing::Test {
 protected:
   PPMemoryAllocationsTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -37,7 +37,6 @@ class PPMemoryAllocationsTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 912e96e5700aa..7d03dda1f516b 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -67,7 +67,8 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
 protected:
   ParseHLSLRootSignatureTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Consumer(new ExpectedDiagConsumer()), Diags(DiagID, DiagOpts, Consumer),
+        Consumer(new ExpectedDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, Consumer),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     // This is an arbitrarily chosen target triple to create the target info.
     TargetOpts->Triple = "dxil";
@@ -94,7 +95,6 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  DiagnosticOptions DiagOpts;
   ExpectedDiagConsumer *Consumer;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
index 5a04f42697b99..c68a71ae05d3f 100644
--- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp
+++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
@@ -59,9 +59,9 @@ class NoloadLookupTest : public ::testing::Test {
 
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+        CompilerInstance::createDiagnostics(*CIOpts.VFS,
+                                            new DiagnosticOptions());
     CIOpts.Diags = Diags;
 
     std::string CacheBMIPath =
diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
index 970eeef3c953e..16742a6cb01e8 100644
--- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
+++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
@@ -66,9 +66,9 @@ export int aa = 43;
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
 
-    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+        CompilerInstance::createDiagnostics(*CIOpts.VFS,
+                                            new DiagnosticOptions());
     CIOpts.Diags = Diags;
 
     const char *Args[] = {"clang++",       "-std=c++20",
@@ -106,9 +106,9 @@ export int aa = 43;
   {
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+        CompilerInstance::createDiagnostics(*CIOpts.VFS,
+                                            new DiagnosticOptions());
     CIOpts.Diags = Diags;
 
     std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str();
diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
index 631547431ce7c..d62d669149f51 100644
--- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
+++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
@@ -53,9 +53,8 @@ class LoadSpecLazilyTest : public ::testing::Test {
 
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
         llvm::vfs::createPhysicalFileSystem();
-    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*VFS, DiagOpts);
+        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
     CIOpts.VFS = VFS;
diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp
index de6e13a738cb8..38003e93c5d9d 100644
--- a/clang/unittests/Serialization/ModuleCacheTest.cpp
+++ b/clang/unittests/Serialization/ModuleCacheTest.cpp
@@ -108,9 +108,8 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
@@ -158,9 +157,8 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp
index 05efeef990d43..3aaaa548c6eff 100644
--- a/clang/unittests/Serialization/NoCommentsTest.cpp
+++ b/clang/unittests/Serialization/NoCommentsTest.cpp
@@ -85,9 +85,8 @@ void foo() {}
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
   CIOpts.Diags = Diags;
 
   std::string CacheBMIPath = llvm::Twine(TestDir + "/Comments.pcm").str();
diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
index c43520f79b02c..7a037d22d5c0d 100644
--- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
+++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
@@ -77,9 +77,8 @@ export using ::E;
 
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       llvm::vfs::createPhysicalFileSystem();
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, DiagOpts);
+      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
index 5b2988ed26336..33c3c6b5e61fd 100644
--- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
+++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
@@ -92,9 +92,8 @@ export namespace Fibonacci
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
-  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
   CIOpts.Diags = Diags;
 
   const char *Args[] = {"clang++",       "-std=c++20",
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 85d36b5d21423..a92b0eb11c423 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -58,9 +58,9 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
 
   auto Invocation = std::make_shared<CompilerInvocation>();
   std::vector<const char *> Args = {Standard.data(), File.data()};
-  DiagnosticOptions InvocationDiagOpts;
+  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
   auto InvocationDiags =
-      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts);
+      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts.get());
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Tooling/RewriterTestContext.h b/clang/unittests/Tooling/RewriterTestContext.h
index 2d697e276c5e8..b7aa1a133c83e 100644
--- a/clang/unittests/Tooling/RewriterTestContext.h
+++ b/clang/unittests/Tooling/RewriterTestContext.h
@@ -49,8 +49,9 @@ struct RewriterDiagnosticConsumer : public DiagnosticConsumer {
 class RewriterTestContext {
  public:
    RewriterTestContext()
-       : Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-                     DiagOpts),
+       : DiagOpts(new DiagnosticOptions()),
+         Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+                     &*DiagOpts),
          InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
          OverlayFileSystem(
              new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())),
@@ -60,7 +61,7 @@ class RewriterTestContext {
      // FIXME: To make these tests truly in-memory, we need to overlay the
      // builtin headers.
      OverlayFileSystem->pushOverlay(InMemoryFileSystem);
-   }
+  }
 
   ~RewriterTestContext() {}
 
@@ -123,7 +124,7 @@ class RewriterTestContext {
     return std::string((*FileBuffer)->getBuffer());
   }
 
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
   DiagnosticsEngine Diagnostics;
   RewriterDiagnosticConsumer DiagnosticPrinter;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp
index b5f44454e862d..d42273be1858c 100644
--- a/clang/unittests/Tooling/Syntax/TokensTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -248,9 +248,8 @@ class TokenCollectorTest : public ::testing::Test {
   }
 
   // Data fields.
-  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
+      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
index 9f22b1d64c913..7710a9cc5a743 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
@@ -126,7 +126,7 @@ SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) {
   FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
 
   if (!Diags->getClient())
-    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
+    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
   Diags->setSeverityForGroup(diag::Flavor::WarningOrError, "unused-value",
                              diag::Severity::Ignored, SourceLocation());
 
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.h b/clang/unittests/Tooling/Syntax/TreeTestBase.h
index 6110cffa708d9..1176f457cf8b3 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.h
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.h
@@ -40,9 +40,9 @@ class SyntaxTreeTest : public ::testing::Test,
   syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root);
 
   // Data fields.
-  DiagnosticOptions DiagOpts;
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
+      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts.get());
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index 32af4b6b3b359..cfa021a5ef137 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -294,8 +294,8 @@ TEST(ToolInvocation, CustomDiagnosticOptionsOverwriteParsedOnes) {
   Invocation.setDiagnosticConsumer(&Consumer);
 
   // Inject custom `DiagnosticOptions` for command-line parsing.
-  DiagnosticOptions DiagOpts;
-  Invocation.setDiagnosticOptions(&DiagOpts);
+  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  Invocation.setDiagnosticOptions(&*DiagOpts);
 
   EXPECT_TRUE(Invocation.run());
   // Check that the warning was issued during command-line parsing due to the
@@ -392,14 +392,14 @@ overlayRealFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
 
 struct CommandLineExtractorTest : public ::testing::Test {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
-  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   driver::Driver Driver;
 
 public:
   CommandLineExtractorTest()
       : InMemoryFS(new llvm::vfs::InMemoryFileSystem),
-        Diags(CompilerInstance::createDiagnostics(*InMemoryFS, DiagOpts)),
+        Diags(CompilerInstance::createDiagnostics(*InMemoryFS,
+                                                  new DiagnosticOptions)),
         Driver("clang", llvm::sys::getDefaultTargetTriple(), *Diags,
                "clang LLVM compiler", overlayRealFS(InMemoryFS)) {}
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 959cbb282b043..25b4c8b876265 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -166,12 +166,13 @@ static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) {
 class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 public:
   ClangDiagnosticManagerAdapter(DiagnosticOptions &opts, StringRef filename)
-      : m_options(opts), m_filename(filename) {
-    m_options.ShowPresumedLoc = true;
-    m_options.ShowLevel = false;
+      : m_filename(filename) {
+    DiagnosticOptions *options = new DiagnosticOptions(opts);
+    options->ShowPresumedLoc = true;
+    options->ShowLevel = false;
     m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
     m_passthrough =
-        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options);
+        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options);
   }
 
   void ResetManager(DiagnosticManager *manager = nullptr) {
@@ -312,7 +313,6 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 
 private:
   DiagnosticManager *m_manager = nullptr;
-  DiagnosticOptions m_options;
   std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
   /// Output stream of m_passthrough.
   std::shared_ptr<llvm::raw_string_ostream> m_os;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 06f3a7efac7a2..1feeeb64aa9e5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -261,7 +261,8 @@ TokenVerifier::TokenVerifier(std::string body) {
   // Let's build the actual source code Clang needs and setup some utility
   // objects.
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  DiagnosticOptions diags_opts;
+  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
+      new DiagnosticOptions());
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(body);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index eb62cb618f254..eee6166e43f98 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -66,7 +66,6 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
   typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
       IDAndDiagnostic;
   std::vector<IDAndDiagnostic> m_diagnostics;
-  std::unique_ptr<clang::DiagnosticOptions> m_diag_opts;
   /// The DiagnosticPrinter used for creating the full diagnostic messages
   /// that are stored in m_diagnostics.
   std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
@@ -84,7 +83,6 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
 class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 public:
   ClangModulesDeclVendorImpl(
-      std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
       llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
       std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
       std::unique_ptr<clang::CompilerInstance> compiler_instance,
@@ -117,7 +115,6 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 
   bool m_enabled = false;
 
-  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options;
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
   std::shared_ptr<clang::CompilerInvocation> m_compiler_invocation;
   std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
@@ -137,10 +134,10 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 } // anonymous namespace
 
 StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
-  m_diag_opts = std::make_unique<clang::DiagnosticOptions>();
+  auto *options = new clang::DiagnosticOptions();
   m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
   m_diag_printer =
-      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, *m_diag_opts);
+      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options);
 }
 
 void StoringDiagnosticConsumer::HandleDiagnostic(
@@ -231,13 +228,11 @@ ClangModulesDeclVendor::ClangModulesDeclVendor()
 ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
 
 ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(
-    std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
     llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
     std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
     std::unique_ptr<clang::CompilerInstance> compiler_instance,
     std::unique_ptr<clang::Parser> parser)
-    : m_diagnostic_options(std::move(diagnostic_options)),
-      m_diagnostics_engine(std::move(diagnostics_engine)),
+    : m_diagnostics_engine(std::move(diagnostics_engine)),
       m_compiler_invocation(std::move(compiler_invocation)),
       m_compiler_instance(std::move(compiler_instance)),
       m_parser(std::move(parser)) {
@@ -711,8 +706,8 @@ ClangModulesDeclVendor::Create(Target &target) {
       clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
       clang::CompilerInstance::createDiagnostics(
-          *FileSystem::Instance().GetVirtualFileSystem(), *diag_options_up,
-          new StoringDiagnosticConsumer);
+          *FileSystem::Instance().GetVirtualFileSystem(),
+          diag_options_up.release(), new StoringDiagnosticConsumer);
 
   Log *log = GetLog(LLDBLog::Expressions);
   LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
@@ -772,7 +767,7 @@ ClangModulesDeclVendor::Create(Target &target) {
   while (!parser->ParseTopLevelDecl(parsed, ImportState))
     ;
 
-  return new ClangModulesDeclVendorImpl(
-      std::move(diag_options_up), std::move(diagnostics_engine),
-      std::move(invocation), std::move(instance), std::move(parser));
+  return new ClangModulesDeclVendorImpl(std::move(diagnostics_engine),
+                                        std::move(invocation),
+                                        std::move(instance), std::move(parser));
 }
diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
index 8cc5714d0f0fc..6e56e29f8c31c 100644
--- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
+++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
@@ -163,7 +163,8 @@ void ClangHighlighter::Highlight(const HighlightStyle &options,
   // objects.
   std::string full_source = previous_lines.str() + line.str();
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  DiagnosticOptions diags_opts;
+  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
+      new DiagnosticOptions());
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(full_source);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 150c08ff353ea..bc9a41b58c0d7 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -680,9 +680,8 @@ void TypeSystemClang::CreateASTContext() {
       file_system_options, FileSystem::Instance().GetVirtualFileSystem());
 
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
-  m_diagnostic_options_up = std::make_unique<DiagnosticOptions>();
   m_diagnostics_engine_up =
-      std::make_unique<DiagnosticsEngine>(diag_id_sp, *m_diagnostic_options_up);
+      std::make_unique<DiagnosticsEngine>(diag_id_sp, new DiagnosticOptions());
 
   m_source_manager_up = std::make_unique<clang::SourceManager>(
       *m_diagnostics_engine_up, *m_file_manager_up);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 285748719390c..f918cb017f51b 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1204,7 +1204,6 @@ class TypeSystemClang : public TypeSystem {
   std::unique_ptr<clang::LangOptions> m_language_options_up;
   std::unique_ptr<clang::FileManager> m_file_manager_up;
   std::unique_ptr<clang::SourceManager> m_source_manager_up;
-  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options_up;
   std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up;
   std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up;
   std::shared_ptr<clang::TargetOptions> m_target_options_rp;

>From 45f6036533bd30966f5e815568b792a7e293a0e8 Mon Sep 17 00:00:00 2001
From: Mingming Liu <mingmingl at google.com>
Date: Thu, 22 May 2025 12:51:04 -0700
Subject: [PATCH 045/105] [StaticDataLayout][PGO]Implement reader and writer
 change for data access profiles (#139997)

https://github.com/llvm/llvm-project/pull/138170 introduces classes to
operate on data access profiles. This change supports the read and write
of `DataAccessProfData` in indexed format of MemProf (v4) as well as its
the text (yaml) format.

For indexed format:
* InstrProfWriter owns (by `std::unique_ptr<DataAccessProfData>`) the
data access profiles, and gives a non-owned copy when it calls
`writeMemProf`.
* MemProf v4 header has a new `uint64_t` to record the byte offset of
data access profiles. This `uint64_t` field is zero if data access
profile is not set (nullptr).
* MemProfReader reads the offset from v4 header and de-serializes
in-memory bytes into class `DataAccessProfData`.

For textual format:
* MemProfYAML.h adds the mapping for DAP class, and make DAP optional
for both read and write.

099a0fa (by @snehasish) introduces v4 which contains CalleeGuids in
CallSiteInfo, and this change changes the v4 format in place with data
access profiles. The current plan is to bump the version and enable v4
profiles with both features, assuming waiting for this change won't
delay the callsite change too long.

---------

Co-authored-by: Kazu Hirata <kazu at google.com>
---
 .../include/llvm/ProfileData/DataAccessProf.h | 22 +++--
 .../llvm/ProfileData/IndexedMemProfData.h     | 12 ++-
 .../llvm/ProfileData/InstrProfReader.h        |  6 +-
 .../llvm/ProfileData/InstrProfWriter.h        |  6 ++
 llvm/include/llvm/ProfileData/MemProfReader.h | 14 +++
 llvm/include/llvm/ProfileData/MemProfYAML.h   | 61 +++++++++++++
 llvm/lib/ProfileData/DataAccessProf.cpp       |  7 +-
 llvm/lib/ProfileData/IndexedMemProfData.cpp   | 62 ++++++++++---
 llvm/lib/ProfileData/InstrProfReader.cpp      | 14 +++
 llvm/lib/ProfileData/InstrProfWriter.cpp      | 13 ++-
 llvm/lib/ProfileData/MemProfReader.cpp        | 29 ++++++
 .../tools/llvm-profdata/memprof-yaml.test     | 91 ++++++++++++++++++-
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  4 +
 .../ProfileData/DataAccessProfTest.cpp        |  4 +-
 14 files changed, 313 insertions(+), 32 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/DataAccessProf.h b/llvm/include/llvm/ProfileData/DataAccessProf.h
index 3cc8835a776dd..cd4b200486a3f 100644
--- a/llvm/include/llvm/ProfileData/DataAccessProf.h
+++ b/llvm/include/llvm/ProfileData/DataAccessProf.h
@@ -17,10 +17,8 @@
 #ifndef LLVM_PROFILEDATA_DATAACCESSPROF_H_
 #define LLVM_PROFILEDATA_DATAACCESSPROF_H_
 
-#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseMapInfoVariant.h"
 #include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -35,12 +33,15 @@
 
 namespace llvm {
 
-namespace data_access_prof {
+namespace memprof {
 
 /// The location of data in the source code. Used by profile lookup API.
 struct SourceLocation {
   SourceLocation(StringRef FileNameRef, uint32_t Line)
       : FileName(FileNameRef.str()), Line(Line) {}
+
+  // Empty constructor is used in yaml conversion.
+  SourceLocation() {}
   /// The filename where the data is located.
   std::string FileName;
   /// The line number in the source code.
@@ -53,6 +54,8 @@ namespace internal {
 // which strings are owned by `DataAccessProfData`. Used by `DataAccessProfData`
 // to represent data locations internally.
 struct SourceLocationRef {
+  SourceLocationRef(StringRef FileNameRef, uint32_t Line)
+      : FileName(FileNameRef), Line(Line) {}
   // The filename where the data is located.
   StringRef FileName;
   // The line number in the source code.
@@ -100,18 +103,21 @@ using SymbolHandle = std::variant<std::string, uint64_t>;
 /// The data access profiles for a symbol.
 struct DataAccessProfRecord {
 public:
-  DataAccessProfRecord(SymbolHandleRef SymHandleRef,
-                       ArrayRef<internal::SourceLocationRef> LocRefs) {
+  DataAccessProfRecord(SymbolHandleRef SymHandleRef, uint64_t AccessCount,
+                       ArrayRef<internal::SourceLocationRef> LocRefs)
+      : AccessCount(AccessCount) {
     if (std::holds_alternative<StringRef>(SymHandleRef)) {
       SymHandle = std::get<StringRef>(SymHandleRef).str();
     } else
       SymHandle = std::get<uint64_t>(SymHandleRef);
 
     for (auto Loc : LocRefs)
-      Locations.push_back(SourceLocation(Loc.FileName, Loc.Line));
+      Locations.emplace_back(Loc.FileName, Loc.Line);
   }
+  // Empty constructor is used in yaml conversion.
+  DataAccessProfRecord() {}
   SymbolHandle SymHandle;
-
+  uint64_t AccessCount;
   // The locations of data in the source code. Optional.
   SmallVector<SourceLocation> Locations;
 };
@@ -208,7 +214,7 @@ class DataAccessProfData {
   llvm::SetVector<StringRef> KnownColdSymbols;
 };
 
-} // namespace data_access_prof
+} // namespace memprof
 } // namespace llvm
 
 #endif // LLVM_PROFILEDATA_DATAACCESSPROF_H_
diff --git a/llvm/include/llvm/ProfileData/IndexedMemProfData.h b/llvm/include/llvm/ProfileData/IndexedMemProfData.h
index f33b160e0b6a9..2b40094a9bc21 100644
--- a/llvm/include/llvm/ProfileData/IndexedMemProfData.h
+++ b/llvm/include/llvm/ProfileData/IndexedMemProfData.h
@@ -15,9 +15,13 @@
 #ifndef LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H
 #define LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H
 
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/MemProf.h"
 
+#include <functional>
+#include <optional>
+
 namespace llvm {
 namespace memprof {
 struct IndexedMemProfData {
@@ -82,8 +86,10 @@ struct IndexedMemProfData {
 } // namespace memprof
 
 // Write the MemProf data to OS.
-Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-                   memprof::IndexedVersion MemProfVersionRequested,
-                   bool MemProfFullSchema);
+Error writeMemProf(
+    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
+    memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
+    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData);
+
 } // namespace llvm
 #endif
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index c250a9ede39bc..d104ab51430d1 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -18,6 +18,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
 #include "llvm/Object/BuildID.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/MemProf.h"
@@ -703,10 +704,13 @@ class IndexedMemProfReader {
   const unsigned char *CallStackBase = nullptr;
   // The number of elements in the radix tree array.
   unsigned RadixTreeSize = 0;
+  /// The data access profiles, deserialized from binary data.
+  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
 
   Error deserializeV2(const unsigned char *Start, const unsigned char *Ptr);
   Error deserializeRadixTreeBased(const unsigned char *Start,
-                                  const unsigned char *Ptr);
+                                  const unsigned char *Ptr,
+                                  memprof::IndexedVersion Version);
 
 public:
   IndexedMemProfReader() = default;
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index b72c901dbb5b2..cdb7afb623378 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -19,6 +19,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/Object/BuildID.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/Error.h"
@@ -81,6 +82,8 @@ class InstrProfWriter {
   // Whether to generated random memprof hotness for testing.
   bool MemprofGenerateRandomHotness;
 
+  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
+
 public:
   // For memprof testing, random hotness can be assigned to the contexts if
   // MemprofGenerateRandomHotness is enabled. The random seed can be either
@@ -122,6 +125,9 @@ class InstrProfWriter {
   // Add a binary id to the binary ids list.
   void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs);
 
+  void addDataAccessProfData(
+      std::unique_ptr<memprof::DataAccessProfData> DataAccessProfile);
+
   /// Merge existing function counts from the given writer.
   void mergeRecordsFromWriter(InstrProfWriter &&IPW,
                               function_ref<void(Error)> Warn);
diff --git a/llvm/include/llvm/ProfileData/MemProfReader.h b/llvm/include/llvm/ProfileData/MemProfReader.h
index 130493ec77c08..3bfcdf0f42cde 100644
--- a/llvm/include/llvm/ProfileData/MemProfReader.h
+++ b/llvm/include/llvm/ProfileData/MemProfReader.h
@@ -229,6 +229,20 @@ class YAMLMemProfReader final : public MemProfReader {
   create(std::unique_ptr<MemoryBuffer> Buffer);
 
   void parse(StringRef YAMLData);
+
+  std::unique_ptr<memprof::DataAccessProfData> takeDataAccessProfData() {
+    return std::move(DataAccessProfileData);
+  }
+
+private:
+  // Called by `parse` to set data access profiles after parsing them from Yaml
+  // files.
+  void
+  setDataAccessProfileData(std::unique_ptr<memprof::DataAccessProfData> Data) {
+    DataAccessProfileData = std::move(Data);
+  }
+
+  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
 };
 } // namespace memprof
 } // namespace llvm
diff --git a/llvm/include/llvm/ProfileData/MemProfYAML.h b/llvm/include/llvm/ProfileData/MemProfYAML.h
index b642e3098aa0e..f8dc659f66662 100644
--- a/llvm/include/llvm/ProfileData/MemProfYAML.h
+++ b/llvm/include/llvm/ProfileData/MemProfYAML.h
@@ -2,6 +2,7 @@
 #define LLVM_PROFILEDATA_MEMPROFYAML_H_
 
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/MemProf.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -20,9 +21,24 @@ struct GUIDMemProfRecordPair {
   MemProfRecord Record;
 };
 
+// Helper struct to yamlify memprof::DataAccessProfData. The struct
+// members use owned strings. This is for simplicity and assumes that most real
+// world use cases do look-ups and regression test scale is small.
+struct YamlDataAccessProfData {
+  std::vector<memprof::DataAccessProfRecord> Records;
+  std::vector<uint64_t> KnownColdStrHashes;
+  std::vector<std::string> KnownColdSymbols;
+
+  bool isEmpty() const {
+    return Records.empty() && KnownColdStrHashes.empty() &&
+           KnownColdSymbols.empty();
+  }
+};
+
 // The top-level data structure, only used with YAML for now.
 struct AllMemProfData {
   std::vector<GUIDMemProfRecordPair> HeapProfileRecords;
+  YamlDataAccessProfData YamlifiedDataAccessProfiles;
 };
 } // namespace memprof
 
@@ -206,9 +222,52 @@ template <> struct MappingTraits<memprof::GUIDMemProfRecordPair> {
   }
 };
 
+template <> struct MappingTraits<memprof::SourceLocation> {
+  static void mapping(IO &Io, memprof::SourceLocation &Loc) {
+    Io.mapOptional("FileName", Loc.FileName);
+    Io.mapOptional("Line", Loc.Line);
+  }
+};
+
+template <> struct MappingTraits<memprof::DataAccessProfRecord> {
+  static void mapping(IO &Io, memprof::DataAccessProfRecord &Rec) {
+    if (Io.outputting()) {
+      if (std::holds_alternative<std::string>(Rec.SymHandle)) {
+        Io.mapOptional("Symbol", std::get<std::string>(Rec.SymHandle));
+      } else {
+        Io.mapOptional("Hash", std::get<uint64_t>(Rec.SymHandle));
+      }
+    } else {
+      std::string SymName;
+      uint64_t Hash = 0;
+      Io.mapOptional("Symbol", SymName);
+      Io.mapOptional("Hash", Hash);
+      if (!SymName.empty()) {
+        Rec.SymHandle = SymName;
+      } else {
+        Rec.SymHandle = Hash;
+      }
+    }
+
+    Io.mapOptional("Locations", Rec.Locations);
+  }
+};
+
+template <> struct MappingTraits<memprof::YamlDataAccessProfData> {
+  static void mapping(IO &Io, memprof::YamlDataAccessProfData &Data) {
+    Io.mapOptional("SampledRecords", Data.Records);
+    Io.mapOptional("KnownColdSymbols", Data.KnownColdSymbols);
+    Io.mapOptional("KnownColdStrHashes", Data.KnownColdStrHashes);
+  }
+};
+
 template <> struct MappingTraits<memprof::AllMemProfData> {
   static void mapping(IO &Io, memprof::AllMemProfData &Data) {
     Io.mapRequired("HeapProfileRecords", Data.HeapProfileRecords);
+    // Map data access profiles if reading input, or if writing output &&
+    // the struct is populated.
+    if (!Io.outputting() || !Data.YamlifiedDataAccessProfiles.isEmpty())
+      Io.mapOptional("DataAccessProfiles", Data.YamlifiedDataAccessProfiles);
   }
 };
 
@@ -234,5 +293,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::AllocationInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::CallSiteInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDMemProfRecordPair)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDHex64) // Used for CalleeGuids
+LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::DataAccessProfRecord)
+LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::SourceLocation)
 
 #endif // LLVM_PROFILEDATA_MEMPROFYAML_H_
diff --git a/llvm/lib/ProfileData/DataAccessProf.cpp b/llvm/lib/ProfileData/DataAccessProf.cpp
index a31f3db0621fb..090dcb3dcc1b9 100644
--- a/llvm/lib/ProfileData/DataAccessProf.cpp
+++ b/llvm/lib/ProfileData/DataAccessProf.cpp
@@ -11,7 +11,7 @@
 #include <sys/types.h>
 
 namespace llvm {
-namespace data_access_prof {
+namespace memprof {
 
 // If `Map` has an entry keyed by `Str`, returns the entry iterator. Otherwise,
 // creates an owned copy of `Str`, adds a map entry for it and returns the
@@ -48,7 +48,8 @@ DataAccessProfData::getProfileRecord(const SymbolHandleRef SymbolID) const {
 
   auto It = Records.find(Key);
   if (It != Records.end()) {
-    return DataAccessProfRecord(Key, It->second.Locations);
+    return DataAccessProfRecord(Key, It->second.AccessCount,
+                                It->second.Locations);
   }
 
   return std::nullopt;
@@ -261,5 +262,5 @@ Error DataAccessProfData::deserializeRecords(const unsigned char *&Ptr) {
   }
   return Error::success();
 }
-} // namespace data_access_prof
+} // namespace memprof
 } // namespace llvm
diff --git a/llvm/lib/ProfileData/IndexedMemProfData.cpp b/llvm/lib/ProfileData/IndexedMemProfData.cpp
index 59e59720179af..7398e4c468bbe 100644
--- a/llvm/lib/ProfileData/IndexedMemProfData.cpp
+++ b/llvm/lib/ProfileData/IndexedMemProfData.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/MemProf.h"
@@ -217,7 +218,9 @@ static Error writeMemProfV2(ProfOStream &OS,
 
 static Error writeMemProfRadixTreeBased(
     ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-    memprof::IndexedVersion Version, bool MemProfFullSchema) {
+    memprof::IndexedVersion Version, bool MemProfFullSchema,
+    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData =
+        nullptr) {
   assert((Version == memprof::Version3 || Version == memprof::Version4) &&
          "Unsupported version for radix tree format");
 
@@ -226,6 +229,8 @@ static Error writeMemProfRadixTreeBased(
   OS.write(0ULL); // Reserve space for the memprof call stack payload offset.
   OS.write(0ULL); // Reserve space for the memprof record payload offset.
   OS.write(0ULL); // Reserve space for the memprof record table offset.
+  if (Version >= memprof::Version4)
+    OS.write(0ULL); // Reserve space for the data access profile offset.
 
   auto Schema = memprof::getHotColdSchema();
   if (MemProfFullSchema)
@@ -252,17 +257,29 @@ static Error writeMemProfRadixTreeBased(
   uint64_t RecordTableOffset = writeMemProfRecords(
       OS, MemProfData.Records, &Schema, Version, &MemProfCallStackIndexes);
 
+  uint64_t DataAccessProfOffset = 0;
+  if (DataAccessProfileData != nullptr) {
+    assert(Version >= memprof::Version4 &&
+           "Data access profiles are added starting from v4");
+    DataAccessProfOffset = OS.tell();
+    if (Error E = DataAccessProfileData->serialize(OS))
+      return E;
+  }
+
   // Verify that the computation for the number of elements in the call stack
   // array works.
   assert(CallStackPayloadOffset +
              NumElements * sizeof(memprof::LinearFrameId) ==
          RecordPayloadOffset);
 
-  uint64_t Header[] = {
+  SmallVector<uint64_t, 4> Header = {
       CallStackPayloadOffset,
       RecordPayloadOffset,
       RecordTableOffset,
   };
+  if (Version >= memprof::Version4)
+    Header.push_back(DataAccessProfOffset);
+
   OS.patch({{HeaderUpdatePos, Header}});
 
   return Error::success();
@@ -277,24 +294,28 @@ static Error writeMemProfV3(ProfOStream &OS,
 }
 
 // Write out MemProf Version4
-static Error writeMemProfV4(ProfOStream &OS,
-                            memprof::IndexedMemProfData &MemProfData,
-                            bool MemProfFullSchema) {
+static Error writeMemProfV4(
+    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
+    bool MemProfFullSchema,
+    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData) {
   return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version4,
-                                    MemProfFullSchema);
+                                    MemProfFullSchema,
+                                    std::move(DataAccessProfileData));
 }
 
 // Write out the MemProf data in a requested version.
-Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-                   memprof::IndexedVersion MemProfVersionRequested,
-                   bool MemProfFullSchema) {
+Error writeMemProf(
+    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
+    memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
+    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData) {
   switch (MemProfVersionRequested) {
   case memprof::Version2:
     return writeMemProfV2(OS, MemProfData, MemProfFullSchema);
   case memprof::Version3:
     return writeMemProfV3(OS, MemProfData, MemProfFullSchema);
   case memprof::Version4:
-    return writeMemProfV4(OS, MemProfData, MemProfFullSchema);
+    return writeMemProfV4(OS, MemProfData, MemProfFullSchema,
+                          std::move(DataAccessProfileData));
   }
 
   return make_error<InstrProfError>(
@@ -358,7 +379,10 @@ Error IndexedMemProfReader::deserializeV2(const unsigned char *Start,
 }
 
 Error IndexedMemProfReader::deserializeRadixTreeBased(
-    const unsigned char *Start, const unsigned char *Ptr) {
+    const unsigned char *Start, const unsigned char *Ptr,
+    memprof::IndexedVersion Version) {
+  assert((Version == memprof::Version3 || Version == memprof::Version4) &&
+         "Unsupported version for radix tree format");
   // The offset in the stream right before invoking
   // CallStackTableGenerator.Emit.
   const uint64_t CallStackPayloadOffset =
@@ -370,6 +394,11 @@ Error IndexedMemProfReader::deserializeRadixTreeBased(
   const uint64_t RecordTableOffset =
       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
 
+  uint64_t DataAccessProfOffset = 0;
+  if (Version == memprof::Version4)
+    DataAccessProfOffset =
+        support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
+
   // Read the schema.
   auto SchemaOr = memprof::readMemProfSchema(Ptr);
   if (!SchemaOr)
@@ -391,6 +420,15 @@ Error IndexedMemProfReader::deserializeRadixTreeBased(
       /*Payload=*/Start + RecordPayloadOffset,
       /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema)));
 
+  assert((!DataAccessProfOffset || DataAccessProfOffset > RecordTableOffset) &&
+         "Data access profile is either empty or after the record table");
+  if (DataAccessProfOffset > RecordTableOffset) {
+    DataAccessProfileData = std::make_unique<memprof::DataAccessProfData>();
+    const unsigned char *DAPPtr = Start + DataAccessProfOffset;
+    if (Error E = DataAccessProfileData->deserialize(DAPPtr))
+      return E;
+  }
+
   return Error::success();
 }
 
@@ -424,7 +462,7 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start,
   case memprof::Version3:
   case memprof::Version4:
     // V3 and V4 share the same high-level structure (radix tree, linear IDs).
-    if (Error E = deserializeRadixTreeBased(Start, Ptr))
+    if (Error E = deserializeRadixTreeBased(Start, Ptr, Version))
       return E;
     break;
   }
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index a1eb08362087f..ab109cd5b13a7 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -1552,6 +1552,20 @@ memprof::AllMemProfData IndexedMemProfReader::getAllMemProfData() const {
     Pair.Record = std::move(*Record);
     AllMemProfData.HeapProfileRecords.push_back(std::move(Pair));
   }
+  // Populate the data access profiles for yaml output.
+  if (DataAccessProfileData != nullptr) {
+    for (const auto &[SymHandleRef, RecordRef] :
+         DataAccessProfileData->getRecords())
+      AllMemProfData.YamlifiedDataAccessProfiles.Records.push_back(
+          memprof::DataAccessProfRecord(SymHandleRef, RecordRef.AccessCount,
+                                        RecordRef.Locations));
+    for (StringRef ColdSymbol : DataAccessProfileData->getKnownColdSymbols())
+      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdSymbols.push_back(
+          ColdSymbol.str());
+    for (uint64_t Hash : DataAccessProfileData->getKnownColdHashes())
+      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdStrHashes.push_back(
+          Hash);
+  }
   return AllMemProfData;
 }
 
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 2c6640eedebd9..039e1bc955cd4 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -16,6 +16,7 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/ProfileCommon.h"
@@ -320,6 +321,11 @@ void InstrProfWriter::addBinaryIds(ArrayRef<llvm::object::BuildID> BIs) {
   llvm::append_range(BinaryIds, BIs);
 }
 
+void InstrProfWriter::addDataAccessProfData(
+    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfDataIn) {
+  DataAccessProfileData = std::move(DataAccessProfDataIn);
+}
+
 void InstrProfWriter::addTemporalProfileTrace(TemporalProfTraceTy Trace) {
   assert(Trace.FunctionNameRefs.size() <= MaxTemporalProfTraceLength);
   assert(!Trace.FunctionNameRefs.empty());
@@ -605,8 +611,11 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
   uint64_t MemProfSectionStart = 0;
   if (static_cast<bool>(ProfileKind & InstrProfKind::MemProf)) {
     MemProfSectionStart = OS.tell();
-    if (auto E = writeMemProf(OS, MemProfData, MemProfVersionRequested,
-                              MemProfFullSchema))
+
+    if (auto E =
+            writeMemProf(OS, MemProfData, MemProfVersionRequested,
+                         MemProfFullSchema, std::move(DataAccessProfileData)))
+
       return E;
   }
 
diff --git a/llvm/lib/ProfileData/MemProfReader.cpp b/llvm/lib/ProfileData/MemProfReader.cpp
index d6bc4fdf5e448..9c723e495e7f9 100644
--- a/llvm/lib/ProfileData/MemProfReader.cpp
+++ b/llvm/lib/ProfileData/MemProfReader.cpp
@@ -37,6 +37,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 
@@ -822,6 +823,34 @@ void YAMLMemProfReader::parse(StringRef YAMLData) {
 
     MemProfData.Records.try_emplace(GUID, std::move(IndexedRecord));
   }
+
+  if (Doc.YamlifiedDataAccessProfiles.isEmpty())
+    return;
+
+  auto ToSymHandleRef =
+      [](const memprof::SymbolHandle &Handle) -> memprof::SymbolHandleRef {
+    if (std::holds_alternative<std::string>(Handle))
+      return StringRef(std::get<std::string>(Handle));
+    return std::get<uint64_t>(Handle);
+  };
+
+  auto DataAccessProfileData = std::make_unique<memprof::DataAccessProfData>();
+  for (const auto &Record : Doc.YamlifiedDataAccessProfiles.Records)
+    if (Error E = DataAccessProfileData->setDataAccessProfile(
+            ToSymHandleRef(Record.SymHandle), Record.AccessCount,
+            Record.Locations))
+      reportFatalInternalError(std::move(E));
+
+  for (const uint64_t Hash : Doc.YamlifiedDataAccessProfiles.KnownColdStrHashes)
+    if (Error E = DataAccessProfileData->addKnownSymbolWithoutSamples(Hash))
+      reportFatalInternalError(std::move(E));
+
+  for (const std::string &Sym :
+       Doc.YamlifiedDataAccessProfiles.KnownColdSymbols)
+    if (Error E = DataAccessProfileData->addKnownSymbolWithoutSamples(Sym))
+      reportFatalInternalError(std::move(E));
+
+  setDataAccessProfileData(std::move(DataAccessProfileData));
 }
 } // namespace memprof
 } // namespace llvm
diff --git a/llvm/test/tools/llvm-profdata/memprof-yaml.test b/llvm/test/tools/llvm-profdata/memprof-yaml.test
index 9766cc50f37d7..5beda8c036a12 100644
--- a/llvm/test/tools/llvm-profdata/memprof-yaml.test
+++ b/llvm/test/tools/llvm-profdata/memprof-yaml.test
@@ -1,12 +1,101 @@
 ; RUN: split-file %s %t
 ; COM: The text format only supports the latest version.
+
+; Verify that the YAML output is identical to the YAML input.
+; memprof-in.yaml has both heap profile records and data access profiles.
 ; RUN: llvm-profdata merge --memprof-version=4 %t/memprof-in.yaml -o %t/memprof-out.indexed
 ; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out.yaml
 ; RUN: diff -b %t/memprof-in.yaml %t/memprof-out.yaml
 
-; Verify that the YAML output is identical to the YAML input.
+; Merge text profile as v3 binary profile. Test that the merged v3 profile
+; are identical to memprof-in-v3.yaml, and doesn't have callee guids or dap.
+; RUN: llvm-profdata merge --memprof-version=3 %t/memprof-in.yaml -o %t/memprof-out-v3.indexed
+; RUN: llvm-profdata show --memory %t/memprof-out-v3.indexed > %t/memprof-out-v3.yaml
+; RUN: diff -b %t/memprof-out-v3.yaml %t/memprof-in-v3.yaml
+
+; memprof-in-no-dap.yaml has empty data access profiles.
+; RUN: llvm-profdata merge --memprof-version=4 %t/memprof-in-no-dap.yaml -o %t/memprof-out.indexed
+; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out-no-dap.yaml
+; RUN: diff -b %t/memprof-in-no-dap.yaml %t/memprof-out-no-dap.yaml
+
 ;--- memprof-in.yaml
 ---
+HeapProfileRecords:
+  - GUID:            0xdeadbeef12345678
+    AllocSites:
+      - Callstack:
+          - { Function: 0x1111111111111111, LineOffset: 11, Column: 10, IsInlineFrame: true }
+          - { Function: 0x2222222222222222, LineOffset: 22, Column: 20, IsInlineFrame: false }
+        MemInfoBlock:
+          AllocCount:      111
+          TotalSize:       222
+          TotalLifetime:   333
+          TotalLifetimeAccessDensity: 444
+      - Callstack:
+          - { Function: 0x3333333333333333, LineOffset: 33, Column: 30, IsInlineFrame: false }
+          - { Function: 0x4444444444444444, LineOffset: 44, Column: 40, IsInlineFrame: true }
+        MemInfoBlock:
+          AllocCount:      555
+          TotalSize:       666
+          TotalLifetime:   777
+          TotalLifetimeAccessDensity: 888
+    CallSites:
+      - Frames:
+        - { Function: 0x5555555555555555, LineOffset: 55, Column: 50, IsInlineFrame: true }
+        - { Function: 0x6666666666666666, LineOffset: 66, Column: 60, IsInlineFrame: false }
+        CalleeGuids: [ 0x100, 0x200 ]
+      - Frames:
+        - { Function: 0x7777777777777777, LineOffset: 77, Column: 70, IsInlineFrame: true }
+        - { Function: 0x8888888888888888, LineOffset: 88, Column: 80, IsInlineFrame: false }
+        CalleeGuids: [ 0x300 ]
+DataAccessProfiles:
+  SampledRecords:
+    - Symbol:          abcde
+      Locations:
+      - FileName:      file2.h
+        Line:          123
+      - FileName:      file3.cpp
+        Line:          456
+    - Hash:            101010
+      Locations:
+        - FileName:        file.cpp
+          Line:            233
+  KnownColdSymbols:
+    - foo
+    - bar
+  KnownColdStrHashes: [ 999, 1001 ]
+...
+;--- memprof-in-v3.yaml
+---
+HeapProfileRecords:
+  - GUID:            0xdeadbeef12345678
+    AllocSites:
+      - Callstack:
+          - { Function: 0x1111111111111111, LineOffset: 11, Column: 10, IsInlineFrame: true }
+          - { Function: 0x2222222222222222, LineOffset: 22, Column: 20, IsInlineFrame: false }
+        MemInfoBlock:
+          AllocCount:      111
+          TotalSize:       222
+          TotalLifetime:   333
+          TotalLifetimeAccessDensity: 444
+      - Callstack:
+          - { Function: 0x3333333333333333, LineOffset: 33, Column: 30, IsInlineFrame: false }
+          - { Function: 0x4444444444444444, LineOffset: 44, Column: 40, IsInlineFrame: true }
+        MemInfoBlock:
+          AllocCount:      555
+          TotalSize:       666
+          TotalLifetime:   777
+          TotalLifetimeAccessDensity: 888
+    CallSites:
+      - Frames:
+        - { Function: 0x5555555555555555, LineOffset: 55, Column: 50, IsInlineFrame: true }
+        - { Function: 0x6666666666666666, LineOffset: 66, Column: 60, IsInlineFrame: false }
+      - Frames:
+        - { Function: 0x7777777777777777, LineOffset: 77, Column: 70, IsInlineFrame: true }
+        - { Function: 0x8888888888888888, LineOffset: 88, Column: 80, IsInlineFrame: false }
+...
+;--- memprof-in-no-dap.yaml
+---
 HeapProfileRecords:
   - GUID:            0xdeadbeef12345678
     AllocSites:
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 885e06df6c390..8660eed6be2bf 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -16,6 +16,7 @@
 #include "llvm/Debuginfod/HTTPClient.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/Binary.h"
+#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
@@ -756,6 +757,8 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
 
     auto MemProfData = Reader->takeMemProfData();
 
+    auto DataAccessProfData = Reader->takeDataAccessProfData();
+
     // Check for the empty input in case the YAML file is invalid.
     if (MemProfData.Records.empty()) {
       WC->Errors.emplace_back(
@@ -764,6 +767,7 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
     }
 
     WC->Writer.addMemProfData(std::move(MemProfData), MemProfError);
+    WC->Writer.addDataAccessProfData(std::move(DataAccessProfData));
     return;
   }
 
diff --git a/llvm/unittests/ProfileData/DataAccessProfTest.cpp b/llvm/unittests/ProfileData/DataAccessProfTest.cpp
index 8866c16fe292a..13af3390557d7 100644
--- a/llvm/unittests/ProfileData/DataAccessProfTest.cpp
+++ b/llvm/unittests/ProfileData/DataAccessProfTest.cpp
@@ -14,7 +14,7 @@
 #include "gtest/gtest.h"
 
 namespace llvm {
-namespace data_access_prof {
+namespace memprof {
 namespace {
 
 using ::llvm::StringRef;
@@ -177,5 +177,5 @@ TEST(MemProf, DataAccessProfile) {
   }
 }
 } // namespace
-} // namespace data_access_prof
+} // namespace memprof
 } // namespace llvm

>From 13e1a2cb2246dc5e9a4afcdacabed4d43154ec3f Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 12:51:28 -0700
Subject: [PATCH 046/105] Reapply "[clang] Remove intrusive reference count
 from `DiagnosticOptions` (#139584)"

This reverts commit e2a885537f11f8d9ced1c80c2c90069ab5adeb1d. Build failures were fixed right away and reverting the original commit without the fixes breaks the build again.
---
 .../tool/ClangApplyReplacementsMain.cpp       |  4 +-
 .../tool/ClangChangeNamespace.cpp             |  6 +-
 .../tool/ClangIncludeFixer.cpp                |  6 +-
 .../clang-move/tool/ClangMove.cpp             |  6 +-
 clang-tools-extra/clang-query/Query.cpp       |  2 +-
 .../tool/ClangReorderFields.cpp               |  6 +-
 clang-tools-extra/clang-tidy/ClangTidy.cpp    | 24 +++---
 .../ClangTidyDiagnosticConsumer.cpp           |  4 +-
 .../clang-tidy/ClangTidyDiagnosticConsumer.h  |  5 +-
 .../ExpandModularHeadersPPCallbacks.cpp       |  2 +-
 .../ExpandModularHeadersPPCallbacks.h         |  1 +
 clang-tools-extra/clangd/Compiler.cpp         |  5 +-
 clang-tools-extra/clangd/ModulesBuilder.cpp   |  4 +-
 clang-tools-extra/clangd/ParsedAST.cpp        |  3 +-
 clang-tools-extra/clangd/Preamble.cpp         |  2 +-
 .../clangd/SystemIncludeExtractor.cpp         |  3 +-
 .../clangd/unittests/ConfigCompileTests.cpp   |  3 +-
 .../clangd/unittests/tweaks/TweakTests.cpp    |  3 +-
 .../include-cleaner/unittests/RecordTest.cpp  |  4 +-
 .../include-cleaner/unittests/WalkASTTest.cpp |  6 +-
 .../modularize/ModularizeUtilities.cpp        |  6 +-
 .../modularize/ModularizeUtilities.h          |  2 +-
 .../ApplyReplacementsTest.cpp                 |  4 +-
 .../clang-tidy/ClangTidyOptionsTest.cpp       | 18 ++---
 .../unittests/clang-tidy/ClangTidyTest.h      |  6 +-
 clang/include/clang/Basic/Diagnostic.h        |  6 +-
 clang/include/clang/Basic/DiagnosticOptions.h |  4 +-
 clang/include/clang/Basic/SourceManager.h     |  1 +
 clang/include/clang/Frontend/ASTUnit.h        | 12 ++-
 .../include/clang/Frontend/CompilerInstance.h |  2 +-
 .../clang/Frontend/CompilerInvocation.h       |  2 +-
 .../clang/Frontend/DiagnosticRenderer.h       |  7 +-
 .../clang/Frontend/LogDiagnosticPrinter.h     |  4 +-
 .../include/clang/Frontend/SARIFDiagnostic.h  |  2 +-
 .../clang/Frontend/SARIFDiagnosticPrinter.h   |  4 +-
 .../Frontend/SerializedDiagnosticPrinter.h    |  2 +-
 clang/include/clang/Frontend/TextDiagnostic.h |  2 +-
 .../clang/Frontend/TextDiagnosticPrinter.h    |  4 +-
 clang/include/clang/Serialization/ASTReader.h |  9 +--
 clang/lib/Basic/Diagnostic.cpp                | 10 +--
 clang/lib/Basic/SourceManager.cpp             |  4 +-
 clang/lib/CrossTU/CrossTranslationUnit.cpp    | 20 ++---
 clang/lib/Frontend/ASTMerge.cpp               | 13 ++-
 clang/lib/Frontend/ASTUnit.cpp                | 14 +++-
 clang/lib/Frontend/ChainedIncludesSource.cpp  |  4 +-
 clang/lib/Frontend/CompilerInstance.cpp       | 27 +++----
 clang/lib/Frontend/CompilerInvocation.cpp     | 27 ++-----
 .../CreateInvocationFromCommandLine.cpp       | 14 ++--
 clang/lib/Frontend/DiagnosticRenderer.cpp     | 17 ++--
 clang/lib/Frontend/FrontendAction.cpp         | 12 +--
 clang/lib/Frontend/FrontendActions.cpp        | 16 ++--
 clang/lib/Frontend/LogDiagnosticPrinter.cpp   |  4 +-
 clang/lib/Frontend/SARIFDiagnostic.cpp        |  4 +-
 clang/lib/Frontend/SARIFDiagnosticPrinter.cpp |  7 +-
 .../Frontend/SerializedDiagnosticPrinter.cpp  | 29 +++----
 clang/lib/Frontend/TextDiagnostic.cpp         | 79 +++++++++----------
 clang/lib/Frontend/TextDiagnosticPrinter.cpp  | 15 ++--
 clang/lib/Interpreter/CodeCompletion.cpp      |  3 +-
 clang/lib/Interpreter/Interpreter.cpp         |  8 +-
 clang/lib/Rewrite/HTMLRewrite.cpp             |  4 +-
 clang/lib/Serialization/ASTReader.cpp         | 25 +++---
 clang/lib/Testing/TestAST.cpp                 |  2 +-
 clang/lib/Tooling/CompilationDatabase.cpp     |  8 +-
 clang/lib/Tooling/Core/Replacement.cpp        |  4 +-
 .../DependencyScanningWorker.cpp              |  6 +-
 clang/lib/Tooling/Refactoring.cpp             |  8 +-
 clang/lib/Tooling/Tooling.cpp                 | 10 +--
 clang/tools/c-index-test/core_main.cpp        | 20 ++---
 .../ClangExtDefMapGen.cpp                     | 14 ++--
 clang/tools/clang-format/ClangFormat.cpp      |  8 +-
 .../clang-import-test/clang-import-test.cpp   |  4 +-
 .../clang-installapi/ClangInstallAPI.cpp      |  8 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  9 ++-
 clang/tools/diagtool/ShowEnabledWarnings.cpp  |  6 +-
 clang/tools/diagtool/TreeView.cpp             |  4 +-
 clang/tools/driver/cc1_main.cpp               |  4 +-
 clang/tools/driver/cc1as_main.cpp             |  8 +-
 clang/tools/driver/cc1gen_reproducer_main.cpp |  6 +-
 clang/tools/driver/driver.cpp                 | 11 ++-
 clang/tools/libclang/CIndex.cpp               | 11 +--
 clang/tools/libclang/CIndexCodeCompletion.cpp | 10 +--
 clang/tools/libclang/CIndexDiagnostic.cpp     | 17 ++--
 clang/tools/libclang/Indexing.cpp             |  7 +-
 clang/unittests/AST/ASTVectorTest.cpp         |  3 +-
 clang/unittests/AST/CommentLexer.cpp          | 10 +--
 clang/unittests/AST/CommentParser.cpp         | 10 +--
 clang/unittests/AST/CommentTextTest.cpp       |  3 +-
 clang/unittests/AST/ExternalASTSourceTest.cpp |  4 +-
 .../UncheckedOptionalAccessModelTest.cpp      |  5 +-
 .../Analysis/MacroExpansionContextTest.cpp    |  6 +-
 .../Analysis/UnsafeBufferUsageTest.cpp        |  3 +-
 clang/unittests/Basic/DiagnosticTest.cpp      | 23 +++---
 clang/unittests/Basic/SarifTest.cpp           |  6 +-
 clang/unittests/Basic/SourceManagerTest.cpp   |  9 +--
 clang/unittests/Driver/DXCModeTest.cpp        | 12 +--
 clang/unittests/Driver/SanitizerArgsTest.cpp  |  7 +-
 .../Driver/SimpleDiagnosticConsumer.h         |  5 +-
 clang/unittests/Driver/ToolChainTest.cpp      | 71 +++++++++--------
 clang/unittests/Frontend/ASTUnitTest.cpp      | 37 ++++-----
 .../Frontend/CompilerInstanceTest.cpp         | 11 +--
 .../Frontend/CompilerInvocationTest.cpp       |  3 +-
 clang/unittests/Frontend/OutputStreamTest.cpp | 12 +--
 clang/unittests/Frontend/PCHPreambleTest.cpp  |  7 +-
 .../Frontend/ReparseWorkingDirTest.cpp        |  6 +-
 clang/unittests/Frontend/SearchPathTest.cpp   |  4 +-
 .../unittests/Frontend/TextDiagnosticTest.cpp |  8 +-
 clang/unittests/Frontend/UtilsTest.cpp        |  9 ++-
 .../unittests/Interpreter/InterpreterTest.cpp | 15 ++--
 clang/unittests/Lex/HeaderSearchTest.cpp      |  3 +-
 clang/unittests/Lex/LexerTest.cpp             | 10 +--
 clang/unittests/Lex/ModuleDeclStateTest.cpp   |  3 +-
 clang/unittests/Lex/PPCallbacksTest.cpp       |  8 +-
 .../Lex/PPConditionalDirectiveRecordTest.cpp  | 10 +--
 .../Lex/PPDependencyDirectivesTest.cpp        |  3 +-
 .../unittests/Lex/PPMemoryAllocationsTest.cpp |  3 +-
 .../Parse/ParseHLSLRootSignatureTest.cpp      |  4 +-
 clang/unittests/Sema/SemaNoloadLookupTest.cpp |  4 +-
 .../Serialization/ForceCheckFileInputTest.cpp |  8 +-
 .../Serialization/LoadSpecLazilyTest.cpp      |  3 +-
 .../Serialization/ModuleCacheTest.cpp         |  6 +-
 .../Serialization/NoCommentsTest.cpp          |  3 +-
 .../PreambleInNamedModulesTest.cpp            |  3 +-
 .../Serialization/VarDeclConstantInitTest.cpp |  3 +-
 clang/unittests/Support/TimeProfilerTest.cpp  |  4 +-
 clang/unittests/Tooling/RewriterTestContext.h |  9 +--
 clang/unittests/Tooling/Syntax/TokensTest.cpp |  3 +-
 .../unittests/Tooling/Syntax/TreeTestBase.cpp |  2 +-
 clang/unittests/Tooling/Syntax/TreeTestBase.h |  4 +-
 clang/unittests/Tooling/ToolingTest.cpp       |  8 +-
 .../Clang/ClangExpressionParser.cpp           | 10 +--
 .../Clang/ClangExpressionSourceCode.cpp       |  3 +-
 .../Clang/ClangModulesDeclVendor.cpp          | 21 +++--
 .../Language/ClangCommon/ClangHighlighter.cpp |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.cpp      |  3 +-
 .../TypeSystem/Clang/TypeSystemClang.h        |  1 +
 135 files changed, 603 insertions(+), 568 deletions(-)

diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 68b5743c6540f..062e236d3e51f 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -96,9 +96,9 @@ int main(int argc, char **argv) {
   cl::SetVersionPrinter(printVersion);
   cl::ParseCommandLineOptions(argc, argv);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 22d26db0c11bc..2a8fe2d06d185 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -126,10 +126,10 @@ int main(int argc, const char **argv) {
   if (int Result = Tool.run(Factory.get()))
     return Result;
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager Sources(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 6e51f25a66407..746ba7bcea015 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -455,9 +455,9 @@ int includeFixerMain(int argc, const char **argv) {
   }
 
   // Set up a new source manager for applying the resulting replacements.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
-  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
-  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diagnostics(new DiagnosticIDs, DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(outs(), DiagOpts);
   SourceManager SM(Diagnostics, tool.getFiles());
   Diagnostics.setClient(&DiagnosticPrinter, false);
 
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 655ea81ee37d4..750eb952714f7 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -176,10 +176,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
   auto &FileMgr = Tool.getFiles();
   SourceManager SM(Diagnostics, FileMgr);
diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp
index 382aa5d6fe25e..574b64ee0f759 100644
--- a/clang-tools-extra/clang-query/Query.cpp
+++ b/clang-tools-extra/clang-query/Query.cpp
@@ -172,7 +172,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
           clang::SourceRange R = BI->second.getSourceRange();
           if (R.isValid()) {
             TextDiagnostic TD(OS, AST->getASTContext().getLangOpts(),
-                              &AST->getDiagnostics().getDiagnosticOptions());
+                              AST->getDiagnostics().getDiagnosticOptions());
             TD.emitDiagnostic(
                 FullSourceLoc(R.getBegin(), AST->getSourceManager()),
                 DiagnosticsEngine::Note, "\"" + BI->first + "\" binds here",
diff --git a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
index 5b77ee7b5738c..03502525417b2 100644
--- a/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
+++ b/clang-tools-extra/clang-reorder-fields/tool/ClangReorderFields.cpp
@@ -72,10 +72,10 @@ int main(int argc, const char **argv) {
 
   int ExitCode = Tool.run(Factory.get());
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
       &DiagnosticPrinter, false);
 
   auto &FileMgr = Tool.getFiles();
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 733a53a0f5dcc..26f9afbc0880e 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -97,15 +97,14 @@ class ErrorReporter {
   ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes,
                 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
       : Files(FileSystemOptions(), std::move(BaseFS)),
-        DiagOpts(new DiagnosticOptions()),
-        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
-        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
+        Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
               DiagPrinter),
         SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
-    DiagOpts->ShowColors = Context.getOptions().UseColor.value_or(
+    DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
         llvm::sys::Process::StandardOutHasColors());
     DiagPrinter->BeginSourceFile(LangOpts);
-    if (DiagOpts->ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
+    if (DiagOpts.ShowColors && !llvm::sys::Process::StandardOutIsDisplayed()) {
       llvm::sys::Process::UseANSIEscapeCodes(true);
     }
   }
@@ -308,7 +307,7 @@ class ErrorReporter {
 
   FileManager Files;
   LangOptions LangOpts; // FIXME: use langopts from each original file
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticConsumer *DiagPrinter;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
@@ -516,10 +515,10 @@ getCheckOptions(const ClangTidyOptions &Options,
                                                 Options),
       AllowEnablingAnalyzerAlphaCheckers);
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(),
-                       llvm::makeIntrusiveRefCnt<DiagnosticOptions>(),
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(llvm::makeIntrusiveRefCnt<DiagnosticIDs>(), *DiagOpts,
                        &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   ClangTidyASTConsumerFactory Factory(Context);
   return Factory.getCheckOptions();
 }
@@ -558,9 +557,10 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
   Context.setProfileStoragePrefix(StoreCheckProfile);
 
   ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions(),
-                       &DiagConsumer, /*ShouldOwnClient=*/false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
+                       /*ShouldOwnClient=*/false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   Tool.setDiagnosticConsumer(&DiagConsumer);
 
   class ActionFactory : public FrontendActionFactory {
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index b216970bfbd8c..a0253a5fd1a48 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -49,7 +49,7 @@ namespace {
 class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
 public:
   ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
-                              DiagnosticOptions *DiagOpts,
+                              DiagnosticOptions &DiagOpts,
                               ClangTidyError &Error)
       : DiagnosticRenderer(LangOpts, DiagOpts), Error(Error) {}
 
@@ -429,7 +429,7 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
     forwardDiagnostic(Info);
   } else {
     ClangTidyDiagnosticRenderer Converter(
-        Context.getLangOpts(), &Context.DiagEngine->getDiagnosticOptions(),
+        Context.getLangOpts(), Context.DiagEngine->getDiagnosticOptions(),
         Errors.back());
     SmallString<100> Message;
     Info.FormatDiagnostic(Message);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index d6cf6a2b2731e..bd7a1bf2c11c7 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -75,7 +75,9 @@ class ClangTidyContext {
   /// Sets the DiagnosticsEngine that diag() will emit diagnostics to.
   // FIXME: this is required initialization, and should be a constructor param.
   // Fix the context -> diag engine -> consumer -> context initialization cycle.
-  void setDiagnosticsEngine(DiagnosticsEngine *DiagEngine) {
+  void setDiagnosticsEngine(std::unique_ptr<DiagnosticOptions> DiagOpts,
+                            DiagnosticsEngine *DiagEngine) {
+    this->DiagOpts = std::move(DiagOpts);
     this->DiagEngine = DiagEngine;
   }
 
@@ -231,6 +233,7 @@ class ClangTidyContext {
   // Writes to Stats.
   friend class ClangTidyDiagnosticConsumer;
 
+  std::unique_ptr<DiagnosticOptions> DiagOpts = nullptr;
   DiagnosticsEngine *DiagEngine = nullptr;
   std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
 
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 03a3e8404e069..6a84704434c33 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
       InMemoryFs(new llvm::vfs::InMemoryFileSystem),
       Sources(Compiler.getSourceManager()),
       // Forward the new diagnostics to the original DiagnosticConsumer.
-      Diags(new DiagnosticIDs, new DiagnosticOptions,
+      Diags(new DiagnosticIDs, DiagOpts,
             new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
       LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
   // Add a FileSystem containing the extra files needed in place of modular
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
index a263681b3c633..c3478917ef498 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.h
@@ -128,6 +128,7 @@ class ExpandModularHeadersPPCallbacks : public PPCallbacks {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFs;
 
   SourceManager &Sources;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   LangOptions LangOpts;
   HeaderSearchOptions HSOpts;
diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp
index 9be0152afd2f7..8b3865c8a8e5c 100644
--- a/clang-tools-extra/clangd/Compiler.cpp
+++ b/clang-tools-extra/clangd/Compiler.cpp
@@ -110,8 +110,9 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
   CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   CIOpts.CC1Args = CC1Args;
   CIOpts.RecoverOnError = true;
-  CIOpts.Diags = CompilerInstance::createDiagnostics(
-      *CIOpts.VFS, new DiagnosticOptions, &D, false);
+  DiagnosticOptions DiagOpts;
+  CIOpts.Diags =
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts, &D, false);
   CIOpts.ProbePrecompiled = false;
   std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
   if (!CI)
diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp
index c1878f91b5e16..bf77f43bd28bb 100644
--- a/clang-tools-extra/clangd/ModulesBuilder.cpp
+++ b/clang-tools-extra/clangd/ModulesBuilder.cpp
@@ -187,9 +187,9 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath,
   HSOpts.ValidateASTInputFilesContent = true;
 
   clang::clangd::IgnoreDiagnostics IgnoreDiags;
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
-                                          &IgnoreDiags,
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts, &IgnoreDiags,
                                           /*ShouldOwnClient=*/false);
 
   LangOptions LangOpts;
diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 3f63daaf400db..9e1f6bb977226 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -556,7 +556,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
         *AllCTFactories, Cfg.Diagnostics.ClangTidy.FastCheckFilter);
     CTContext.emplace(std::make_unique<tidy::DefaultOptionsProvider>(
         tidy::ClangTidyGlobalOptions(), ClangTidyOpts));
-    CTContext->setDiagnosticsEngine(&Clang->getDiagnostics());
+    // The lifetime of DiagnosticOptions is managed by \c Clang.
+    CTContext->setDiagnosticsEngine(nullptr, &Clang->getDiagnostics());
     CTContext->setASTContext(&Clang->getASTContext());
     CTContext->setCurrentFile(Filename);
     CTContext->setSelfContainedDiags(true);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index ba9a53db8a0dc..7b4d63ff197e7 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -615,7 +615,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       });
   auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
-      CompilerInstance::createDiagnostics(*VFS, &CI.getDiagnosticOpts(),
+      CompilerInstance::createDiagnostics(*VFS, CI.getDiagnosticOpts(),
                                           &PreambleDiagnostics,
                                           /*ShouldOwnClient=*/false);
   const Config &Cfg = Config::current();
diff --git a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
index 6417bf8765622..0b067e8b0b2b2 100644
--- a/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
+++ b/clang-tools-extra/clangd/SystemIncludeExtractor.cpp
@@ -253,7 +253,8 @@ namespace {
 bool isValidTarget(llvm::StringRef Triple) {
   std::shared_ptr<TargetOptions> TargetOpts(new TargetOptions);
   TargetOpts->Triple = Triple.str();
-  DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
                           new IgnoringDiagConsumer);
   llvm::IntrusiveRefCntPtr<TargetInfo> Target =
       TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
diff --git a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
index c3e484a1a79c4..75d0ff244038d 100644
--- a/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ConfigCompileTests.cpp
@@ -298,7 +298,8 @@ TEST_F(ConfigCompileTests, DiagnosticSuppression) {
                                    "unreachable-code", "unused-variable",
                                    "typecheck_bool_condition",
                                    "unexpected_friend", "warn_alloca"));
-  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, nullptr,
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine DiagEngine(new DiagnosticIDs, DiagOpts,
                                       new clang::IgnoringDiagConsumer);
 
   using Diag = clang::Diagnostic;
diff --git a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
index 8bd40c1429012..e39b70224d97c 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/TweakTests.cpp
@@ -44,7 +44,8 @@ TEST(FileEdits, AbsolutePath) {
   for (const auto *Path : RelPaths)
     MemFS->addFile(Path, 0, llvm::MemoryBuffer::getMemBuffer("", Path));
   FileManager FM(FileSystemOptions(), MemFS);
-  DiagnosticsEngine DE(new DiagnosticIDs, new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine DE(new DiagnosticIDs, DiagOpts);
   SourceManager SM(DE, FM);
 
   for (const auto *Path : RelPaths) {
diff --git a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
index a10c0d5a54a95..91d2697712b6e 100644
--- a/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/RecordTest.cpp
@@ -618,8 +618,8 @@ TEST_F(PragmaIncludeTest, ExportInUnnamedBuffer) {
                  llvm::MemoryBuffer::getMemBufferCopy(Extra.getValue(),
                                                       /*BufferName=*/""));
 
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts.get());
+  DiagnosticOptions DiagOpts;
+  auto Diags = CompilerInstance::createDiagnostics(*VFS, DiagOpts);
   auto Invocation = std::make_unique<CompilerInvocation>();
   ASSERT_TRUE(CompilerInvocation::CreateFromArgs(*Invocation, {Filename.data()},
                                                  *Diags, "clang"));
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 0de0b77f33daf..3487f24f2af8f 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -85,9 +85,9 @@ std::vector<Decl::Kind> testWalk(llvm::StringRef TargetCode,
   // For each difference, show the target point in context, like a diagnostic.
   std::string DiagBuf;
   llvm::raw_string_ostream DiagOS(DiagBuf);
-  auto *DiagOpts = new DiagnosticOptions();
-  DiagOpts->ShowLevel = 0;
-  DiagOpts->ShowNoteIncludeStack = 0;
+  DiagnosticOptions DiagOpts;
+  DiagOpts.ShowLevel = 0;
+  DiagOpts.ShowNoteIncludeStack = 0;
   TextDiagnostic Diag(DiagOS, AST.context().getLangOpts(), DiagOpts);
   auto DiagnosePoint = [&](llvm::StringRef Message, unsigned Offset) {
     Diag.emitDiagnostic(
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp
index a8f1ddf64d34b..9ad1731915a8b 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.cpp
+++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp
@@ -48,10 +48,8 @@ ModularizeUtilities::ModularizeUtilities(std::vector<std::string> &InputPaths,
       MissingHeaderCount(0),
       // Init clang stuff needed for loading the module map and preprocessing.
       LangOpts(new LangOptions()), DiagIDs(new DiagnosticIDs()),
-      DiagnosticOpts(new DiagnosticOptions()),
-      DC(llvm::errs(), DiagnosticOpts.get()),
-      Diagnostics(
-          new DiagnosticsEngine(DiagIDs, DiagnosticOpts.get(), &DC, false)),
+      DC(llvm::errs(), DiagnosticOpts),
+      Diagnostics(new DiagnosticsEngine(DiagIDs, DiagnosticOpts, &DC, false)),
       TargetOpts(new ModuleMapTargetOptions()),
       Target(TargetInfo::CreateTargetInfo(*Diagnostics, *TargetOpts)),
       FileMgr(new FileManager(FileSystemOpts)),
diff --git a/clang-tools-extra/modularize/ModularizeUtilities.h b/clang-tools-extra/modularize/ModularizeUtilities.h
index 7b4c16a492b89..3242ea0c4b97e 100644
--- a/clang-tools-extra/modularize/ModularizeUtilities.h
+++ b/clang-tools-extra/modularize/ModularizeUtilities.h
@@ -198,7 +198,7 @@ class ModularizeUtilities {
   /// Diagnostic IDs.
   const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs;
   /// Options controlling the diagnostic engine.
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagnosticOpts;
+  clang::DiagnosticOptions DiagnosticOpts;
   /// Diagnostic consumer.
   clang::TextDiagnosticPrinter DC;
   /// Diagnostic engine.
diff --git a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
index 4fe57e618004d..87b0d69f4654a 100644
--- a/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
+++ b/clang-tools-extra/unittests/clang-apply-replacements/ApplyReplacementsTest.cpp
@@ -32,9 +32,9 @@ makeTUDiagnostics(const std::string &MainSourceFile, StringRef DiagnosticName,
 // Test to ensure diagnostics with no fixes, will be merged correctly
 // before applying.
 TEST(ApplyReplacementsTest, mergeDiagnosticsWithNoFixes) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts.get());
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts);
   FileManager Files((FileSystemOptions()));
   SourceManager SM(Diagnostics, Files);
   TUReplacements TURs;
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index aaec0e6b50bbf..d3ca26a19dd63 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -317,9 +317,9 @@ TEST(CheckOptionsValidation, MissingOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
   EXPECT_FALSE(TestCheck.getLocal("Opt"));
   EXPECT_EQ(TestCheck.getLocal("Opt", "Unknown"), "Unknown");
@@ -347,9 +347,9 @@ TEST(CheckOptionsValidation, ValidIntOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal("IntExpected"), 1);
@@ -409,9 +409,9 @@ TEST(ValidConfiguration, ValidEnumOptions) {
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
   TestCheck TestCheck(&Context);
 
   CHECK_VAL(TestCheck.getIntLocal<Colours>("Valid"), Colours::Red);
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
index e511eb6e49e8d..789cc2afb4f0c 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -96,9 +96,9 @@ runCheckOnCode(StringRef Code, std::vector<ClangTidyError> *Errors = nullptr,
   ClangTidyContext Context(std::make_unique<DefaultOptionsProvider>(
       ClangTidyGlobalOptions(), Options));
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
-  DiagnosticsEngine DE(new DiagnosticIDs(), new DiagnosticOptions,
-                       &DiagConsumer, false);
-  Context.setDiagnosticsEngine(&DE);
+  auto DiagOpts = std::make_unique<DiagnosticOptions>();
+  DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer, false);
+  Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
 
   std::vector<std::string> Args(1, "clang-tidy");
   Args.push_back("-fsyntax-only");
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 49ef22d4e4eb6..e9c54c3c487c9 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -330,7 +330,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   unsigned ConstexprBacktraceLimit = 0;
 
   IntrusiveRefCntPtr<DiagnosticIDs> Diags;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
   DiagnosticConsumer *Client = nullptr;
   std::unique_ptr<DiagnosticConsumer> Owner;
   SourceManager *SourceMgr = nullptr;
@@ -566,7 +566,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
 
 public:
   explicit DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> Diags,
-                             IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+                             DiagnosticOptions &DiagOpts,
                              DiagnosticConsumer *client = nullptr,
                              bool ShouldOwnClient = true);
   DiagnosticsEngine(const DiagnosticsEngine &) = delete;
@@ -582,7 +582,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
   }
 
   /// Retrieve the diagnostic options.
-  DiagnosticOptions &getDiagnosticOptions() const { return *DiagOpts; }
+  DiagnosticOptions &getDiagnosticOptions() const { return DiagOpts; }
 
   using diag_mapping_range = llvm::iterator_range<DiagState::const_iterator>;
 
diff --git a/clang/include/clang/Basic/DiagnosticOptions.h b/clang/include/clang/Basic/DiagnosticOptions.h
index 29146532f9524..a230022224de5 100644
--- a/clang/include/clang/Basic/DiagnosticOptions.h
+++ b/clang/include/clang/Basic/DiagnosticOptions.h
@@ -10,7 +10,6 @@
 #define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
 
 #include "clang/Basic/LLVM.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -67,8 +66,7 @@ inline DiagnosticLevelMask operator&(DiagnosticLevelMask LHS,
 raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M);
 
 /// Options for controlling the compiler diagnostics engine.
-class DiagnosticOptions
-    : public llvm::ThreadSafeRefCountedBase<DiagnosticOptions> {
+class DiagnosticOptions {
   friend bool ParseDiagnosticArgs(DiagnosticOptions &, llvm::opt::ArgList &,
                                   clang::DiagnosticsEngine *, bool);
 
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 3762dbc2ccee8..cd3dac9133223 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -2041,6 +2041,7 @@ class SourceManagerForFile {
   // as they are created in `createSourceManagerForFile` so that they can be
   // deleted in the reverse order as they are created.
   std::unique_ptr<FileManager> FileMgr;
+  std::unique_ptr<DiagnosticOptions> DiagOpts;
   std::unique_ptr<DiagnosticsEngine> Diagnostics;
   std::unique_ptr<SourceManager> SourceMgr;
 };
diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h
index ac99f0fb2b471..1485192e8f1e3 100644
--- a/clang/include/clang/Frontend/ASTUnit.h
+++ b/clang/include/clang/Frontend/ASTUnit.h
@@ -107,6 +107,11 @@ class ASTUnit {
 
 private:
   std::unique_ptr<LangOptions> LangOpts;
+  // FIXME: The documentation on \c LoadFrom* member functions states that the
+  // DiagnosticsEngine (and therefore DiagnosticOptions) must outlive the
+  // returned ASTUnit. This is not the case. Enfore it by storing non-owning
+  // pointers here.
+  std::shared_ptr<DiagnosticOptions> DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine>   Diagnostics;
   IntrusiveRefCntPtr<FileManager>         FileMgr;
   IntrusiveRefCntPtr<SourceManager>       SourceMgr;
@@ -674,6 +679,7 @@ class ASTUnit {
   /// Create a ASTUnit. Gets ownership of the passed CompilerInvocation.
   static std::unique_ptr<ASTUnit>
   create(std::shared_ptr<CompilerInvocation> CI,
+         std::shared_ptr<DiagnosticOptions> DiagOpts,
          IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
          CaptureDiagsKind CaptureDiagnostics, bool UserFilesAreVolatile);
 
@@ -700,7 +706,8 @@ class ASTUnit {
   /// \returns - The initialized ASTUnit or null if the AST failed to load.
   static std::unique_ptr<ASTUnit> LoadFromASTFile(
       StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-      WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+      WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
+      IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       const FileSystemOptions &FileSystemOpts,
       const HeaderSearchOptions &HSOpts, const LangOptions *LangOpts = nullptr,
       bool OnlyLocalDecls = false,
@@ -762,6 +769,7 @@ class ASTUnit {
   static ASTUnit *LoadFromCompilerInvocationAction(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
       FrontendAction *Action = nullptr, ASTUnit *Unit = nullptr,
       bool Persistent = true, StringRef ResourceFilesPath = StringRef(),
@@ -789,6 +797,7 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation(
       std::shared_ptr<CompilerInvocation> CI,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
       bool OnlyLocalDecls = false,
       CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None,
@@ -837,6 +846,7 @@ class ASTUnit {
   static std::unique_ptr<ASTUnit> LoadFromCommandLine(
       const char **ArgBegin, const char **ArgEnd,
       std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+      std::shared_ptr<DiagnosticOptions> DiagOpts,
       IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
       bool StorePreamblesInMemory = false,
       StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false,
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 5f25a932c5052..0ae490f0e8073 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -674,7 +674,7 @@ class CompilerInstance : public ModuleLoader {
   ///
   /// \return The new object on success, or null on failure.
   static IntrusiveRefCntPtr<DiagnosticsEngine>
-  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
+  createDiagnostics(llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
                     DiagnosticConsumer *Client = nullptr,
                     bool ShouldOwnClient = true,
                     const CodeGenOptions *CodeGenOpts = nullptr);
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 3ca900729b4a8..e147d2ba6087e 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -80,7 +80,7 @@ class CompilerInvocationBase {
   std::shared_ptr<TargetOptions> TargetOpts;
 
   /// Options controlling the diagnostic engine.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagnosticOpts;
+  std::shared_ptr<DiagnosticOptions> DiagnosticOpts;
 
   /// Options controlling the \#include directive.
   std::shared_ptr<HeaderSearchOptions> HSOpts;
diff --git a/clang/include/clang/Frontend/DiagnosticRenderer.h b/clang/include/clang/Frontend/DiagnosticRenderer.h
index b939ebe979e71..3f03a6e02da4b 100644
--- a/clang/include/clang/Frontend/DiagnosticRenderer.h
+++ b/clang/include/clang/Frontend/DiagnosticRenderer.h
@@ -47,7 +47,7 @@ using DiagOrStoredDiag =
 class DiagnosticRenderer {
 protected:
   const LangOptions &LangOpts;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// The location of the previous diagnostic if known.
   ///
@@ -68,8 +68,7 @@ class DiagnosticRenderer {
   /// which change the amount of information displayed.
   DiagnosticsEngine::Level LastLevel = DiagnosticsEngine::Ignored;
 
-  DiagnosticRenderer(const LangOptions &LangOpts,
-                     DiagnosticOptions *DiagOpts);
+  DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts);
 
   virtual ~DiagnosticRenderer();
 
@@ -142,7 +141,7 @@ class DiagnosticRenderer {
 class DiagnosticNoteRenderer : public DiagnosticRenderer {
 public:
   DiagnosticNoteRenderer(const LangOptions &LangOpts,
-                         DiagnosticOptions *DiagOpts)
+                         DiagnosticOptions &DiagOpts)
       : DiagnosticRenderer(LangOpts, DiagOpts) {}
 
   ~DiagnosticNoteRenderer() override;
diff --git a/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
index ec22a8b6cc5fb..b43b0da13967a 100644
--- a/clang/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -51,7 +51,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
   std::unique_ptr<raw_ostream> StreamOwner;
   const LangOptions *LangOpts;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   SourceLocation LastWarningLoc;
   FullSourceLoc LastLoc;
@@ -62,7 +62,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   std::string DwarfDebugFlags;
 
 public:
-  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags,
+  LogDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts,
                        std::unique_ptr<raw_ostream> StreamOwner);
 
   void setDwarfDebugFlags(StringRef Value) {
diff --git a/clang/include/clang/Frontend/SARIFDiagnostic.h b/clang/include/clang/Frontend/SARIFDiagnostic.h
index ec1d0b8e6a7c9..780f36c874109 100644
--- a/clang/include/clang/Frontend/SARIFDiagnostic.h
+++ b/clang/include/clang/Frontend/SARIFDiagnostic.h
@@ -23,7 +23,7 @@ namespace clang {
 class SARIFDiagnostic : public DiagnosticRenderer {
 public:
   SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                  DiagnosticOptions *DiagOpts, SarifDocumentWriter *Writer);
+                  DiagnosticOptions &DiagOpts, SarifDocumentWriter *Writer);
 
   ~SARIFDiagnostic() = default;
 
diff --git a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
index f2652833b3c18..3406ed16c2fba 100644
--- a/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SARIFDiagnosticPrinter.h
@@ -29,7 +29,7 @@ class SarifDocumentWriter;
 
 class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 public:
-  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions *Diags);
+  SARIFDiagnosticPrinter(raw_ostream &OS, DiagnosticOptions &DiagOpts);
   ~SARIFDiagnosticPrinter() = default;
 
   SARIFDiagnosticPrinter &operator=(const SARIFDiagnosticPrinter &&) = delete;
@@ -60,7 +60,7 @@ class SARIFDiagnosticPrinter : public DiagnosticConsumer {
 
 private:
   raw_ostream &OS;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// Handle to the currently active SARIF diagnostic emitter.
   std::unique_ptr<SARIFDiagnostic> SARIFDiag;
diff --git a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
index 5586ef65e393f..2b6d2e4477d58 100644
--- a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -32,7 +32,7 @@ namespace serialized_diags {
 /// (via libclang) without needing to parse Clang's command line output.
 ///
 std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
-                                           DiagnosticOptions *Diags,
+                                           DiagnosticOptions &DiagOpts,
                                            bool MergeChildRecords = false);
 
 } // end serialized_diags namespace
diff --git a/clang/include/clang/Frontend/TextDiagnostic.h b/clang/include/clang/Frontend/TextDiagnostic.h
index a2fe8ae995423..e2e88d4d648a2 100644
--- a/clang/include/clang/Frontend/TextDiagnostic.h
+++ b/clang/include/clang/Frontend/TextDiagnostic.h
@@ -38,7 +38,7 @@ class TextDiagnostic : public DiagnosticRenderer {
 
 public:
   TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                 DiagnosticOptions *DiagOpts, const Preprocessor *PP = nullptr);
+                 DiagnosticOptions &DiagOpts, const Preprocessor *PP = nullptr);
 
   ~TextDiagnostic() override;
 
diff --git a/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
index 2610bde7513a1..dd1ca6b2248b7 100644
--- a/clang/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -26,7 +26,7 @@ class TextDiagnostic;
 
 class TextDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions &DiagOpts;
 
   /// Handle to the currently active text diagnostic emitter.
   std::unique_ptr<TextDiagnostic> TextDiag;
@@ -38,7 +38,7 @@ class TextDiagnosticPrinter : public DiagnosticConsumer {
   unsigned OwnsOutputStream : 1;
 
 public:
-  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags,
+  TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions &DiagOpts,
                         bool OwnsOutputStream = false);
   ~TextDiagnosticPrinter() override;
 
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 57b0266af26bb..6963611c6a815 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -151,9 +151,8 @@ class ASTReaderListener {
   ///
   /// \returns true to indicate the diagnostic options are invalid, or false
   /// otherwise.
-  virtual bool
-  ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
-                        StringRef ModuleFilename, bool Complain) {
+  virtual bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+                                     StringRef ModuleFilename, bool Complain) {
     return false;
   }
 
@@ -285,7 +284,7 @@ class ChainedASTReaderListener : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadFileSystemOptions(const FileSystemOptions &FSOpts,
                              bool Complain) override;
@@ -326,7 +325,7 @@ class PCHValidator : public ASTReaderListener {
   bool ReadTargetOptions(const TargetOptions &TargetOpts,
                          StringRef ModuleFilename, bool Complain,
                          bool AllowCompatibleDifferences) override;
-  bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+  bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                              StringRef ModuleFilename, bool Complain) override;
   bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
                                StringRef ModuleFilename, bool ReadMacros,
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index b48eed8650672..22821418c7078 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -77,11 +77,11 @@ DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
   Output.append(Str.begin(), Str.end());
 }
 
-DiagnosticsEngine::DiagnosticsEngine(
-    IntrusiveRefCntPtr<DiagnosticIDs> diags,
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
-    bool ShouldOwnClient)
-    : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
+DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
+                                     DiagnosticOptions &DiagOpts,
+                                     DiagnosticConsumer *client,
+                                     bool ShouldOwnClient)
+    : Diags(std::move(diags)), DiagOpts(DiagOpts) {
   setClient(client, ShouldOwnClient);
   ArgToStringFn = DummyArgToStringFn;
 
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 4028bbf060364..09e5c6547fb51 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2391,11 +2391,11 @@ SourceManagerForFile::SourceManagerForFile(StringRef FileName,
   // in `Environment` so that `FileMgr` can out-live this function scope.
   FileMgr =
       std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
+  DiagOpts = std::make_unique<DiagnosticOptions>();
   // This is passed to `SM` as reference, so the pointer has to be referenced
   // by `Environment` due to the same reason above.
   Diagnostics = std::make_unique<DiagnosticsEngine>(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), *DiagOpts);
   SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr);
   FileEntryRef FE = llvm::cantFail(FileMgr->getFileRef(FileName));
   FileID ID =
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index ef395f497216c..6d0f042d5accd 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -560,15 +560,15 @@ CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
 
 CrossTranslationUnitContext::LoadResultTy
 CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, *DiagOpts, DiagClient));
   return ASTUnit::LoadFromASTFile(
       ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(),
+      ASTUnit::LoadEverything, DiagOpts, Diags, CI.getFileSystemOpts(),
       CI.getHeaderSearchOpts());
 }
 
@@ -603,17 +603,17 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource(
                  CommandLineArgs.begin(),
                  [](auto &&CmdPart) { return CmdPart.c_str(); });
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
+  auto DiagOpts = std::make_shared<DiagnosticOptions>(CI.getDiagnosticOpts());
   auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
       CI.getDiagnostics().getDiagnosticIDs()};
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
+      new DiagnosticsEngine{DiagID, *DiagOpts, DiagClient});
 
-  return ASTUnit::LoadFromCommandLine(CommandLineArgs.begin(),
-                                      (CommandLineArgs.end()),
-                                      CI.getPCHContainerOperations(), Diags,
-                                      CI.getHeaderSearchOpts().ResourceDir);
+  return ASTUnit::LoadFromCommandLine(
+      CommandLineArgs.begin(), (CommandLineArgs.end()),
+      CI.getPCHContainerOperations(), DiagOpts, Diags,
+      CI.getHeaderSearchOpts().ResourceDir);
 }
 
 llvm::Expected<InvocationListTy>
diff --git a/clang/lib/Frontend/ASTMerge.cpp b/clang/lib/Frontend/ASTMerge.cpp
index b6b06440bc3f8..a4ce88351e28e 100644
--- a/clang/lib/Frontend/ASTMerge.cpp
+++ b/clang/lib/Frontend/ASTMerge.cpp
@@ -41,14 +41,13 @@ void ASTMergeAction::ExecuteAction() {
   auto SharedState = std::make_shared<ASTImporterSharedState>(
       *CI.getASTContext().getTranslationUnitDecl());
   for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
-    IntrusiveRefCntPtr<DiagnosticsEngine>
-        Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(),
-                                    new ForwardingDiagnosticConsumer(
-                                          *CI.getDiagnostics().getClient()),
-                                    /*ShouldOwnClient=*/true));
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags(new DiagnosticsEngine(
+        DiagIDs, CI.getDiagnosticOpts(),
+        new ForwardingDiagnosticConsumer(*CI.getDiagnostics().getClient()),
+        /*ShouldOwnClient=*/true));
     std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
-        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
-        CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        ASTFiles[I], CI.getPCHContainerReader(), ASTUnit::LoadEverything,
+        nullptr, Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
 
     if (!Unit)
       continue;
diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp
index 5a79fe070c384..457043c6bd7ce 100644
--- a/clang/lib/Frontend/ASTUnit.cpp
+++ b/clang/lib/Frontend/ASTUnit.cpp
@@ -803,7 +803,8 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
 
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
     StringRef Filename, const PCHContainerReader &PCHContainerRdr,
-    WhatToLoad ToLoad, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+    WhatToLoad ToLoad, std::shared_ptr<DiagnosticOptions> DiagOpts,
+    IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
     const FileSystemOptions &FileSystemOpts, const HeaderSearchOptions &HSOpts,
     const LangOptions *LangOpts, bool OnlyLocalDecls,
     CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors,
@@ -823,6 +824,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
                            : std::make_unique<LangOptions>();
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileMgr = new FileManager(FileSystemOpts, VFS);
   AST->UserFilesAreVolatile = UserFilesAreVolatile;
@@ -1534,6 +1536,7 @@ StringRef ASTUnit::getASTFileName() const {
 
 std::unique_ptr<ASTUnit>
 ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
+                std::shared_ptr<DiagnosticOptions> DiagOpts,
                 IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
                 CaptureDiagsKind CaptureDiagnostics,
                 bool UserFilesAreVolatile) {
@@ -1541,6 +1544,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       createVFSFromCompilerInvocation(*CI, *Diags);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   AST->Invocation = std::move(CI);
@@ -1556,6 +1560,7 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI,
 ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FrontendAction *Action,
     ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1567,7 +1572,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
   ASTUnit *AST = Unit;
   if (!AST) {
     // Create the AST unit.
-    OwnAST = create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile);
+    OwnAST =
+        create(CI, DiagOpts, Diags, CaptureDiagnostics, UserFilesAreVolatile);
     AST = OwnAST.get();
     if (!AST)
       return nullptr;
@@ -1729,6 +1735,7 @@ bool ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
     std::shared_ptr<CompilerInvocation> CI,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
     unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind,
@@ -1737,6 +1744,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
   // Create the AST unit.
   std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->CaptureDiagnostics = CaptureDiagnostics;
@@ -1766,6 +1774,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
 std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
     const char **ArgBegin, const char **ArgEnd,
     std::shared_ptr<PCHContainerOperations> PCHContainerOps,
+    std::shared_ptr<DiagnosticOptions> DiagOpts,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
     bool StorePreamblesInMemory, StringRef PreambleStoragePath,
     bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics,
@@ -1828,6 +1837,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine(
   AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
   AST->StoredDiagnostics.swap(StoredDiagnostics);
   ConfigureDiags(Diags, *AST, CaptureDiagnostics);
+  AST->DiagOpts = DiagOpts;
   AST->Diagnostics = Diags;
   AST->FileSystemOpts = CI->getFileSystemOpts();
   VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS);
diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp
index 95b0ed248d545..f9a398dbfb90f 100644
--- a/clang/lib/Frontend/ChainedIncludesSource.cpp
+++ b/clang/lib/Frontend/ChainedIncludesSource.cpp
@@ -117,10 +117,10 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
     CInvok->getFrontendOpts().Inputs.push_back(InputFile);
 
     TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
+        new TextDiagnosticPrinter(llvm::errs(), CI.getDiagnosticOpts());
     IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient));
+        new DiagnosticsEngine(DiagID, CI.getDiagnosticOpts(), DiagClient));
 
     auto Clang = std::make_unique<CompilerInstance>(
         std::move(CInvok), CI.getPCHContainerOperations());
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 503d36467653e..cc39049167687 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -280,20 +280,20 @@ static void collectVFSEntries(CompilerInstance &CI,
 }
 
 // Diagnostics
-static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
+static void SetUpDiagnosticLog(DiagnosticOptions &DiagOpts,
                                const CodeGenOptions *CodeGenOpts,
                                DiagnosticsEngine &Diags) {
   std::error_code EC;
   std::unique_ptr<raw_ostream> StreamOwner;
   raw_ostream *OS = &llvm::errs();
-  if (DiagOpts->DiagnosticLogFile != "-") {
+  if (DiagOpts.DiagnosticLogFile != "-") {
     // Create the output stream.
     auto FileOS = std::make_unique<llvm::raw_fd_ostream>(
-        DiagOpts->DiagnosticLogFile, EC,
+        DiagOpts.DiagnosticLogFile, EC,
         llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF);
     if (EC) {
       Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
-          << DiagOpts->DiagnosticLogFile << EC.message();
+          << DiagOpts.DiagnosticLogFile << EC.message();
     } else {
       FileOS->SetUnbuffered();
       OS = FileOS.get();
@@ -315,7 +315,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
   }
 }
 
-static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
+static void SetupSerializedDiagnostics(DiagnosticOptions &DiagOpts,
                                        DiagnosticsEngine &Diags,
                                        StringRef OutputFile) {
   auto SerializedConsumer =
@@ -333,12 +333,12 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
 void CompilerInstance::createDiagnostics(llvm::vfs::FileSystem &VFS,
                                          DiagnosticConsumer *Client,
                                          bool ShouldOwnClient) {
-  Diagnostics = createDiagnostics(VFS, &getDiagnosticOpts(), Client,
+  Diagnostics = createDiagnostics(VFS, getDiagnosticOpts(), Client,
                                   ShouldOwnClient, &getCodeGenOpts());
 }
 
 IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
-    llvm::vfs::FileSystem &VFS, DiagnosticOptions *Opts,
+    llvm::vfs::FileSystem &VFS, DiagnosticOptions &Opts,
     DiagnosticConsumer *Client, bool ShouldOwnClient,
     const CodeGenOptions *CodeGenOpts) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -349,25 +349,24 @@ IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
   // implementing -verify.
   if (Client) {
     Diags->setClient(Client, ShouldOwnClient);
-  } else if (Opts->getFormat() == DiagnosticOptions::SARIF) {
+  } else if (Opts.getFormat() == DiagnosticOptions::SARIF) {
     Diags->setClient(new SARIFDiagnosticPrinter(llvm::errs(), Opts));
   } else
     Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
 
   // Chain in -verify checker, if requested.
-  if (Opts->VerifyDiagnostics)
+  if (Opts.VerifyDiagnostics)
     Diags->setClient(new VerifyDiagnosticConsumer(*Diags));
 
   // Chain in -diagnostic-log-file dumper, if requested.
-  if (!Opts->DiagnosticLogFile.empty())
+  if (!Opts.DiagnosticLogFile.empty())
     SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
 
-  if (!Opts->DiagnosticSerializationFile.empty())
-    SetupSerializedDiagnostics(Opts, *Diags,
-                               Opts->DiagnosticSerializationFile);
+  if (!Opts.DiagnosticSerializationFile.empty())
+    SetupSerializedDiagnostics(Opts, *Diags, Opts.DiagnosticSerializationFile);
 
   // Configure our handling of diagnostics.
-  ProcessWarningOptions(*Diags, *Opts, VFS);
+  ProcessWarningOptions(*Diags, Opts, VFS);
 
   return Diags;
 }
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 3c23073fc6a8c..9c33910eff57e 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -125,21 +125,14 @@ static Expected<std::optional<uint32_t>> parseToleranceOption(StringRef Arg) {
 // Initialization.
 //===----------------------------------------------------------------------===//
 
-namespace {
 template <class T> std::shared_ptr<T> make_shared_copy(const T &X) {
   return std::make_shared<T>(X);
 }
 
-template <class T>
-llvm::IntrusiveRefCntPtr<T> makeIntrusiveRefCntCopy(const T &X) {
-  return llvm::makeIntrusiveRefCnt<T>(X);
-}
-} // namespace
-
 CompilerInvocationBase::CompilerInvocationBase()
     : LangOpts(std::make_shared<LangOptions>()),
       TargetOpts(std::make_shared<TargetOptions>()),
-      DiagnosticOpts(llvm::makeIntrusiveRefCnt<DiagnosticOptions>()),
+      DiagnosticOpts(std::make_shared<DiagnosticOptions>()),
       HSOpts(std::make_shared<HeaderSearchOptions>()),
       PPOpts(std::make_shared<PreprocessorOptions>()),
       AnalyzerOpts(std::make_shared<AnalyzerOptions>()),
@@ -156,7 +149,7 @@ CompilerInvocationBase::deep_copy_assign(const CompilerInvocationBase &X) {
   if (this != &X) {
     LangOpts = make_shared_copy(X.getLangOpts());
     TargetOpts = make_shared_copy(X.getTargetOpts());
-    DiagnosticOpts = makeIntrusiveRefCntCopy(X.getDiagnosticOpts());
+    DiagnosticOpts = make_shared_copy(X.getDiagnosticOpts());
     HSOpts = make_shared_copy(X.getHeaderSearchOpts());
     PPOpts = make_shared_copy(X.getPreprocessorOpts());
     AnalyzerOpts = make_shared_copy(X.getAnalyzerOpts());
@@ -202,7 +195,6 @@ CompilerInvocation::operator=(const CowCompilerInvocation &X) {
   return *this;
 }
 
-namespace {
 template <typename T>
 T &ensureOwned(std::shared_ptr<T> &Storage) {
   if (Storage.use_count() > 1)
@@ -210,14 +202,6 @@ T &ensureOwned(std::shared_ptr<T> &Storage) {
   return *Storage;
 }
 
-template <typename T>
-T &ensureOwned(llvm::IntrusiveRefCntPtr<T> &Storage) {
-  if (Storage.useCount() > 1)
-    Storage = llvm::makeIntrusiveRefCnt<T>(*Storage);
-  return *Storage;
-}
-} // namespace
-
 LangOptions &CowCompilerInvocation::getMutLangOpts() {
   return ensureOwned(LangOpts);
 }
@@ -844,7 +828,8 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate,
   };
 
   // Setup a dummy DiagnosticsEngine.
-  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), new DiagnosticOptions());
+  DiagnosticOptions DummyDiagOpts;
+  DiagnosticsEngine DummyDiags(new DiagnosticIDs(), DummyDiagOpts);
   DummyDiags.setClient(new TextDiagnosticBuffer());
 
   // Run the first parse on the original arguments with the dummy invocation and
@@ -2663,9 +2648,11 @@ clang::CreateAndPopulateDiagOpts(ArrayRef<const char *> Argv) {
 bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
                                 DiagnosticsEngine *Diags,
                                 bool DefaultDiagColor) {
+  std::optional<DiagnosticOptions> IgnoringDiagOpts;
   std::optional<DiagnosticsEngine> IgnoringDiags;
   if (!Diags) {
-    IgnoringDiags.emplace(new DiagnosticIDs(), new DiagnosticOptions(),
+    IgnoringDiagOpts.emplace();
+    IgnoringDiags.emplace(new DiagnosticIDs(), *IgnoringDiagOpts,
                           new IgnoringDiagConsumer());
     Diags = &*IgnoringDiags;
   }
diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index d0b855fff2534..99212b81fe064 100644
--- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -31,11 +31,15 @@ std::unique_ptr<CompilerInvocation>
 clang::createInvocation(ArrayRef<const char *> ArgList,
                         CreateInvocationOptions Opts) {
   assert(!ArgList.empty());
-  auto Diags = Opts.Diags
-                   ? std::move(Opts.Diags)
-                   : CompilerInstance::createDiagnostics(
-                         Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(),
-                         new DiagnosticOptions);
+  std::optional<DiagnosticOptions> LocalDiagOpts;
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+  if (Opts.Diags) {
+    Diags = std::move(Opts.Diags);
+  } else {
+    LocalDiagOpts.emplace();
+    Diags = CompilerInstance::createDiagnostics(
+        Opts.VFS ? *Opts.VFS : *llvm::vfs::getRealFileSystem(), *LocalDiagOpts);
+  }
 
   SmallVector<const char *, 16> Args(ArgList);
 
diff --git a/clang/lib/Frontend/DiagnosticRenderer.cpp b/clang/lib/Frontend/DiagnosticRenderer.cpp
index 3b120abbc3a7a..1396b2bfbd151 100644
--- a/clang/lib/Frontend/DiagnosticRenderer.cpp
+++ b/clang/lib/Frontend/DiagnosticRenderer.cpp
@@ -30,7 +30,7 @@
 using namespace clang;
 
 DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts,
-                                       DiagnosticOptions *DiagOpts)
+                                       DiagnosticOptions &DiagOpts)
     : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
 
 DiagnosticRenderer::~DiagnosticRenderer() = default;
@@ -115,7 +115,7 @@ void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc,
     // Find the ultimate expansion location for the diagnostic.
     Loc = Loc.getFileLoc();
 
-    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+    PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
 
     // First, if this diagnostic is not in the main file, print out the
     // "included from" lines.
@@ -172,7 +172,7 @@ void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc,
 
   LastIncludeLoc = IncludeLoc;
 
-  if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+  if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
     return;
 
   if (IncludeLoc.isValid())
@@ -191,7 +191,7 @@ void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
   if (PLoc.isInvalid())
     return;
 
@@ -232,7 +232,7 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
     return;
   }
 
-  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc);
+  PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts.ShowPresumedLoc);
 
   // Emit the other import frames first.
   std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();
@@ -247,9 +247,8 @@ void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,
 void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
   ModuleBuildStack Stack = SM.getModuleBuildStack();
   for (const auto &I : Stack) {
-    emitBuildingModuleLocation(I.second, I.second.getPresumedLoc(
-                                              DiagOpts->ShowPresumedLoc),
-                               I.first);
+    emitBuildingModuleLocation(
+        I.second, I.second.getPresumedLoc(DiagOpts.ShowPresumedLoc), I.first);
   }
 }
 
@@ -539,7 +538,7 @@ void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,
                       LocationStack.begin() + IgnoredEnd);
 
   unsigned MacroDepth = LocationStack.size();
-  unsigned MacroLimit = DiagOpts->MacroBacktraceLimit;
+  unsigned MacroLimit = DiagOpts.MacroBacktraceLimit;
   if (MacroDepth <= MacroLimit || MacroLimit == 0) {
     for (auto I = LocationStack.rbegin(), E = LocationStack.rend();
          I != E; ++I)
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 54a2e3eb297f5..af9d18ab66108 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -766,9 +766,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
 
     // The AST unit populates its own diagnostics engine rather than ours.
-    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
-        new DiagnosticsEngine(Diags->getDiagnosticIDs(),
-                              &Diags->getDiagnosticOptions()));
+    IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine(
+        Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions()));
     ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
 
     // FIXME: What if the input is a memory buffer?
@@ -776,7 +775,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
         InputFile, CI.getPCHContainerReader(), ASTUnit::LoadPreprocessorOnly,
-        ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
+        nullptr, ASTDiags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts());
     if (!AST)
       return false;
 
@@ -842,8 +841,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     StringRef InputFile = Input.getFile();
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
-        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, Diags,
-        CI.getFileSystemOpts(), CI.getHeaderSearchOpts(), &CI.getLangOpts());
+        InputFile, CI.getPCHContainerReader(), ASTUnit::LoadEverything, nullptr,
+        Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOpts(),
+        &CI.getLangOpts());
 
     if (!AST)
       return false;
diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index 8c75e1a46da54..d14d091e3fe38 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -685,21 +685,21 @@ namespace {
       return false;
     }
 
-    bool ReadDiagnosticOptions(IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,
+    bool ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
                                StringRef ModuleFilename,
                                bool Complain) override {
       Out.indent(2) << "Diagnostic options:\n";
-#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts->Name, #Name);
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
-      Out.indent(4) << #Name << ": " << DiagOpts->get##Name() << "\n";
-#define VALUE_DIAGOPT(Name, Bits, Default) \
-      Out.indent(4) << #Name << ": " << DiagOpts->Name << "\n";
+#define DIAGOPT(Name, Bits, Default) DUMP_BOOLEAN(DiagOpts.Name, #Name);
+#define ENUM_DIAGOPT(Name, Type, Bits, Default)                              \
+    Out.indent(4) << #Name << ": " << DiagOpts.get##Name() << "\n";
+#define VALUE_DIAGOPT(Name, Bits, Default)                                   \
+    Out.indent(4) << #Name << ": " << DiagOpts.Name << "\n";
 #include "clang/Basic/DiagnosticOptions.def"
 
       Out.indent(4) << "Diagnostic flags:\n";
-      for (const std::string &Warning : DiagOpts->Warnings)
+      for (const std::string &Warning : DiagOpts.Warnings)
         Out.indent(6) << "-W" << Warning << "\n";
-      for (const std::string &Remark : DiagOpts->Remarks)
+      for (const std::string &Remark : DiagOpts.Remarks)
         Out.indent(6) << "-R" << Remark << "\n";
 
       return false;
diff --git a/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 4e963af837f01..2d188931e4f8a 100644
--- a/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -18,10 +18,10 @@ using namespace clang;
 using namespace markup;
 
 LogDiagnosticPrinter::LogDiagnosticPrinter(
-    raw_ostream &os, DiagnosticOptions *diags,
+    raw_ostream &os, DiagnosticOptions &DiagOpts,
     std::unique_ptr<raw_ostream> StreamOwner)
     : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
-      DiagOpts(diags) {}
+      DiagOpts(DiagOpts) {}
 
 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
   switch (Level) {
diff --git a/clang/lib/Frontend/SARIFDiagnostic.cpp b/clang/lib/Frontend/SARIFDiagnostic.cpp
index 4e36153ed5391..e2aec7f677f12 100644
--- a/clang/lib/Frontend/SARIFDiagnostic.cpp
+++ b/clang/lib/Frontend/SARIFDiagnostic.cpp
@@ -31,7 +31,7 @@
 namespace clang {
 
 SARIFDiagnostic::SARIFDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                                 DiagnosticOptions *DiagOpts,
+                                 DiagnosticOptions &DiagOpts,
                                  SarifDocumentWriter *Writer)
     : DiagnosticRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
@@ -163,7 +163,7 @@ SARIFDiagnostic::addDiagnosticLevelToRule(SarifRule Rule,
 
 llvm::StringRef SARIFDiagnostic::emitFilename(StringRef Filename,
                                               const SourceManager &SM) {
-  if (DiagOpts->AbsolutePath) {
+  if (DiagOpts.AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
diff --git a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
index 73928d19a031a..23fbc3e4fa92b 100644
--- a/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SARIFDiagnosticPrinter.cpp
@@ -26,15 +26,15 @@
 namespace clang {
 
 SARIFDiagnosticPrinter::SARIFDiagnosticPrinter(raw_ostream &OS,
-                                               DiagnosticOptions *Diags)
-    : OS(OS), DiagOpts(Diags) {}
+                                               DiagnosticOptions &DiagOpts)
+    : OS(OS), DiagOpts(DiagOpts) {}
 
 void SARIFDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                              const Preprocessor *PP) {
   // Build the SARIFDiagnostic utility.
   assert(hasSarifWriter() && "Writer not set!");
   assert(!SARIFDiag && "SARIFDiagnostic already set.");
-  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, &*DiagOpts, &*Writer);
+  SARIFDiag = std::make_unique<SARIFDiagnostic>(OS, LO, DiagOpts, &*Writer);
   // Initialize the SARIF object.
   Writer->createRun("clang", Prefix);
 }
@@ -72,7 +72,6 @@ void SARIFDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   }
 
   // Assert that the rest of our infrastructure is setup properly.
-  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
 
diff --git a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 02aa3e8e4d984..ee49cdd84e79e 100644
--- a/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -57,8 +57,8 @@ class SDiagsRenderer : public DiagnosticNoteRenderer {
   SDiagsWriter &Writer;
 public:
   SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts,
-                 DiagnosticOptions *DiagOpts)
-    : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
+                 DiagnosticOptions &DiagOpts)
+      : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {}
 
   ~SDiagsRenderer() override {}
 
@@ -140,7 +140,7 @@ class SDiagsWriter : public DiagnosticConsumer {
         State(std::move(State)) {}
 
 public:
-  SDiagsWriter(StringRef File, DiagnosticOptions *Diags, bool MergeChildRecords)
+  SDiagsWriter(StringRef File, DiagnosticOptions &Diags, bool MergeChildRecords)
       : LangOpts(nullptr), OriginalInstance(true),
         MergeChildRecords(MergeChildRecords),
         State(std::make_shared<SharedState>(File, Diags)) {
@@ -242,12 +242,12 @@ class SDiagsWriter : public DiagnosticConsumer {
   /// State that is shared among the various clones of this diagnostic
   /// consumer.
   struct SharedState {
-    SharedState(StringRef File, DiagnosticOptions *Diags)
-        : DiagOpts(Diags), Stream(Buffer), OutputFile(File.str()),
+    SharedState(StringRef File, DiagnosticOptions &DiagOpts)
+        : DiagOpts(DiagOpts), Stream(Buffer), OutputFile(File.str()),
           EmittedAnyDiagBlocks(false) {}
 
     /// Diagnostic options.
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+    DiagnosticOptions DiagOpts;
 
     /// The byte buffer for the serialized content.
     SmallString<1024> Buffer;
@@ -295,9 +295,11 @@ class SDiagsWriter : public DiagnosticConsumer {
 
 namespace clang {
 namespace serialized_diags {
-std::unique_ptr<DiagnosticConsumer>
-create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
-  return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
+std::unique_ptr<DiagnosticConsumer> create(StringRef OutputFile,
+                                           DiagnosticOptions &DiagOpts,
+                                           bool MergeChildRecords) {
+  return std::make_unique<SDiagsWriter>(OutputFile, DiagOpts,
+                                        MergeChildRecords);
 }
 
 } // end namespace serialized_diags
@@ -617,7 +619,7 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 
   assert(Info.hasSourceManager() && LangOpts &&
          "Unexpected diagnostic with valid location outside of a source file");
-  SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
+  SDiagsRenderer Renderer(*this, *LangOpts, State->DiagOpts);
   Renderer.emitDiagnostic(
       FullSourceLoc(Info.getLocation(), Info.getSourceManager()), DiagLevel,
       State->diagBuf, Info.getRanges(), Info.getFixItHints(), &Info);
@@ -755,10 +757,9 @@ DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
   //    normally not be used.
   if (!State->MetaDiagnostics) {
     IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
-    auto Client =
-        new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
-    State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
-        IDs, State->DiagOpts.get(), Client);
+    auto Client = new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts);
+    State->MetaDiagnostics =
+        std::make_unique<DiagnosticsEngine>(IDs, State->DiagOpts, Client);
   }
   return State->MetaDiagnostics.get();
 }
diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp
index 4119ce6048d45..25ab13b7ae6c2 100644
--- a/clang/lib/Frontend/TextDiagnostic.cpp
+++ b/clang/lib/Frontend/TextDiagnostic.cpp
@@ -654,7 +654,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns,
 }
 
 TextDiagnostic::TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts,
-                               DiagnosticOptions *DiagOpts,
+                               DiagnosticOptions &DiagOpts,
                                const Preprocessor *PP)
     : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS), PP(PP) {}
 
@@ -670,15 +670,15 @@ void TextDiagnostic::emitDiagnosticMessage(
   if (Loc.isValid())
     emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.resetColor();
 
-  if (DiagOpts->ShowLevel)
-    printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+  if (DiagOpts.ShowLevel)
+    printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
   printDiagnosticMessage(OS,
                          /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
                          Message, OS.tell() - StartOfLocationInfo,
-                         DiagOpts->MessageLength, DiagOpts->ShowColors);
+                         DiagOpts.MessageLength, DiagOpts.ShowColors);
 }
 
 /*static*/ void
@@ -743,7 +743,7 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
 #ifdef _WIN32
   SmallString<4096> TmpFilename;
 #endif
-  if (DiagOpts->AbsolutePath) {
+  if (DiagOpts.AbsolutePath) {
     auto File = SM.getFileManager().getOptionalFileRef(Filename);
     if (File) {
       // We want to print a simplified absolute path, i. e. without "dots".
@@ -796,27 +796,27 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
   }
   unsigned LineNo = PLoc.getLine();
 
-  if (!DiagOpts->ShowLocation)
+  if (!DiagOpts.ShowLocation)
     return;
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.changeColor(savedColor, true);
 
   emitFilename(PLoc.getFilename(), Loc.getManager());
-  switch (DiagOpts->getFormat()) {
+  switch (DiagOpts.getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
-    if (DiagOpts->ShowLine)
+    if (DiagOpts.ShowLine)
       OS << ':' << LineNo;
     break;
   case DiagnosticOptions::MSVC:  OS << '('  << LineNo; break;
   case DiagnosticOptions::Vi:    OS << " +" << LineNo; break;
   }
 
-  if (DiagOpts->ShowColumn)
+  if (DiagOpts.ShowColumn)
     // Compute the column number.
     if (unsigned ColNo = PLoc.getColumn()) {
-      if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
+      if (DiagOpts.getFormat() == DiagnosticOptions::MSVC) {
         OS << ',';
         // Visual Studio 2010 or earlier expects column number to be off by one
         if (LangOpts.MSCompatibilityVersion &&
@@ -826,7 +826,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
         OS << ':';
       OS << ColNo;
     }
-  switch (DiagOpts->getFormat()) {
+  switch (DiagOpts.getFormat()) {
   case DiagnosticOptions::SARIF:
   case DiagnosticOptions::Clang:
   case DiagnosticOptions::Vi:    OS << ':';    break;
@@ -841,7 +841,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
     break;
   }
 
-  if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
+  if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
     FileID CaretFileID = Loc.getExpansionLoc().getFileID();
     bool PrintedRange = false;
     const SourceManager &SM = Loc.getManager();
@@ -881,7 +881,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
 }
 
 void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
-  if (DiagOpts->ShowLocation && PLoc.isValid()) {
+  if (DiagOpts.ShowLocation && PLoc.isValid()) {
     OS << "In file included from ";
     emitFilename(PLoc.getFilename(), Loc.getManager());
     OS << ':' << PLoc.getLine() << ":\n";
@@ -891,7 +891,7 @@ void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
 
 void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
                                         StringRef ModuleName) {
-  if (DiagOpts->ShowLocation && PLoc.isValid())
+  if (DiagOpts.ShowLocation && PLoc.isValid())
     OS << "In module '" << ModuleName << "' imported from "
        << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -901,7 +901,7 @@ void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
 void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
                                                 PresumedLoc PLoc,
                                                 StringRef ModuleName) {
-  if (DiagOpts->ShowLocation && PLoc.isValid())
+  if (DiagOpts.ShowLocation && PLoc.isValid())
     OS << "While building module '" << ModuleName << "' imported from "
       << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
   else
@@ -998,14 +998,13 @@ static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
   std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo, '~');
 }
 
-static std::string buildFixItInsertionLine(FileID FID,
-                                           unsigned LineNo,
+static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
                                            const SourceColumnMap &map,
                                            ArrayRef<FixItHint> Hints,
                                            const SourceManager &SM,
-                                           const DiagnosticOptions *DiagOpts) {
+                                           const DiagnosticOptions &DiagOpts) {
   std::string FixItInsertionLine;
-  if (Hints.empty() || !DiagOpts->ShowFixits)
+  if (Hints.empty() || !DiagOpts.ShowFixits)
     return FixItInsertionLine;
   unsigned PrevHintEndCol = 0;
 
@@ -1057,7 +1056,7 @@ static std::string buildFixItInsertionLine(FileID FID,
     }
   }
 
-  expandTabs(FixItInsertionLine, DiagOpts->TabStop);
+  expandTabs(FixItInsertionLine, DiagOpts.TabStop);
 
   return FixItInsertionLine;
 }
@@ -1296,7 +1295,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // was part of a different warning or error diagnostic, or if the
   // diagnostic has ranges.  We don't want to emit the same caret
   // multiple times if one loc has multiple diagnostics.
-  if (!DiagOpts->ShowCarets)
+  if (!DiagOpts.ShowCarets)
     return;
   if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
       (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
@@ -1322,7 +1321,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     return;
 
   // Find the set of lines to include.
-  const unsigned MaxLines = DiagOpts->SnippetLineLimit;
+  const unsigned MaxLines = DiagOpts.SnippetLineLimit;
   std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
   unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
   for (const auto &I : Ranges) {
@@ -1338,7 +1337,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // Where [number] is MaxLineNoDisplayWidth columns
   // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
   unsigned MaxLineNoDisplayWidth =
-      DiagOpts->ShowLineNumbers
+      DiagOpts.ShowLineNumbers
           ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
           : 0;
   auto indentForLineNumbers = [&] {
@@ -1350,7 +1349,7 @@ void TextDiagnostic::emitSnippetAndCaret(
   // emit, starting from the first line.
   std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
       highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
-                     DiagOpts->ShowColors, FID, SM);
+                     DiagOpts.ShowColors, FID, SM);
 
   SmallVector<LineRange> LineRanges =
       prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
@@ -1382,7 +1381,7 @@ void TextDiagnostic::emitSnippetAndCaret(
       SourceLine.pop_back();
 
     // Build the byte to column map.
-    const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
+    const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
 
     std::string CaretLine;
     // Highlight all of the characters covered by Ranges with ~ characters.
@@ -1398,12 +1397,12 @@ void TextDiagnostic::emitSnippetAndCaret(
       CaretLine[Col] = '^';
     }
 
-    std::string FixItInsertionLine = buildFixItInsertionLine(
-        FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
+    std::string FixItInsertionLine =
+        buildFixItInsertionLine(FID, LineNo, sourceColMap, Hints, SM, DiagOpts);
 
     // If the source line is too long for our terminal, select only the
     // "interesting" source region within that line.
-    unsigned Columns = DiagOpts->MessageLength;
+    unsigned Columns = DiagOpts.MessageLength;
     if (Columns)
       selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
                                     Columns, sourceColMap);
@@ -1412,7 +1411,7 @@ void TextDiagnostic::emitSnippetAndCaret(
     // to produce easily machine parsable output.  Add a space before the
     // source line and the caret to make it trivial to tell the main diagnostic
     // line from what the user is intended to see.
-    if (DiagOpts->ShowSourceRanges && !SourceLine.empty()) {
+    if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
       SourceLine = ' ' + SourceLine;
       CaretLine = ' ' + CaretLine;
     }
@@ -1423,22 +1422,22 @@ void TextDiagnostic::emitSnippetAndCaret(
 
     if (!CaretLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.changeColor(caretColor, true);
       OS << CaretLine << '\n';
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.resetColor();
     }
 
     if (!FixItInsertionLine.empty()) {
       indentForLineNumbers();
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         // Print fixit line in color
         OS.changeColor(fixitColor, false);
-      if (DiagOpts->ShowSourceRanges)
+      if (DiagOpts.ShowSourceRanges)
         OS << ' ';
       OS << FixItInsertionLine << '\n';
-      if (DiagOpts->ShowColors)
+      if (DiagOpts.ShowColors)
         OS.resetColor();
     }
   }
@@ -1464,10 +1463,10 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
   size_t I = 0;
   while (I < SourceLine.size()) {
     auto [Str, WasPrintable] =
-        printableTextForNextCharacter(SourceLine, &I, DiagOpts->TabStop);
+        printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
 
     // Toggle inverted colors on or off for this character.
-    if (DiagOpts->ShowColors) {
+    if (DiagOpts.ShowColors) {
       if (WasPrintable == PrintReversed) {
         PrintReversed = !PrintReversed;
         if (PrintReversed)
@@ -1498,7 +1497,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
     OS << Str;
   }
 
-  if (DiagOpts->ShowColors)
+  if (DiagOpts.ShowColors)
     OS.resetColor();
 
   OS << '\n';
@@ -1506,7 +1505,7 @@ void TextDiagnostic::emitSnippet(StringRef SourceLine,
 
 void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
                                          const SourceManager &SM) {
-  if (!DiagOpts->ShowParseableFixits)
+  if (!DiagOpts.ShowParseableFixits)
     return;
 
   // We follow FixItRewriter's example in not (yet) handling
diff --git a/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 28f7218dc23f5..e878c630fa01d 100644
--- a/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -22,11 +22,9 @@
 using namespace clang;
 
 TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
-                                             DiagnosticOptions *diags,
+                                             DiagnosticOptions &DiagOpts,
                                              bool _OwnsOutputStream)
-  : OS(os), DiagOpts(diags),
-    OwnsOutputStream(_OwnsOutputStream) {
-}
+    : OS(os), DiagOpts(DiagOpts), OwnsOutputStream(_OwnsOutputStream) {}
 
 TextDiagnosticPrinter::~TextDiagnosticPrinter() {
   if (OwnsOutputStream)
@@ -36,7 +34,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() {
 void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
                                             const Preprocessor *PP) {
   // Build the TextDiagnostic utility.
-  TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts, PP));
+  TextDiag.reset(new TextDiagnostic(OS, LO, DiagOpts, PP));
 }
 
 void TextDiagnosticPrinter::EndSourceFile() {
@@ -121,7 +119,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   Info.FormatDiagnostic(OutStr);
 
   llvm::raw_svector_ostream DiagMessageStream(OutStr);
-  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
+  printDiagnosticOptions(DiagMessageStream, Level, Info, DiagOpts);
 
   // Keeps track of the starting position of the location
   // information (e.g., "foo.c:10:4:") that precedes the error
@@ -137,17 +135,16 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
   // diagnostics in a context that lacks language options, a source manager, or
   // other infrastructure necessary when emitting more rich diagnostics.
   if (!Info.getLocation().isValid()) {
-    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
+    TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
     TextDiagnostic::printDiagnosticMessage(
         OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note,
         DiagMessageStream.str(), OS.tell() - StartOfLocationInfo,
-        DiagOpts->MessageLength, DiagOpts->ShowColors);
+        DiagOpts.MessageLength, DiagOpts.ShowColors);
     OS.flush();
     return;
   }
 
   // Assert that the rest of our infrastructure is setup properly.
-  assert(DiagOpts && "Unexpected diagnostic without options set");
   assert(Info.hasSourceManager() &&
          "Unexpected diagnostic with no source manager");
   assert(TextDiag && "Unexpected diagnostic outside source file processing");
diff --git a/clang/lib/Interpreter/CodeCompletion.cpp b/clang/lib/Interpreter/CodeCompletion.cpp
index aa90663538128..dac38887cd0a1 100644
--- a/clang/lib/Interpreter/CodeCompletion.cpp
+++ b/clang/lib/Interpreter/CodeCompletion.cpp
@@ -359,13 +359,12 @@ void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI,
                                      unsigned Col,
                                      const CompilerInstance *ParentCI,
                                      std::vector<std::string> &CCResults) {
-  auto DiagOpts = DiagnosticOptions();
   auto consumer = ReplCompletionConsumer(CCResults, *this);
 
   auto diag = InterpCI->getDiagnosticsPtr();
   std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
       InterpCI->getInvocationPtr(), std::make_shared<PCHContainerOperations>(),
-      diag));
+      nullptr, diag));
   llvm::SmallVector<clang::StoredDiagnostic, 8> sd = {};
   llvm::SmallVector<const llvm::MemoryBuffer *, 1> tb = {};
   InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile(
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 4b407a0172adb..84feff82c63a7 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -95,9 +95,9 @@ CreateCI(const llvm::opt::ArgStringList &Argv) {
 
   // Buffer diagnostics from argument parsing so that we can output them using
   // a well formed diagnostic object.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
   bool Success = CompilerInvocation::CreateFromArgs(
       Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
 
@@ -173,10 +173,10 @@ IncrementalCompilerBuilder::create(std::string TT,
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+  std::unique_ptr<DiagnosticOptions> DiagOpts =
       CreateAndPopulateDiagOpts(ClangArgv);
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagsBuffer);
 
   driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
   Driver.setCheckInputsExist(false); // the input comes from mem buffers
diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp
index c75835df2c98e..1829a4ff3504a 100644
--- a/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/clang/lib/Rewrite/HTMLRewrite.cpp
@@ -636,8 +636,8 @@ static void HighlightMacrosImpl(
   // Temporarily change the diagnostics object so that we ignore any generated
   // diagnostics from this pass.
   DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(),
-                             &PP.getDiagnostics().getDiagnosticOptions(),
-                      new IgnoringDiagConsumer);
+                             PP.getDiagnostics().getDiagnosticOptions(),
+                             new IgnoringDiagConsumer);
 
   // FIXME: This is a huge hack; we reuse the input preprocessor because we want
   // its state, but we aren't actually changing it (we hope). This should really
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d068f5e163176..c113fd7cbb911 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -193,8 +193,7 @@ bool ChainedASTReaderListener::ReadTargetOptions(
 }
 
 bool ChainedASTReaderListener::ReadDiagnosticOptions(
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
-    bool Complain) {
+    DiagnosticOptions &DiagOpts, StringRef ModuleFilename, bool Complain) {
   return First->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain) ||
          Second->ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
@@ -595,16 +594,16 @@ static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr,
   return M;
 }
 
-bool PCHValidator::ReadDiagnosticOptions(
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, StringRef ModuleFilename,
-    bool Complain) {
+bool PCHValidator::ReadDiagnosticOptions(DiagnosticOptions &DiagOpts,
+                                         StringRef ModuleFilename,
+                                         bool Complain) {
   DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-      new DiagnosticsEngine(DiagIDs, DiagOpts.get()));
+      new DiagnosticsEngine(DiagIDs, DiagOpts));
   // This should never fail, because we would have processed these options
   // before writing them to an ASTFile.
-  ProcessWarningOptions(*Diags, *DiagOpts,
+  ProcessWarningOptions(*Diags, DiagOpts,
                         PP.getFileManager().getVirtualFileSystem(),
                         /*Report*/ false);
 
@@ -6422,17 +6421,17 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
 bool ASTReader::ParseDiagnosticOptions(const RecordData &Record,
                                        StringRef ModuleFilename, bool Complain,
                                        ASTReaderListener &Listener) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
   unsigned Idx = 0;
-#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
-#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
-  DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
+#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
+#define ENUM_DIAGOPT(Name, Type, Bits, Default)                                \
+  DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
 #include "clang/Basic/DiagnosticOptions.def"
 
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts->Warnings.push_back(ReadString(Record, Idx));
+    DiagOpts.Warnings.push_back(ReadString(Record, Idx));
   for (unsigned N = Record[Idx++]; N; --N)
-    DiagOpts->Remarks.push_back(ReadString(Record, Idx));
+    DiagOpts.Remarks.push_back(ReadString(Record, Idx));
 
   return Listener.ReadDiagnosticOptions(DiagOpts, ModuleFilename, Complain);
 }
diff --git a/clang/lib/Testing/TestAST.cpp b/clang/lib/Testing/TestAST.cpp
index 748f59b856e83..b59a8d55129de 100644
--- a/clang/lib/Testing/TestAST.cpp
+++ b/clang/lib/Testing/TestAST.cpp
@@ -44,7 +44,7 @@ class StoreDiagnostics : public DiagnosticConsumer {
       std::string Text;
       llvm::raw_string_ostream OS(Text);
       TextDiagnostic Renderer(OS, LangOpts,
-                              &Info.getDiags()->getDiagnosticOptions());
+                              Info.getDiags()->getDiagnosticOptions());
       Renderer.emitStoredDiagnostic(Out.back());
       ADD_FAILURE() << Text;
     }
diff --git a/clang/lib/Tooling/CompilationDatabase.cpp b/clang/lib/Tooling/CompilationDatabase.cpp
index af18194ae0fe4..09596b9799833 100644
--- a/clang/lib/Tooling/CompilationDatabase.cpp
+++ b/clang/lib/Tooling/CompilationDatabase.cpp
@@ -243,13 +243,13 @@ std::string GetClangToolCommand() {
 static bool stripPositionalArgs(std::vector<const char *> Args,
                                 std::vector<std::string> &Result,
                                 std::string &ErrorMsg) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   llvm::raw_string_ostream Output(ErrorMsg);
-  TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(Output, DiagOpts);
   UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagClient, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      &DiagClient, false);
 
   // The clang executable path isn't required since the jobs the driver builds
   // will not be executed.
diff --git a/clang/lib/Tooling/Core/Replacement.cpp b/clang/lib/Tooling/Core/Replacement.cpp
index 92e9859ca206e..9e2582ee53c59 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -585,9 +585,9 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
   SourceManager SourceMgr(Diagnostics, Files);
   Rewriter Rewrite(SourceMgr, LangOptions());
   InMemoryFileSystem->addFile(
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 21eea72b198b3..207b0a96aaf27 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -642,7 +642,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, TUBuffer))
@@ -660,7 +660,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
   auto DiagOpts = createDiagOptions(CommandLine);
-  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release());
+  TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, *DiagOpts);
 
   if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
                           DiagPrinter, ModuleName))
@@ -744,7 +744,7 @@ bool DependencyScanningWorker::scanDependencies(
   sanitizeDiagOpts(*DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(FileMgr->getVirtualFileSystem(),
-                                          DiagOpts.release(), &DC,
+                                          *DiagOpts, &DC,
                                           /*ShouldOwnClient=*/false);
 
   // Although `Diagnostics` are used only for command-line parsing, the
diff --git a/clang/lib/Tooling/Refactoring.cpp b/clang/lib/Tooling/Refactoring.cpp
index 961fc1c180154..874d44ff6731c 100644
--- a/clang/lib/Tooling/Refactoring.cpp
+++ b/clang/lib/Tooling/Refactoring.cpp
@@ -39,11 +39,11 @@ int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
   }
 
   LangOptions DefaultLangOptions;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      &*DiagOpts, &DiagnosticPrinter, false);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), DiagOpts,
+      &DiagnosticPrinter, false);
   SourceManager Sources(Diagnostics, getFiles());
   Rewriter Rewrite(Sources, DefaultLangOptions);
 
diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp
index 3c72f52040142..1abd7c7adb127 100644
--- a/clang/lib/Tooling/Tooling.cpp
+++ b/clang/lib/Tooling/Tooling.cpp
@@ -377,17 +377,17 @@ bool ToolInvocation::run() {
 
   // Parse diagnostic options from the driver command-line only if none were
   // explicitly set.
-  IntrusiveRefCntPtr<DiagnosticOptions> ParsedDiagOpts;
+  std::unique_ptr<DiagnosticOptions> ParsedDiagOpts;
   DiagnosticOptions *DiagOpts = this->DiagOpts;
   if (!DiagOpts) {
     ParsedDiagOpts = CreateAndPopulateDiagOpts(Argv);
     DiagOpts = &*ParsedDiagOpts;
   }
 
-  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts);
+  TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), *DiagOpts);
   IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics =
       CompilerInstance::createDiagnostics(
-          Files->getVirtualFileSystem(), &*DiagOpts,
+          Files->getVirtualFileSystem(), *DiagOpts,
           DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false);
   // Although `Diagnostics` are used only for command-line parsing, the custom
   // `DiagConsumer` might expect a `SourceManager` to be present.
@@ -652,9 +652,9 @@ class ASTBuilderAction : public ToolAction {
                      std::shared_ptr<PCHContainerOperations> PCHContainerOps,
                      DiagnosticConsumer *DiagConsumer) override {
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        Invocation, std::move(PCHContainerOps),
+        Invocation, std::move(PCHContainerOps), nullptr,
         CompilerInstance::createDiagnostics(Files->getVirtualFileSystem(),
-                                            &Invocation->getDiagnosticOpts(),
+                                            Invocation->getDiagnosticOpts(),
                                             DiagConsumer,
                                             /*ShouldOwnClient=*/false),
         Files);
diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp
index 8d023a0b22121..25104304322d4 100644
--- a/clang/tools/c-index-test/core_main.cpp
+++ b/clang/tools/c-index-test/core_main.cpp
@@ -220,9 +220,10 @@ static bool printSourceSymbols(const char *Executable,
   SmallVector<const char *, 4> ArgsWithProgName;
   ArgsWithProgName.push_back(Executable);
   ArgsWithProgName.append(Args.begin(), Args.end());
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions));
+                                          *DiagOpts));
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed?
@@ -241,7 +242,7 @@ static bool printSourceSymbols(const char *Executable,
 
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), PCHContainerOps, Diags, IndexAction.get()));
+      std::move(CInvok), PCHContainerOps, DiagOpts, Diags, IndexAction.get()));
 
   if (!Unit)
     return true;
@@ -274,15 +275,16 @@ static bool printSourceSymbolsFromModule(StringRef modulePath,
 
   HeaderSearchOptions HSOpts;
 
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
-  std::unique_ptr<ASTUnit> AU =
-      ASTUnit::LoadFromASTFile(modulePath, *pchRdr, ASTUnit::LoadASTOnly, Diags,
-                               FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
-                               /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
-                               /*AllowASTWithCompilerErrors=*/true,
-                               /*UserFilesAreVolatile=*/false);
+                                          *DiagOpts);
+  std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
+      modulePath, *pchRdr, ASTUnit::LoadASTOnly, DiagOpts, Diags,
+      FileSystemOpts, HSOpts, /*LangOpts=*/nullptr,
+      /*OnlyLocalDecls=*/true, CaptureDiagsKind::None,
+      /*AllowASTWithCompilerErrors=*/true,
+      /*UserFilesAreVolatile=*/false);
   if (!AU) {
     errs() << "failed to create TU for: " << modulePath << '\n';
     return true;
diff --git a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
index ff684d20c150c..0b621b849e92f 100644
--- a/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
+++ b/clang/tools/clang-extdef-mapping/ClangExtDefMapGen.cpp
@@ -123,21 +123,21 @@ static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
 
 static IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
 
-IntrusiveRefCntPtr<DiagnosticsEngine> GetDiagnosticsEngine() {
+IntrusiveRefCntPtr<DiagnosticsEngine>
+GetDiagnosticsEngine(DiagnosticOptions &DiagOpts) {
   if (Diags) {
     // Call reset to make sure we don't mix errors
     Diags->Reset(false);
     return Diags;
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   TextDiagnosticPrinter *DiagClient =
-      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+      new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
   DiagClient->setPrefix("clang-extdef-mappping");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
   IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
-      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+      new DiagnosticsEngine(DiagID, DiagOpts, DiagClient));
   Diags.swap(DiagEngine);
 
   // Retain this one time so it's not destroyed by ASTUnit::LoadFromASTFile
@@ -152,11 +152,13 @@ static bool HandleAST(StringRef AstPath) {
   if (!CI)
     CI = new CompilerInstance();
 
-  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine = GetDiagnosticsEngine();
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
+  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine =
+      GetDiagnosticsEngine(*DiagOpts);
 
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromASTFile(
       AstPath, CI->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadASTOnly, DiagEngine, CI->getFileSystemOpts(),
+      ASTUnit::LoadASTOnly, DiagOpts, DiagEngine, CI->getFileSystemOpts(),
       CI->getHeaderSearchOpts());
 
   if (!Unit)
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index e40e04eac5472..b22d3aaf3183b 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -240,9 +240,9 @@ static bool fillRanges(MemoryBuffer *Code,
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts);
   SourceManager Sources(Diagnostics, Files);
   FileID ID = createInMemoryFile("<irrelevant>", *Code, Sources, Files,
                                  InMemoryFileSystem.get());
@@ -519,10 +519,10 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
         new llvm::vfs::InMemoryFileSystem);
     FileManager Files(FileSystemOptions(), InMemoryFileSystem);
 
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+    DiagnosticOptions DiagOpts;
     ClangFormatDiagConsumer IgnoreDiagnostics;
     DiagnosticsEngine Diagnostics(
-        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
+        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
         &IgnoreDiagnostics, false);
     SourceManager Sources(Diagnostics, Files);
     FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files,
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 765f342947046..aefc2f5728eda 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -162,10 +162,10 @@ class TestDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions DiagOpts;
   auto DC = std::make_unique<TestDiagnosticConsumer>();
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), DiagOpts.get(), DC.get(),
+      *llvm::vfs::getRealFileSystem(), DiagOpts, DC.get(),
       /*ShouldOwnClient=*/false);
 
   auto Inv = std::make_unique<CompilerInvocation>();
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index 14e7b53d74b09..f68236abaa6c9 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -70,16 +70,16 @@ static bool runFrontend(StringRef ProgName, Twine Label, bool Verbose,
 
 static bool run(ArrayRef<const char *> Args, const char *ProgName) {
   // Setup Diagnostics engine.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   const llvm::opt::OptTable &ClangOpts = clang::driver::getDriverOptTable();
   unsigned MissingArgIndex, MissingArgCount;
   llvm::opt::InputArgList ParsedArgs = ClangOpts.ParseArgs(
       ArrayRef(Args).slice(1), MissingArgIndex, MissingArgCount);
-  ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
+  ParseDiagnosticArgs(DiagOpts, ParsedArgs);
 
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag = new clang::DiagnosticsEngine(
-      new clang::DiagnosticIDs(), DiagOpts.get(),
-      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
+      new clang::DiagnosticIDs(), DiagOpts,
+      new clang::TextDiagnosticPrinter(llvm::errs(), DiagOpts));
 
   // Create file manager for all file operations and holding in-memory generated
   // inputs.
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 3b42267f4d5f4..c17eb9dcadfd7 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -452,11 +452,11 @@ class FullDeps {
   // Returns \c true if any command lines fail to round-trip. We expect
   // commands already be canonical when output by the scanner.
   bool roundTripCommands(raw_ostream &ErrOS) {
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions{};
-    TextDiagnosticPrinter DiagConsumer(ErrOS, &*DiagOpts);
+    DiagnosticOptions DiagOpts;
+    TextDiagnosticPrinter DiagConsumer(ErrOS, DiagOpts);
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
         CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                            &*DiagOpts, &DiagConsumer,
+                                            DiagOpts, &DiagConsumer,
                                             /*ShouldOwnClient=*/false);
 
     for (auto &&M : Modules)
@@ -779,9 +779,10 @@ getCompilationDatabase(int argc, char **argv, std::string &ErrorMessage) {
         CompilationDB, ErrorMessage,
         tooling::JSONCommandLineSyntax::AutoDetect);
 
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions);
+                                          DiagOpts);
   driver::Driver TheDriver(CommandLine[0], llvm::sys::getDefaultTargetTriple(),
                            *Diags);
   TheDriver.setCheckInputsExist(false);
diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp
index 1f32f791de082..0d1455d270436 100644
--- a/clang/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp
@@ -56,6 +56,7 @@ static char getCharForLevel(DiagnosticsEngine::Level Level) {
 static IntrusiveRefCntPtr<DiagnosticsEngine>
 createDiagnostics(unsigned int argc, char **argv) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs());
+  DiagnosticOptions DiagOpts;
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
@@ -66,8 +67,7 @@ createDiagnostics(unsigned int argc, char **argv) {
   Args.push_back("diagtool");
   Args.append(argv, argv + argc);
   CreateInvocationOptions CIOpts;
-  CIOpts.Diags =
-      new DiagnosticsEngine(DiagIDs, new DiagnosticOptions(), DiagsBuffer);
+  CIOpts.Diags = new DiagnosticsEngine(DiagIDs, DiagOpts, DiagsBuffer);
   std::unique_ptr<CompilerInvocation> Invocation =
       createInvocation(Args, CIOpts);
   if (!Invocation)
@@ -76,7 +76,7 @@ createDiagnostics(unsigned int argc, char **argv) {
   // Build the diagnostics parser
   IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          &Invocation->getDiagnosticOpts());
+                                          Invocation->getDiagnosticOpts());
   if (!FinalDiags)
     return nullptr;
 
diff --git a/clang/tools/diagtool/TreeView.cpp b/clang/tools/diagtool/TreeView.cpp
index 8d1ce14b0f520..7e47c748af959 100644
--- a/clang/tools/diagtool/TreeView.cpp
+++ b/clang/tools/diagtool/TreeView.cpp
@@ -31,8 +31,8 @@ class TreePrinter {
 
   static bool isIgnored(unsigned DiagID) {
     // FIXME: This feels like a hack.
-    static clang::DiagnosticsEngine Diags(new DiagnosticIDs,
-                                          new DiagnosticOptions);
+    static DiagnosticOptions DiagOpts;
+    static clang::DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
     return Diags.isIgnored(DiagID, SourceLocation());
   }
 
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 6638a15ff7e12..2c17f28621f5f 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -232,9 +232,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Buffer diagnostics from argument parsing so that we can output them using a
   // well formed diagnostic object.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagsBuffer);
 
   // Setup round-trip remarks for the DiagnosticsEngine used in CreateFromArgs.
   if (find(Argv, StringRef("-Rround-trip-cc1-args")) != Argv.end())
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index ab7ba238bcc57..f938e7e4041e8 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -658,12 +658,12 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   InitializeAllAsmParsers();
 
   // Construct our diagnostic client.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(errs(), DiagOpts);
   DiagClient->setPrefix("clang -cc1as");
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagClient);
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
diff --git a/clang/tools/driver/cc1gen_reproducer_main.cpp b/clang/tools/driver/cc1gen_reproducer_main.cpp
index df59b53f9ef18..8d7171eb2e5e0 100644
--- a/clang/tools/driver/cc1gen_reproducer_main.cpp
+++ b/clang/tools/driver/cc1gen_reproducer_main.cpp
@@ -117,12 +117,12 @@ generateReproducerForInvocationArguments(ArrayRef<const char *> Argv,
   using namespace driver;
   auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Argv[0]);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new IgnoringDiagConsumer());
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new IgnoringDiagConsumer());
   auto VFS = llvm::vfs::getRealFileSystem();
-  ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false);
+  ProcessWarningOptions(Diags, DiagOpts, *VFS, /*ReportDiags=*/false);
   Driver TheDriver(ToolContext.Path, llvm::sys::getDefaultTargetTriple(), Diags,
                    /*Title=*/"clang LLVM compiler", VFS);
   TheDriver.setTargetAndMode(TargetAndMode);
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 82f47ab973064..d21a34e961394 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -321,25 +321,24 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
                            .Case("-fintegrated-cc1", false)
                            .Default(UseNewCC1Process);
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
-      CreateAndPopulateDiagOpts(Args);
+  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Args);
   // Driver's diagnostics don't use suppression mappings, so don't bother
   // parsing them. CC1 still receives full args, so this doesn't impact other
   // actions.
   DiagOpts->DiagnosticSuppressionMappingsFile.clear();
 
-  TextDiagnosticPrinter *DiagClient
-    = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+  TextDiagnosticPrinter *DiagClient =
+      new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
   FixupDiagPrefixExeName(DiagClient, ProgName);
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
 
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
+  DiagnosticsEngine Diags(DiagID, *DiagOpts, DiagClient);
 
   if (!DiagOpts->DiagnosticSerializationFile.empty()) {
     auto SerializedConsumer =
         clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
-                                        &*DiagOpts, /*MergeChildRecords=*/true);
+                                        *DiagOpts, /*MergeChildRecords=*/true);
     Diags.setClient(new ChainedDiagnosticConsumer(
         Diags.takeClient(), std::move(SerializedConsumer)));
   }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 06a17006fdee9..1d9d1027521bc 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -4227,12 +4227,13 @@ enum CXErrorCode clang_createTranslationUnit2(CXIndex CIdx,
   FileSystemOptions FileSystemOpts;
   HeaderSearchOptions HSOpts;
 
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
+                                          *DiagOpts);
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(),
-      ASTUnit::LoadEverything, Diags, FileSystemOpts, HSOpts,
+      ASTUnit::LoadEverything, DiagOpts, Diags, FileSystemOpts, HSOpts,
       /*LangOpts=*/nullptr, CXXIdx->getOnlyLocalDecls(), CaptureDiagsKind::All,
       /*AllowASTWithCompilerErrors=*/true,
       /*UserFilesAreVolatile=*/true);
@@ -4299,11 +4300,11 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
   }
 
   // Configure the diagnostics.
-  std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
+  std::shared_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(
       llvm::ArrayRef(command_line_args, num_command_line_args));
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          DiagOpts.release()));
+                                          *DiagOpts));
 
   if (options & CXTranslationUnit_KeepGoing)
     Diags->setFatalsAsError(true);
@@ -4387,7 +4388,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,
       options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files);
   std::unique_ptr<ASTUnit> Unit = ASTUnit::LoadFromCommandLine(
       Args->data(), Args->data() + Args->size(),
-      CXXIdx->getPCHContainerOperations(), Diags,
+      CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
       CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(),
       CXXIdx->getPreambleStoragePath(), CXXIdx->getOnlyLocalDecls(),
       CaptureDiagnostics, *RemappedFiles,
diff --git a/clang/tools/libclang/CIndexCodeCompletion.cpp b/clang/tools/libclang/CIndexCodeCompletion.cpp
index 850c004680fd9..8f6729b83ffa0 100644
--- a/clang/tools/libclang/CIndexCodeCompletion.cpp
+++ b/clang/tools/libclang/CIndexCodeCompletion.cpp
@@ -256,8 +256,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
   /// Allocated API-exposed wrappters for Diagnostics.
   SmallVector<std::unique_ptr<CXStoredDiagnostic>, 8> DiagnosticsWrappers;
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
-  
+  DiagnosticOptions DiagOpts;
+
   /// Diag object
   IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
   
@@ -356,9 +356,9 @@ static std::atomic<unsigned> CodeCompletionResultObjects;
 
 AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     IntrusiveRefCntPtr<FileManager> FileMgr)
-    : CXCodeCompleteResults(), DiagOpts(new DiagnosticOptions),
+    : CXCodeCompleteResults(),
       Diag(new DiagnosticsEngine(
-          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
+          IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts)),
       FileMgr(std::move(FileMgr)),
       SourceMgr(new SourceManager(*Diag, *this->FileMgr)),
       CodeCompletionAllocator(
@@ -369,7 +369,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
     fprintf(stderr, "+++ %u completion results\n",
             ++CodeCompletionResultObjects);
 }
-  
+
 AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
   delete [] Results;
 
diff --git a/clang/tools/libclang/CIndexDiagnostic.cpp b/clang/tools/libclang/CIndexDiagnostic.cpp
index 92271d9c37f86..d37597e747a84 100644
--- a/clang/tools/libclang/CIndexDiagnostic.cpp
+++ b/clang/tools/libclang/CIndexDiagnostic.cpp
@@ -80,12 +80,11 @@ class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
 };    
     
 class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
-public:  
-  CXDiagnosticRenderer(const LangOptions &LangOpts,
-                       DiagnosticOptions *DiagOpts,
+public:
+  CXDiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts,
                        CXDiagnosticSetImpl *mainSet)
-  : DiagnosticNoteRenderer(LangOpts, DiagOpts),
-    CurrentSet(mainSet), MainSet(mainSet) {}
+      : DiagnosticNoteRenderer(LangOpts, DiagOpts), CurrentSet(mainSet),
+        MainSet(mainSet) {}
 
   ~CXDiagnosticRenderer() override {}
 
@@ -182,10 +181,10 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
   if (!TU->Diagnostics) {
     CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
     TU->Diagnostics = Set;
-    IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
-    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
-                                  &*DOpts, Set);
-    
+    DiagnosticOptions DOpts;
+    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(), DOpts,
+                                  Set);
+
     for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
          ei = AU->stored_diag_end(); it != ei; ++it) {
       Renderer.emitStoredDiagnostic(*it);
diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index e1441bce15f88..3cd49bf90235b 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -480,9 +480,10 @@ static CXErrorCode clang_indexSourceFile_Impl(
     CaptureDiag = new CaptureDiagnosticConsumer();
 
   // Configure the diagnostics.
+  auto DiagOpts = std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions, CaptureDiag,
+                                          *DiagOpts, CaptureDiag,
                                           /*ShouldOwnClient=*/true));
 
   // Recover resources if we crash before exiting this function.
@@ -554,7 +555,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
   CInvok->getHeaderSearchOpts().ModuleFormat = std::string(
       CXXIdx->getPCHContainerOperations()->getRawReader().getFormats().front());
 
-  auto Unit = ASTUnit::create(CInvok, Diags, CaptureDiagnostics,
+  auto Unit = ASTUnit::create(CInvok, DiagOpts, Diags, CaptureDiagnostics,
                               /*UserFilesAreVolatile=*/true);
   if (!Unit)
     return CXError_InvalidArguments;
@@ -617,7 +618,7 @@ static CXErrorCode clang_indexSourceFile_Impl(
       !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse;
   DiagnosticErrorTrap DiagTrap(*Diags);
   bool Success = ASTUnit::LoadFromCompilerInvocationAction(
-      std::move(CInvok), CXXIdx->getPCHContainerOperations(), Diags,
+      std::move(CInvok), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags,
       IndexAction.get(), UPtr, Persistent, CXXIdx->getClangResourcesPath(),
       OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses,
       CacheCodeCompletionResults, /*UserFilesAreVolatile=*/true);
diff --git a/clang/unittests/AST/ASTVectorTest.cpp b/clang/unittests/AST/ASTVectorTest.cpp
index 1c17eb9210ac3..66003b49eccb2 100644
--- a/clang/unittests/AST/ASTVectorTest.cpp
+++ b/clang/unittests/AST/ASTVectorTest.cpp
@@ -27,13 +27,14 @@ class ASTVectorTest : public ::testing::Test {
 protected:
   ASTVectorTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), Idents(LangOpts, nullptr),
         Ctxt(LangOpts, SourceMgr, Idents, Sels, Builtins, TU_Complete) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp
index 22866f0eb23ed..dc10dae7a2f8f 100644
--- a/clang/unittests/AST/CommentLexer.cpp
+++ b/clang/unittests/AST/CommentLexer.cpp
@@ -27,16 +27,14 @@ namespace {
 class CommentLexerTest : public ::testing::Test {
 protected:
   CommentLexerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      Traits(Allocator, CommentOptions()) {
-  }
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentParser.cpp b/clang/unittests/AST/CommentParser.cpp
index aa08b6718e506..67fabe5181798 100644
--- a/clang/unittests/AST/CommentParser.cpp
+++ b/clang/unittests/AST/CommentParser.cpp
@@ -33,16 +33,14 @@ const bool MY_DEBUG = true;
 class CommentParserTest : public ::testing::Test {
 protected:
   CommentParserTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      Traits(Allocator, CommentOptions()) {
-  }
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), Traits(Allocator, CommentOptions()) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   llvm::BumpPtrAllocator Allocator;
diff --git a/clang/unittests/AST/CommentTextTest.cpp b/clang/unittests/AST/CommentTextTest.cpp
index b697828698d85..84ec51a308360 100644
--- a/clang/unittests/AST/CommentTextTest.cpp
+++ b/clang/unittests/AST/CommentTextTest.cpp
@@ -43,7 +43,8 @@ class CommentTextTest : public ::testing::Test {
     // FIXME: technically, merged that we set here is incorrect, but that
     // shouldn't matter.
     RawComment Comment(SourceMgr, CommentRange, EmptyOpts, /*Merged=*/true);
-    DiagnosticsEngine Diags(new DiagnosticIDs, new DiagnosticOptions);
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts);
     return Comment.getFormattedText(SourceMgr, Diags);
   }
 };
diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp b/clang/unittests/AST/ExternalASTSourceTest.cpp
index 807bab1b3dd81..11715bb8ce7cd 100644
--- a/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -51,9 +51,9 @@ bool testExternalASTSource(ExternalASTSource *Source, StringRef FileContents) {
       "test.cc", MemoryBuffer::getMemBuffer(FileContents).release());
   const char *Args[] = { "test.cc" };
 
-  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions InvocationDiagOpts;
   auto InvocationDiags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts.get());
+      *llvm::vfs::getRealFileSystem(), InvocationDiagOpts);
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index 6f69ccbd36552..1dd07834bfd7e 100644
--- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -1388,10 +1388,9 @@ class UncheckedOptionalAccessTest
             unsigned Line = SrcMgr.getPresumedLineNumber(Diag.Range.getBegin());
             DiagnosticLines.insert(Line);
             if (!AnnotationLines.contains(Line)) {
-              IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
-                  new DiagnosticOptions());
+              DiagnosticOptions DiagOpts;
               TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
-                                DiagOpts.get());
+                                DiagOpts);
               TD.emitDiagnostic(FullSourceLoc(Diag.Range.getBegin(), SrcMgr),
                                 DiagnosticsEngine::Error,
                                 "unexpected diagnostic", {Diag.Range}, {});
diff --git a/clang/unittests/Analysis/MacroExpansionContextTest.cpp b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
index 929d4122cdec7..9874ea687f3ed 100644
--- a/clang/unittests/Analysis/MacroExpansionContextTest.cpp
+++ b/clang/unittests/Analysis/MacroExpansionContextTest.cpp
@@ -35,8 +35,8 @@ class MacroExpansionContextTest : public ::testing::Test {
   MacroExpansionContextTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-pc-linux-unknown";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -46,7 +46,7 @@ class MacroExpansionContextTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
index e48f39bf13f44..9da2c58970b84 100644
--- a/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
+++ b/clang/unittests/Analysis/UnsafeBufferUsageTest.cpp
@@ -13,12 +13,13 @@ class UnsafeBufferUsageTest : public ::testing::Test {
 protected:
   UnsafeBufferUsageTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
 };
diff --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp
index 88fa1800f0ff2..b0a034e9af1cd 100644
--- a/clang/unittests/Basic/DiagnosticTest.cpp
+++ b/clang/unittests/Basic/DiagnosticTest.cpp
@@ -46,8 +46,8 @@ using testing::IsEmpty;
 
 // Check that DiagnosticErrorTrap works with SuppressAllDiagnostics.
 TEST(DiagnosticTest, suppressAndTrap) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(),
-                          new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   Diags.setSuppressAllDiagnostics(true);
 
@@ -77,8 +77,8 @@ TEST(DiagnosticTest, suppressAndTrap) {
 // Check that FatalsAsError works as intended
 TEST(DiagnosticTest, fatalsAsError) {
   for (unsigned FatalsAsError = 0; FatalsAsError != 2; ++FatalsAsError) {
-    DiagnosticsEngine Diags(new DiagnosticIDs(),
-                            new DiagnosticOptions,
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                             new IgnoringDiagConsumer());
     Diags.setFatalsAsError(FatalsAsError);
 
@@ -101,7 +101,8 @@ TEST(DiagnosticTest, fatalsAsError) {
 }
 
 TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   Diags.setFatalsAsError(true);
 
@@ -117,7 +118,8 @@ TEST(DiagnosticTest, tooManyErrorsIsAlwaysFatal) {
 
 // Check that soft RESET works as intended
 TEST(DiagnosticTest, softReset) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
 
   unsigned numWarnings = 0U, numErrors = 0U;
@@ -140,7 +142,8 @@ TEST(DiagnosticTest, softReset) {
 }
 
 TEST(DiagnosticTest, diagnosticError) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts,
                           new IgnoringDiagConsumer());
   PartialDiagnostic::DiagStorageAllocator Alloc;
   llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create(
@@ -162,7 +165,8 @@ TEST(DiagnosticTest, diagnosticError) {
 }
 
 TEST(DiagnosticTest, storedDiagEmptyWarning) {
-  DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(new DiagnosticIDs(), DiagOpts);
 
   class CaptureDiagnosticConsumer : public DiagnosticConsumer {
   public:
@@ -192,7 +196,8 @@ class SuppressionMappingTest : public testing::Test {
 protected:
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  DiagnosticsEngine Diags{new DiagnosticIDs(), new DiagnosticOptions};
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags{new DiagnosticIDs(), DiagOpts};
 
   llvm::ArrayRef<StoredDiagnostic> diags() {
     return CaptureConsumer.StoredDiags;
diff --git a/clang/unittests/Basic/SarifTest.cpp b/clang/unittests/Basic/SarifTest.cpp
index febfbabe8695e..ad9f8ecc208a4 100644
--- a/clang/unittests/Basic/SarifTest.cpp
+++ b/clang/unittests/Basic/SarifTest.cpp
@@ -43,14 +43,14 @@ class SarifDocumentWriterTest : public ::testing::Test {
   SarifDocumentWriterTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr) {}
 
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp
index 1f0986f61dfa9..cbe047b5e599a 100644
--- a/clang/unittests/Basic/SourceManagerTest.cpp
+++ b/clang/unittests/Basic/SourceManagerTest.cpp
@@ -40,11 +40,9 @@ namespace {
 class SourceManagerTest : public ::testing::Test {
 protected:
   SourceManagerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions) {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -52,6 +50,7 @@ class SourceManagerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp
index 616c07c0d389d..f6845939d04b4 100644
--- a/clang/unittests/Driver/DXCModeTest.cpp
+++ b/clang/unittests/Driver/DXCModeTest.cpp
@@ -64,8 +64,8 @@ TEST(DxcModeTest, TargetProfileValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
 
   validateTargetProfile("-Tvs_6_0", "dxilv1.0--shadermodel6.0-vertex",
                         InMemoryFileSystem, Diags);
@@ -114,8 +114,8 @@ TEST(DxcModeTest, ValidatorVersionValidation) {
                               llvm::MemoryBuffer::getMemBuffer("\n"));
 
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
   Driver TheDriver("/bin/clang", "", Diags, "", InMemoryFileSystem);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"clang", "--driver-mode=dxc", "-Tlib_6_7", "foo.hlsl"}));
@@ -218,9 +218,9 @@ TEST(DxcModeTest, DefaultEntry) {
 
   const char *Args[] = {"clang", "--driver-mode=dxc", "-Tcs_6_7", "foo.hlsl"};
 
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*InMemoryFileSystem,
-                                          new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*InMemoryFileSystem, DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Driver/SanitizerArgsTest.cpp b/clang/unittests/Driver/SanitizerArgsTest.cpp
index 5a4221023c950..b8bfc6806da6d 100644
--- a/clang/unittests/Driver/SanitizerArgsTest.cpp
+++ b/clang/unittests/Driver/SanitizerArgsTest.cpp
@@ -52,10 +52,9 @@ class SanitizerArgsTest : public ::testing::Test {
                                           std::vector<std::string> ExtraFiles) {
     assert(!DriverInstance && "Running twice is not allowed");
 
-    llvm::IntrusiveRefCntPtr<DiagnosticOptions> Opts = new DiagnosticOptions;
-    DiagnosticsEngine Diags(
-        new DiagnosticIDs, Opts,
-        new TextDiagnosticPrinter(llvm::errs(), Opts.get()));
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(new DiagnosticIDs, DiagOpts,
+                            new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
     DriverInstance.emplace(ClangBinary, "x86_64-unknown-linux-gnu", Diags,
                            "clang LLVM compiler", prepareFS(ExtraFiles));
 
diff --git a/clang/unittests/Driver/SimpleDiagnosticConsumer.h b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
index 6515bdedb3d5d..c3772baade566 100644
--- a/clang/unittests/Driver/SimpleDiagnosticConsumer.h
+++ b/clang/unittests/Driver/SimpleDiagnosticConsumer.h
@@ -47,9 +47,8 @@ inline clang::driver::Driver diagnostic_test_driver() {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   auto *DiagConsumer = new SimpleDiagnosticConsumer;
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
-      new clang::DiagnosticOptions();
-  clang::DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer);
+  clang::DiagnosticOptions DiagOpts;
+  clang::DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer);
   return clang::driver::Driver("/bin/clang", "", Diags, "", InMemoryFileSystem);
 }
 
diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp
index c1ffe4a82ce4b..670090a01b0d3 100644
--- a/clang/unittests/Driver/ToolChainTest.cpp
+++ b/clang/unittests/Driver/ToolChainTest.cpp
@@ -38,7 +38,7 @@ using namespace clang::driver;
 namespace {
 
 TEST(ToolChainTest, VFSGCCInstallation) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -84,7 +84,7 @@ TEST(ToolChainTest, VFSGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -107,7 +107,8 @@ TEST(ToolChainTest, VFSGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticOptions DiagOpts;
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -134,11 +135,11 @@ TEST(ToolChainTest, VFSGCCInstallation) {
 }
 
 TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -173,7 +174,7 @@ TEST(ToolChainTest, VFSGCCInstallationRelativeDir) {
 }
 
 TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -201,7 +202,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "i386-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -225,7 +226,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "amd64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -249,7 +250,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-pc-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -273,7 +274,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
   }
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparc-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -296,7 +297,7 @@ TEST(ToolChainTest, VFSSolarisMultiGCCInstallation) {
               S);
   }
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "sparcv9-sun-solaris2.11", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(
@@ -337,7 +338,7 @@ MATCHER_P(jobHasArgs, Substr, "") {
 }
 
 TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
@@ -355,7 +356,7 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
                                 llvm::MemoryBuffer::getMemBuffer("\n"));
 
   {
-    DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+    DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
     Driver TheDriver("/bin/clang", "x86_64-unknown-linux-gnu", Diags,
                      "clang LLVM compiler", InMemoryFileSystem);
     std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
@@ -368,11 +369,11 @@ TEST(ToolChainTest, VFSGnuLibcxxPathNoSysroot) {
 }
 
 TEST(ToolChainTest, DefaultDriverMode) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -403,8 +404,8 @@ TEST(ToolChainTest, DefaultDriverMode) {
 TEST(ToolChainTest, InvalidArgument) {
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   Driver TheDriver("/bin/clang", "arm-linux-gnueabihf", Diags);
   std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(
       {"-fsyntax-only", "-fan-unknown-option", "foo.cpp"}));
@@ -514,11 +515,11 @@ TEST(ToolChainTest, GetTargetAndMode) {
 }
 
 TEST(ToolChainTest, CommandOutput) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
 
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -543,10 +544,10 @@ TEST(ToolChainTest, CommandOutput) {
 }
 
 TEST(ToolChainTest, PostCallback) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -596,10 +597,10 @@ TEST(ToolChainTest, UEFICallingConventionTest) {
 }
 
 TEST(ToolChainTest, UEFIDefaultDebugFormatTest) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
       new llvm::vfs::InMemoryFileSystem);
   Driver CCDriver("/home/test/bin/clang", "x86_64-unknown-uefi", Diags,
@@ -638,10 +639,10 @@ struct SimpleDiagnosticConsumer : public DiagnosticConsumer {
 };
 
 TEST(ToolChainTest, ConfigFileSearch) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -715,11 +716,11 @@ struct FileSystemWithError : public llvm::vfs::FileSystem {
 };
 
 TEST(ToolChainTest, ConfigFileError) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS(new FileSystemWithError);
 
   Driver TheDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags,
@@ -736,11 +737,11 @@ TEST(ToolChainTest, ConfigFileError) {
 }
 
 TEST(ToolChainTest, BadConfigFile) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -810,11 +811,11 @@ TEST(ToolChainTest, BadConfigFile) {
 }
 
 TEST(ToolChainTest, ConfigInexistentInclude) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -851,11 +852,11 @@ TEST(ToolChainTest, ConfigInexistentInclude) {
 }
 
 TEST(ToolChainTest, ConfigRecursiveInclude) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   std::unique_ptr<SimpleDiagnosticConsumer> DiagConsumer(
       new SimpleDiagnosticConsumer());
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagConsumer.get(), false);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, DiagConsumer.get(), false);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
@@ -897,10 +898,10 @@ TEST(ToolChainTest, ConfigRecursiveInclude) {
 }
 
 TEST(ToolChainTest, NestedConfigFile) {
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   struct TestDiagnosticConsumer : public DiagnosticConsumer {};
-  DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer);
+  DiagnosticsEngine Diags(DiagID, DiagOpts, new TestDiagnosticConsumer);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem);
 
diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp
index 08daca9111e64..afa64b5e90a6d 100644
--- a/clang/unittests/Frontend/ASTUnitTest.cpp
+++ b/clang/unittests/Frontend/ASTUnitTest.cpp
@@ -30,6 +30,8 @@ class ASTUnitTest : public ::testing::Test {
   int FD;
   llvm::SmallString<256> InputFileName;
   std::unique_ptr<ToolOutputFile> input_file;
+  std::shared_ptr<DiagnosticOptions> DiagOpts =
+      std::make_shared<DiagnosticOptions>();
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   std::shared_ptr<CompilerInvocation> CInvok;
   std::shared_ptr<PCHContainerOperations> PCHContainerOps;
@@ -43,7 +45,7 @@ class ASTUnitTest : public ::testing::Test {
     const char *Args[] = {"clang", "-xc++", InputFileName.c_str()};
 
     auto VFS = llvm::vfs::getRealFileSystem();
-    Diags = CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+    Diags = CompilerInstance::createDiagnostics(*VFS, *DiagOpts);
 
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
@@ -57,8 +59,8 @@ class ASTUnitTest : public ::testing::Test {
     PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
     return ASTUnit::LoadFromCompilerInvocation(
-        CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None,
-        0, TU_Complete, false, false, isVolatile);
+        CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None, 0, TU_Complete, false, false, isVolatile);
   }
 };
 
@@ -95,7 +97,7 @@ TEST_F(ASTUnitTest, SaveLoadPreservesLangOptionsInPrintingPolicy) {
 
   std::unique_ptr<ASTUnit> AU = ASTUnit::LoadFromASTFile(
       ASTFileName, PCHContainerOps->getRawReader(), ASTUnit::LoadEverything,
-      Diags, FileSystemOptions(), HSOpts);
+      DiagOpts, Diags, FileSystemOptions(), HSOpts);
 
   if (!AU)
     FAIL() << "failed to load ASTUnit";
@@ -136,8 +138,7 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
 
   const char *Args[] = {"clang", "test.cpp", "-fmodule-map-file=m.modulemap",
                         "-fmodule-name=M"};
-  Diags =
-      CompilerInstance::createDiagnostics(*InMemoryFs, new DiagnosticOptions());
+  Diags = CompilerInstance::createDiagnostics(*InMemoryFs, *DiagOpts);
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
   CInvok = createInvocation(Args, std::move(CIOpts));
@@ -147,8 +148,8 @@ TEST_F(ASTUnitTest, ModuleTextualHeader) {
   PCHContainerOps = std::make_shared<PCHContainerOperations>();
 
   auto AU = ASTUnit::LoadFromCompilerInvocation(
-      CInvok, PCHContainerOps, Diags, FileMgr, false, CaptureDiagsKind::None, 1,
-      TU_Complete, false, false, false);
+      CInvok, PCHContainerOps, DiagOpts, Diags, FileMgr, false,
+      CaptureDiagsKind::None, 1, TU_Complete, false, false, false);
   ASSERT_TRUE(AU);
   auto File = AU->getFileManager().getFileRef("Textual.h", false, false);
   ASSERT_TRUE(bool(File));
@@ -166,15 +167,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) {
   const char *Args[] = {"clang", "-target", "foobar", InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
+      *llvm::vfs::getRealFileSystem(), *DiagOpts);
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
-      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
-      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
-      &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
+      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
+      false, SkipFunctionBodiesScope::None, false, true, false, false,
+      std::nullopt, &ErrUnit, nullptr);
 
   ASSERT_EQ(AST, nullptr);
   ASSERT_NE(ErrUnit, nullptr);
@@ -194,15 +195,15 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) {
                         InputFileName.c_str()};
 
   auto Diags = CompilerInstance::createDiagnostics(
-      *llvm::vfs::getRealFileSystem(), new DiagnosticOptions());
+      *llvm::vfs::getRealFileSystem(), *DiagOpts);
   auto PCHContainerOps = std::make_shared<PCHContainerOperations>();
   std::unique_ptr<clang::ASTUnit> ErrUnit;
 
   std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCommandLine(
-      &Args[0], &Args[4], PCHContainerOps, Diags, "", false, "", false,
-      CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false,
-      SkipFunctionBodiesScope::None, false, true, false, false, std::nullopt,
-      &ErrUnit, nullptr);
+      &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "",
+      false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false,
+      false, SkipFunctionBodiesScope::None, false, true, false, false,
+      std::nullopt, &ErrUnit, nullptr);
 
   ASSERT_NE(AST, nullptr);
   ASSERT_FALSE(Diags->hasErrorOccurred());
diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp
index 6e9a6f5f728a5..a7b258d5e537e 100644
--- a/clang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -53,9 +53,10 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
   const std::string VFSArg = "-ivfsoverlay" + FileNameStr;
   const char *Args[] = {"clang", VFSArg.c_str(), "-xc++", "-"};
 
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       CompilerInstance::createDiagnostics(*llvm::vfs::getRealFileSystem(),
-                                          new DiagnosticOptions());
+                                          DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
@@ -76,17 +77,17 @@ TEST(CompilerInstance, DefaultVFSOverlayFromInvocation) {
 }
 
 TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
-  auto DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
   // ensures that a chained diagnostic consumer is created so that the test can
   // exercise the unowned diagnostic consumer in a chained consumer.
-  DiagOpts->DiagnosticLogFile = "-";
+  DiagOpts.DiagnosticLogFile = "-";
 
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
   CompilerInstance Instance;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
       Instance.createDiagnostics(*llvm::vfs::getRealFileSystem(), DiagOpts,
diff --git a/clang/unittests/Frontend/CompilerInvocationTest.cpp b/clang/unittests/Frontend/CompilerInvocationTest.cpp
index 94ab9fe8451e0..75390aa42d00e 100644
--- a/clang/unittests/Frontend/CompilerInvocationTest.cpp
+++ b/clang/unittests/Frontend/CompilerInvocationTest.cpp
@@ -29,6 +29,7 @@ using ::testing::StartsWith;
 namespace {
 class CommandLineTest : public ::testing::Test {
 public:
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   SmallVector<const char *, 32> GeneratedArgs;
   BumpPtrAllocator Alloc;
@@ -41,7 +42,7 @@ class CommandLineTest : public ::testing::Test {
 
   CommandLineTest()
       : Diags(CompilerInstance::createDiagnostics(
-            *llvm::vfs::getRealFileSystem(), new DiagnosticOptions(),
+            *llvm::vfs::getRealFileSystem(), DiagOpts,
             new TextDiagnosticBuffer())),
         StringPool(Alloc) {}
 };
diff --git a/clang/unittests/Frontend/OutputStreamTest.cpp b/clang/unittests/Frontend/OutputStreamTest.cpp
index 0eda3a1dab403..dfb5a544cb88a 100644
--- a/clang/unittests/Frontend/OutputStreamTest.cpp
+++ b/clang/unittests/Frontend/OutputStreamTest.cpp
@@ -61,10 +61,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamShared) {
   raw_string_ostream VerboseStream(VerboseBuffer);
 
   Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
-  Compiler.createDiagnostics(
-      *llvm::vfs::getRealFileSystem(),
-      new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+  DiagnosticOptions DiagOpts;
+  Compiler.createDiagnostics(*llvm::vfs::getRealFileSystem(),
+                             new TextDiagnosticPrinter(llvm::nulls(), DiagOpts),
+                             true);
   Compiler.setVerboseOutputStream(VerboseStream);
 
   bool Success = ExecuteCompilerInvocation(&Compiler);
@@ -91,10 +91,10 @@ TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) {
         std::make_unique<raw_string_ostream>(VerboseBuffer);
 
     Compiler.setOutputStream(std::make_unique<raw_null_ostream>());
-    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+    DiagnosticOptions DiagOpts;
     Compiler.createDiagnostics(
         *llvm::vfs::getRealFileSystem(),
-        new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+        new TextDiagnosticPrinter(llvm::nulls(), DiagOpts), true);
     Compiler.setVerboseOutputStream(std::move(VerboseStream));
 
     Success = ExecuteCompilerInvocation(&Compiler);
diff --git a/clang/unittests/Frontend/PCHPreambleTest.cpp b/clang/unittests/Frontend/PCHPreambleTest.cpp
index 58ec2e2ce7058..faad408193f62 100644
--- a/clang/unittests/Frontend/PCHPreambleTest.cpp
+++ b/clang/unittests/Frontend/PCHPreambleTest.cpp
@@ -53,6 +53,8 @@ class PCHPreambleTest : public ::testing::Test {
   IntrusiveRefCntPtr<ReadCountingInMemoryFileSystem> VFS;
   StringMap<std::string> RemappedFiles;
   std::shared_ptr<PCHContainerOperations> PCHContainerOpts;
+  std::shared_ptr<DiagnosticOptions> DiagOpts =
+      std::make_shared<DiagnosticOptions>();
   FileSystemOptions FSOpts;
 
 public:
@@ -95,13 +97,14 @@ class PCHPreambleTest : public ::testing::Test {
     PPOpts.RemappedFilesKeepOriginalName = true;
 
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
+        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(FSOpts, VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
+        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
index b0f2d51b80b9e..1b8051f80e9b8 100644
--- a/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
+++ b/clang/unittests/Frontend/ReparseWorkingDirTest.cpp
@@ -57,14 +57,16 @@ class ReparseWorkingDirTest : public ::testing::Test {
     CI->getFileSystemOpts().WorkingDir = *VFS->getCurrentWorkingDirectory();
     CI->getTargetOpts().Triple = "i386-unknown-linux-gnu";
 
+    auto DiagOpts = std::make_shared<DiagnosticOptions>();
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions,
+        CompilerInstance::createDiagnostics(*VFS, *DiagOpts,
                                             new DiagnosticConsumer));
 
     FileManager *FileMgr = new FileManager(CI->getFileSystemOpts(), VFS);
 
     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
-        CI, PCHContainerOpts, Diags, FileMgr, false, CaptureDiagsKind::None,
+        CI, PCHContainerOpts, DiagOpts, Diags, FileMgr, false,
+        CaptureDiagsKind::None,
         /*PrecompilePreambleAfterNParses=*/1);
     return AST;
   }
diff --git a/clang/unittests/Frontend/SearchPathTest.cpp b/clang/unittests/Frontend/SearchPathTest.cpp
index 2ebe74d47eb02..c74a5c75fada5 100644
--- a/clang/unittests/Frontend/SearchPathTest.cpp
+++ b/clang/unittests/Frontend/SearchPathTest.cpp
@@ -40,12 +40,12 @@ namespace {
 class SearchPathTest : public ::testing::Test {
 protected:
   SearchPathTest()
-      : Diags(new DiagnosticIDs(), new DiagnosticOptions,
-              new IgnoringDiagConsumer()),
+      : Diags(new DiagnosticIDs(), DiagOpts, new IgnoringDiagConsumer()),
         VFS(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), VFS), SourceMgr(Diags, FileMgr),
         Invocation(std::make_unique<CompilerInvocation>()) {}
 
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
   FileManager FileMgr;
diff --git a/clang/unittests/Frontend/TextDiagnosticTest.cpp b/clang/unittests/Frontend/TextDiagnosticTest.cpp
index fef5726f053f1..8fd8187134b63 100644
--- a/clang/unittests/Frontend/TextDiagnosticTest.cpp
+++ b/clang/unittests/Frontend/TextDiagnosticTest.cpp
@@ -20,13 +20,12 @@ namespace {
 
 /// Prints a diagnostic with the given DiagnosticOptions and the given
 /// SourceLocation and returns the printed diagnostic text.
-static std::string PrintDiag(const DiagnosticOptions &Opts, FullSourceLoc Loc) {
+static std::string PrintDiag(DiagnosticOptions &Opts, FullSourceLoc Loc) {
   std::string Out;
   llvm::raw_string_ostream OS(Out);
   clang::LangOptions LangOpts;
   // Owned by TextDiagnostic.
-  DiagnosticOptions *DiagOpts = new DiagnosticOptions(Opts);
-  TextDiagnostic Diag(OS, LangOpts, DiagOpts);
+  TextDiagnostic Diag(OS, LangOpts, Opts);
   // Emit a dummy diagnostic that is just 'message'.
   Diag.emitDiagnostic(Loc, DiagnosticsEngine::Level::Warning, "message",
                       /*Ranges=*/{}, /*FixItHints=*/{});
@@ -38,7 +37,8 @@ TEST(TextDiagnostic, ShowLine) {
   FileSystemOptions FSOpts;
   FileManager FileMgr(FSOpts);
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs);
-  DiagnosticsEngine DiagEngine(DiagID, new DiagnosticOptions,
+  DiagnosticOptions DiagEngineOpts;
+  DiagnosticsEngine DiagEngine(DiagID, DiagEngineOpts,
                                new IgnoringDiagConsumer());
   SourceManager SrcMgr(DiagEngine, FileMgr);
 
diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp
index 47ca3210ab596..cf385a5323c61 100644
--- a/clang/unittests/Frontend/UtilsTest.cpp
+++ b/clang/unittests/Frontend/UtilsTest.cpp
@@ -26,11 +26,12 @@ TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
   std::vector<const char *> Args = {"clang", "--target=macho", "-arch",  "i386",
                                     "-arch", "x86_64",         "foo.cpp"};
   clang::IgnoringDiagConsumer D;
+  clang::DiagnosticOptions DiagOpts;
   CreateInvocationOptions Opts;
   Opts.RecoverOnError = true;
   Opts.VFS = new llvm::vfs::InMemoryFileSystem();
-  Opts.Diags = clang::CompilerInstance::createDiagnostics(
-      *Opts.VFS, new DiagnosticOptions, &D, false);
+  Opts.Diags = clang::CompilerInstance::createDiagnostics(*Opts.VFS, DiagOpts,
+                                                          &D, false);
   std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
   ASSERT_TRUE(CI);
   EXPECT_THAT(CI->getTargetOpts().Triple, testing::StartsWith("i386-"));
@@ -45,9 +46,9 @@ TEST(BuildCompilerInvocationTest, ProbePrecompiled) {
   FS->addFile("foo.h.pch", 0, llvm::MemoryBuffer::getMemBuffer(""));
 
   clang::IgnoringDiagConsumer D;
+  clang::DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
-      clang::CompilerInstance::createDiagnostics(*FS, new DiagnosticOptions, &D,
-                                                 false);
+      clang::CompilerInstance::createDiagnostics(*FS, DiagOpts, &D, false);
   // Default: ProbePrecompiled=false
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = CommandLineDiagsEngine;
diff --git a/clang/unittests/Interpreter/InterpreterTest.cpp b/clang/unittests/Interpreter/InterpreterTest.cpp
index 03b9c33232080..b97f5ae17c9f0 100644
--- a/clang/unittests/Interpreter/InterpreterTest.cpp
+++ b/clang/unittests/Interpreter/InterpreterTest.cpp
@@ -95,8 +95,9 @@ TEST_F(InterpreterTest, Errors) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto Err = Interp->Parse("intentional_error v1 = 42; ").takeError();
@@ -126,8 +127,9 @@ TEST_F(InterpreterTest, DeclsAndStatements) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
   auto R1 = Interp->Parse(
@@ -148,8 +150,9 @@ TEST_F(InterpreterTest, UndoCommand) {
   // Create the diagnostic engine with unowned consumer.
   std::string DiagnosticOutput;
   llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
-  auto DiagPrinter = std::make_unique<TextDiagnosticPrinter>(
-      DiagnosticsOS, new DiagnosticOptions());
+  DiagnosticOptions DiagOpts;
+  auto DiagPrinter =
+      std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS, DiagOpts);
 
   auto Interp = createInterpreter(ExtraArgs, DiagPrinter.get());
 
diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp b/clang/unittests/Lex/HeaderSearchTest.cpp
index b8896261703cd..9903c1246d33d 100644
--- a/clang/unittests/Lex/HeaderSearchTest.cpp
+++ b/clang/unittests/Lex/HeaderSearchTest.cpp
@@ -30,7 +30,7 @@ class HeaderSearchTest : public ::testing::Test {
   HeaderSearchTest()
       : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS),
         DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
         Search(HSOpts, SourceMgr, Diags, LangOpts, Target.get()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
@@ -81,6 +81,7 @@ class HeaderSearchTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp
index 9806d4c7bf145..381755d4d1b6f 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -41,12 +41,9 @@ using testing::ElementsAre;
 class LexerTest : public ::testing::Test {
 protected:
   LexerTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions)
-  {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -104,6 +101,7 @@ class LexerTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/ModuleDeclStateTest.cpp b/clang/unittests/Lex/ModuleDeclStateTest.cpp
index 6fbc6bff12d8a..6ecba4de3187c 100644
--- a/clang/unittests/Lex/ModuleDeclStateTest.cpp
+++ b/clang/unittests/Lex/ModuleDeclStateTest.cpp
@@ -55,7 +55,7 @@ class ModuleDeclStateTest : public ::testing::Test {
 protected:
   ModuleDeclStateTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-unknown-linux-gnu";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -94,6 +94,7 @@ class ModuleDeclStateTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   std::shared_ptr<TargetOptions> TargetOpts;
diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp
index c2a84d974dd39..af86c1888f2c7 100644
--- a/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -135,8 +135,8 @@ class PPCallbacksTest : public ::testing::Test {
   PPCallbacksTest()
       : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
         FileMgr(FileSystemOptions(), InMemoryFileSystem),
-        DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
-        Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
+        DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -145,7 +145,7 @@ class PPCallbacksTest : public ::testing::Test {
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
@@ -437,7 +437,7 @@ TEST_F(PPCallbacksTest, FileNotFoundSkipped) {
   HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get());
 
   DiagnosticConsumer *DiagConsumer = new DiagnosticConsumer;
-  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts.get(), DiagConsumer);
+  DiagnosticsEngine FileNotFoundDiags(DiagID, DiagOpts, DiagConsumer);
   Preprocessor PP(PPOpts, FileNotFoundDiags, LangOpts, SourceMgr, HeaderInfo,
                   ModLoader, /*IILookup=*/nullptr, /*OwnsHeaderSearch=*/false);
   PP.Initialize(*Target);
diff --git a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 5c3ce6fa33012..54c1d020aa0ea 100644
--- a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -29,12 +29,9 @@ namespace {
 class PPConditionalDirectiveRecordTest : public ::testing::Test {
 protected:
   PPConditionalDirectiveRecordTest()
-    : FileMgr(FileMgrOpts),
-      DiagID(new DiagnosticIDs()),
-      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
-      SourceMgr(Diags, FileMgr),
-      TargetOpts(new TargetOptions)
-  {
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
   }
@@ -42,6 +39,7 @@ class PPConditionalDirectiveRecordTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
index 74e3c00b451ba..061cb136a552a 100644
--- a/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
+++ b/clang/unittests/Lex/PPDependencyDirectivesTest.cpp
@@ -32,7 +32,7 @@ class PPDependencyDirectivesTest : public ::testing::Test {
 protected:
   PPDependencyDirectivesTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-macos12";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -41,6 +41,7 @@ class PPDependencyDirectivesTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
index 304a66ab96caa..4d83003e28b36 100644
--- a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
+++ b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
@@ -28,7 +28,7 @@ class PPMemoryAllocationsTest : public ::testing::Test {
 protected:
   PPMemoryAllocationsTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
+        Diags(DiagID, DiagOpts, new IgnoringDiagConsumer()),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
     Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
@@ -37,6 +37,7 @@ class PPMemoryAllocationsTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
   LangOptions LangOpts;
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 7d03dda1f516b..912e96e5700aa 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -67,8 +67,7 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
 protected:
   ParseHLSLRootSignatureTest()
       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
-        Consumer(new ExpectedDiagConsumer()),
-        Diags(DiagID, new DiagnosticOptions, Consumer),
+        Consumer(new ExpectedDiagConsumer()), Diags(DiagID, DiagOpts, Consumer),
         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
     // This is an arbitrarily chosen target triple to create the target info.
     TargetOpts->Triple = "dxil";
@@ -95,6 +94,7 @@ class ParseHLSLRootSignatureTest : public ::testing::Test {
   FileSystemOptions FileMgrOpts;
   FileManager FileMgr;
   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  DiagnosticOptions DiagOpts;
   ExpectedDiagConsumer *Consumer;
   DiagnosticsEngine Diags;
   SourceManager SourceMgr;
diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
index c68a71ae05d3f..5a04f42697b99 100644
--- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp
+++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp
@@ -59,9 +59,9 @@ class NoloadLookupTest : public ::testing::Test {
 
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     std::string CacheBMIPath =
diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
index 16742a6cb01e8..970eeef3c953e 100644
--- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
+++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp
@@ -66,9 +66,9 @@ export int aa = 43;
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
 
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     const char *Args[] = {"clang++",       "-std=c++20",
@@ -106,9 +106,9 @@ export int aa = 43;
   {
     CreateInvocationOptions CIOpts;
     CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*CIOpts.VFS,
-                                            new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
     CIOpts.Diags = Diags;
 
     std::string BMIPath = llvm::Twine(TestDir + "/a.pcm").str();
diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
index d62d669149f51..631547431ce7c 100644
--- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
+++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp
@@ -53,8 +53,9 @@ class LoadSpecLazilyTest : public ::testing::Test {
 
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
         llvm::vfs::createPhysicalFileSystem();
+    DiagnosticOptions DiagOpts;
     IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-        CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+        CompilerInstance::createDiagnostics(*VFS, DiagOpts);
     CreateInvocationOptions CIOpts;
     CIOpts.Diags = Diags;
     CIOpts.VFS = VFS;
diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp
index 38003e93c5d9d..de6e13a738cb8 100644
--- a/clang/unittests/Serialization/ModuleCacheTest.cpp
+++ b/clang/unittests/Serialization/ModuleCacheTest.cpp
@@ -108,8 +108,9 @@ TEST_F(ModuleCacheTest, CachedModuleNewPath) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
@@ -157,8 +158,9 @@ TEST_F(ModuleCacheTest, CachedModuleNewPathAllowErrors) {
   MCPArg.append(ModuleCachePath);
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   // First run should pass with no errors
diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp
index 3aaaa548c6eff..05efeef990d43 100644
--- a/clang/unittests/Serialization/NoCommentsTest.cpp
+++ b/clang/unittests/Serialization/NoCommentsTest.cpp
@@ -85,8 +85,9 @@ void foo() {}
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   std::string CacheBMIPath = llvm::Twine(TestDir + "/Comments.pcm").str();
diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
index 7a037d22d5c0d..c43520f79b02c 100644
--- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
+++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp
@@ -77,8 +77,9 @@ export using ::E;
 
   IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
       llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*VFS, DiagOpts);
 
   CreateInvocationOptions CIOpts;
   CIOpts.Diags = Diags;
diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
index 33c3c6b5e61fd..5b2988ed26336 100644
--- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
+++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp
@@ -92,8 +92,9 @@ export namespace Fibonacci
 
   CreateInvocationOptions CIOpts;
   CIOpts.VFS = llvm::vfs::createPhysicalFileSystem();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      CompilerInstance::createDiagnostics(*CIOpts.VFS, new DiagnosticOptions());
+      CompilerInstance::createDiagnostics(*CIOpts.VFS, DiagOpts);
   CIOpts.Diags = Diags;
 
   const char *Args[] = {"clang++",       "-std=c++20",
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index a92b0eb11c423..85d36b5d21423 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -58,9 +58,9 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
 
   auto Invocation = std::make_shared<CompilerInvocation>();
   std::vector<const char *> Args = {Standard.data(), File.data()};
-  auto InvocationDiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
+  DiagnosticOptions InvocationDiagOpts;
   auto InvocationDiags =
-      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts.get());
+      CompilerInstance::createDiagnostics(*FS, InvocationDiagOpts);
   CompilerInvocation::CreateFromArgs(*Invocation, Args, *InvocationDiags);
 
   CompilerInstance Compiler(std::move(Invocation));
diff --git a/clang/unittests/Tooling/RewriterTestContext.h b/clang/unittests/Tooling/RewriterTestContext.h
index b7aa1a133c83e..2d697e276c5e8 100644
--- a/clang/unittests/Tooling/RewriterTestContext.h
+++ b/clang/unittests/Tooling/RewriterTestContext.h
@@ -49,9 +49,8 @@ struct RewriterDiagnosticConsumer : public DiagnosticConsumer {
 class RewriterTestContext {
  public:
    RewriterTestContext()
-       : DiagOpts(new DiagnosticOptions()),
-         Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-                     &*DiagOpts),
+       : Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+                     DiagOpts),
          InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
          OverlayFileSystem(
              new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())),
@@ -61,7 +60,7 @@ class RewriterTestContext {
      // FIXME: To make these tests truly in-memory, we need to overlay the
      // builtin headers.
      OverlayFileSystem->pushOverlay(InMemoryFileSystem);
-  }
+   }
 
   ~RewriterTestContext() {}
 
@@ -124,7 +123,7 @@ class RewriterTestContext {
     return std::string((*FileBuffer)->getBuffer());
   }
 
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+  DiagnosticOptions DiagOpts;
   DiagnosticsEngine Diagnostics;
   RewriterDiagnosticConsumer DiagnosticPrinter;
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp
index d42273be1858c..b5f44454e862d 100644
--- a/clang/unittests/Tooling/Syntax/TokensTest.cpp
+++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp
@@ -248,8 +248,9 @@ class TokenCollectorTest : public ::testing::Test {
   }
 
   // Data fields.
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions);
+      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   llvm::IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
index 7710a9cc5a743..9f22b1d64c913 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp
@@ -126,7 +126,7 @@ SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) {
   FS->addFile(FileName, time_t(), llvm::MemoryBuffer::getMemBufferCopy(""));
 
   if (!Diags->getClient())
-    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts.get()));
+    Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), DiagOpts));
   Diags->setSeverityForGroup(diag::Flavor::WarningOrError, "unused-value",
                              diag::Severity::Ignored, SourceLocation());
 
diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.h b/clang/unittests/Tooling/Syntax/TreeTestBase.h
index 1176f457cf8b3..6110cffa708d9 100644
--- a/clang/unittests/Tooling/Syntax/TreeTestBase.h
+++ b/clang/unittests/Tooling/Syntax/TreeTestBase.h
@@ -40,9 +40,9 @@ class SyntaxTreeTest : public ::testing::Test,
   syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root);
 
   // Data fields.
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  DiagnosticOptions DiagOpts;
   IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
-      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts.get());
+      new DiagnosticsEngine(new DiagnosticIDs, DiagOpts);
   IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS =
       new llvm::vfs::InMemoryFileSystem;
   IntrusiveRefCntPtr<FileManager> FileMgr =
diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp
index cfa021a5ef137..32af4b6b3b359 100644
--- a/clang/unittests/Tooling/ToolingTest.cpp
+++ b/clang/unittests/Tooling/ToolingTest.cpp
@@ -294,8 +294,8 @@ TEST(ToolInvocation, CustomDiagnosticOptionsOverwriteParsedOnes) {
   Invocation.setDiagnosticConsumer(&Consumer);
 
   // Inject custom `DiagnosticOptions` for command-line parsing.
-  auto DiagOpts = llvm::makeIntrusiveRefCnt<DiagnosticOptions>();
-  Invocation.setDiagnosticOptions(&*DiagOpts);
+  DiagnosticOptions DiagOpts;
+  Invocation.setDiagnosticOptions(&DiagOpts);
 
   EXPECT_TRUE(Invocation.run());
   // Check that the warning was issued during command-line parsing due to the
@@ -392,14 +392,14 @@ overlayRealFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
 
 struct CommandLineExtractorTest : public ::testing::Test {
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
+  DiagnosticOptions DiagOpts;
   llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
   driver::Driver Driver;
 
 public:
   CommandLineExtractorTest()
       : InMemoryFS(new llvm::vfs::InMemoryFileSystem),
-        Diags(CompilerInstance::createDiagnostics(*InMemoryFS,
-                                                  new DiagnosticOptions)),
+        Diags(CompilerInstance::createDiagnostics(*InMemoryFS, DiagOpts)),
         Driver("clang", llvm::sys::getDefaultTargetTriple(), *Diags,
                "clang LLVM compiler", overlayRealFS(InMemoryFS)) {}
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 25b4c8b876265..959cbb282b043 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -166,13 +166,12 @@ static void AddAllFixIts(ClangDiagnostic *diag, const clang::Diagnostic &Info) {
 class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 public:
   ClangDiagnosticManagerAdapter(DiagnosticOptions &opts, StringRef filename)
-      : m_filename(filename) {
-    DiagnosticOptions *options = new DiagnosticOptions(opts);
-    options->ShowPresumedLoc = true;
-    options->ShowLevel = false;
+      : m_options(opts), m_filename(filename) {
+    m_options.ShowPresumedLoc = true;
+    m_options.ShowLevel = false;
     m_os = std::make_shared<llvm::raw_string_ostream>(m_output);
     m_passthrough =
-        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, options);
+        std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options);
   }
 
   void ResetManager(DiagnosticManager *manager = nullptr) {
@@ -313,6 +312,7 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
 
 private:
   DiagnosticManager *m_manager = nullptr;
+  DiagnosticOptions m_options;
   std::shared_ptr<clang::TextDiagnosticPrinter> m_passthrough;
   /// Output stream of m_passthrough.
   std::shared_ptr<llvm::raw_string_ostream> m_os;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 1feeeb64aa9e5..06f3a7efac7a2 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -261,8 +261,7 @@ TokenVerifier::TokenVerifier(std::string body) {
   // Let's build the actual source code Clang needs and setup some utility
   // objects.
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
-      new DiagnosticOptions());
+  DiagnosticOptions diags_opts;
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(body);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
index eee6166e43f98..eb62cb618f254 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -66,6 +66,7 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
   typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
       IDAndDiagnostic;
   std::vector<IDAndDiagnostic> m_diagnostics;
+  std::unique_ptr<clang::DiagnosticOptions> m_diag_opts;
   /// The DiagnosticPrinter used for creating the full diagnostic messages
   /// that are stored in m_diagnostics.
   std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer;
@@ -83,6 +84,7 @@ class StoringDiagnosticConsumer : public clang::DiagnosticConsumer {
 class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 public:
   ClangModulesDeclVendorImpl(
+      std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
       llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
       std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
       std::unique_ptr<clang::CompilerInstance> compiler_instance,
@@ -115,6 +117,7 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 
   bool m_enabled = false;
 
+  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options;
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> m_diagnostics_engine;
   std::shared_ptr<clang::CompilerInvocation> m_compiler_invocation;
   std::unique_ptr<clang::CompilerInstance> m_compiler_instance;
@@ -134,10 +137,10 @@ class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor {
 } // anonymous namespace
 
 StoringDiagnosticConsumer::StoringDiagnosticConsumer() {
-  auto *options = new clang::DiagnosticOptions();
+  m_diag_opts = std::make_unique<clang::DiagnosticOptions>();
   m_os = std::make_unique<llvm::raw_string_ostream>(m_output);
   m_diag_printer =
-      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options);
+      std::make_unique<clang::TextDiagnosticPrinter>(*m_os, *m_diag_opts);
 }
 
 void StoringDiagnosticConsumer::HandleDiagnostic(
@@ -228,11 +231,13 @@ ClangModulesDeclVendor::ClangModulesDeclVendor()
 ClangModulesDeclVendor::~ClangModulesDeclVendor() = default;
 
 ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl(
+    std::unique_ptr<clang::DiagnosticOptions> diagnostic_options,
     llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine,
     std::shared_ptr<clang::CompilerInvocation> compiler_invocation,
     std::unique_ptr<clang::CompilerInstance> compiler_instance,
     std::unique_ptr<clang::Parser> parser)
-    : m_diagnostics_engine(std::move(diagnostics_engine)),
+    : m_diagnostic_options(std::move(diagnostic_options)),
+      m_diagnostics_engine(std::move(diagnostics_engine)),
       m_compiler_invocation(std::move(compiler_invocation)),
       m_compiler_instance(std::move(compiler_instance)),
       m_parser(std::move(parser)) {
@@ -706,8 +711,8 @@ ClangModulesDeclVendor::Create(Target &target) {
       clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
   llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
       clang::CompilerInstance::createDiagnostics(
-          *FileSystem::Instance().GetVirtualFileSystem(),
-          diag_options_up.release(), new StoringDiagnosticConsumer);
+          *FileSystem::Instance().GetVirtualFileSystem(), *diag_options_up,
+          new StoringDiagnosticConsumer);
 
   Log *log = GetLog(LLDBLog::Expressions);
   LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
@@ -767,7 +772,7 @@ ClangModulesDeclVendor::Create(Target &target) {
   while (!parser->ParseTopLevelDecl(parsed, ImportState))
     ;
 
-  return new ClangModulesDeclVendorImpl(std::move(diagnostics_engine),
-                                        std::move(invocation),
-                                        std::move(instance), std::move(parser));
+  return new ClangModulesDeclVendorImpl(
+      std::move(diag_options_up), std::move(diagnostics_engine),
+      std::move(invocation), std::move(instance), std::move(parser));
 }
diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
index 6e56e29f8c31c..8cc5714d0f0fc 100644
--- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
+++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
@@ -163,8 +163,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options,
   // objects.
   std::string full_source = previous_lines.str() + line.str();
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
-      new DiagnosticOptions());
+  DiagnosticOptions diags_opts;
   DiagnosticsEngine diags(diag_ids, diags_opts);
   clang::SourceManager SM(diags, file_mgr);
   auto buf = llvm::MemoryBuffer::getMemBuffer(full_source);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index bc9a41b58c0d7..150c08ff353ea 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -680,8 +680,9 @@ void TypeSystemClang::CreateASTContext() {
       file_system_options, FileSystem::Instance().GetVirtualFileSystem());
 
   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
+  m_diagnostic_options_up = std::make_unique<DiagnosticOptions>();
   m_diagnostics_engine_up =
-      std::make_unique<DiagnosticsEngine>(diag_id_sp, new DiagnosticOptions());
+      std::make_unique<DiagnosticsEngine>(diag_id_sp, *m_diagnostic_options_up);
 
   m_source_manager_up = std::make_unique<clang::SourceManager>(
       *m_diagnostics_engine_up, *m_file_manager_up);
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index f918cb017f51b..285748719390c 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1204,6 +1204,7 @@ class TypeSystemClang : public TypeSystem {
   std::unique_ptr<clang::LangOptions> m_language_options_up;
   std::unique_ptr<clang::FileManager> m_file_manager_up;
   std::unique_ptr<clang::SourceManager> m_source_manager_up;
+  std::unique_ptr<clang::DiagnosticOptions> m_diagnostic_options_up;
   std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_up;
   std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_up;
   std::shared_ptr<clang::TargetOptions> m_target_options_rp;

>From 73fda8327539106d2644fd3c566e528564f74562 Mon Sep 17 00:00:00 2001
From: cor3ntin <corentinjabot at gmail.com>
Date: Thu, 22 May 2025 21:57:45 +0200
Subject: [PATCH 047/105] [Clang] Do not put the definition of concept nodes in
 the Sema library (#141104)

It is a layering violation
---
 clang/lib/AST/ASTConcept.cpp   | 59 ++++++++++++++++++++++++++++++++++
 clang/lib/Sema/SemaConcept.cpp | 58 ---------------------------------
 2 files changed, 59 insertions(+), 58 deletions(-)

diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index c9adccdbc77ef..c9cfec6bd64b5 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "llvm/ADT/StringExtras.h"
 
@@ -107,3 +108,61 @@ void ConceptReference::print(llvm::raw_ostream &OS,
     OS << ">";
   }
 }
+
+concepts::ExprRequirement::ExprRequirement(
+    Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+    ReturnTypeRequirement Req, SatisfactionStatus Status,
+    ConceptSpecializationExpr *SubstitutedConstraintExpr)
+    : Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
+                  Status == SS_Dependent &&
+                      (E->containsUnexpandedParameterPack() ||
+                       Req.containsUnexpandedParameterPack()),
+                  Status == SS_Satisfied),
+      Value(E), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+      SubstitutedConstraintExpr(SubstitutedConstraintExpr), Status(Status) {
+  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+         "Simple requirement must not have a return type requirement or a "
+         "noexcept specification");
+  assert((Status > SS_TypeRequirementSubstitutionFailure &&
+          Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr));
+}
+
+concepts::ExprRequirement::ExprRequirement(
+    SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
+    SourceLocation NoexceptLoc, ReturnTypeRequirement Req)
+    : Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
+                  Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
+      Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+      Status(SS_ExprSubstitutionFailure) {
+  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+         "Simple requirement must not have a return type requirement or a "
+         "noexcept specification");
+}
+
+concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(
+    TemplateParameterList *TPL)
+    : TypeConstraintInfo(TPL, false) {
+  assert(TPL->size() == 1);
+  const TypeConstraint *TC =
+      cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
+  assert(TC &&
+         "TPL must have a template type parameter with a type constraint");
+  auto *Constraint =
+      cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
+  bool Dependent =
+      Constraint->getTemplateArgsAsWritten() &&
+      TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
+          Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
+  TypeConstraintInfo.setInt(Dependent ? true : false);
+}
+
+concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T)
+    : Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
+                  T->getType()->containsUnexpandedParameterPack(),
+                  // We reach this ctor with either dependent types (in which
+                  // IsSatisfied doesn't matter) or with non-dependent type in
+                  // which the existence of the type indicates satisfaction.
+                  /*IsSatisfied=*/true),
+      Value(T),
+      Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
+                                                          : SS_Satisfied) {}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index aef78644992b7..7da8e696c90bd 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1782,64 +1782,6 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(
   return true;
 }
 
-concepts::ExprRequirement::ExprRequirement(
-    Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
-    ReturnTypeRequirement Req, SatisfactionStatus Status,
-    ConceptSpecializationExpr *SubstitutedConstraintExpr) :
-    Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
-                Status == SS_Dependent &&
-                (E->containsUnexpandedParameterPack() ||
-                 Req.containsUnexpandedParameterPack()),
-                Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc),
-    TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr),
-    Status(Status) {
-  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
-         "Simple requirement must not have a return type requirement or a "
-         "noexcept specification");
-  assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==
-         (SubstitutedConstraintExpr != nullptr));
-}
-
-concepts::ExprRequirement::ExprRequirement(
-    SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
-    SourceLocation NoexceptLoc, ReturnTypeRequirement Req) :
-    Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
-                Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
-    Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
-    Status(SS_ExprSubstitutionFailure) {
-  assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
-         "Simple requirement must not have a return type requirement or a "
-         "noexcept specification");
-}
-
-concepts::ExprRequirement::ReturnTypeRequirement::
-ReturnTypeRequirement(TemplateParameterList *TPL) :
-    TypeConstraintInfo(TPL, false) {
-  assert(TPL->size() == 1);
-  const TypeConstraint *TC =
-      cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
-  assert(TC &&
-         "TPL must have a template type parameter with a type constraint");
-  auto *Constraint =
-      cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
-  bool Dependent =
-      Constraint->getTemplateArgsAsWritten() &&
-      TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
-          Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
-  TypeConstraintInfo.setInt(Dependent ? true : false);
-}
-
-concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
-    Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
-                T->getType()->containsUnexpandedParameterPack(),
-                // We reach this ctor with either dependent types (in which
-                // IsSatisfied doesn't matter) or with non-dependent type in
-                // which the existence of the type indicates satisfaction.
-                /*IsSatisfied=*/true),
-    Value(T),
-    Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
-                                                        : SS_Satisfied) {}
-
 NormalizedConstraint::CompoundConstraintKind
 NormalizedConstraint::getCompoundKind() const {
   assert(isCompound() && "getCompoundKind on a non-compound constraint..");

>From 48ace3f872e4d844471cd1e821502dece3fe2bc0 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Thu, 22 May 2025 13:04:13 -0700
Subject: [PATCH 048/105] [lldb] Convert Maintainers file from reStructuredText
 -> Markdown (#140958)

Convert the Maintainers file from reStructuredText to Markdown and
include links to GitHub and Discouse. The new layout improves
readability, makes it easier to navigate from GitHub and matches LLVM's
Maintainer's file [1].

[1] https://github.com/llvm/llvm-project/blob/main/llvm/Maintainers.md
---
 lldb/Maintainers.md  | 242 ++++++++++++++++++++++++++++++++++++++++
 lldb/Maintainers.rst | 256 -------------------------------------------
 2 files changed, 242 insertions(+), 256 deletions(-)
 create mode 100644 lldb/Maintainers.md
 delete mode 100644 lldb/Maintainers.rst

diff --git a/lldb/Maintainers.md b/lldb/Maintainers.md
new file mode 100644
index 0000000000000..4903a9ea36248
--- /dev/null
+++ b/lldb/Maintainers.md
@@ -0,0 +1,242 @@
+# LLDB Maintainers
+
+This file is a list of the [maintainers](https://llvm.org/docs/DeveloperPolicy.html#maintainers) for LLDB.
+
+## Current Maintainers
+
+The following people are the active maintainers for the project. Please reach out to them for code reviews, questions about their area of expertise, or other assistance.
+
+### Lead Maintainer
+
+Responsible for project as a whole, and for any areas not covered by a specific maintainer.
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+### Components
+
+These maintainers are responsible for particular high-level components within LLDB.
+
+#### ABI
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+David Spickett
+david.spickett at linaro.org (email), [DavidSpickett](https://github.com/DavidSpickett) (GitHub), [DavidSpickett](https://discourse.llvm.org/u/DavidSpickett) (Discourse), davidspickett (Discord)
+
+#### Breakpoint
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+#### CMake & Build System
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+Alex Langford
+alangford at apple.com (email), [bulbazord](https://github.com/bulbazord) (GitHub), [bulbazord](https://discourse.llvm.org/u/bulbazord) (Discourse), bulba_zord (Discord)
+
+#### Commands
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+#### Expression Parser
+
+Michael Buch
+michaelbuch12 at gmail.com (email), [Michael137](https://github.com/Michael137) (GitHub), [Michael137](https://discourse.llvm.org/u/Michael137) (Discourse)
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+#### Interpreter
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+Greg Clayton
+gclayton at fb.com (email), [clayborg](https://github.com/clayborg) (GitHub), [clayborg](https://discourse.llvm.org/u/clayborg) (Discourse)
+
+#### Lua
+
+Jonas Delvieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+#### Python
+
+Med Ismail Bennani
+ismail at bennani.ma (email), [medismailben](https://github.com/medismailben) (GitHub), [mib](https://discourse.llvm.org/u/mib) (Discourse), mib#8727 (Discord)
+
+#### Target/Process Control
+
+Med Ismail Bennani
+ismail at bennani.ma (email), [medismailben](https://github.com/medismailben) (GitHub), [mib](https://discourse.llvm.org/u/mib) (Discourse), mib#8727 (Discord)
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+#### Test Suite
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### Trace
+
+Walter Erquinigo
+a20012251 at gmail.com (email), [walter-erquinigo](https://github.com/walter-erquinigo) (GitHub), [wallace](https://discourse.llvm.org/u/wallace) (Discourse), werquinigo (Discord)
+
+#### Unwinding
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+#### Utility
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### ValueObject
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+#### Watchpoints
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+### File Formats
+
+The following people are responsible for decisions involving file and
+debug info formats.
+
+#### (PE)COFF
+
+Saleem Abdulrasool
+compnerd at compnerd.org (email), [compnerd](https://github.com/compnerd) (GitHub), [compnerd](https://discourse.llvm.org/u/compnerd) (Discourse), compnerd (Discord)
+
+#### Breakpad
+
+Zequan Wu
+zequanwu at google.com (email), [ZequanWu](https://github.com/ZequanWu) (GitHub), [ZequanWu](https://discourse.llvm.org/u/ZequanWu) (Discourse)
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### CTF
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+#### DWARF
+
+Adrian Prantl
+aprantl at apple.com (email), [adrian-prantl](https://github.com/adrian-prantl) (GitHub), [adrian.prantl](https://discourse.llvm.org/u/adrian.prantl) (Discourse), adrian.prantl (Discord), Adrian Prantl#4366 (Discourse)
+
+Greg Clayton
+gclayton at fb.com (email), [clayborg](https://github.com/clayborg) (GitHub), [clayborg](https://discourse.llvm.org/u/clayborg) (Discourse)
+
+#### ELF
+
+David Spickett
+david.spickett at linaro.org (email), [DavidSpickett](https://github.com/DavidSpickett) (GitHub), [DavidSpickett](https://discourse.llvm.org/u/DavidSpickett) (Discourse), davidspickett (Discord)
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### JSON
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+#### MachO
+
+Greg Clayton
+gclayton at fb.com (email), [clayborg](https://github.com/clayborg) (GitHub), [clayborg](https://discourse.llvm.org/u/clayborg) (Discourse)
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+#### PDB
+
+Zequan Wu
+zequanwu at google.com (email), [ZequanWu](https://github.com/ZequanWu) (GitHub), [ZequanWu](https://discourse.llvm.org/u/ZequanWu) (Discourse)
+
+### Platforms
+
+The following people are responsible for decisions involving platforms.
+
+#### Android
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### Darwin
+
+Jim Ingham
+jingham at apple.com (email), [jimingham](https://github.com/jimingham) (GitHub), [jingham](https://discourse.llvm.org/u/jingham) (Discourse)
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+Jonas Devlieghere
+jonas at devlieghere.com (email), [jdevlieghere](https://github.com/jdevlieghere) (GitHub), [jdevlieghere](https://discourse.llvm.org/u/jdevlieghere) (Discourse), jdevlieghere (Discord)
+
+#### FreeBSD
+
+Ed Maste
+emaste at freebsd.org (email), [emaste](https://github.com/emaste) (GitHub), [emaste](https://discourse.llvm.org/u/emaste) (Discourse), emaste (Discord)
+
+#### Linux
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+David Spickett
+david.spickett at linaro.org (email), [DavidSpickett](https://github.com/DavidSpickett) (GitHub), [DavidSpickett](https://discourse.llvm.org/u/DavidSpickett) (Discourse), davidspickett (Discord)
+
+#### Windows
+
+Omair Javaid
+omair.javaid at linaro.org (email), [omjavaid](https://github.com/omjavaid) (GitHub), [omjavaid](https://discourse.llvm.org/u/omjavaid) (Discourse), omjavaid#9902 (Discord)
+
+### Tools
+
+The following people are responsible for decisions involving specific tools.
+
+#### debugserver
+
+Jason Molenda
+jmolenda at apple.com (email), [jasonmolenda](https://github.com/jasonmolenda) (GitHub), [jasonmolenda](https://discourse.llvm.org/u/jasonmolenda) (Discourse), jasonmolenda (Discord)
+
+#### lldb-server
+
+David Spickett
+david.spickett at linaro.org (email), [DavidSpickett](https://github.com/DavidSpickett) (GitHub), [DavidSpickett](https://discourse.llvm.org/u/DavidSpickett) (Discourse), davidspickett (Discord)
+
+Pavel Labath
+pavel at labath.sk (email), [labath](https://github.com/labath) (GitHub), [labath](https://discourse.llvm.org/u/labath) (Discourse)
+
+#### lldb-dap
+
+Greg Clayton
+gclayton at fb.com (email), [clayborg](https://github.com/clayborg) (GitHub), [clayborg](https://discourse.llvm.org/u/clayborg) (Discourse)
+
+Walter Erquinigo
+a20012251 at gmail.com (email), [walter-erquinigo](https://github.com/walter-erquinigo) (GitHub), [wallace](https://discourse.llvm.org/u/wallace) (Discourse), werquinigo (Discord)
+
+## Former Maintainers
+
+The following people have graciously spent time performing maintainership duties but are no longer active in that role. Thank you for all your help with the success of the project!
+
+Kamil Rytarowski (kamil at netbsd.org)
+
+Zachary Turner (zturner at google.com)
diff --git a/lldb/Maintainers.rst b/lldb/Maintainers.rst
deleted file mode 100644
index e83591d5f162b..0000000000000
--- a/lldb/Maintainers.rst
+++ /dev/null
@@ -1,256 +0,0 @@
-================
-LLDB Maintainers
-================
-
-This file is a list of the `maintainers <https://llvm.org/docs/DeveloperPolicy.html#maintainers>`_ for LLDB.
-
-.. contents::
-   :depth: 2
-   :local:
-
-Current Maintainers
-===================
-The following people are the active maintainers for the project. Please reach
-out to them for code reviews, questions about their area of expertise, or other
-assistance.
-
-Lead Maintainer
----------------
-
-Responsible for project as a whole, and for any areas not covered by a specific
-maintainer.
-
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-Components
-----------
-These maintainers are responsible for particular high-level components within
-LLDB.
-
-ABI
-~~~
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-| David Spickett
-| david.spickett\@linaro.org (email), DavidSpickett (GitHub), DavidSpickett (Discourse), davidspickett (Discord)
-
-
-Breakpoint
-~~~~~~~~~~
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-CMake & Build System
-~~~~~~~~~~~~~~~~~~~~
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-| Alex Langford
-| alangford\@apple.com (email), bulbazord (GitHub), bulbazord (Discourse), bulba_zord (Discord)
-
-Commands
-~~~~~~~~
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-Expression Parser
-~~~~~~~~~~~~~~~~~
-| Michael Buch
-| michaelbuch12\@gmail.com (email), Michael137 (GitHub), Michael137 (Discourse)
-
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-Interpreter
-~~~~~~~~~~~
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-| Greg Clayton
-| gclayton\@fb.com (email), clayborg (GitHub), clayborg (Discourse)
-
-
-Lua
-~~~
-| Jonas Delvieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-Python
-~~~~~~
-| Med Ismail Bennani
-| ismail\@bennani.ma (email), medismailben (GitHub), mib (Discourse), mib#8727 (Discord)
-
-Target/Process Control
-~~~~~~~~~~~~~~~~~~~~~~
-| Med Ismail Bennani
-| ismail\@bennani.ma (email), medismailben (GitHub), mib (Discourse), mib#8727 (Discord)
-
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-Test Suite
-~~~~~~~~~~
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-Trace
-~~~~~
-| Walter Erquinigo
-| a20012251\@gmail.com (email), walter-erquinigo (GitHub), wallace (Discourse), werquinigo (Discord)
-
-Unwinding
-~~~~~~~~~
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-Utility
-~~~~~~~
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-ValueObject
-~~~~~~~~~~~
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-Watchpoints
-~~~~~~~~~~~
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-File Formats
-------------
-The following people are responsible for decisions involving file and debug
-info formats.
-
-(PE)COFF
-~~~~~~~~
-| Saleem Abdulrasool
-| compnerd\@compnerd.org (email), compnerd (GitHub), compnerd (Discourse), compnerd (Discord)
-
-Breakpad
-~~~~~~~~
-| Zequan Wu
-| zequanwu\@google.com (email), ZequanWu (GitHub), ZequanWu (Discourse)
-
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-CTF
-~~~
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-DWARF
-~~~~~
-| Adrian Prantl
-| aprantl\@apple.com (email), adrian-prantl (GitHub), adrian.prantl (Discourse), adrian.prantl (Discord), Adrian Prantl#4366 (Discourse)
-
-| Greg Clayton
-| gclayton\@fb.com (email), clayborg (GitHub), clayborg (Discourse)
-
-ELF
-~~~
-| David Spickett
-| david.spickett\@linaro.org (email), DavidSpickett (GitHub), DavidSpickett (Discourse), davidspickett (Discord)
-
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-JSON
-~~~~
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-MachO
-~~~~~
-| Greg Clayton
-| gclayton\@fb.com (email), clayborg (GitHub), clayborg (Discourse)
-
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-PDB
-~~~
-| Zequan Wu
-| zequanwu\@google.com (email), ZequanWu (GitHub), ZequanWu (Discourse)
-
-Platforms
----------
-The following people are responsible for decisions involving platforms.
-
-Android
-~~~~~~~
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-Darwin
-~~~~~~
-| Jim Ingham
-| jingham\@apple.com (email), jimingham (GitHub), jingham (Discourse)
-
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-| Jonas Devlieghere
-| jonas\@devlieghere.com (email), jdevlieghere (GitHub), jdevlieghere (Discourse), jdevlieghere (Discord)
-
-FreeBSD
-~~~~~~~
-| Ed Maste
-| emaste\@freebsd.org (email), emaste (GitHub), emaste (Discourse), emaste (Discord)
-
-Linux
-~~~~~
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-| David Spickett
-| david.spickett\@linaro.org (email), DavidSpickett (GitHub), DavidSpickett (Discourse), davidspickett (Discord)
-
-Windows
-~~~~~~~
-| Omair Javaid
-| omair.javaid\@linaro.org (email), omjavaid (GitHub), omjavaid (Discourse), omjavaid#9902 (Discord)
-
-Tools
------
-The following people are responsible for decisions involving specific tools.
-
-debugserver
-~~~~~~~~~~~
-| Jason Molenda
-| jmolenda\@apple.com (email), jasonmolenda (GitHub), jasonmolenda (Discourse), jasonmolenda (Discord)
-
-lldb-server
-~~~~~~~~~~~
-| David Spickett
-| david.spickett\@linaro.org (email), DavidSpickett (GitHub), DavidSpickett (Discourse), davidspickett (Discord)
-
-| Pavel Labath
-| pavel\@labath.sk (email), labath (GitHub), labath (Discourse)
-
-lldb-dap
-~~~~~~~~
-| Greg Clayton
-| gclayton\@fb.com (email), clayborg (GitHub), clayborg (Discourse)
-
-| Walter Erquinigo
-| a20012251\@gmail.com (email), walter-erquinigo (GitHub), wallace (Discourse), werquinigo (Discord)
-
-Former Maintainers
-==================
-The following people have graciously spent time performing maintainership
-duties but are no longer active in that role. Thank you for all your
-help with the success of the project!
-
-| Kamil Rytarowski (kamil\@netbsd.org)
-| Zachary Turner (zturner\@google.com)

>From f3eea1251148d09fe58bf6935dc4911ad4154122 Mon Sep 17 00:00:00 2001
From: Alex MacLean <amaclean at nvidia.com>
Date: Thu, 22 May 2025 13:05:17 -0700
Subject: [PATCH 049/105] [NVPTX] Add intrinsic support for specialized prmt
 variants (#140951)

---
 llvm/docs/NVPTXUsage.rst                 | 120 +++++++++++++++++++++++
 llvm/include/llvm/IR/IntrinsicsNVVM.td   |  21 +++-
 llvm/lib/Target/NVPTX/NVPTXInstrInfo.td  |  98 +++++++++++++-----
 llvm/lib/Target/NVPTX/NVPTXIntrinsics.td |  19 +++-
 llvm/test/CodeGen/NVPTX/bswap.ll         |  46 +++++----
 llvm/test/CodeGen/NVPTX/prmt.ll          | 113 +++++++++++++++++++++
 6 files changed, 369 insertions(+), 48 deletions(-)
 create mode 100644 llvm/test/CodeGen/NVPTX/prmt.ll

diff --git a/llvm/docs/NVPTXUsage.rst b/llvm/docs/NVPTXUsage.rst
index e0a5c02114779..6f230a1635f3b 100644
--- a/llvm/docs/NVPTXUsage.rst
+++ b/llvm/docs/NVPTXUsage.rst
@@ -624,6 +624,126 @@ all bits set to 0 except for %b bits starting at bit position %a. For the
 '``clamp``' variants, the values of %a and %b are clamped to the range [0, 32],
 which in practice is equivalent to using them as is.
 
+'``llvm.nvvm.prmt``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+.. code-block:: llvm
+
+    declare i32 @llvm.nvvm.prmt(i32 %lo, i32 %hi, i32 %selector)
+
+Overview:
+"""""""""
+
+The '``llvm.nvvm.prmt``' constructs a permutation of the bytes of the first two
+operands, selecting based on the third operand.
+
+Semantics:
+""""""""""
+
+The bytes in the first two source operands are numbered from 0 to 7:
+{%hi, %lo} = {{b7, b6, b5, b4}, {b3, b2, b1, b0}}. For each byte in the target
+register, a 4-bit selection value is defined.
+
+The 3 lsbs of the selection value specify which of the 8 source bytes should be
+moved into the target position. The msb defines if the byte value should be
+copied, or if the sign (msb of the byte) should be replicated over all 8 bits
+of the target position (sign extend of the byte value); msb=0 means copy the
+literal value; msb=1 means replicate the sign.
+
+These 4-bit selection values are pulled from the lower 16-bits of the %selector
+operand, with the least significant selection value corresponding to the least
+significant byte of the destination.
+
+
+'``llvm.nvvm.prmt.*``' Intrinsics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+.. code-block:: llvm
+
+    declare i32 @llvm.nvvm.prmt.f4e(i32 %lo, i32 %hi, i32 %selector)
+    declare i32 @llvm.nvvm.prmt.b4e(i32 %lo, i32 %hi, i32 %selector)
+
+    declare i32 @llvm.nvvm.prmt.rc8(i32 %lo, i32 %selector)
+    declare i32 @llvm.nvvm.prmt.ecl(i32 %lo, i32 %selector)
+    declare i32 @llvm.nvvm.prmt.ecr(i32 %lo, i32 %selector)
+    declare i32 @llvm.nvvm.prmt.rc16(i32 %lo, i32 %selector)
+
+Overview:
+"""""""""
+
+The '``llvm.nvvm.prmt.*``' family of intrinsics constructs a permutation of the
+bytes of the first one or two operands, selecting based on the 2 least
+significant bits of the final operand.
+
+Semantics:
+""""""""""
+
+As with the generic '``llvm.nvvm.prmt``' intrinsic, the bytes in the first one
+or two source operands are numbered. The first source operand (%lo) is numbered
+{b3, b2, b1, b0}, in the case of the '``f4e``' and '``b4e``' variants, the
+second source operand (%hi) is numbered {b7, b6, b5, b4}.
+
+Depending on the 2 least significant bits of the %selector operand, the result
+of the permutation is defined as follows:
+
++------------+----------------+--------------+
+|    Mode    | %selector[1:0] |    Output    |
++------------+----------------+--------------+
+| '``f4e``'  | 0              | {3, 2, 1, 0} |
+|            +----------------+--------------+
+|            | 1              | {4, 3, 2, 1} |
+|            +----------------+--------------+
+|            | 2              | {5, 4, 3, 2} |
+|            +----------------+--------------+
+|            | 3              | {6, 5, 4, 3} |
++------------+----------------+--------------+
+| '``b4e``'  | 0              | {5, 6, 7, 0} |
+|            +----------------+--------------+
+|            | 1              | {6, 7, 0, 1} |
+|            +----------------+--------------+
+|            | 2              | {7, 0, 1, 2} |
+|            +----------------+--------------+
+|            | 3              | {0, 1, 2, 3} |
++------------+----------------+--------------+
+| '``rc8``'  | 0              | {0, 0, 0, 0} |
+|            +----------------+--------------+
+|            | 1              | {1, 1, 1, 1} |
+|            +----------------+--------------+
+|            | 2              | {2, 2, 2, 2} |
+|            +----------------+--------------+
+|            | 3              | {3, 3, 3, 3} |
++------------+----------------+--------------+
+| '``ecl``'  | 0              | {3, 2, 1, 0} |
+|            +----------------+--------------+
+|            | 1              | {3, 2, 1, 1} |
+|            +----------------+--------------+
+|            | 2              | {3, 2, 2, 2} |
+|            +----------------+--------------+
+|            | 3              | {3, 3, 3, 3} |
++------------+----------------+--------------+
+| '``ecr``'  | 0              | {0, 0, 0, 0} |
+|            +----------------+--------------+
+|            | 1              | {1, 1, 1, 0} |
+|            +----------------+--------------+
+|            | 2              | {2, 2, 1, 0} |
+|            +----------------+--------------+
+|            | 3              | {3, 2, 1, 0} |
++------------+----------------+--------------+
+| '``rc16``' | 0              | {1, 0, 1, 0} |
+|            +----------------+--------------+
+|            | 1              | {3, 2, 3, 2} |
+|            +----------------+--------------+
+|            | 2              | {1, 0, 1, 0} |
+|            +----------------+--------------+
+|            | 3              | {3, 2, 3, 2} |
++------------+----------------+--------------+
+
 TMA family of Intrinsics
 ------------------------
 
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index 3aa9b0303c63d..50dc1fd0f8ab0 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -739,9 +739,24 @@ class NVVMBuiltin :
 }
 
 let TargetPrefix = "nvvm" in {
-  def int_nvvm_prmt : NVVMBuiltin,
-      DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
-        [IntrNoMem, IntrSpeculatable]>;
+
+  // PRMT - permute
+
+  let IntrProperties = [IntrNoMem, IntrSpeculatable] in {
+    def int_nvvm_prmt : NVVMBuiltin,
+      DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty]>;
+
+    foreach mode = ["f4e", "b4e"] in
+      def int_nvvm_prmt_ # mode :
+          DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty]>;
+
+    // Note: these variants also have 2 source operands but only one will ever
+    // be used so we eliminate the other operand in the IR (0 is used as the
+    // placeholder in the backend).
+    foreach mode = ["rc8", "ecl", "ecr", "rc16"] in
+      def int_nvvm_prmt_ # mode :
+          DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty]>;
+  }
 
   def int_nvvm_nanosleep : NVVMBuiltin,
       DefaultAttrsIntrinsic<[], [llvm_i32_ty],
diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
index 444d35b3115ba..d0538f579f94e 100644
--- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
+++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td
@@ -238,6 +238,48 @@ def F16X2RT  : RegTyInfo<v2f16, Int32Regs, ?, ?, supports_imm = 0>;
 def BF16X2RT : RegTyInfo<v2bf16, Int32Regs, ?, ?, supports_imm = 0>;
 
 
+// This class provides a basic wrapper around an NVPTXInst that abstracts the
+// specific syntax of most PTX instructions. It automatically handles the
+// construction of the asm string based on the provided dag arguments.
+// For example, the following asm-strings would be computed:
+//
+//   * BasicFlagsNVPTXInst<(outs Int32Regs:$dst),
+//                         (ins Int32Regs:$a, Int32Regs:$b), (ins),
+//                         "add.s32">;
+//         ---> "add.s32 \t$dst, $a, $b;"
+//
+//   * BasicFlagsNVPTXInst<(outs Int32Regs:$d),
+//                         (ins Int32Regs:$a, Int32Regs:$b, Hexu32imm:$c),
+//                         (ins PrmtMode:$mode),
+//                         "prmt.b32${mode}">;
+//         ---> "prmt.b32${mode} \t$d, $a, $b, $c;"
+//
+class BasicFlagsNVPTXInst<dag outs_dag, dag ins_dag, dag flags_dag, string asmstr,
+                          list<dag> pattern = []>
+  : NVPTXInst<
+      outs_dag,
+      !con(ins_dag, flags_dag),
+      !strconcat(
+        asmstr,
+        !if(!and(!empty(ins_dag), !empty(outs_dag)), "",
+          !strconcat(
+            " \t",
+            !interleave(
+              !foreach(i, !range(!size(outs_dag)),
+                "$" # !getdagname(outs_dag, i)),
+              "|"),
+            !if(!or(!empty(ins_dag), !empty(outs_dag)), "", ", "),
+            !interleave(
+              !foreach(i, !range(!size(ins_dag)),
+                "$" # !getdagname(ins_dag, i)),
+              ", "))),
+        ";"),
+      pattern>;
+
+class BasicNVPTXInst<dag outs, dag insv, string asmstr, list<dag> pattern = []>
+  : BasicFlagsNVPTXInst<outs, insv, (ins), asmstr, pattern>;
+
+
 multiclass I3Inst<string op_str, SDPatternOperator op_node, RegTyInfo t,
                   bit commutative, list<Predicate> requires = []> {
   defvar asmstr = op_str # " \t$dst, $a, $b;";
@@ -1581,24 +1623,6 @@ def Hexu32imm : Operand<i32> {
   let PrintMethod = "printHexu32imm";
 }
 
-multiclass PRMT<ValueType T, RegisterClass RC> {
-  def rrr
-    : NVPTXInst<(outs RC:$d),
-                (ins RC:$a, Int32Regs:$b, Int32Regs:$c, PrmtMode:$mode),
-                !strconcat("prmt.b32${mode}", " \t$d, $a, $b, $c;"),
-                [(set T:$d, (prmt T:$a, T:$b, i32:$c, imm:$mode))]>;
-  def rri
-    : NVPTXInst<(outs RC:$d),
-                (ins RC:$a, Int32Regs:$b, Hexu32imm:$c, PrmtMode:$mode),
-                !strconcat("prmt.b32${mode}", " \t$d, $a, $b, $c;"),
-                [(set T:$d, (prmt T:$a, T:$b, imm:$c, imm:$mode))]>;
-  def rii
-    : NVPTXInst<(outs RC:$d),
-                (ins RC:$a, i32imm:$b, Hexu32imm:$c, PrmtMode:$mode),
-                !strconcat("prmt.b32${mode}", " \t$d, $a, $b, $c;"),
-                [(set T:$d, (prmt T:$a, imm:$b, imm:$c, imm:$mode))]>;
-}
-
 let hasSideEffects = false in {
   // order is somewhat important here. signed/unsigned variants match
   // the same patterns, so the first one wins. Having unsigned byte extraction
@@ -1612,7 +1636,31 @@ let hasSideEffects = false in {
   defm BFI_B32 : BFI<"bfi.b32", i32, Int32Regs, i32imm>;
   defm BFI_B64 : BFI<"bfi.b64", i64, Int64Regs, i64imm>;
 
-  defm PRMT_B32 : PRMT<i32, Int32Regs>;
+  def PRMT_B32rrr
+    : BasicFlagsNVPTXInst<(outs Int32Regs:$d),
+                (ins Int32Regs:$a, Int32Regs:$b, Int32Regs:$c),
+                (ins PrmtMode:$mode),
+                "prmt.b32$mode",
+                [(set i32:$d, (prmt i32:$a, i32:$b, i32:$c, imm:$mode))]>;
+  def PRMT_B32rri
+    : BasicFlagsNVPTXInst<(outs Int32Regs:$d),
+                (ins Int32Regs:$a, Int32Regs:$b, Hexu32imm:$c),
+                (ins PrmtMode:$mode),
+                "prmt.b32$mode",
+                [(set i32:$d, (prmt i32:$a, i32:$b, imm:$c, imm:$mode))]>;
+  def PRMT_B32rii
+    : BasicFlagsNVPTXInst<(outs Int32Regs:$d),
+                (ins Int32Regs:$a, i32imm:$b, Hexu32imm:$c),
+                (ins PrmtMode:$mode),
+                "prmt.b32$mode",
+                [(set i32:$d, (prmt i32:$a, imm:$b, imm:$c, imm:$mode))]>;
+  def PRMT_B32rir
+    : BasicFlagsNVPTXInst<(outs Int32Regs:$d),
+                (ins Int32Regs:$a, i32imm:$b, Int32Regs:$c),
+                (ins PrmtMode:$mode),
+                "prmt.b32$mode",
+                [(set i32:$d, (prmt i32:$a, imm:$b, i32:$c, imm:$mode))]>;
+
 }
 
 
@@ -3265,25 +3313,25 @@ include "NVPTXIntrinsics.td"
 
 def : Pat <
   (i32 (bswap i32:$a)),
-  (INT_NVVM_PRMT $a, (i32 0), (i32 0x0123))>;
+  (PRMT_B32rii $a, (i32 0), (i32 0x0123), PrmtNONE)>;
 
 def : Pat <
   (v2i16 (bswap v2i16:$a)),
-  (INT_NVVM_PRMT $a, (i32 0), (i32 0x2301))>;
+  (PRMT_B32rii $a, (i32 0), (i32 0x2301), PrmtNONE)>;
 
 def : Pat <
   (i64 (bswap i64:$a)),
   (V2I32toI64
-    (INT_NVVM_PRMT (I64toI32H_Sink $a), (i32 0), (i32 0x0123)),
-    (INT_NVVM_PRMT (I64toI32L_Sink $a), (i32 0), (i32 0x0123)))>,
+    (PRMT_B32rii (I64toI32H_Sink $a), (i32 0), (i32 0x0123), PrmtNONE),
+    (PRMT_B32rii (I64toI32L_Sink $a), (i32 0), (i32 0x0123), PrmtNONE))>,
   Requires<[hasPTX<71>]>;
 
 // Fall back to the old way if we don't have PTX 7.1.
 def : Pat <
   (i64 (bswap i64:$a)),
   (V2I32toI64
-    (INT_NVVM_PRMT (I64toI32H $a), (i32 0), (i32 0x0123)),
-    (INT_NVVM_PRMT (I64toI32L $a), (i32 0), (i32 0x0123)))>;
+    (PRMT_B32rii (I64toI32H $a), (i32 0), (i32 0x0123), PrmtNONE),
+    (PRMT_B32rii (I64toI32L $a), (i32 0), (i32 0x0123), PrmtNONE))>;
 
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index 193418ca391e5..56b5fde652e2c 100644
--- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -1025,8 +1025,23 @@ class F_MATH_3<string OpcStr, NVPTXRegClass t_regclass,
 // MISC
 //
 
-def INT_NVVM_PRMT : F_MATH_3<"prmt.b32 \t$dst, $src0, $src1, $src2;", Int32Regs,
-  Int32Regs, Int32Regs, Int32Regs, int_nvvm_prmt>;
+class PRMT3Pat<Intrinsic prmt_intrinsic, PatLeaf prmt_mode>
+    : Pat<(prmt_intrinsic i32:$a, i32:$b, i32:$c),
+          (PRMT_B32rrr $a, $b, $c, prmt_mode)>;
+
+class PRMT2Pat<Intrinsic prmt_intrinsic, PatLeaf prmt_mode>
+    : Pat<(prmt_intrinsic i32:$a, i32:$c),
+          (PRMT_B32rir $a, (i32 0), $c, prmt_mode)>;
+
+def : PRMT3Pat<int_nvvm_prmt,      PrmtNONE>;
+def : PRMT3Pat<int_nvvm_prmt_f4e,  PrmtF4E>;
+def : PRMT3Pat<int_nvvm_prmt_b4e,  PrmtB4E>;
+
+def : PRMT2Pat<int_nvvm_prmt_rc8,  PrmtRC8>;
+def : PRMT2Pat<int_nvvm_prmt_ecl,  PrmtECL>;
+def : PRMT2Pat<int_nvvm_prmt_ecr,  PrmtECR>;
+def : PRMT2Pat<int_nvvm_prmt_rc16, PrmtRC16>;
+
 
 def INT_NVVM_NANOSLEEP_I : NVPTXInst<(outs), (ins i32imm:$i), "nanosleep.u32 \t$i;",
                              [(int_nvvm_nanosleep imm:$i)]>,
diff --git a/llvm/test/CodeGen/NVPTX/bswap.ll b/llvm/test/CodeGen/NVPTX/bswap.ll
index 0e16682641edd..0d1d6da4ba2b6 100644
--- a/llvm/test/CodeGen/NVPTX/bswap.ll
+++ b/llvm/test/CodeGen/NVPTX/bswap.ll
@@ -33,7 +33,7 @@ define i32 @bswap32(i32 %a) {
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  // %bb.0:
 ; CHECK-NEXT:    ld.param.b32 %r1, [bswap32_param_0];
-; CHECK-NEXT:    prmt.b32 %r2, %r1, 0, 291;
+; CHECK-NEXT:    prmt.b32 %r2, %r1, 0, 0x123U;
 ; CHECK-NEXT:    st.param.b32 [func_retval0], %r2;
 ; CHECK-NEXT:    ret;
   %b = tail call i32 @llvm.bswap.i32(i32 %a)
@@ -48,7 +48,7 @@ define <2 x i16> @bswapv2i16(<2 x i16> %a) #0 {
 ; CHECK-EMPTY:
 ; CHECK-NEXT:  // %bb.0:
 ; CHECK-NEXT:    ld.param.b32 %r1, [bswapv2i16_param_0];
-; CHECK-NEXT:    prmt.b32 %r2, %r1, 0, 8961;
+; CHECK-NEXT:    prmt.b32 %r2, %r1, 0, 0x2301U;
 ; CHECK-NEXT:    st.param.b32 [func_retval0], %r2;
 ; CHECK-NEXT:    ret;
   %b = tail call <2 x i16> @llvm.bswap.v2i16(<2 x i16> %a)
@@ -56,25 +56,35 @@ define <2 x i16> @bswapv2i16(<2 x i16> %a) #0 {
 }
 
 define i64 @bswap64(i64 %a) {
-; CHECK-LABEL: bswap64(
-; CHECK:       {
-; CHECK-NEXT:    .reg .b32 %r<5>;
-; CHECK-NEXT:    .reg .b64 %rd<3>;
-; CHECK-EMPTY:
-; CHECK-NEXT:  // %bb.0:
-; CHECK-NEXT:    ld.param.b64 %rd1, [bswap64_param_0];
+; PTX70-LABEL: bswap64(
+; PTX70:       {
+; PTX70-NEXT:    .reg .b32 %r<5>;
+; PTX70-NEXT:    .reg .b64 %rd<3>;
+; PTX70-EMPTY:
+; PTX70-NEXT:  // %bb.0:
+; PTX70-NEXT:    ld.param.b64 %rd1, [bswap64_param_0];
 ; PTX70-NEXT:    { .reg .b32 tmp; mov.b64 {%r1, tmp}, %rd1; }
-; PTX70-NEXT:    prmt.b32 %r2, %r1, 0, 291;
+; PTX70-NEXT:    prmt.b32 %r2, %r1, 0, 0x123U;
 ; PTX70-NEXT:    { .reg .b32 tmp; mov.b64 {tmp, %r3}, %rd1; }
-; PTX70-NEXT:    prmt.b32 %r4, %r3, 0, 291;
+; PTX70-NEXT:    prmt.b32 %r4, %r3, 0, 0x123U;
 ; PTX70-NEXT:    mov.b64 %rd2, {%r4, %r2};
-; PTX71-NEXT:    mov.b64         {%r1, _}, %rd1;
-; PTX71-NEXT:    prmt.b32        %r2, %r1, 0, 291;
-; PTX71-NEXT:    mov.b64         {_, %r3}, %rd1;
-; PTX71-NEXT:    prmt.b32        %r4, %r3, 0, 291;
-; PTX71-NEXT:    mov.b64         %rd2, {%r4, %r2};
-; CHECK-NEXT:    st.param.b64 [func_retval0], %rd2;
-; CHECK-NEXT:    ret;
+; PTX70-NEXT:    st.param.b64 [func_retval0], %rd2;
+; PTX70-NEXT:    ret;
+;
+; PTX71-LABEL: bswap64(
+; PTX71:       {
+; PTX71-NEXT:    .reg .b32 %r<5>;
+; PTX71-NEXT:    .reg .b64 %rd<3>;
+; PTX71-EMPTY:
+; PTX71-NEXT:  // %bb.0:
+; PTX71-NEXT:    ld.param.b64 %rd1, [bswap64_param_0];
+; PTX71-NEXT:    mov.b64 {%r1, _}, %rd1;
+; PTX71-NEXT:    prmt.b32 %r2, %r1, 0, 0x123U;
+; PTX71-NEXT:    mov.b64 {_, %r3}, %rd1;
+; PTX71-NEXT:    prmt.b32 %r4, %r3, 0, 0x123U;
+; PTX71-NEXT:    mov.b64 %rd2, {%r4, %r2};
+; PTX71-NEXT:    st.param.b64 [func_retval0], %rd2;
+; PTX71-NEXT:    ret;
   %b = tail call i64 @llvm.bswap.i64(i64 %a)
   ret i64 %b
 }
diff --git a/llvm/test/CodeGen/NVPTX/prmt.ll b/llvm/test/CodeGen/NVPTX/prmt.ll
new file mode 100644
index 0000000000000..271e4c86cd23e
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/prmt.ll
@@ -0,0 +1,113 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -verify-machineinstrs | FileCheck %s
+; RUN: %if ptxas %{ llc < %s -verify-machineinstrs | %ptxas-verify %}
+
+target triple = "nvptx64-nvidia-cuda"
+
+define i32 @test_prmt_basic(i32 %lo, i32 %hi, i32 %selector) {
+; CHECK-LABEL: test_prmt_basic(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<5>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_basic_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_basic_param_1];
+; CHECK-NEXT:    ld.param.b32 %r3, [test_prmt_basic_param_2];
+; CHECK-NEXT:    prmt.b32 %r4, %r1, %r2, %r3;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r4;
+; CHECK-NEXT:    ret;
+    %val = call i32 @llvm.nvvm.prmt(i32 %lo, i32 %hi, i32 %selector)
+    ret i32 %val
+}
+
+define i32 @test_prmt_f4e(i32 %lo, i32 %hi, i32 %selector) {
+; CHECK-LABEL: test_prmt_f4e(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<5>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_f4e_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_f4e_param_1];
+; CHECK-NEXT:    ld.param.b32 %r3, [test_prmt_f4e_param_2];
+; CHECK-NEXT:    prmt.b32.f4e %r4, %r1, %r2, %r3;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r4;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.f4e(i32 %lo, i32 %hi, i32 %selector)
+  ret i32 %val
+}
+
+define i32 @test_prmt_b4e(i32 %lo, i32 %hi, i32 %selector) {
+; CHECK-LABEL: test_prmt_b4e(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<5>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_b4e_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_b4e_param_1];
+; CHECK-NEXT:    ld.param.b32 %r3, [test_prmt_b4e_param_2];
+; CHECK-NEXT:    prmt.b32.b4e %r4, %r1, %r2, %r3;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r4;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.b4e(i32 %lo, i32 %hi, i32 %selector)
+  ret i32 %val
+}
+
+define i32 @test_prmt_rc8(i32 %lo, i32 %selector) {
+; CHECK-LABEL: test_prmt_rc8(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<4>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_rc8_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_rc8_param_1];
+; CHECK-NEXT:    prmt.b32.rc8 %r3, %r1, 0, %r2;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r3;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.rc8(i32 %lo, i32 %selector)
+  ret i32 %val
+}
+
+define i32 @test_prmt_ecl(i32 %lo, i32 %selector) {
+; CHECK-LABEL: test_prmt_ecl(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<4>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_ecl_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_ecl_param_1];
+; CHECK-NEXT:    prmt.b32.ecl %r3, %r1, 0, %r2;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r3;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.ecl(i32 %lo, i32 %selector)
+  ret i32 %val
+}
+
+define i32 @test_prmt_ecr(i32 %lo, i32 %selector) {
+; CHECK-LABEL: test_prmt_ecr(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<4>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_ecr_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_ecr_param_1];
+; CHECK-NEXT:    prmt.b32.ecr %r3, %r1, 0, %r2;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r3;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.ecr(i32 %lo, i32 %selector)
+  ret i32 %val
+}
+
+define i32 @test_prmt_rc16(i32 %lo, i32 %selector) {
+; CHECK-LABEL: test_prmt_rc16(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<4>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [test_prmt_rc16_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [test_prmt_rc16_param_1];
+; CHECK-NEXT:    prmt.b32.rc16 %r3, %r1, 0, %r2;
+; CHECK-NEXT:    st.param.b32 [func_retval0], %r3;
+; CHECK-NEXT:    ret;
+  %val = call i32 @llvm.nvvm.prmt.rc16(i32 %lo, i32 %selector)
+  ret i32 %val
+}

>From d6d52a4abc71c583bd5391c5c0b36483c65081fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?=
 =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?=
 =?UTF-8?q?=E3=83=B3=29?= <clementval at gmail.com>
Date: Thu, 22 May 2025 13:30:34 -0700
Subject: [PATCH 050/105] [flang][cuda] Do not generate cuf.alloc/cuf.free in
 device context (#141117)

`cuf.alloc` and `cuf.free` are converted to `fir.alloca` or deleted when
in device context during the CUFOpConversion pass. Do not generate them
in lowering to avoid confusion.
---
 flang/lib/Lower/ConvertVariable.cpp        | 12 ++++++++----
 flang/test/Lower/CUDA/cuda-allocatable.cuf |  2 +-
 flang/test/Lower/CUDA/cuda-shared.cuf      |  1 -
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 372c71b6d4821..a28596bfd0099 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -25,6 +25,7 @@
 #include "flang/Lower/StatementContext.h"
 #include "flang/Lower/Support/Utils.h"
 #include "flang/Lower/SymbolMap.h"
+#include "flang/Optimizer/Builder/CUFCommon.h"
 #include "flang/Optimizer/Builder/Character.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
@@ -735,8 +736,10 @@ static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
     if (dataAttr.getValue() == cuf::DataAttribute::Shared)
       return builder.create<cuf::SharedMemoryOp>(loc, ty, nm, symNm, lenParams,
                                                  indices);
-    return builder.create<cuf::AllocOp>(loc, ty, nm, symNm, dataAttr, lenParams,
-                                        indices);
+
+    if (!cuf::isCUDADeviceContext(builder.getRegion()))
+      return builder.create<cuf::AllocOp>(loc, ty, nm, symNm, dataAttr,
+                                          lenParams, indices);
   }
 
   // Let the builder do all the heavy lifting.
@@ -1072,8 +1075,9 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter,
   if (mustBeDefaultInitializedAtRuntime(var))
     Fortran::lower::defaultInitializeAtRuntime(converter, var.getSymbol(),
                                                symMap);
-  if (Fortran::semantics::NeedCUDAAlloc(var.getSymbol())) {
-    auto *builder = &converter.getFirOpBuilder();
+  auto *builder = &converter.getFirOpBuilder();
+  if (Fortran::semantics::NeedCUDAAlloc(var.getSymbol()) &&
+      !cuf::isCUDADeviceContext(builder->getRegion())) {
     cuf::DataAttributeAttr dataAttr =
         Fortran::lower::translateSymbolCUFDataAttribute(builder->getContext(),
                                                         var.getSymbol());
diff --git a/flang/test/Lower/CUDA/cuda-allocatable.cuf b/flang/test/Lower/CUDA/cuda-allocatable.cuf
index cec10dda839e9..36e768bd7d92c 100644
--- a/flang/test/Lower/CUDA/cuda-allocatable.cuf
+++ b/flang/test/Lower/CUDA/cuda-allocatable.cuf
@@ -186,7 +186,7 @@ attributes(global) subroutine sub8()
 end subroutine
 
 ! CHECK-LABEL: func.func @_QPsub8() attributes {cuf.proc_attr = #cuf.cuda_proc<global>}
-! CHECK: %[[DESC:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub8Ea"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+! CHECK: %[[DESC:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", uniq_name = "_QFsub8Ea"}
 ! CHECK: %[[A:.*]]:2 = hlfir.declare %[[DESC]] {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub8Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
 ! CHECK: %[[HEAP:.*]] = fir.allocmem !fir.array<?xf32>, %{{.*}} {fir.must_be_heap = true, uniq_name = "_QFsub8Ea.alloc"}
 ! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
diff --git a/flang/test/Lower/CUDA/cuda-shared.cuf b/flang/test/Lower/CUDA/cuda-shared.cuf
index 565857f01bdb8..f41011df06ae7 100644
--- a/flang/test/Lower/CUDA/cuda-shared.cuf
+++ b/flang/test/Lower/CUDA/cuda-shared.cuf
@@ -9,5 +9,4 @@ end subroutine
 
 ! CHECK-LABEL: func.func @_QPsharedmem() attributes {cuf.proc_attr = #cuf.cuda_proc<global>}
 ! CHECK: %{{.*}} = cuf.shared_memory !fir.array<32xf32> {bindc_name = "s", uniq_name = "_QFsharedmemEs"} -> !fir.ref<!fir.array<32xf32>>
-! CHECK: cuf.free %{{.*}}#0 : !fir.ref<i32> {data_attr = #cuf.cuda<device>}
 ! CHECK-NOT: cuf.free

>From ffa5ce04d0a5440f939881e0e329a173d486dd68 Mon Sep 17 00:00:00 2001
From: Umang Yadav <29876643+umangyadav at users.noreply.github.com>
Date: Thu, 22 May 2025 16:36:00 -0400
Subject: [PATCH 051/105] Add arith expansion of f8E8M0 type for extf/trunc ops
 (#140332)

F8E8M0 floating type is supposed to represent biased exponent bits of
F32 type in OCP Micro scaling floating point formats.


https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf

This PR expands `arith.truncf` and `arith.extf` to support this
behavior.

For the `arith.truncf` thing to note here is that F8E8M0FNU type has one
NaN representation which is encoded as `0xFF`. Therefore alll kinds of
NaNs and +/-Inf in Float32Type would map to NaN in F8E8M0FNU. F8E8M0FNU
doesn't have a sign bit therefore it is a lossy and irreversible
downcast.

cc: @krzysz00  @MaheshRavishankar @Muzammiluddin-Syed-ECE
---
 .../mlir/Dialect/Arith/Transforms/Passes.h    |   3 +
 .../mlir/Dialect/Arith/Transforms/Passes.td   |   8 +-
 .../Dialect/Arith/Transforms/ExpandOps.cpp    | 163 ++++++++++++++----
 mlir/test/Dialect/Arith/expand-ops.mlir       | 130 +++++++++++++-
 4 files changed, 270 insertions(+), 34 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
index 8d81d8ec14ee7..5aaac8d8e3dc5 100644
--- a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
+++ b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.h
@@ -59,6 +59,9 @@ void populateCeilFloorDivExpandOpsPatterns(RewritePatternSet &patterns);
 /// Add patterns to expand Arith bf16 patterns to lower level bitcasts/shifts.
 void populateExpandBFloat16Patterns(RewritePatternSet &patterns);
 
+/// Add patterns to expand Arith f8e8m0 patterns to lower level bitcasts/shifts.
+void populateExpandF8E8M0Patterns(RewritePatternSet &patterns);
+
 /// Add patterns to expand Arith ops.
 void populateArithExpandOpsPatterns(RewritePatternSet &patterns);
 
diff --git a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.td b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.td
index d026d494cb50c..e14b2aeee1c69 100644
--- a/mlir/include/mlir/Dialect/Arith/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Arith/Transforms/Passes.td
@@ -14,9 +14,11 @@ include "mlir/Pass/PassBase.td"
 def ArithExpandOpsPass : Pass<"arith-expand"> {
   let summary = "Legalize Arith ops to be convertible to LLVM.";
   let dependentDialects = ["vector::VectorDialect"];
-  let options = [
-    Option<"includeBf16", "include-bf16", "bool", /*default=*/"false",
-           "Enable the BF16 expansion patterns">,
+  let options =
+      [Option<"includeBf16", "include-bf16", "bool", /*default=*/"false",
+              "Enable the BF16 expansion patterns">,
+       Option<"includeF8E8M0", "include-f8e8m0", "bool", /*default=*/"false",
+              "Enable the F8E8M0 expansion patterns">,
   ];
 }
 
diff --git a/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp b/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
index 2d627e523cde5..95546bb09e765 100644
--- a/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/ExpandOps.cpp
@@ -35,6 +35,14 @@ static Value createConst(Location loc, Type type, int value,
   return rewriter.create<arith::ConstantOp>(loc, attr);
 }
 
+/// Creates shapedType using shape from cloneFrom and base type from cloneTo
+static Type cloneToShapedType(Type cloneFrom, Type cloneTo) {
+  if (auto shapedTy = dyn_cast<ShapedType>(cloneFrom)) {
+    return shapedTy.clone(cloneTo);
+  }
+  return cloneTo;
+}
+
 namespace {
 
 /// Expands CeilDivUIOp (n, m) into
@@ -225,12 +233,8 @@ struct BFloat16ExtFOpConverter : public OpRewritePattern<arith::ExtFOp> {
       return rewriter.notifyMatchFailure(op, "not a ext of bf16 to f32.");
     }
 
-    Type i16Ty = b.getI16Type();
-    Type i32Ty = b.getI32Type();
-    if (auto shapedTy = dyn_cast<ShapedType>(operandTy)) {
-      i16Ty = shapedTy.clone(i16Ty);
-      i32Ty = shapedTy.clone(i32Ty);
-    }
+    Type i16Ty = cloneToShapedType(operandTy, b.getI16Type());
+    Type i32Ty = cloneToShapedType(operandTy, b.getI32Type());
 
     Value bitcast = b.create<arith::BitcastOp>(i16Ty, operand);
     Value exti = b.create<arith::ExtUIOp>(i32Ty, bitcast);
@@ -264,14 +268,8 @@ struct BFloat16TruncFOpConverter : public OpRewritePattern<arith::TruncFOp> {
           op, "only applicable to default rounding mode.");
     }
 
-    Type i16Ty = b.getI16Type();
-    Type i32Ty = b.getI32Type();
-    Type f32Ty = b.getF32Type();
-    if (auto shapedTy = dyn_cast<ShapedType>(operandTy)) {
-      i16Ty = shapedTy.clone(i16Ty);
-      i32Ty = shapedTy.clone(i32Ty);
-      f32Ty = shapedTy.clone(f32Ty);
-    }
+    Type i16Ty = cloneToShapedType(operandTy, b.getI16Type());
+    Type i32Ty = cloneToShapedType(operandTy, b.getI32Type());
 
     // Algorithm borrowed from this excellent code:
     // https://github.com/pytorch/pytorch/blob/e1502c0cdbfd17548c612f25d5a65b1e4b86224d/c10/util/BFloat16.h#L60-L79
@@ -291,7 +289,7 @@ struct BFloat16TruncFOpConverter : public OpRewritePattern<arith::TruncFOp> {
     // Constant used to make the rounding bias.
     Value c7FFF = createConst(op.getLoc(), i32Ty, 0x7fff, rewriter);
     // Constant used to generate a quiet NaN.
-    Value c7FC0_i16 = createConst(op.getLoc(), i16Ty, 0x7fc0, rewriter);
+    Value c7FC0I16 = createConst(op.getLoc(), i16Ty, 0x7fc0, rewriter);
     // Small constants used to address bits.
     Value c16 = createConst(op.getLoc(), i32Ty, 16, rewriter);
     Value c1 = createConst(op.getLoc(), i32Ty, 1, rewriter);
@@ -313,18 +311,104 @@ struct BFloat16TruncFOpConverter : public OpRewritePattern<arith::TruncFOp> {
     // Now that the rounding-bias has been added, truncating the low bits
     // yields the correctly rounded result.
     Value biasedAndShifted = b.create<arith::ShRUIOp>(biased, c16);
-    Value normalCaseResult_i16 =
+    Value normalCaseResultI16 =
         b.create<arith::TruncIOp>(i16Ty, biasedAndShifted);
     // Select either the above-computed result, or a quiet NaN constant
     // if the input was NaN.
     Value select =
-        b.create<arith::SelectOp>(isNan, c7FC0_i16, normalCaseResult_i16);
+        b.create<arith::SelectOp>(isNan, c7FC0I16, normalCaseResultI16);
     Value result = b.create<arith::BitcastOp>(resultTy, select);
     rewriter.replaceOp(op, result);
     return success();
   }
 };
 
+struct F8E8M0ExtFOpConverter : public OpRewritePattern<arith::ExtFOp> {
+  using OpRewritePattern::OpRewritePattern;
+  LogicalResult matchAndRewrite(arith::ExtFOp op,
+                                PatternRewriter &rewriter) const final {
+    ImplicitLocOpBuilder b(op.getLoc(), rewriter);
+    Value operand = op.getOperand();
+    Type operandTy = operand.getType();
+    Type resultTy = op.getType();
+    Type operandETy = getElementTypeOrSelf(operandTy);
+    Type resultETy = getElementTypeOrSelf(resultTy);
+
+    if (!llvm::isa<Float8E8M0FNUType>(operandETy)) {
+      return rewriter.notifyMatchFailure(op, "not a ext of F8E8M0FNU");
+    }
+
+    Type i8Ty = cloneToShapedType(operandTy, b.getI8Type());
+    Type i32Ty = cloneToShapedType(operandTy, b.getI32Type());
+    Type f32Ty = cloneToShapedType(operandTy, b.getF32Type());
+
+    Value bitcast = b.create<arith::BitcastOp>(i8Ty, operand);
+    // create constants for NaNs
+    Value cF8NaN = createConst(op.getLoc(), i8Ty, 0xff, rewriter);
+    Value cF32NaN = createConst(op.getLoc(), i32Ty, 0xffffffff, rewriter);
+    Value cF32MantissaWidth = createConst(op->getLoc(), i32Ty, 23, rewriter);
+
+    Value exti = b.create<arith::ExtUIOp>(i32Ty, bitcast);
+    Value f32Bits = b.create<arith::ShLIOp>(exti, cF32MantissaWidth);
+
+    Value isNan =
+        b.create<arith::CmpIOp>(arith::CmpIPredicate::eq, bitcast, cF8NaN);
+    // select for NaNs
+    f32Bits = b.create<arith::SelectOp>(isNan, cF32NaN, f32Bits);
+    Value result = b.create<arith::BitcastOp>(f32Ty, f32Bits);
+    if (resultETy.getIntOrFloatBitWidth() < 32) {
+      result = b.create<arith::TruncFOp>(resultTy, result);
+    } else if (resultETy.getIntOrFloatBitWidth() > 32) {
+      result = b.create<arith::ExtFOp>(resultTy, result);
+    }
+    rewriter.replaceOp(op, result);
+    return success();
+  }
+};
+
+/*
+TruncF to F8E8M0 is expected to extract exponent bits out of F32 type
+Since All kinds of Infs and NaNs are mapped to same exponent bits in F32 type,
+they all map to NaN in F8E8M0 Type.
+*/
+struct F8E8M0TruncFOpConverter : public OpRewritePattern<arith::TruncFOp> {
+  using OpRewritePattern::OpRewritePattern;
+  LogicalResult matchAndRewrite(arith::TruncFOp op,
+                                PatternRewriter &rewriter) const final {
+    ImplicitLocOpBuilder b(op.getLoc(), rewriter);
+    Value operand = op.getOperand();
+    Type operandTy = operand.getType();
+    Type operandETy = getElementTypeOrSelf(operandTy);
+    Type resultTy = op.getType();
+    Type resultETy = getElementTypeOrSelf(resultTy);
+    if (!llvm::isa<Float8E8M0FNUType>(resultETy)) {
+      return rewriter.notifyMatchFailure(op, "not a truncf to f8E8M0FNU");
+    }
+
+    if (op.getRoundingmodeAttr()) {
+      return rewriter.notifyMatchFailure(
+          op, "only applicable to default rounding mode.");
+    }
+
+    Type i8Ty = cloneToShapedType(operandTy, b.getI8Type());
+    Type i32Ty = cloneToShapedType(operandTy, b.getI32Type());
+    Type f32Ty = cloneToShapedType(operandTy, b.getF32Type());
+
+    if (operandETy.getIntOrFloatBitWidth() < 32) {
+      operand = b.create<arith::ExtFOp>(f32Ty, operand);
+    } else if (operandETy.getIntOrFloatBitWidth() > 32) {
+      operand = b.create<arith::TruncFOp>(f32Ty, operand);
+    }
+    Value f32Bits = b.create<arith::BitcastOp>(i32Ty, operand);
+    Value cF32MantissaWidth = createConst(op->getLoc(), i32Ty, 23, rewriter);
+    Value f32SignExp = b.create<arith::ShRUIOp>(f32Bits, cF32MantissaWidth);
+    Value exp8Bits = b.create<arith::TruncIOp>(i8Ty, f32SignExp);
+    Value result = b.create<arith::BitcastOp>(resultTy, exp8Bits);
+    rewriter.replaceOp(op, result);
+    return success();
+  }
+};
+
 struct ArithExpandOpsPass
     : public arith::impl::ArithExpandOpsPassBase<ArithExpandOpsPass> {
   using ArithExpandOpsPassBase::ArithExpandOpsPassBase;
@@ -353,20 +437,34 @@ struct ArithExpandOpsPass
 
     if (includeBf16) {
       arith::populateExpandBFloat16Patterns(patterns);
-      target.addDynamicallyLegalOp<arith::ExtFOp>(
-        [](arith::ExtFOp op) {
-          Type inETy = getElementTypeOrSelf(op.getOperand().getType());
-          Type outETy = getElementTypeOrSelf(op.getType());
-          return !(inETy.isBF16() && outETy.isF32());
-        });
-
-      target.addDynamicallyLegalOp<arith::TruncFOp>(
-        [](arith::TruncFOp op)  {
-          Type inETy = getElementTypeOrSelf(op.getOperand().getType());
-          Type outETy = getElementTypeOrSelf(op.getType());
-          return !(inETy.isF32() && outETy.isBF16());
-        });
     }
+    if (includeF8E8M0) {
+      arith::populateExpandF8E8M0Patterns(patterns);
+    }
+
+    target.addDynamicallyLegalOp<arith::ExtFOp>(
+      [=](arith::ExtFOp op) {
+        Type inETy = getElementTypeOrSelf(op.getOperand().getType());
+        Type outETy = getElementTypeOrSelf(op.getType());
+        bool legalTypes = true;
+        if (includeBf16) 
+          legalTypes &= !(inETy.isBF16() && outETy.isF32());
+        if (includeF8E8M0)
+          legalTypes &= !llvm::isa<Float8E8M0FNUType>(inETy);
+        return legalTypes;
+      });
+
+    target.addDynamicallyLegalOp<arith::TruncFOp>(
+      [=](arith::TruncFOp op)  {
+        Type inETy = getElementTypeOrSelf(op.getOperand().getType());
+        Type outETy = getElementTypeOrSelf(op.getType());
+        bool legalTypes = true;
+        if (includeBf16) 
+          legalTypes &= !(inETy.isF32() && outETy.isBF16());
+        if (includeF8E8M0) 
+          legalTypes &= !(llvm::isa<Float8E8M0FNUType>(outETy)); 
+        return legalTypes;
+      });
 
     // clang-format on
     if (failed(applyPartialConversion(getOperation(), target,
@@ -389,6 +487,11 @@ void mlir::arith::populateExpandBFloat16Patterns(RewritePatternSet &patterns) {
       patterns.getContext());
 }
 
+void mlir::arith::populateExpandF8E8M0Patterns(RewritePatternSet &patterns) {
+  patterns.add<F8E8M0ExtFOpConverter, F8E8M0TruncFOpConverter>(
+      patterns.getContext());
+}
+
 void mlir::arith::populateArithExpandOpsPatterns(RewritePatternSet &patterns) {
   populateCeilFloorDivExpandOpsPatterns(patterns);
   // clang-format off
diff --git a/mlir/test/Dialect/Arith/expand-ops.mlir b/mlir/test/Dialect/Arith/expand-ops.mlir
index bdf022642b717..5b6badf13d763 100644
--- a/mlir/test/Dialect/Arith/expand-ops.mlir
+++ b/mlir/test/Dialect/Arith/expand-ops.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -arith-expand="include-bf16=true" -split-input-file | FileCheck %s
+// RUN: mlir-opt %s -arith-expand="include-bf16=true include-f8e8m0=true" -split-input-file | FileCheck %s
 
 // Test ceil divide with signed integer
 // CHECK-LABEL:       func @ceildivi
@@ -248,6 +248,134 @@ func.func @truncf_vector_f32(%arg0 : vector<4xf32>) -> vector<4xbf16> {
 // CHECK-LABEL: @truncf_vector_f32
 // CHECK-NOT: arith.truncf
 
+// -----
+func.func @truncf_f32_to_f8E8M0FNU(%arg0 : f32) -> f8E8M0FNU {
+    %0 = arith.truncf %arg0 : f32 to f8E8M0FNU
+    return %0 : f8E8M0FNU
+}
+// CHECK-LABLE: @truncf_f32_to_f8E8M0FNU
+// CHECK: %[[BITCAST:.+]] = arith.bitcast %arg0 : f32 to i32
+// CHECK: %[[C23_i32:.+]] = arith.constant 23 : i32
+// CHECK: %[[SHRUI:.+]] = arith.shrui %[[BITCAST]], %[[C23_i32]] : i32
+// CHECK: %[[TRUNCI:.+]] = arith.trunci %[[SHRUI]] : i32 to i8
+// CHECK: %[[RESULT:.+]] = arith.bitcast %[[TRUNCI]] : i8 to f8E8M0FNU
+// CHECK: return %[[RESULT]]
+
+// -----
+
+func.func @truncf_f16_to_f8E8M0FNU(%arg0 : f16) -> f8E8M0FNU {
+    %0 = arith.truncf %arg0 : f16 to f8E8M0FNU
+    return %0 : f8E8M0FNU
+}
+// CHECK-LABLE: @truncf_f16_to_f8E8M0FNU
+// CHECK: %[[EXTF:.+]] = arith.extf %arg0 : f16 to f32
+// CHECK: %[[BITCAST:.+]] = arith.bitcast %[[EXTF]] : f32 to i32
+// CHECK: %[[C23_i32:.+]] = arith.constant 23 : i32
+// CHECK: %[[SHRUI:.+]] = arith.shrui %[[BITCAST]], %[[C23_i32]] : i32
+// CHECK: %[[TRUNCI:.+]] = arith.trunci %[[SHRUI]] : i32 to i8
+// CHECK: %[[RESULT:.+]] = arith.bitcast %[[TRUNCI]] : i8 to f8E8M0FNU
+// CHECK: return %[[RESULT]]
+
+// -----
+
+func.func @truncf_vector_f32_to_f8E8M0FNU(%arg0 : vector<4xf32>) -> vector<4xf8E8M0FNU> {
+    %0 = arith.truncf %arg0 : vector<4xf32> to vector<4xf8E8M0FNU>
+    return %0 : vector<4xf8E8M0FNU>
+}
+
+// CHECK-LABEL: @truncf_vector_f32_to_f8E8M0FNU
+// CHECK-NOT: arith.truncf
+
+// -----
+
+func.func @truncf_vector_f16_to_f8E8M0FNU(%arg0 : vector<4xf16>) -> vector<4xf8E8M0FNU> {
+    %0 = arith.truncf %arg0 : vector<4xf16> to vector<4xf8E8M0FNU>
+    return %0 : vector<4xf8E8M0FNU>
+}
+
+// CHECK-LABEL: @truncf_vector_f16_to_f8E8M0FNU
+// CHECK-NOT: arith.truncf
+
+// -----
+
+func.func @truncf_vector_bf16_to_f8E8M0FNU(%arg0 : vector<4xbf16>) -> vector<4xf8E8M0FNU> {
+    %0 = arith.truncf %arg0 : vector<4xbf16> to vector<4xf8E8M0FNU>
+    return %0 : vector<4xf8E8M0FNU>
+}
+
+// CHECK-LABEL: @truncf_vector_bf16_to_f8E8M0FNU
+// CHECK-NOT: arith.truncf
+
+
+// -----
+func.func @extf_f8E8M0FNU_to_f32(%arg0 : f8E8M0FNU) -> f32 {
+    %0 = arith.extf %arg0 : f8E8M0FNU to f32
+    return %0 : f32
+}
+
+// CHECK-LABLE: @extf_f8E8M0FNU_to_f32
+// CHECK: %[[BITCAST:.+]] = arith.bitcast %arg0 : f8E8M0FNU to i8
+// CHECK-DAG: %[[CF8NAN:.+]] = arith.constant -1 : i8
+// CHECK-DAG: %[[CF32NAN:.+]] = arith.constant -1 : i32
+// CHECK-DAG: %[[C23_i32:.+]] = arith.constant 23 : i32
+// CHECK: %[[EXTUI:.+]] = arith.extui %[[BITCAST]] : i8 to i32
+// CHECK: %[[SHLI:.+]] = arith.shli %[[EXTUI]], %[[C23_i32]] : i32
+// CHECK: %[[CMP_NAN:.+]] = arith.cmpi eq, %[[BITCAST]], %[[CF8NAN]] : i8
+// CHECK: %[[SELECT_NAN:.+]] = arith.select %[[CMP_NAN]], %[[CF32NAN]], %[[SHLI]] : i32
+// CHECK: %[[RESULT:.+]] = arith.bitcast %[[SELECT_NAN]] : i32 to f32
+// CHECK: return %[[RESULT]]
+
+// -----
+
+func.func @extf_f8E8M0FNU_to_f16(%arg0 : f8E8M0FNU) -> f16 {
+    %0 = arith.extf %arg0 : f8E8M0FNU to f16
+    return %0 : f16
+}
+
+// CHECK-LABLE: @extf_f8E8M0FNU_to_f16
+// CHECK: %[[BITCAST:.+]] = arith.bitcast %arg0 : f8E8M0FNU to i8
+// CHECK-DAG: %[[CF8NAN:.+]] = arith.constant -1 : i8
+// CHECK-DAG: %[[CF32NAN:.+]] = arith.constant -1 : i32
+// CHECK-DAG: %[[C23_i32:.+]] = arith.constant 23 : i32
+// CHECK: %[[EXTUI:.+]] = arith.extui %[[BITCAST]] : i8 to i32
+// CHECK: %[[SHLI:.+]] = arith.shli %[[EXTUI]], %[[C23_i32]] : i32
+// CHECK: %[[CMP_NAN:.+]] = arith.cmpi eq, %[[BITCAST]], %[[CF8NAN]] : i8
+// CHECK: %[[SELECT_NAN:.+]] = arith.select %[[CMP_NAN]], %[[CF32NAN]], %[[SHLI]] : i32
+// CHECK: %[[F32_RESULT:.+]] = arith.bitcast %[[SELECT_NAN]] : i32 to f32
+// CHECK: %[[F16_RESULT:.+]] = arith.truncf %[[F32_RESULT]] : f32 to f16
+// CHECK: return %[[F16_RESULT]]
+
+// -----
+
+func.func @extf_vector_f8E8M0FNU_to_f32(%arg0 : vector<4xf8E8M0FNU>) -> vector<4xf32> {
+    %0 = arith.extf %arg0 : vector<4xf8E8M0FNU> to vector<4xf32>
+    return %0 : vector<4xf32>
+}
+
+// CHECK-LABEL: @extf_vector_f8E8M0FNU_to_f32
+// CHECK-NOT: arith.extf
+
+// -----
+
+func.func @extf_vector_f8E8M0FNU_to_f16(%arg0 : vector<4xf8E8M0FNU>) -> vector<4xf16> {
+    %0 = arith.extf %arg0 : vector<4xf8E8M0FNU> to vector<4xf16>
+    return %0 : vector<4xf16>
+}
+
+// CHECK-LABEL: @extf_vector_f8E8M0FNU_to_f16
+// CHECK-NOT: arith.extf
+
+// -----
+
+func.func @extf_vector_f8E8M0FNU_to_bf16(%arg0 : vector<4xf8E8M0FNU>) -> vector<4xbf16> {
+    %0 = arith.extf %arg0 : vector<4xf8E8M0FNU> to vector<4xbf16>
+    return %0 : vector<4xbf16>
+}
+
+// CHECK-LABEL: @extf_vector_f8E8M0FNU_to_bf16
+// CHECK-NOT: arith.extf
+
+
 // -----
 
 func.func @maxsi(%a: i32, %b: i32) -> i32 {

>From 656d9ba9346ad32aeffd5215c2bed43dfa710e16 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 13:39:54 -0700
Subject: [PATCH 052/105] [clang] Fix LogDiagnosticPrinter.h and
 ClangTidyPlugin.cpp after 9e306ad4 (#141131)

---
 clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp | 5 +++--
 clang/include/clang/Frontend/LogDiagnosticPrinter.h     | 1 -
 clang/lib/Frontend/LogDiagnosticPrinter.cpp             | 5 ++---
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
index 7911583db30e4..8c98ba7b9238a 100644
--- a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
+++ b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
@@ -40,9 +40,10 @@ class ClangTidyPluginAction : public PluginASTAction {
     // Create and set diagnostics engine
     auto *DiagConsumer =
         new ClangTidyDiagnosticConsumer(*Context, &Compiler.getDiagnostics());
+    auto DiagOpts = std::make_unique<DiagnosticOptions>();
     auto DiagEngine = std::make_unique<DiagnosticsEngine>(
-        new DiagnosticIDs, new DiagnosticOptions, DiagConsumer);
-    Context->setDiagnosticsEngine(DiagEngine.get());
+        new DiagnosticIDs, *DiagOpts, DiagConsumer);
+    Context->setDiagnosticsEngine(std::move(DiagOpts), DiagEngine.get());
 
     // Create the AST consumer.
     ClangTidyASTConsumerFactory Factory(*Context);
diff --git a/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
index b43b0da13967a..9807dfa3aba1a 100644
--- a/clang/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/clang/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -51,7 +51,6 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
   raw_ostream &OS;
   std::unique_ptr<raw_ostream> StreamOwner;
   const LangOptions *LangOpts;
-  DiagnosticOptions &DiagOpts;
 
   SourceLocation LastWarningLoc;
   FullSourceLoc LastLoc;
diff --git a/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 2d188931e4f8a..a4dd0298ef5e3 100644
--- a/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/clang/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -18,10 +18,9 @@ using namespace clang;
 using namespace markup;
 
 LogDiagnosticPrinter::LogDiagnosticPrinter(
-    raw_ostream &os, DiagnosticOptions &DiagOpts,
+    raw_ostream &os, DiagnosticOptions &,
     std::unique_ptr<raw_ostream> StreamOwner)
-    : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr),
-      DiagOpts(DiagOpts) {}
+    : OS(os), StreamOwner(std::move(StreamOwner)), LangOpts(nullptr) {}
 
 static StringRef getLevelName(DiagnosticsEngine::Level Level) {
   switch (Level) {

>From 45d8759cbed0f216786729718608a8be72a505c6 Mon Sep 17 00:00:00 2001
From: Peiyong Lin <linpyong at gmail.com>
Date: Thu, 22 May 2025 13:40:26 -0700
Subject: [PATCH 053/105] Emit nuw and nsw for mul and add when lowering to
 llvm.getelementptr (#140966)

Now that the GEP no wrap flags are known when lowering to
llvm.getelementptr, we can also emit nuw and nsw for the generated
llvm.mul and llvm.add when no unsigned wrap and no signed wrap are used
respectively.

fixes: iree-org/iree#20483

Signed-off-by: Lin, Peiyong <linpyong at gmail.com>
---
 mlir/lib/Conversion/LLVMCommon/Pattern.cpp      | 17 ++++++++++++++---
 .../convert-dynamic-memref-ops.mlir             | 16 ++++++++--------
 .../MemRefToLLVM/convert-static-memref-ops.mlir |  8 ++++----
 3 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/mlir/lib/Conversion/LLVMCommon/Pattern.cpp b/mlir/lib/Conversion/LLVMCommon/Pattern.cpp
index 8da850678878d..48fbcbcdbbde9 100644
--- a/mlir/lib/Conversion/LLVMCommon/Pattern.cpp
+++ b/mlir/lib/Conversion/LLVMCommon/Pattern.cpp
@@ -73,6 +73,15 @@ Value ConvertToLLVMPattern::getStridedElementPtr(
   Value base =
       memRefDescriptor.bufferPtr(rewriter, loc, *getTypeConverter(), type);
 
+  LLVM::IntegerOverflowFlags intOverflowFlags =
+      LLVM::IntegerOverflowFlags::none;
+  if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nusw)) {
+    intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nsw;
+  }
+  if (LLVM::bitEnumContainsAny(noWrapFlags, LLVM::GEPNoWrapFlags::nuw)) {
+    intOverflowFlags = intOverflowFlags | LLVM::IntegerOverflowFlags::nuw;
+  }
+
   Type indexType = getIndexType();
   Value index;
   for (int i = 0, e = indices.size(); i < e; ++i) {
@@ -82,10 +91,12 @@ Value ConvertToLLVMPattern::getStridedElementPtr(
           ShapedType::isDynamic(strides[i])
               ? memRefDescriptor.stride(rewriter, loc, i)
               : createIndexAttrConstant(rewriter, loc, indexType, strides[i]);
-      increment = rewriter.create<LLVM::MulOp>(loc, increment, stride);
+      increment = rewriter.create<LLVM::MulOp>(loc, increment, stride,
+                                               intOverflowFlags);
     }
-    index =
-        index ? rewriter.create<LLVM::AddOp>(loc, index, increment) : increment;
+    index = index ? rewriter.create<LLVM::AddOp>(loc, index, increment,
+                                                 intOverflowFlags)
+                  : increment;
   }
 
   Type elementPtrType = memRefDescriptor.getElementPtrType();
diff --git a/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir b/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
index 9ca8bcd1491bc..543fdf5c26f5e 100644
--- a/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/convert-dynamic-memref-ops.mlir
@@ -175,8 +175,8 @@ func.func @mixed_load(%mixed : memref<42x?xf32>, %i : index, %j : index) {
 //   CHECK-DAG:  %[[J:.*]] = builtin.unrealized_conversion_cast %[[Jarg]]
 //       CHECK:  %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 //  CHECK-NEXT:  %[[st0:.*]] = llvm.extractvalue %[[ld]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
-//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
-//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
+//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] overflow<nsw, nuw> : i64
+//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] overflow<nsw, nuw> : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 //  CHECK-NEXT:  llvm.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %mixed[%i, %j] : memref<42x?xf32>
@@ -192,8 +192,8 @@ func.func @dynamic_load(%dynamic : memref<?x?xf32>, %i : index, %j : index) {
 //   CHECK-DAG:  %[[J:.*]] = builtin.unrealized_conversion_cast %[[Jarg]]
 //       CHECK:  %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 //  CHECK-NEXT:  %[[st0:.*]] = llvm.extractvalue %[[ld]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
-//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
-//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
+//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] overflow<nsw, nuw> : i64
+//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] overflow<nsw, nuw> : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 //  CHECK-NEXT:  llvm.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %dynamic[%i, %j] : memref<?x?xf32>
@@ -230,8 +230,8 @@ func.func @dynamic_store(%dynamic : memref<?x?xf32>, %i : index, %j : index, %va
 //   CHECK-DAG:  %[[J:.*]] = builtin.unrealized_conversion_cast %[[Jarg]]
 //       CHECK:  %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 //  CHECK-NEXT:  %[[st0:.*]] = llvm.extractvalue %[[ld]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
-//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
-//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
+//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] overflow<nsw, nuw> : i64
+//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] overflow<nsw, nuw> : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 //  CHECK-NEXT:  llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
   memref.store %val, %dynamic[%i, %j] : memref<?x?xf32>
@@ -247,8 +247,8 @@ func.func @mixed_store(%mixed : memref<42x?xf32>, %i : index, %j : index, %val :
 //   CHECK-DAG:  %[[J:.*]] = builtin.unrealized_conversion_cast %[[Jarg]]
 //       CHECK:  %[[ptr:.*]] = llvm.extractvalue %[[ld:.*]][1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 //  CHECK-NEXT:  %[[st0:.*]] = llvm.extractvalue %[[ld]][4, 0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
-//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] : i64
-//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] : i64
+//  CHECK-NEXT:  %[[offI:.*]] = llvm.mul %[[I]], %[[st0]] overflow<nsw, nuw> : i64
+//  CHECK-NEXT:  %[[off1:.*]] = llvm.add %[[offI]], %[[J]] overflow<nsw, nuw> : i64
 //  CHECK-NEXT:  %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 //  CHECK-NEXT:  llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
   memref.store %val, %mixed[%i, %j] : memref<42x?xf32>
diff --git a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
index b03ac2c20112b..040a27e160557 100644
--- a/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/convert-static-memref-ops.mlir
@@ -138,8 +138,8 @@ func.func @static_load(%static : memref<10x42xf32>, %i : index, %j : index) {
 // CHECK-DAG:  %[[JJ:.*]] = builtin.unrealized_conversion_cast %[[J]]
 // CHECK:  %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 // CHECK:  %[[st0:.*]] = llvm.mlir.constant(42 : index) : i64
-// CHECK:  %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
-// CHECK:  %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
+// CHECK:  %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] overflow<nsw, nuw> : i64
+// CHECK:  %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] overflow<nsw, nuw> : i64
 // CHECK:  %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 // CHECK:  llvm.load %[[addr]] : !llvm.ptr -> f32
   %0 = memref.load %static[%i, %j] : memref<10x42xf32>
@@ -166,8 +166,8 @@ func.func @static_store(%static : memref<10x42xf32>, %i : index, %j : index, %va
 // CHECK-DAG: %[[JJ:.*]] = builtin.unrealized_conversion_cast %[[J]]
 // CHECK: %[[ptr:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
 // CHECK: %[[st0:.*]] = llvm.mlir.constant(42 : index) : i64
-// CHECK: %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] : i64
-// CHECK: %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] : i64
+// CHECK: %[[offI:.*]] = llvm.mul %[[II]], %[[st0]] overflow<nsw, nuw> : i64
+// CHECK: %[[off1:.*]] = llvm.add %[[offI]], %[[JJ]] overflow<nsw, nuw> : i64
 // CHECK: %[[addr:.*]] = llvm.getelementptr inbounds|nuw %[[ptr]][%[[off1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
 // CHECK: llvm.store %{{.*}}, %[[addr]] : f32, !llvm.ptr
 

>From 3ea2cec7324e1e4569cd15b9e6cb1a4a6e8aa521 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 22 May 2025 13:51:20 -0700
Subject: [PATCH 054/105] [flang] Fix build after 9e306ad4 (#141134)

---
 flang/include/flang/Frontend/CompilerInstance.h      |  2 +-
 flang/include/flang/Frontend/CompilerInvocation.h    |  2 +-
 flang/include/flang/Frontend/TextDiagnosticPrinter.h |  4 ++--
 flang/lib/Frontend/CompilerInstance.cpp              |  5 ++---
 flang/lib/Frontend/TextDiagnosticPrinter.cpp         |  8 ++++----
 flang/tools/flang-driver/driver.cpp                  | 10 +++++-----
 flang/tools/flang-driver/fc1_main.cpp                |  5 ++---
 flang/unittests/Frontend/CodeGenActionTest.cpp       |  3 ++-
 flang/unittests/Frontend/CompilerInstanceTest.cpp    |  7 ++++---
 9 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index 4ad95c9df42d7..4234e13597cd7 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -347,7 +347,7 @@ class CompilerInstance {
   ///
   /// \return The new object on success, or null on failure.
   static clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine>
-  createDiagnostics(clang::DiagnosticOptions *opts,
+  createDiagnostics(clang::DiagnosticOptions &opts,
                     clang::DiagnosticConsumer *client = nullptr,
                     bool shouldOwnClient = true);
   void createDiagnostics(clang::DiagnosticConsumer *client = nullptr,
diff --git a/flang/include/flang/Frontend/CompilerInvocation.h b/flang/include/flang/Frontend/CompilerInvocation.h
index d6ee1511cdb4b..06978029435b7 100644
--- a/flang/include/flang/Frontend/CompilerInvocation.h
+++ b/flang/include/flang/Frontend/CompilerInvocation.h
@@ -43,7 +43,7 @@ bool parseDiagnosticArgs(clang::DiagnosticOptions &opts,
 class CompilerInvocationBase {
 public:
   /// Options controlling the diagnostic engine.
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagnosticOpts;
+  std::shared_ptr<clang::DiagnosticOptions> diagnosticOpts;
   /// Options for the preprocessor.
   std::shared_ptr<Fortran::frontend::PreprocessorOptions> preprocessorOpts;
 
diff --git a/flang/include/flang/Frontend/TextDiagnosticPrinter.h b/flang/include/flang/Frontend/TextDiagnosticPrinter.h
index 9c99a0c314351..4913713b6c365 100644
--- a/flang/include/flang/Frontend/TextDiagnosticPrinter.h
+++ b/flang/include/flang/Frontend/TextDiagnosticPrinter.h
@@ -37,13 +37,13 @@ class TextDiagnostic;
 
 class TextDiagnosticPrinter : public clang::DiagnosticConsumer {
   raw_ostream &os;
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts;
+  clang::DiagnosticOptions &diagOpts;
 
   /// A string to prefix to error messages.
   std::string prefix;
 
 public:
-  TextDiagnosticPrinter(raw_ostream &os, clang::DiagnosticOptions *diags);
+  TextDiagnosticPrinter(raw_ostream &os, clang::DiagnosticOptions &diags);
   ~TextDiagnosticPrinter() override;
 
   /// Set the diagnostic printer prefix string, which will be printed at the
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index cbd2c58eeeb47..2e0f91fb0521c 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -226,12 +226,11 @@ bool CompilerInstance::executeAction(FrontendAction &act) {
 
 void CompilerInstance::createDiagnostics(clang::DiagnosticConsumer *client,
                                          bool shouldOwnClient) {
-  diagnostics =
-      createDiagnostics(&getDiagnosticOpts(), client, shouldOwnClient);
+  diagnostics = createDiagnostics(getDiagnosticOpts(), client, shouldOwnClient);
 }
 
 clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine>
-CompilerInstance::createDiagnostics(clang::DiagnosticOptions *opts,
+CompilerInstance::createDiagnostics(clang::DiagnosticOptions &opts,
                                     clang::DiagnosticConsumer *client,
                                     bool shouldOwnClient) {
   clang::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
diff --git a/flang/lib/Frontend/TextDiagnosticPrinter.cpp b/flang/lib/Frontend/TextDiagnosticPrinter.cpp
index 65626827af3b3..911b78a109e2e 100644
--- a/flang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/flang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -27,7 +27,7 @@
 using namespace Fortran::frontend;
 
 TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &diagOs,
-                                             clang::DiagnosticOptions *diags)
+                                             clang::DiagnosticOptions &diags)
     : os(diagOs), diagOpts(diags) {}
 
 TextDiagnosticPrinter::~TextDiagnosticPrinter() {}
@@ -81,7 +81,7 @@ void TextDiagnosticPrinter::printLocForRemarks(
     llvm::sys::path::make_preferred(absPath);
 
     // Used for changing only the bold attribute
-    if (diagOpts->ShowColors)
+    if (diagOpts.ShowColors)
       os.changeColor(llvm::raw_ostream::SAVEDCOLOR, true);
 
     // Print path, file name, line and column
@@ -113,11 +113,11 @@ void TextDiagnosticPrinter::HandleDiagnostic(
   printLocForRemarks(diagMessageStream, diagMsg);
 
   Fortran::frontend::TextDiagnostic::printDiagnosticLevel(os, level,
-                                                          diagOpts->ShowColors);
+                                                          diagOpts.ShowColors);
   Fortran::frontend::TextDiagnostic::printDiagnosticMessage(
       os,
       /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note, diagMsg,
-      diagOpts->ShowColors);
+      diagOpts.ShowColors);
 
   os.flush();
 }
diff --git a/flang/tools/flang-driver/driver.cpp b/flang/tools/flang-driver/driver.cpp
index ed52988feaa59..35cc2efc0ac01 100644
--- a/flang/tools/flang-driver/driver.cpp
+++ b/flang/tools/flang-driver/driver.cpp
@@ -43,9 +43,9 @@ std::string getExecutablePath(const char *argv0) {
 
 // This lets us create the DiagnosticsEngine with a properly-filled-out
 // DiagnosticOptions instance
-static clang::DiagnosticOptions *
+static std::unique_ptr<clang::DiagnosticOptions>
 createAndPopulateDiagOpts(llvm::ArrayRef<const char *> argv) {
-  auto *diagOpts = new clang::DiagnosticOptions;
+  auto diagOpts = std::make_unique<clang::DiagnosticOptions>();
 
   // Ignore missingArgCount and the return value of ParseDiagnosticArgs.
   // Any errors that would be diagnosed here will also be diagnosed later,
@@ -114,17 +114,17 @@ int main(int argc, const char **argv) {
   // Not in the frontend mode - continue in the compiler driver mode.
 
   // Create DiagnosticsEngine for the compiler driver
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
+  std::unique_ptr<clang::DiagnosticOptions> diagOpts =
       createAndPopulateDiagOpts(args);
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
       new clang::DiagnosticIDs());
   Fortran::frontend::TextDiagnosticPrinter *diagClient =
-      new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
+      new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), *diagOpts);
 
   diagClient->setPrefix(
       std::string(llvm::sys::path::stem(getExecutablePath(args[0]))));
 
-  clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient);
+  clang::DiagnosticsEngine diags(diagID, *diagOpts, diagClient);
 
   // Prepare the driver
   clang::driver::Driver theDriver(driverPath,
diff --git a/flang/tools/flang-driver/fc1_main.cpp b/flang/tools/flang-driver/fc1_main.cpp
index 49535275d084d..f2cd513d0028c 100644
--- a/flang/tools/flang-driver/fc1_main.cpp
+++ b/flang/tools/flang-driver/fc1_main.cpp
@@ -67,9 +67,8 @@ int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0) {
   // for parsing the arguments
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
       new clang::DiagnosticIDs());
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
-      new clang::DiagnosticOptions();
-  clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
+  clang::DiagnosticOptions diagOpts;
+  clang::DiagnosticsEngine diags(diagID, diagOpts, diagsBuffer);
   bool success = CompilerInvocation::createFromArgs(flang->getInvocation(),
                                                     argv, diags, argv0);
 
diff --git a/flang/unittests/Frontend/CodeGenActionTest.cpp b/flang/unittests/Frontend/CodeGenActionTest.cpp
index e9ff095973b97..6020abc463eda 100644
--- a/flang/unittests/Frontend/CodeGenActionTest.cpp
+++ b/flang/unittests/Frontend/CodeGenActionTest.cpp
@@ -86,8 +86,9 @@ class LLVMConversionFailureCodeGenAction : public CodeGenAction {
 TEST(CodeGenAction, GracefullyHandleLLVMConversionFailure) {
   std::string diagnosticOutput;
   llvm::raw_string_ostream diagnosticsOS(diagnosticOutput);
+  clang::DiagnosticOptions diagOpts;
   auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>(
-      diagnosticsOS, new clang::DiagnosticOptions());
+      diagnosticsOS, diagOpts);
 
   CompilerInstance ci;
   ci.createDiagnostics(diagPrinter.get(), /*ShouldOwnClient=*/false);
diff --git a/flang/unittests/Frontend/CompilerInstanceTest.cpp b/flang/unittests/Frontend/CompilerInstanceTest.cpp
index 3fe2f063e996a..8621c14029c15 100644
--- a/flang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/flang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -67,18 +67,19 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
   // 1. Set-up a basic DiagnosticConsumer
   std::string diagnosticOutput;
   llvm::raw_string_ostream diagnosticsOS(diagnosticOutput);
+  clang::DiagnosticOptions diagPrinterOpts;
   auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>(
-      diagnosticsOS, new clang::DiagnosticOptions());
+      diagnosticsOS, diagPrinterOpts);
 
   // 2. Create a CompilerInstance (to manage a DiagnosticEngine)
   CompilerInstance compInst;
 
   // 3. Set-up DiagnosticOptions
-  auto diagOpts = new clang::DiagnosticOptions();
+  clang::DiagnosticOptions diagOpts;
   // Tell the diagnostics engine to emit the diagnostic log to STDERR. This
   // ensures that a chained diagnostic consumer is created so that the test can
   // exercise the unowned diagnostic consumer in a chained consumer.
-  diagOpts->DiagnosticLogFile = "-";
+  diagOpts.DiagnosticLogFile = "-";
 
   // 4. Create a DiagnosticEngine with an unowned consumer
   IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags =

>From 23f0fbf8fff563c77f770f83096b522c3c99a82d Mon Sep 17 00:00:00 2001
From: Simon Pilgrim <llvm-dev at redking.me.uk>
Date: Thu, 22 May 2025 21:52:59 +0100
Subject: [PATCH 055/105] [APInt] APInt::clearBitsSlowCase - fix cut+paste typo
 when merging lo/himasks (#141108)

Fixes #141098
---
 llvm/lib/Support/APInt.cpp       | 4 ++--
 llvm/unittests/ADT/APIntTest.cpp | 9 +++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 4743a039a9eb6..954af7fff92a8 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -349,9 +349,9 @@ void APInt::clearBitsSlowCase(unsigned LoBit, unsigned HiBit) {
     // Create a high mask with ones above HiBit.
     uint64_t HiMask = ~(WORDTYPE_MAX >> (APINT_BITS_PER_WORD - HiShiftAmt));
     // If LoWord and HiWord are equal, then we combine the masks. Otherwise,
-    // set the bits in HiWord.
+    // clear the bits in HiWord.
     if (HiWord == LoWord)
-      LoMask &= HiMask;
+      LoMask |= HiMask;
     else
       U.pVal[HiWord] &= HiMask;
   }
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index a58fbd6deffa5..4741c7bcc140f 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -2556,6 +2556,15 @@ TEST(APIntTest, clearBits) {
   EXPECT_EQ(6u, i256.countl_one());
   EXPECT_EQ(16u, i256.popcount());
 
+  APInt i299 = APInt::getAllOnes(299);
+  i299.clearBits(240, 250);
+  EXPECT_EQ(240u, i299.countr_one());
+  EXPECT_EQ(0u, i299.countr_zero());
+  EXPECT_EQ(299u, i299.getActiveBits());
+  EXPECT_EQ(0u, i299.countl_zero());
+  EXPECT_EQ(49u, i299.countl_one());
+  EXPECT_EQ(289u, i299.popcount());
+
   APInt i311 = APInt::getAllOnes(311);
   i311.clearBits(33, 99);
   EXPECT_EQ(33u, i311.countr_one());

>From 19a4e5202db40117265cfd704e7d1b7370045f17 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 13:58:42 -0700
Subject: [PATCH 056/105] [llvm] Fix typos in documentation (#141078)

---
 llvm/docs/CommandGuide/llvm-dwarfdump.rst |  2 +-
 llvm/docs/CommandGuide/llvm-objcopy.rst   |  2 +-
 llvm/docs/DirectX/DXContainer.rst         | 12 ++++++------
 llvm/docs/PDB/CodeViewTypes.rst           |  4 ++--
 llvm/docs/RISCV/RISCVVectorExtension.rst  |  2 +-
 llvm/docs/SPIRVUsage.rst                  |  2 +-
 llvm/docs/ScudoHardenedAllocator.rst      |  2 +-
 llvm/docs/SecurityTransparencyReports.rst |  2 +-
 llvm/docs/StackMaps.rst                   |  2 +-
 llvm/docs/TableGen/BackEnds.rst           |  2 +-
 10 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/llvm/docs/CommandGuide/llvm-dwarfdump.rst b/llvm/docs/CommandGuide/llvm-dwarfdump.rst
index 426a6d596a1b8..c566b40346f4b 100644
--- a/llvm/docs/CommandGuide/llvm-dwarfdump.rst
+++ b/llvm/docs/CommandGuide/llvm-dwarfdump.rst
@@ -162,7 +162,7 @@ OPTIONS
 
 .. option:: --verify-json=<path>
 
-            Output JSON-formatted error summary to the a file specfied by
+            Output JSON-formatted error summary to the a file specified by
             <path>. Implies :option:`--verify`.  The output format is described
             in the section below (:ref:`verify-json-format`).
 
diff --git a/llvm/docs/CommandGuide/llvm-objcopy.rst b/llvm/docs/CommandGuide/llvm-objcopy.rst
index 96f3247780b3b..35d907fbe44d4 100644
--- a/llvm/docs/CommandGuide/llvm-objcopy.rst
+++ b/llvm/docs/CommandGuide/llvm-objcopy.rst
@@ -606,7 +606,7 @@ options. For GNU :program:`objcopy` compatibility, the values are all bfdnames.
 - `elf64-loongarch`
 - `elf64-s390`
 
-The following formats are suppoprted by :program:`llvm-objcopy` for the
+The following formats are supported by :program:`llvm-objcopy` for the
 :option:`--output-target` only:
 
 - `srec`
diff --git a/llvm/docs/DirectX/DXContainer.rst b/llvm/docs/DirectX/DXContainer.rst
index f2cd27257af7b..4ace8a13dd89f 100644
--- a/llvm/docs/DirectX/DXContainer.rst
+++ b/llvm/docs/DirectX/DXContainer.rst
@@ -222,7 +222,7 @@ is an index table, and the third block is the elements themselves, which in turn
 are separeated by input, output and patch constant or primitive elements.
 
 Signature elements capture much of the same data captured in the :ref:`SG1
-<ISG1>` parts. The use of an index table allows de-duplciation of data for a more
+<ISG1>` parts. The use of an index table allows de-duplication of data for a more
 compact final representation.
 
 The string table begins with a 32-bit unsigned integer specifying the table
@@ -430,7 +430,7 @@ Static Samplers          52                                          Many
 Root Signature Header
 ~~~~~~~~~~~~~~~~~~~~~
 
-The root signature header is 24 bytes long, consisting of six 32 bit values 
+The root signature header is 24 bytes long, consisting of six 32-bit values
 representing the version, number and offset of parameters, number and offset 
 of static samplers, and a flags field for global behaviours:
 
@@ -454,7 +454,7 @@ type having different size and fields.
 
 The slot of root parameters is preceded by a variable size section containing 
 the header information for such parameters. Such structure is 12 bytes long, 
-composed of three 32 bit values, representing the parameter type, a flag 
+composed of three 32-bit values, representing the parameter type, a flag
 encoding the pipeline stages where the data is visible, and an offset 
 calculated from the start of RTS0 section.
 
@@ -467,7 +467,7 @@ calculated from the start of RTS0 section.
    };
 
 After the header information has been serialized, the actual data for each of the
-root parameters is layout in a single continous blob. The parameters can be fetch 
+root parameters is layout in a single continuous blob. The parameters can be fetch 
 from such using the offset information, present in the header.
 
 The following sections will describe each of the root parameters types and their 
@@ -477,7 +477,7 @@ Root Constants
 ''''''''''''''
 
 The root constants are inline 32-bit values that show up in the shader 
-as a constant buffer. It is a 12 bytes long structure, two 32 bit values 
+as a constant buffer. It is a 12 bytes long structure, two 32-bit values
 encoding the register and space the constant is assigned to, and 
 the last 32 bits encode the number of constants being defined in the buffer.
 
@@ -520,7 +520,7 @@ Descriptor tables let shaders access multiple resources through a single pointer
 to a descriptor heap. 
 
 The tables are made of a collection of descriptor ranges. In Version 1.0, the 
-descriptor range is 20 bytes, containing five 32 bit values. It encodes a range 
+descriptor range is 20 bytes, containing five 32-bit values. It encodes a range
 of registers, including the register type, range length, register numbers and 
 space within range and the offset locating each range inside the table.
 
diff --git a/llvm/docs/PDB/CodeViewTypes.rst b/llvm/docs/PDB/CodeViewTypes.rst
index 64fe745d116e8..7a93ebec75405 100644
--- a/llvm/docs/PDB/CodeViewTypes.rst
+++ b/llvm/docs/PDB/CodeViewTypes.rst
@@ -43,12 +43,12 @@ records -- called ``member records`` do not.
 Leaf Records
 ------------
 
-All leaf records begin with the following 4 byte prefix:
+All leaf records begin with the following 4-byte prefix:
 
 .. code-block:: c++
 
   struct RecordHeader {
-    uint16_t RecordLen;  // Record length, not including this 2 byte field.
+    uint16_t RecordLen;  // Record length, not including this 2-byte field.
     uint16_t RecordKind; // Record kind enum.
   };
 
diff --git a/llvm/docs/RISCV/RISCVVectorExtension.rst b/llvm/docs/RISCV/RISCVVectorExtension.rst
index 6b2d2b2f18e4f..cfe9abfbdfcdb 100644
--- a/llvm/docs/RISCV/RISCVVectorExtension.rst
+++ b/llvm/docs/RISCV/RISCVVectorExtension.rst
@@ -260,7 +260,7 @@ VMV0 elimination
 
 Because masked instructions must have the mask register in ``v0``, a specific register class ``vmv0`` is used that contains only one register, ``v0``.
 
-However register coalescing may end up coleascing copies into ``vmv0``, resulting in instructions with multiple uses of ``vmv0`` that the register allocator can't allocate:
+However register coalescing may end up coalescing copies into ``vmv0``, resulting in instructions with multiple uses of ``vmv0`` that the register allocator can't allocate:
 
 .. code-block::
 
diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst
index 373dd1e3856d8..1858bda6160d4 100644
--- a/llvm/docs/SPIRVUsage.rst
+++ b/llvm/docs/SPIRVUsage.rst
@@ -188,7 +188,7 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na
    * - ``SPV_INTEL_variable_length_array``
      - Allows to allocate local arrays whose number of elements is unknown at compile time.
    * - ``SPV_INTEL_joint_matrix``
-     - Adds few matrix capabilities on top of SPV_KHR_cooperative_matrix extension, such as matrix prefetch, get element coordinate and checked load/store/construct instructions, tensor float 32 and bfloat type interpretations for multuply-add instruction.
+     - Adds few matrix capabilities on top of SPV_KHR_cooperative_matrix extension, such as matrix prefetch, get element coordinate and checked load/store/construct instructions, tensor float 32 and bfloat type interpretations for multiply-add instruction.
    * - ``SPV_KHR_bit_instructions``
      - Enables bit instructions to be used by SPIR-V modules without requiring the Shader capability.
    * - ``SPV_KHR_expect_assume``
diff --git a/llvm/docs/ScudoHardenedAllocator.rst b/llvm/docs/ScudoHardenedAllocator.rst
index 3268268e939d1..328c883bbd5db 100644
--- a/llvm/docs/ScudoHardenedAllocator.rst
+++ b/llvm/docs/ScudoHardenedAllocator.rst
@@ -36,7 +36,7 @@ The allocator combines several components that serve distinct purposes:
 
 - the Primary allocator: fast and efficient, it services smaller allocation
   sizes by carving reserved memory regions into blocks of identical size. There
-  are currently two Primary allocators implemented, specific to 32 and 64 bit
+  are currently two Primary allocators implemented, specific to 32- and 64-bit
   architectures. It is configurable via compile time options.
 
 - the Secondary allocator: slower, it services larger allocation sizes via the
diff --git a/llvm/docs/SecurityTransparencyReports.rst b/llvm/docs/SecurityTransparencyReports.rst
index e4d7c23236b6c..b9092785a1eac 100644
--- a/llvm/docs/SecurityTransparencyReports.rst
+++ b/llvm/docs/SecurityTransparencyReports.rst
@@ -218,7 +218,7 @@ Supply chain security related issues and project services-related issues
    Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=71 |br|
    redirect: https://issuetracker.google.com/issues/42410066 |br|
    archive: https://github.com/llvm/llvm-project/issues/132187
-2. “llvmbot account suspended due to supicious login” |br|
+2. “llvmbot account suspended due to suspicious login” |br|
    Details are available at https://bugs.chromium.org/p/llvm/issues/detail?id=72 |br|
    redirect: https://issuetracker.google.com/issues/42410067 |br|
    archive: https://github.com/llvm/llvm-project/issues/132243
diff --git a/llvm/docs/StackMaps.rst b/llvm/docs/StackMaps.rst
index 11b6b3e2ca321..56c82e2863c3b 100644
--- a/llvm/docs/StackMaps.rst
+++ b/llvm/docs/StackMaps.rst
@@ -144,7 +144,7 @@ destructive patching could overwrite program text or data outside the
 current function. We disallow overlapping stack map shadows so that
 the runtime does not need to consider this corner case.
 
-For example, a stack map with 8 byte shadow:
+For example, a stack map with 8-byte shadow:
 
 .. code-block:: llvm
 
diff --git a/llvm/docs/TableGen/BackEnds.rst b/llvm/docs/TableGen/BackEnds.rst
index 94af2e4ab8f5c..14232bc3f9f54 100644
--- a/llvm/docs/TableGen/BackEnds.rst
+++ b/llvm/docs/TableGen/BackEnds.rst
@@ -914,7 +914,7 @@ table, record with name ``Banana`` will come before the record with name
 ``Pear``. Because of this, the ``lookupCEntryByEncoding`` function will always
 return a pointer to the record with name ``Banana`` even though in some cases
 the correct result can be the record with name ``Pear``. Such kind of scenario
-makes the exisitng lookup function insufficient because they always return a
+makes the existing lookup function insufficient because they always return a
 pointer to a single entry from the table, but instead it should return a range
 of results because multiple entries match the criteria sought by the lookup
 function. In this case, the definition of the lookup function needs to be

>From 778801cc84399cf1cfe3d5534a911320ae9a7976 Mon Sep 17 00:00:00 2001
From: Maksim Panchenko <maks at fb.com>
Date: Thu, 22 May 2025 14:01:54 -0700
Subject: [PATCH 057/105] [BOLT] Never call fixBranches() on non-simple
 functions (#141112)

We should never call fixBranches() on a function with invalid CFG. E.g.,
ValidateInternalCalls modifies CFG for its internal analysis purposes.
At the same time, it marks the function as non-simple with an assumption
that fixBranches() will never run on that function.

However, calculateEmittedSize() by default calls fixBranches() which can
lead to all sorts of issues, including assertions firing in
fixBranches().

The fix is to use the original size for non-simple functions in
calculateEmittedSize() since we are supposed to emit the function
unmodified. Additionally, add an assertion at the start of
fixBranches().
---
 bolt/lib/Core/BinaryContext.cpp         |  4 +++
 bolt/lib/Core/BinaryFunction.cpp        |  2 ++
 bolt/test/X86/fix-branches-broken-cfg.s | 42 +++++++++++++++++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 bolt/test/X86/fix-branches-broken-cfg.s

diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 73059ef23775a..36b789d429363 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -2425,6 +2425,10 @@ BinaryContext::createInstructionPatch(uint64_t Address,
 
 std::pair<size_t, size_t>
 BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {
+  // Use the original size for non-simple functions.
+  if (!BF.isSimple() || BF.isIgnored())
+    return std::make_pair(BF.getSize(), 0);
+
   // Adjust branch instruction to match the current layout.
   if (FixBranches)
     BF.fixBranches();
diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index 22bd8f8ddb110..ceb9390b546e1 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -3579,6 +3579,8 @@ bool BinaryFunction::validateCFG() const {
 }
 
 void BinaryFunction::fixBranches() {
+  assert(isSimple() && "Expected function with valid CFG.");
+
   auto &MIB = BC.MIB;
   MCContext *Ctx = BC.Ctx.get();
 
diff --git a/bolt/test/X86/fix-branches-broken-cfg.s b/bolt/test/X86/fix-branches-broken-cfg.s
new file mode 100644
index 0000000000000..0de1d7ea92f9b
--- /dev/null
+++ b/bolt/test/X86/fix-branches-broken-cfg.s
@@ -0,0 +1,42 @@
+## Check that fixBranches() is not invoked on a broken CFG which could lead to
+## unintended consequences including a firing assertion.
+
+# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.o
+# RUN: link_fdata %s %t.o %t.fdata
+# RUN: llvm-strip --strip-unneeded %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=cdsplit \
+# RUN:         --data=%t.fdata --reorder-blocks=ext-tsp 2>&1 | FileCheck %s
+
+# CHECK: internal call detected
+
+        .text
+
+        .globl  foo
+        .type   foo, @function
+foo:
+        ret
+        .size foo, .-foo
+
+## main contains an internal call. ValidateInternalCalls pass will modify CFG
+## (making it invalid) and mark the function as non-simple. After that, we
+## cannot make any assumption about the CFG.
+
+        .globl  main
+        .type   main, @function
+main:
+        call .L1
+        ret
+.L1:
+        pushq   %rbp
+        movq    %rsp, %rbp
+        movl    $1, %edi
+LLmain_foo1:
+        call    foo
+# FDATA: 1 main #LLmain_foo1# 1 foo 0 0 600
+        movl    $4, %edi
+        xorl    %eax, %eax
+        popq    %rbp
+        retq
+.Lmain_end:
+        .size   main, .Lmain_end-main

>From 9d3ce552618da9630c29c5ff5f034f56cc6fd747 Mon Sep 17 00:00:00 2001
From: Jan Patrick Lehr <JanPatrick.Lehr at amd.com>
Date: Thu, 22 May 2025 23:03:27 +0200
Subject: [PATCH 058/105] [MC] Fix HIP buildbot errors after 68472a3 (#141138)

This fixes the errors on our HIP-Kokkos buildbot after
68472a39a0fbf38f5da7bb4ebe43e2ca87ff8308.
---
 .../Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp    | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
index 19e394e5bc38c..0c98c32c21c2c 100644
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp
@@ -18,6 +18,7 @@
 #include "llvm/MC/MCFixupKindInfo.h"
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/EndianStream.h"
 #include "llvm/TargetParser/TargetParser.h"
@@ -51,6 +52,8 @@ class AMDGPUAsmBackend : public MCAsmBackend {
 
   std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
   MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
+  bool shouldForceRelocation(const MCAssembler &, const MCFixup &,
+                             const MCValue &, const MCSubtargetInfo *) override;
 };
 
 } //End anonymous namespace
@@ -189,6 +192,13 @@ MCFixupKindInfo AMDGPUAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
   return Infos[Kind - FirstTargetFixupKind];
 }
 
+bool AMDGPUAsmBackend::shouldForceRelocation(const MCAssembler &,
+                                             const MCFixup &,
+                                             const MCValue &Target,
+                                             const MCSubtargetInfo *) {
+  return Target.getSpecifier();
+}
+
 unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
   return 4;
 }

>From 0c42aeff9e2ec4aa41952ef24fd6b56789d3e404 Mon Sep 17 00:00:00 2001
From: Finn Plummer <finn.c.plum at gmail.com>
Date: Thu, 22 May 2025 14:07:24 -0700
Subject: [PATCH 059/105] [HLSL][RootSignature] Add parsing of Register in
 params for RootDescriptors (#140148)

- defines the `parseRootDescriptorParams` infrastructure for parsing the
params of a `RootDescriptor`
- defines the register type to illustrate use
- add tests to demonstrate functionality

Part 2 of https://github.com/llvm/llvm-project/issues/126577
---
 .../clang/Parse/ParseHLSLRootSignature.h      |  6 +++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 42 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 34 +++++++++++++--
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  1 +
 4 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 939d45e0c01bc..0d56d2a16a268 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -89,6 +89,12 @@ class RootSignatureParser {
   };
   std::optional<ParsedConstantParams> parseRootConstantParams();
 
+  struct ParsedRootDescriptorParams {
+    std::optional<llvm::hlsl::rootsig::Register> Reg;
+  };
+  std::optional<ParsedRootDescriptorParams>
+  parseRootDescriptorParams(RootSignatureToken::Kind RegType);
+
   struct ParsedClauseParams {
     std::optional<llvm::hlsl::rootsig::Register> Reg;
     std::optional<uint32_t> NumDescriptors;
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index d71f2c22d5d4b..da01df04ac78e 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -176,20 +176,37 @@ std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() {
     return std::nullopt;
 
   RootDescriptor Descriptor;
+  TokenKind ExpectedReg;
   switch (DescriptorKind) {
   default:
     llvm_unreachable("Switch for consumed token was not provided");
   case TokenKind::kw_CBV:
     Descriptor.Type = DescriptorType::CBuffer;
+    ExpectedReg = TokenKind::bReg;
     break;
   case TokenKind::kw_SRV:
     Descriptor.Type = DescriptorType::SRV;
+    ExpectedReg = TokenKind::tReg;
     break;
   case TokenKind::kw_UAV:
     Descriptor.Type = DescriptorType::UAV;
+    ExpectedReg = TokenKind::uReg;
     break;
   }
 
+  auto Params = parseRootDescriptorParams(ExpectedReg);
+  if (!Params.has_value())
+    return std::nullopt;
+
+  // Check mandatory parameters were provided
+  if (!Params->Reg.has_value()) {
+    getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_missing_param)
+        << ExpectedReg;
+    return std::nullopt;
+  }
+
+  Descriptor.Reg = Params->Reg.value();
+
   if (consumeExpectedToken(TokenKind::pu_r_paren,
                            diag::err_hlsl_unexpected_end_of_params,
                            /*param of=*/TokenKind::kw_RootConstants))
@@ -398,6 +415,31 @@ RootSignatureParser::parseRootConstantParams() {
   return Params;
 }
 
+std::optional<RootSignatureParser::ParsedRootDescriptorParams>
+RootSignatureParser::parseRootDescriptorParams(TokenKind RegType) {
+  assert(CurToken.TokKind == TokenKind::pu_l_paren &&
+         "Expects to only be invoked starting at given token");
+
+  ParsedRootDescriptorParams Params;
+  do {
+    // ( `b` | `t` | `u`) POS_INT
+    if (tryConsumeExpectedToken(RegType)) {
+      if (Params.Reg.has_value()) {
+        getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
+            << CurToken.TokKind;
+        return std::nullopt;
+      }
+      auto Reg = parseRegister();
+      if (!Reg.has_value())
+        return std::nullopt;
+      Params.Reg = Reg;
+    }
+
+  } while (tryConsumeExpectedToken(TokenKind::pu_comma));
+
+  return Params;
+}
+
 std::optional<RootSignatureParser::ParsedClauseParams>
 RootSignatureParser::parseDescriptorTableClauseParams(TokenKind RegType) {
   assert(CurToken.TokKind == TokenKind::pu_l_paren &&
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 912e96e5700aa..665ef5b518be7 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -346,9 +346,9 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) {
 
 TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) {
   const llvm::StringLiteral Source = R"cc(
-    CBV(),
-    SRV(),
-    UAV()
+    CBV(b0),
+    SRV(t42),
+    UAV(u34893247)
   )cc";
 
   TrivialModuleLoader ModLoader;
@@ -369,14 +369,20 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) {
   RootElement Elem = Elements[0];
   ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::BReg);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::SRV);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::TReg);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 42u);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::UAV);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::UReg);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 34893247u);
 
   ASSERT_TRUE(Consumer->isSatisfied());
 }
@@ -494,6 +500,28 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidMissingDTParameterTest) {
   ASSERT_TRUE(Consumer->isSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRDParameterTest) {
+  // This test will check that the parsing fails due a mandatory
+  // parameter (register) not being specified
+  const llvm::StringLiteral Source = R"cc(
+    SRV()
+  )cc";
+
+  TrivialModuleLoader ModLoader;
+  auto PP = createPP(Source, ModLoader);
+  auto TokLoc = SourceLocation();
+
+  hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+  SmallVector<RootElement> Elements;
+  hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+  // Test correct diagnostic produced
+  Consumer->setExpected(diag::err_hlsl_rootsig_missing_param);
+  ASSERT_TRUE(Parser.parse());
+
+  ASSERT_TRUE(Consumer->isSatisfied());
+}
+
 TEST_F(ParseHLSLRootSignatureTest, InvalidMissingRCParameterTest) {
   // This test will check that the parsing fails due a mandatory
   // parameter (num32BitConstants) not being specified
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 7829b842fa2be..4b1bbd0e3bd12 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -89,6 +89,7 @@ using DescriptorType = llvm::dxil::ResourceClass;
 // Models RootDescriptor : CBV | SRV | UAV, by collecting like parameters
 struct RootDescriptor {
   DescriptorType Type;
+  Register Reg;
 };
 
 // Models the end of a descriptor table and stores its visibility

>From 97dee78eb364efab6ddb57bc6580c55971994f41 Mon Sep 17 00:00:00 2001
From: Paul Kirth <paulkirth at google.com>
Date: Thu, 22 May 2025 14:20:08 -0700
Subject: [PATCH 060/105] [clang-doc] Add helpers for Template config (#138062)

This patch adds or fills in some helper functions related to template
setup when initializing the mustache backend. It was split from #133161.

Co-authored-by: Peter Chou <peter.chou at mail.utoronto.ca>
---
 .../clang-doc/HTMLMustacheGenerator.cpp       | 44 ++++++++++++++
 ...ate.mustache => comment-template.mustache} |  0
 .../clang-doc/support/CMakeLists.txt          |  3 +-
 clang-tools-extra/clang-doc/support/Utils.cpp | 60 +++++++++++++++++++
 clang-tools-extra/clang-doc/support/Utils.h   | 26 ++++++++
 .../clang-doc/tool/CMakeLists.txt             |  2 +-
 .../unittests/clang-doc/CMakeLists.txt        | 11 ++++
 .../clang-doc/HTMLMustacheGeneratorTest.cpp   | 11 +++-
 .../unittests/clang-doc/config.h.cmake        |  6 ++
 9 files changed, 159 insertions(+), 4 deletions(-)
 rename clang-tools-extra/clang-doc/assets/{comments-template.mustache => comment-template.mustache} (100%)
 create mode 100644 clang-tools-extra/clang-doc/support/Utils.cpp
 create mode 100644 clang-tools-extra/clang-doc/support/Utils.h
 create mode 100644 clang-tools-extra/unittests/clang-doc/config.h.cmake

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 366deb55b77b9..fd68b2e08ad98 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -18,6 +18,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Mustache.h"
+#include "llvm/Support/Path.h"
 
 using namespace llvm;
 using namespace llvm::json;
@@ -74,7 +75,50 @@ static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;
 
 static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;
 
+static Error
+setupTemplate(std::unique_ptr<MustacheTemplateFile> &Template,
+              StringRef TemplatePath,
+              std::vector<std::pair<StringRef, StringRef>> Partials) {
+  auto T = MustacheTemplateFile::createMustacheFile(TemplatePath);
+  if (Error Err = T.takeError())
+    return Err;
+  Template = std::move(T.get());
+  for (const auto [Name, FileName] : Partials)
+    if (auto Err = Template->registerPartialFile(Name, FileName))
+      return Err;
+  return Error::success();
+}
+
 static Error setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) {
+  // Template files need to use the native path when they're opened,
+  // but have to be used in POSIX style when used in HTML.
+  auto ConvertToNative = [](std::string &&Path) -> std::string {
+    SmallString<128> PathBuf(Path);
+    llvm::sys::path::native(PathBuf);
+    return PathBuf.str().str();
+  };
+
+  std::string NamespaceFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("namespace-template"));
+  std::string ClassFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("class-template"));
+  std::string CommentFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("comment-template"));
+  std::string FunctionFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("function-template"));
+  std::string EnumFilePath =
+      ConvertToNative(CDCtx.MustacheTemplates.lookup("enum-template"));
+  std::vector<std::pair<StringRef, StringRef>> Partials = {
+      {"Comments", CommentFilePath},
+      {"FunctionPartial", FunctionFilePath},
+      {"EnumPartial", EnumFilePath}};
+
+  if (Error Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials))
+    return Err;
+
+  if (Error Err = setupTemplate(RecordTemplate, ClassFilePath, Partials))
+    return Err;
+
   return Error::success();
 }
 
diff --git a/clang-tools-extra/clang-doc/assets/comments-template.mustache b/clang-tools-extra/clang-doc/assets/comment-template.mustache
similarity index 100%
rename from clang-tools-extra/clang-doc/assets/comments-template.mustache
rename to clang-tools-extra/clang-doc/assets/comment-template.mustache
diff --git a/clang-tools-extra/clang-doc/support/CMakeLists.txt b/clang-tools-extra/clang-doc/support/CMakeLists.txt
index a4f7993d5c9d8..8ac913ffbe998 100644
--- a/clang-tools-extra/clang-doc/support/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/support/CMakeLists.txt
@@ -6,4 +6,5 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangDocSupport STATIC
   File.cpp
-  )
\ No newline at end of file
+  Utils.cpp
+  )
diff --git a/clang-tools-extra/clang-doc/support/Utils.cpp b/clang-tools-extra/clang-doc/support/Utils.cpp
new file mode 100644
index 0000000000000..6ed56033738b5
--- /dev/null
+++ b/clang-tools-extra/clang-doc/support/Utils.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Utils.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+using namespace llvm;
+
+SmallString<128> appendPathNative(StringRef Base, StringRef Path) {
+  SmallString<128> Default;
+  sys::path::native(Base, Default);
+  sys::path::append(Default, Path);
+  return Default;
+}
+
+SmallString<128> appendPathPosix(StringRef Base, StringRef Path) {
+  SmallString<128> Default;
+  sys::path::native(Base, Default, sys::path::Style::posix);
+  sys::path::append(Default, Path);
+  return Default;
+}
+
+void getMustacheHtmlFiles(StringRef AssetsPath,
+                          clang::doc::ClangDocContext &CDCtx) {
+  assert(!AssetsPath.empty());
+  assert(sys::fs::is_directory(AssetsPath));
+
+  SmallString<128> DefaultStylesheet =
+      appendPathPosix(AssetsPath, "clang-doc-mustache.css");
+  SmallString<128> NamespaceTemplate =
+      appendPathPosix(AssetsPath, "namespace-template.mustache");
+  SmallString<128> ClassTemplate =
+      appendPathPosix(AssetsPath, "class-template.mustache");
+  SmallString<128> EnumTemplate =
+      appendPathPosix(AssetsPath, "enum-template.mustache");
+  SmallString<128> FunctionTemplate =
+      appendPathPosix(AssetsPath, "function-template.mustache");
+  SmallString<128> CommentTemplate =
+      appendPathPosix(AssetsPath, "comment-template.mustache");
+  SmallString<128> IndexJS = appendPathPosix(AssetsPath, "mustache-index.js");
+
+  CDCtx.JsScripts.insert(CDCtx.JsScripts.begin(), IndexJS.c_str());
+  CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(),
+                               DefaultStylesheet.c_str());
+  CDCtx.MustacheTemplates.insert(
+      {"namespace-template", NamespaceTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"class-template", ClassTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"enum-template", EnumTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert(
+      {"function-template", FunctionTemplate.c_str()});
+  CDCtx.MustacheTemplates.insert({"comment-template", CommentTemplate.c_str()});
+}
diff --git a/clang-tools-extra/clang-doc/support/Utils.h b/clang-tools-extra/clang-doc/support/Utils.h
new file mode 100644
index 0000000000000..8161c37503f81
--- /dev/null
+++ b/clang-tools-extra/clang-doc/support/Utils.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_FILE_H
+
+#include "../Representation.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+
+/// Appends \p Path to \p Base and returns the appended path.
+llvm::SmallString<128> appendPathNative(llvm::StringRef Base,
+                                        llvm::StringRef Path);
+
+/// Appends \p Path to \p Base and returns the appended path in posix style.
+llvm::SmallString<128> appendPathPosix(llvm::StringRef Base,
+                                       llvm::StringRef Path);
+
+void getMustacheHtmlFiles(llvm::StringRef AssetsPath,
+                          clang::doc::ClangDocContext &CDCtx);
+
+#endif
diff --git a/clang-tools-extra/clang-doc/tool/CMakeLists.txt b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
index e359beb5f9079..f380c621890fb 100644
--- a/clang-tools-extra/clang-doc/tool/CMakeLists.txt
+++ b/clang-tools-extra/clang-doc/tool/CMakeLists.txt
@@ -25,7 +25,7 @@ set(assets
   clang-doc-default-stylesheet.css
   clang-doc-mustache.css
   class-template.mustache
-  comments-template.mustache
+  comment-template.mustache
   enum-template.mustache
   function-template.mustache
   namespace-template.mustache
diff --git a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
index fd14d85c63485..59a856ed987dc 100644
--- a/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-doc/CMakeLists.txt
@@ -4,10 +4,21 @@ set(LLVM_LINK_COMPONENTS
   FrontendOpenMP
   )
 
+# Unittests need access to mustache template files, so we use a config file to
+# inject those into a config.h header that can provide it to the unittests.
+set(CLANG_DOC_TEST_ASSET_DIR "${LLVM_RUNTIME_OUTPUT_INTDIR}/../share/clang-doc")
+configure_file(
+  "${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/config.h"
+)
+
+# The config.h file is in ${CMAKE_CURRENT_BINARY_DIR}, so add it to
+# include_directories.
 get_filename_component(CLANG_DOC_SOURCE_DIR
   ${CMAKE_CURRENT_SOURCE_DIR}/../../clang-doc REALPATH)
 include_directories(
   ${CLANG_DOC_SOURCE_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}
   )
 
 add_extra_unittest(ClangDocTests
diff --git a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
index c0ff3f0bbaa74..70491f0754b3d 100644
--- a/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
+++ b/clang-tools-extra/unittests/clang-doc/HTMLMustacheGeneratorTest.cpp
@@ -9,6 +9,8 @@
 #include "ClangDocTest.h"
 #include "Generators.h"
 #include "Representation.h"
+#include "config.h"
+#include "support/Utils.h"
 #include "clang/Basic/Version.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Testing/Support/Error.h"
@@ -86,8 +88,13 @@ TEST(HTMLMustacheGeneratorTest, generateDocs) {
   assert(G && "Could not find HTMLMustacheGenerator");
   ClangDocContext CDCtx = getClangDocContext();
 
-  StringRef RootDir = "";
-  EXPECT_THAT_ERROR(G->generateDocs(RootDir, {}, CDCtx), Succeeded())
+  unittest::TempDir RootTestDirectory("generateDocsTest", /*Unique=*/true);
+  CDCtx.OutDirectory = RootTestDirectory.path();
+
+  getMustacheHtmlFiles(CLANG_DOC_TEST_ASSET_DIR, CDCtx);
+
+  EXPECT_THAT_ERROR(G->generateDocs(RootTestDirectory.path(), {}, CDCtx),
+                    Succeeded())
       << "Failed to generate docs.";
 }
 
diff --git a/clang-tools-extra/unittests/clang-doc/config.h.cmake b/clang-tools-extra/unittests/clang-doc/config.h.cmake
new file mode 100644
index 0000000000000..38edb3530e994
--- /dev/null
+++ b/clang-tools-extra/unittests/clang-doc/config.h.cmake
@@ -0,0 +1,6 @@
+#ifndef CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_DOC_CONFIG_H
+#define CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_DOC_CONFIG_H
+
+#define CLANG_DOC_TEST_ASSET_DIR "${CLANG_DOC_TEST_ASSET_DIR}"
+
+#endif // CLANG_TOOLS_EXTRA_UNITTESTS_CLANG_DOC_CONFIG_H

>From 5a1311d51631d5faf931df0c24fdbca65dd962f5 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 22:47:17 +0100
Subject: [PATCH 061/105] [LAA] Strip isNoWrapGEP: dead code (NFC) (#140308)

isNoWrap is the only caller of isNoWrapGEP, and it has subsuming check
on the GEP immediately after.
---
 llvm/lib/Analysis/LoopAccessAnalysis.cpp | 51 ------------------------
 1 file changed, 51 deletions(-)

diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 6f05d2ac1a8d5..726795a8ee10d 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -851,9 +851,6 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
   return Stride;
 }
 
-static bool isNoWrapGEP(Value *Ptr, PredicatedScalarEvolution &PSE,
-                        const Loop *L);
-
 /// Check whether \p AR is a non-wrapping AddRec. If \p Ptr is not nullptr, use
 /// informating from the IR pointer value to determine no-wrap.
 static bool isNoWrap(PredicatedScalarEvolution &PSE, const SCEVAddRecExpr *AR,
@@ -866,11 +863,6 @@ static bool isNoWrap(PredicatedScalarEvolution &PSE, const SCEVAddRecExpr *AR,
   if (Ptr && PSE.hasNoOverflow(Ptr, SCEVWrapPredicate::IncrementNUSW))
     return true;
 
-  // The address calculation must not wrap. Otherwise, a dependence could be
-  // inverted.
-  if (Ptr && isNoWrapGEP(Ptr, PSE, L))
-    return true;
-
   // An nusw getelementptr that is an AddRec cannot wrap. If it would wrap,
   // the distance between the previously accessed location and the wrapped
   // location will be larger than half the pointer index type space. In that
@@ -1468,49 +1460,6 @@ void AccessAnalysis::processMemAccesses() {
   }
 }
 
-/// Check whether \p Ptr is non-wrapping GEP.
-static bool isNoWrapGEP(Value *Ptr, PredicatedScalarEvolution &PSE,
-                        const Loop *L) {
-  // Scalar evolution does not propagate the non-wrapping flags to values that
-  // are derived from a non-wrapping induction variable because non-wrapping
-  // could be flow-sensitive.
-  //
-  // Look through the potentially overflowing instruction to try to prove
-  // non-wrapping for the *specific* value of Ptr.
-
-  // The arithmetic implied by an nusw GEP can't overflow.
-  const auto *GEP = dyn_cast<GetElementPtrInst>(Ptr);
-  if (!GEP || !GEP->hasNoUnsignedSignedWrap())
-    return false;
-
-  // Make sure there is only one non-const index and analyze that.
-  Value *NonConstIndex = nullptr;
-  for (Value *Index : GEP->indices())
-    if (!isa<ConstantInt>(Index)) {
-      if (NonConstIndex)
-        return false;
-      NonConstIndex = Index;
-    }
-  if (!NonConstIndex)
-    // The recurrence is on the pointer, ignore for now.
-    return false;
-
-  // The index in GEP is signed.  It is non-wrapping if it's derived from a NSW
-  // AddRec using a NSW operation.
-  if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(NonConstIndex))
-    if (OBO->hasNoSignedWrap() &&
-        // Assume constant for other the operand so that the AddRec can be
-        // easily found.
-        isa<ConstantInt>(OBO->getOperand(1))) {
-      const SCEV *OpScev = PSE.getSCEV(OBO->getOperand(0));
-
-      if (auto *OpAR = dyn_cast<SCEVAddRecExpr>(OpScev))
-        return OpAR->getLoop() == L && OpAR->getNoWrapFlags(SCEV::FlagNSW);
-    }
-
-  return false;
-}
-
 /// Check whether the access through \p Ptr has a constant stride.
 std::optional<int64_t>
 llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,

>From b81170ecffb5f53d52eab5d3424ba6f1c8ef97d3 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 22:48:01 +0100
Subject: [PATCH 062/105] [IVDesc] Unify RecurKinds [I|F]FindLastIV (NFC)
 (#141082)

---
 llvm/include/llvm/Analysis/IVDescriptors.h      | 13 ++++++-------
 llvm/lib/Analysis/IVDescriptors.cpp             | 17 +++++------------
 llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp |  9 +++------
 3 files changed, 14 insertions(+), 25 deletions(-)

diff --git a/llvm/include/llvm/Analysis/IVDescriptors.h b/llvm/include/llvm/Analysis/IVDescriptors.h
index 140edff13a67f..c1441de6d816e 100644
--- a/llvm/include/llvm/Analysis/IVDescriptors.h
+++ b/llvm/include/llvm/Analysis/IVDescriptors.h
@@ -31,6 +31,7 @@ class StoreInst;
 
 /// These are the kinds of recurrences that we support.
 enum class RecurKind {
+  // clang-format off
   None,     ///< Not a recurrence.
   Add,      ///< Sum of integers.
   Mul,      ///< Product of integers.
@@ -54,12 +55,10 @@ enum class RecurKind {
             ///< loop invariant, and both x and y are integer type.
   FAnyOf,   ///< Any_of reduction with select(fcmp(),x,y) where one of (x,y) is
             ///< loop invariant, and both x and y are integer type.
-  IFindLastIV, ///< FindLast reduction with select(icmp(),x,y) where one of
-               ///< (x,y) is increasing loop induction, and both x and y are
-               ///< integer type.
-  FFindLastIV ///< FindLast reduction with select(fcmp(),x,y) where one of (x,y)
-              ///< is increasing loop induction, and both x and y are integer
-              ///< type.
+  FindLastIV, ///< FindLast reduction with select(cmp(),x,y) where one of
+              ///< (x,y) is increasing loop induction, and both x and y are
+              ///< integer type.
+  // clang-format on
   // TODO: Any_of and FindLast reduction need not be restricted to integer type
   // only.
 };
@@ -259,7 +258,7 @@ class RecurrenceDescriptor {
   /// Returns true if the recurrence kind is of the form
   ///   select(cmp(),x,y) where one of (x,y) is increasing loop induction.
   static bool isFindLastIVRecurrenceKind(RecurKind Kind) {
-    return Kind == RecurKind::IFindLastIV || Kind == RecurKind::FFindLastIV;
+    return Kind == RecurKind::FindLastIV;
   }
 
   /// Returns the type of the recurrence. This type can be narrower than the
diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp
index 6b7d31463d3a6..42d9e74e50174 100644
--- a/llvm/lib/Analysis/IVDescriptors.cpp
+++ b/llvm/lib/Analysis/IVDescriptors.cpp
@@ -51,8 +51,7 @@ bool RecurrenceDescriptor::isIntegerRecurrenceKind(RecurKind Kind) {
   case RecurKind::UMin:
   case RecurKind::IAnyOf:
   case RecurKind::FAnyOf:
-  case RecurKind::IFindLastIV:
-  case RecurKind::FFindLastIV:
+  case RecurKind::FindLastIV:
     return true;
   }
   return false;
@@ -743,8 +742,7 @@ RecurrenceDescriptor::isFindLastIVPattern(Loop *TheLoop, PHINode *OrigPhi,
   if (!IsIncreasingLoopInduction(NonRdxPhi))
     return InstDesc(false, I);
 
-  return InstDesc(I, isa<ICmpInst>(I->getOperand(0)) ? RecurKind::IFindLastIV
-                                                     : RecurKind::FFindLastIV);
+  return InstDesc(I, RecurKind::FindLastIV);
 }
 
 RecurrenceDescriptor::InstDesc
@@ -989,13 +987,9 @@ bool RecurrenceDescriptor::isReductionPHI(PHINode *Phi, Loop *TheLoop,
                       << *Phi << "\n");
     return true;
   }
-  if (AddReductionVar(Phi, RecurKind::IFindLastIV, TheLoop, FMF, RedDes, DB, AC,
+  if (AddReductionVar(Phi, RecurKind::FindLastIV, TheLoop, FMF, RedDes, DB, AC,
                       DT, SE)) {
-    LLVM_DEBUG(dbgs() << "Found a "
-                      << (RedDes.getRecurrenceKind() == RecurKind::FFindLastIV
-                              ? "F"
-                              : "I")
-                      << "FindLastIV reduction PHI." << *Phi << "\n");
+    LLVM_DEBUG(dbgs() << "Found a FindLastIV reduction PHI." << *Phi << "\n");
     return true;
   }
   if (AddReductionVar(Phi, RecurKind::FMul, TheLoop, FMF, RedDes, DB, AC, DT,
@@ -1152,6 +1146,7 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
     return Instruction::Mul;
   case RecurKind::IAnyOf:
   case RecurKind::FAnyOf:
+  case RecurKind::FindLastIV:
   case RecurKind::Or:
     return Instruction::Or;
   case RecurKind::And:
@@ -1167,7 +1162,6 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
   case RecurKind::SMin:
   case RecurKind::UMax:
   case RecurKind::UMin:
-  case RecurKind::IFindLastIV:
     return Instruction::ICmp;
   case RecurKind::FMax:
   case RecurKind::FMin:
@@ -1175,7 +1169,6 @@ unsigned RecurrenceDescriptor::getOpcode(RecurKind Kind) {
   case RecurKind::FMinimum:
   case RecurKind::FMaximumNum:
   case RecurKind::FMinimumNum:
-  case RecurKind::FFindLastIV:
     return Instruction::FCmp;
   default:
     llvm_unreachable("Unknown recurrence operation");
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 7df9ab039d887..3aefbd8e5e597 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -23091,8 +23091,7 @@ class HorizontalReduction {
         case RecurKind::FMulAdd:
         case RecurKind::IAnyOf:
         case RecurKind::FAnyOf:
-        case RecurKind::IFindLastIV:
-        case RecurKind::FFindLastIV:
+        case RecurKind::FindLastIV:
         case RecurKind::FMaximumNum:
         case RecurKind::FMinimumNum:
         case RecurKind::None:
@@ -23227,8 +23226,7 @@ class HorizontalReduction {
     case RecurKind::FMulAdd:
     case RecurKind::IAnyOf:
     case RecurKind::FAnyOf:
-    case RecurKind::IFindLastIV:
-    case RecurKind::FFindLastIV:
+    case RecurKind::FindLastIV:
     case RecurKind::FMaximumNum:
     case RecurKind::FMinimumNum:
     case RecurKind::None:
@@ -23328,8 +23326,7 @@ class HorizontalReduction {
     case RecurKind::FMulAdd:
     case RecurKind::IAnyOf:
     case RecurKind::FAnyOf:
-    case RecurKind::IFindLastIV:
-    case RecurKind::FFindLastIV:
+    case RecurKind::FindLastIV:
     case RecurKind::FMaximumNum:
     case RecurKind::FMinimumNum:
     case RecurKind::None:

>From f398f2aadcc48849d491839a4e31bc3d4ad08758 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Thu, 22 May 2025 22:48:33 +0100
Subject: [PATCH 063/105] [InstCombine] Preserve GEP no-wrap flags (#141113)

---
 .../InstCombine/InstCombineVectorOps.cpp      |  4 +-
 .../InstCombine/gep-vector-indices.ll         | 28 ++++++++++++-
 .../Transforms/InstCombine/vec_shuffle.ll     | 39 +++++++++++++++++++
 3 files changed, 67 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
index f6423cb40492e..900946e9b335b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp
@@ -537,7 +537,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) {
 
           GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
               GEP->getSourceElementType(), NewPtr, NewOps);
-          NewGEP->setIsInBounds(GEP->isInBounds());
+          NewGEP->setNoWrapFlags(GEP->getNoWrapFlags());
           return NewGEP;
         }
       }
@@ -1982,7 +1982,7 @@ static Value *buildNew(Instruction *I, ArrayRef<Value*> NewOps,
       ArrayRef<Value*> Idx = NewOps.slice(1);
       return Builder.CreateGEP(cast<GEPOperator>(I)->getSourceElementType(),
                                Ptr, Idx, "",
-                               cast<GEPOperator>(I)->isInBounds());
+                               cast<GEPOperator>(I)->getNoWrapFlags());
     }
   }
   llvm_unreachable("failed to rebuild vector instructions");
diff --git a/llvm/test/Transforms/InstCombine/gep-vector-indices.ll b/llvm/test/Transforms/InstCombine/gep-vector-indices.ll
index 660ce317a0f64..ce584e0400cd5 100644
--- a/llvm/test/Transforms/InstCombine/gep-vector-indices.ll
+++ b/llvm/test/Transforms/InstCombine/gep-vector-indices.ll
@@ -12,8 +12,8 @@ define ptr @vector_splat_indices_v2i64_ext0(ptr %a) {
   ret ptr %res
 }
 
-define ptr @vector_splat_indices_nxv2i64_ext0(ptr %a) {
-; CHECK-LABEL: @vector_splat_indices_nxv2i64_ext0(
+define ptr @vector_splat_indices_nxv2i64_ext0_inbounds(ptr %a) {
+; CHECK-LABEL: @vector_splat_indices_nxv2i64_ext0_inbounds(
 ; CHECK-NEXT:    [[RES:%.*]] = getelementptr inbounds nuw i8, ptr [[A:%.*]], i64 16
 ; CHECK-NEXT:    ret ptr [[RES]]
 ;
@@ -24,6 +24,30 @@ define ptr @vector_splat_indices_nxv2i64_ext0(ptr %a) {
   ret ptr %res
 }
 
+define ptr @vector_splat_indices_nxv2i64_ext0_nuw(ptr %a) {
+; CHECK-LABEL: @vector_splat_indices_nxv2i64_ext0_nuw(
+; CHECK-NEXT:    [[RES:%.*]] = getelementptr nuw i8, ptr [[A:%.*]], i64 16
+; CHECK-NEXT:    ret ptr [[RES]]
+;
+  %tmp = insertelement <vscale x 2 x i64> poison, i64 4, i32 0
+  %splatof4 = shufflevector <vscale x 2 x i64> %tmp, <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer
+  %gep = getelementptr nuw i32, ptr %a, <vscale x 2 x i64> %splatof4
+  %res = extractelement <vscale x 2 x ptr> %gep, i32 0
+  ret ptr %res
+}
+
+define ptr @vector_splat_indices_nxv2i64_ext0_nusw(ptr %a) {
+; CHECK-LABEL: @vector_splat_indices_nxv2i64_ext0_nusw(
+; CHECK-NEXT:    [[RES:%.*]] = getelementptr nusw nuw i8, ptr [[A:%.*]], i64 16
+; CHECK-NEXT:    ret ptr [[RES]]
+;
+  %tmp = insertelement <vscale x 2 x i64> poison, i64 4, i32 0
+  %splatof4 = shufflevector <vscale x 2 x i64> %tmp, <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer
+  %gep = getelementptr nusw i32, ptr %a, <vscale x 2 x i64> %splatof4
+  %res = extractelement <vscale x 2 x ptr> %gep, i32 0
+  ret ptr %res
+}
+
 define ptr @vector_indices_v2i64_ext0(ptr %a, <2 x i64> %indices) {
 ; CHECK-LABEL: @vector_indices_v2i64_ext0(
 ; CHECK-NEXT:    [[TMP1:%.*]] = extractelement <2 x i64> [[INDICES:%.*]], i64 0
diff --git a/llvm/test/Transforms/InstCombine/vec_shuffle.ll b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
index fa34a42714c46..53f9df91d6af8 100644
--- a/llvm/test/Transforms/InstCombine/vec_shuffle.ll
+++ b/llvm/test/Transforms/InstCombine/vec_shuffle.ll
@@ -261,6 +261,45 @@ define <1 x ptr> @shuffle_gep(ptr %x1, ptr %x2) {
   ret <1 x ptr> %ret
 }
 
+define <1 x ptr> @shuffle_gep_inbounds(ptr %x1, ptr %x2) {
+; CHECK-LABEL: @shuffle_gep_inbounds(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <1 x ptr> poison, ptr [[X2:%.*]], i64 0
+; CHECK-NEXT:    [[RET:%.*]] = getelementptr inbounds i8, <1 x ptr> [[TMP1]], i64 5
+; CHECK-NEXT:    ret <1 x ptr> [[RET]]
+;
+  %ins.1 = insertelement <2 x ptr> poison, ptr %x1, i32 0
+  %ins.2 = insertelement <2 x ptr> %ins.1, ptr %x2, i32 1
+  %gep = getelementptr inbounds i8, <2 x ptr> %ins.2, i64 5
+  %ret = shufflevector <2 x ptr> %gep, <2 x ptr> poison, <1 x i32> <i32 1>
+  ret <1 x ptr> %ret
+}
+
+define <1 x ptr> @shuffle_gep_nuw(ptr %x1, ptr %x2) {
+; CHECK-LABEL: @shuffle_gep_nuw(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <1 x ptr> poison, ptr [[X2:%.*]], i64 0
+; CHECK-NEXT:    [[RET:%.*]] = getelementptr nuw i8, <1 x ptr> [[TMP1]], i64 5
+; CHECK-NEXT:    ret <1 x ptr> [[RET]]
+;
+  %ins.1 = insertelement <2 x ptr> poison, ptr %x1, i32 0
+  %ins.2 = insertelement <2 x ptr> %ins.1, ptr %x2, i32 1
+  %gep = getelementptr nuw i8, <2 x ptr> %ins.2, i64 5
+  %ret = shufflevector <2 x ptr> %gep, <2 x ptr> poison, <1 x i32> <i32 1>
+  ret <1 x ptr> %ret
+}
+
+define <1 x ptr> @shuffle_gep_nusw(ptr %x1, ptr %x2) {
+; CHECK-LABEL: @shuffle_gep_nusw(
+; CHECK-NEXT:    [[TMP1:%.*]] = insertelement <1 x ptr> poison, ptr [[X2:%.*]], i64 0
+; CHECK-NEXT:    [[RET:%.*]] = getelementptr nusw i8, <1 x ptr> [[TMP1]], i64 5
+; CHECK-NEXT:    ret <1 x ptr> [[RET]]
+;
+  %ins.1 = insertelement <2 x ptr> poison, ptr %x1, i32 0
+  %ins.2 = insertelement <2 x ptr> %ins.1, ptr %x2, i32 1
+  %gep = getelementptr nusw i8, <2 x ptr> %ins.2, i64 5
+  %ret = shufflevector <2 x ptr> %gep, <2 x ptr> poison, <1 x i32> <i32 1>
+  ret <1 x ptr> %ret
+}
+
 ; Increasing length of vector ops is not a good canonicalization.
 
 define <3 x i32> @add_wider(i32 %y, i32 %z) {

>From a2ce5647200ad40ae356affd44db7d054de444d2 Mon Sep 17 00:00:00 2001
From: Usama Hameed <u_hameed at apple.com>
Date: Thu, 22 May 2025 15:08:10 -0700
Subject: [PATCH 064/105] [compiler-rt][cmake] Test COMPILER_RT_HAS_AARCH64_SME
 with arm64 (#141115)

architecture only.

Apple configures CMake only once for compiler-rt, even when building for
multiple architectures. As a result, we need to explicitly test for
arm64 specific attributes by building for that architecture
---
 compiler-rt/cmake/Modules/BuiltinTests.cmake | 13 +++++++++++++
 compiler-rt/cmake/builtin-config-ix.cmake    |  4 ++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/cmake/Modules/BuiltinTests.cmake b/compiler-rt/cmake/Modules/BuiltinTests.cmake
index 63c5f47cb5010..093a1c758e278 100644
--- a/compiler-rt/cmake/Modules/BuiltinTests.cmake
+++ b/compiler-rt/cmake/Modules/BuiltinTests.cmake
@@ -134,3 +134,16 @@ function(builtin_check_c_compiler_source output source)
     endif()
   endif()
 endfunction()
+
+function(builtin_check_c_compiler_source_with_flags output source flags)
+  if(NOT DEFINED ${output})
+    message(STATUS "Performing Test ${output}")
+    try_compile_only(result SOURCE ${source} FLAGS ${flags})
+    set(${output} ${result} CACHE INTERNAL "Compiler supports ${output} with ${flags}")
+    if(${result})
+      message(STATUS "Performing Test ${output} - Success")
+    else()
+      message(STATUS "Performing Test ${output} - Failed")
+    endif()
+  endif()
+endfunction()
diff --git a/compiler-rt/cmake/builtin-config-ix.cmake b/compiler-rt/cmake/builtin-config-ix.cmake
index 8c9c84ad64bc0..c0684ebc519e3 100644
--- a/compiler-rt/cmake/builtin-config-ix.cmake
+++ b/compiler-rt/cmake/builtin-config-ix.cmake
@@ -41,14 +41,14 @@ asm(\".arch armv8-a+lse\");
 asm(\"cas w0, w1, [x2]\");
 ")
 
-builtin_check_c_compiler_source(COMPILER_RT_HAS_AARCH64_SME
+builtin_check_c_compiler_source_with_flags(COMPILER_RT_HAS_AARCH64_SME
 "
 void foo(void)  __arm_streaming_compatible {
   asm(\".arch armv9-a+sme2\\n\"
       \"smstart\\n\"
       \"ldr zt0, [sp]\");
 }
-")
+" "-target aarch64-linux-gnu")
 
 check_include_files("sys/auxv.h"    COMPILER_RT_HAS_AUXV)
 

>From 05494f3bad0322f2f0d2128857ba30479d97deb2 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 22 May 2025 15:30:31 -0700
Subject: [PATCH 065/105] [MLIR][LLVM] Tail call support for inline asm op
 (#140826)

---
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td       | 13 ++++++++++---
 .../Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp    |  3 ++-
 mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp   |  2 +-
 .../LLVMIR/IR/BasicPtxBuilderInterface.cpp        |  2 +-
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp        | 15 +++++++++++++++
 .../Dialect/X86Vector/Transforms/AVXTranspose.cpp |  3 ++-
 .../Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp    |  3 +++
 mlir/lib/Target/LLVMIR/ModuleImport.cpp           |  1 +
 mlir/test/Dialect/LLVMIR/invalid.mlir             |  8 ++++++++
 mlir/test/Target/LLVMIR/Import/instructions.ll    |  7 +++++--
 mlir/test/Target/LLVMIR/llvmir.mlir               | 10 ++++++++--
 11 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 61ba8f7b991c8..6fde45ce5c556 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -758,9 +758,9 @@ def LLVM_CallOp : LLVM_MemAccessOpBase<"call",
     the LLVM function type that uses an explicit void type to model functions
     that do not return a value.
 
-    If this operatin has the `no_inline` attribute, then this specific function call 
-    will never be inlined. The opposite behavior will occur if the call has `always_inline` 
-    attribute. The `inline_hint` attribute indicates that it is desirable to inline 
+    If this operatin has the `no_inline` attribute, then this specific function call
+    will never be inlined. The opposite behavior will occur if the call has `always_inline`
+    attribute. The `inline_hint` attribute indicates that it is desirable to inline
     this function call.
 
     Examples:
@@ -2298,6 +2298,9 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
     written, or referenced.
     Attempting to define or reference any symbol or any global behavior is
     considered undefined behavior at this time.
+    If `tail_call_kind` is used, the operation behaves like the specified
+    tail call kind. The `musttail` kind it's not available for this operation,
+    since it isn't supported by LLVM's inline asm.
   }];
   let arguments = (
     ins Variadic<LLVM_Type>:$operands,
@@ -2305,6 +2308,7 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
         StrAttr:$constraints,
         UnitAttr:$has_side_effects,
         UnitAttr:$is_align_stack,
+        DefaultValuedAttr<TailCallKind, "TailCallKind::None">:$tail_call_kind,
         OptionalAttr<
           DefaultValuedAttr<AsmATTOrIntel, "AsmDialect::AD_ATT">>:$asm_dialect,
         OptionalAttr<ArrayAttr>:$operand_attrs);
@@ -2314,6 +2318,7 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
   let assemblyFormat = [{
     (`has_side_effects` $has_side_effects^)?
     (`is_align_stack` $is_align_stack^)?
+    (`tail_call_kind` `=` $tail_call_kind^)?
     (`asm_dialect` `=` $asm_dialect^)?
     (`operand_attrs` `=` $operand_attrs^)?
     attr-dict
@@ -2326,6 +2331,8 @@ def LLVM_InlineAsmOp : LLVM_Op<"inline_asm", [DeclareOpInterfaceMethods<MemoryEf
       return "elementtype";
     }
   }];
+
+  let hasVerifier = 1;
 }
 
 //===--------------------------------------------------------------------===//
diff --git a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
index c463b64b5f779..c5094799bbef7 100644
--- a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
+++ b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
@@ -439,7 +439,8 @@ struct LDSBarrierOpLowering : public ConvertOpToLLVMPattern<LDSBarrierOp> {
           op,
           /*resultTypes=*/TypeRange(), /*operands=*/ValueRange(),
           /*asm_string=*/asmStr, constraints, /*has_side_effects=*/true,
-          /*is_align_stack=*/false, /*asm_dialect=*/asmDialectAttr,
+          /*is_align_stack=*/false, LLVM::TailCallKind::None,
+          /*asm_dialect=*/asmDialectAttr,
           /*operand_attrs=*/ArrayAttr());
       return success();
     }
diff --git a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
index eb3558d2460e4..80b3d85488495 100644
--- a/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
+++ b/mlir/lib/Conversion/NVGPUToNVVM/NVGPUToNVVM.cpp
@@ -571,7 +571,7 @@ static FailureOr<LLVM::InlineAsmOp> emitMmaSparseSyncOpAsm(
       /*asm_string=*/asmStr,
       /*constraints=*/constraintStr,
       /*has_side_effects=*/true,
-      /*is_align_stack=*/false,
+      /*is_align_stack=*/false, LLVM::TailCallKind::None,
       /*asm_dialect=*/asmDialectAttr,
       /*operand_attrs=*/ArrayAttr());
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp b/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
index f2e71e7795c3e..c17ef1029faf6 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/BasicPtxBuilderInterface.cpp
@@ -139,7 +139,7 @@ LLVM::InlineAsmOp PtxBuilder::build() {
       /*asm_string=*/llvm::StringRef(ptxInstruction),
       /*constraints=*/registerConstraints.data(),
       /*has_side_effects=*/interfaceOp.hasSideEffect(),
-      /*is_align_stack=*/false,
+      /*is_align_stack=*/false, LLVM::TailCallKind::None,
       /*asm_dialect=*/asmDialectAttr,
       /*operand_attrs=*/ArrayAttr());
 }
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index d8abf6fd41301..c7528c970a4ba 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -4042,6 +4042,21 @@ LogicalResult LLVM::masked_scatter::verify() {
   return success();
 }
 
+//===----------------------------------------------------------------------===//
+// InlineAsmOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult InlineAsmOp::verify() {
+  if (!getTailCallKindAttr())
+    return success();
+
+  if (getTailCallKindAttr().getTailCallKind() == TailCallKind::MustTail)
+    return emitOpError(
+        "tail call kind 'musttail' is not supported by this operation");
+
+  return success();
+}
+
 //===----------------------------------------------------------------------===//
 // LLVMDialect initialization, type parsing, and registration.
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp b/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
index 3fc05c8cb8707..63f725084cabf 100644
--- a/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
+++ b/mlir/lib/Dialect/X86Vector/Transforms/AVXTranspose.cpp
@@ -41,7 +41,8 @@ Value mlir::x86vector::avx2::inline_asm::mm256BlendPsAsm(
   auto asmOp = b.create<LLVM::InlineAsmOp>(
       v1.getType(), /*operands=*/asmVals, /*asm_string=*/asmStr,
       /*constraints=*/asmCstr, /*has_side_effects=*/false,
-      /*is_align_stack=*/false, /*asm_dialect=*/asmDialectAttr,
+      /*is_align_stack=*/false, LLVM::TailCallKind::None,
+      /*asm_dialect=*/asmDialectAttr,
       /*operand_attrs=*/ArrayAttr());
   return asmOp.getResult(0);
 }
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index c954dffb376bb..ba87d1ad0dd84 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -19,6 +19,7 @@
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/MDBuilder.h"
 #include "llvm/IR/MatrixBuilder.h"
 #include "llvm/IR/Operator.h"
@@ -507,6 +508,8 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
     llvm::CallInst *inst = builder.CreateCall(
         inlineAsmInst,
         moduleTranslation.lookupValues(inlineAsmOp.getOperands()));
+    inst->setTailCallKind(convertTailCallKindToLLVM(
+        inlineAsmOp.getTailCallKindAttr().getTailCallKind()));
     if (auto maybeOperandAttrs = inlineAsmOp.getOperandAttrs()) {
       llvm::AttributeList attrList;
       for (const auto &it : llvm::enumerate(*maybeOperandAttrs)) {
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 6c82bf572d393..b049064fbd31c 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2200,6 +2200,7 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
                 builder.getStringAttr(asmI->getAsmString()),
                 builder.getStringAttr(asmI->getConstraintString()),
                 asmI->hasSideEffects(), asmI->isAlignStack(),
+                convertTailCallKindFromLLVM(callInst->getTailCallKind()),
                 AsmDialectAttr::get(
                     mlirModule.getContext(),
                     convertAsmDialectFromLLVM(asmI->getDialect())),
diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index f5adf4b3bf33d..251ca716c7a7a 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1882,3 +1882,11 @@ llvm.mlir.global internal constant @bad_array_attr_simple_type() : !llvm.array<2
   %0 = llvm.mlir.constant([2.5, 7.4]) : !llvm.array<2 x f64>
   llvm.return %0 : !llvm.array<2 x f64>
 }
+
+// ----
+
+llvm.func @inlineAsmMustTail(%arg0: i32, %arg1 : !llvm.ptr) {
+  // expected-error at +1 {{op tail call kind 'musttail' is not supported}}
+  %8 = llvm.inline_asm tail_call_kind = <musttail> "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
+  llvm.return
+}
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 68ef47c3f42f1..be245e35f087d 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -554,8 +554,11 @@ define i32 @inlineasm(i32 %arg1) {
 define void @inlineasm2() {
   %p = alloca ptr, align 8
   ; CHECK: {{.*}} = llvm.alloca %0 x !llvm.ptr {alignment = 8 : i64} : (i32) -> !llvm.ptr
-  ; CHECK-NEXT: llvm.inline_asm has_side_effects asm_dialect = att operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" {{.*}} : (!llvm.ptr) -> !llvm.void
-  call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %p)
+  ; CHECK-NEXT: llvm.inline_asm has_side_effects tail_call_kind = <tail> asm_dialect = att operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" {{.*}} : (!llvm.ptr) -> !llvm.void
+  tail call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %p)
+
+  ; CHECK: llvm.inline_asm has_side_effects tail_call_kind = <notail> asm_dialect = att operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" {{.*}} : (!llvm.ptr) -> !llvm.void
+  notail call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %p)
   ret void
 }
 
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 237612244d8de..7742259e7a478 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2081,8 +2081,14 @@ llvm.func @useInlineAsm(%arg0: i32, %arg1 : !llvm.ptr) {
   // CHECK-NEXT:  call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}})
   %5 = llvm.inline_asm "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
 
-  // CHECK-NEXT:  call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %1)
-  %6 = llvm.inline_asm has_side_effects operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" %arg1 : (!llvm.ptr) -> !llvm.void
+  // CHECK-NEXT:  tail call void asm sideeffect "", "*m,~{memory}"(ptr elementtype(ptr) %1)
+  %6 = llvm.inline_asm has_side_effects tail_call_kind = <tail> operand_attrs = [{elementtype = !llvm.ptr}] "", "*m,~{memory}" %arg1 : (!llvm.ptr) -> !llvm.void
+
+  // CHECK-NEXT:  = call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}})
+  %7 = llvm.inline_asm tail_call_kind = <none> "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
+
+  // CHECK-NEXT:  notail call { i8, i8 } asm "foo", "=r,=r,r"(i32 {{.*}})
+  %8 = llvm.inline_asm tail_call_kind = <notail> "foo", "=r,=r,r" %arg0 : (i32) -> !llvm.struct<(i8, i8)>
 
   llvm.return
 }

>From 523d6c3b69ded6a1ba5fcbe72b40a39fa2c20d15 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 22 May 2025 15:55:33 -0700
Subject: [PATCH 066/105] [NFC][TableGen] Code cleanup in StringMatcher
 (#141118)

- Use ArrayRef instead of const vector reference.
- Use range for loops with enumerate and structured bindings.
---
 llvm/include/llvm/TableGen/StringMatcher.h | 12 ++++----
 llvm/lib/TableGen/StringMatcher.cpp        | 33 ++++++++++------------
 2 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/TableGen/StringMatcher.h b/llvm/include/llvm/TableGen/StringMatcher.h
index 795b7a6d41dcc..49769883a98b4 100644
--- a/llvm/include/llvm/TableGen/StringMatcher.h
+++ b/llvm/include/llvm/TableGen/StringMatcher.h
@@ -13,10 +13,10 @@
 #ifndef LLVM_TABLEGEN_STRINGMATCHER_H
 #define LLVM_TABLEGEN_STRINGMATCHER_H
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include <string>
 #include <utility>
-#include <vector>
 
 namespace llvm {
 
@@ -33,18 +33,18 @@ class StringMatcher {
 
 private:
   StringRef StrVariableName;
-  const std::vector<StringPair> &Matches;
+  ArrayRef<StringPair> Matches;
   raw_ostream &OS;
 
 public:
-  StringMatcher(StringRef strVariableName,
-                const std::vector<StringPair> &matches, raw_ostream &os)
-    : StrVariableName(strVariableName), Matches(matches), OS(os) {}
+  StringMatcher(StringRef StrVariableName, ArrayRef<StringPair> Matches,
+                raw_ostream &OS)
+      : StrVariableName(StrVariableName), Matches(Matches), OS(OS) {}
 
   void Emit(unsigned Indent = 0, bool IgnoreDuplicates = false) const;
 
 private:
-  bool EmitStringMatcherForChar(const std::vector<const StringPair *> &Matches,
+  bool EmitStringMatcherForChar(ArrayRef<const StringPair *> Matches,
                                 unsigned CharNo, unsigned IndentCount,
                                 bool IgnoreDuplicates) const;
 };
diff --git a/llvm/lib/TableGen/StringMatcher.cpp b/llvm/lib/TableGen/StringMatcher.cpp
index c169b4e0a3620..b85849e40bb5e 100644
--- a/llvm/lib/TableGen/StringMatcher.cpp
+++ b/llvm/lib/TableGen/StringMatcher.cpp
@@ -26,16 +26,13 @@ using namespace llvm;
 /// string pairs that is not shared across the whole set of strings.  All
 /// strings are assumed to have the same length.
 static unsigned
-FindFirstNonCommonLetter(const std::vector<const
-                              StringMatcher::StringPair*> &Matches) {
+FindFirstNonCommonLetter(ArrayRef<const StringMatcher::StringPair *> Matches) {
   assert(!Matches.empty());
-  for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) {
-    // Check to see if letter i is the same across the set.
-    char Letter = Matches[0]->first[i];
-
+  for (auto [Idx, Letter] : enumerate(Matches[0]->first)) {
+    // Check to see if `Letter` is the same across the set.
     for (const StringMatcher::StringPair *Match : Matches)
-      if (Match->first[i] != Letter)
-        return i;
+      if (Match->first[Idx] != Letter)
+        return Idx;
   }
 
   return Matches[0]->first.size();
@@ -47,8 +44,8 @@ FindFirstNonCommonLetter(const std::vector<const
 ///
 /// \return - True if control can leave the emitted code fragment.
 bool StringMatcher::EmitStringMatcherForChar(
-    const std::vector<const StringPair *> &Matches, unsigned CharNo,
-    unsigned IndentCount, bool IgnoreDuplicates) const {
+    ArrayRef<const StringPair *> Matches, unsigned CharNo, unsigned IndentCount,
+    bool IgnoreDuplicates) const {
   assert(!Matches.empty() && "Must have at least one string to match!");
   std::string Indent(IndentCount * 2 + 4, ' ');
 
@@ -110,14 +107,14 @@ bool StringMatcher::EmitStringMatcherForChar(
   OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n";
   OS << Indent << "default: break;\n";
 
-  for (const auto &LI : MatchesByLetter) {
+  for (const auto &[Letter, Matches] : MatchesByLetter) {
     // TODO: escape hard stuff (like \n) if we ever care about it.
-    OS << Indent << "case '" << LI.first << "':\t // " << LI.second.size()
+    OS << Indent << "case '" << Letter << "':\t // " << Matches.size()
        << " string";
-    if (LI.second.size() != 1)
+    if (Matches.size() != 1)
       OS << 's';
     OS << " to match.\n";
-    if (EmitStringMatcherForChar(LI.second, CharNo + 1, IndentCount + 1,
+    if (EmitStringMatcherForChar(Matches, CharNo + 1, IndentCount + 1,
                                  IgnoreDuplicates))
       OS << Indent << "  break;\n";
   }
@@ -143,11 +140,11 @@ void StringMatcher::Emit(unsigned Indent, bool IgnoreDuplicates) const {
   OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n";
   OS.indent(Indent*2+2) << "default: break;\n";
 
-  for (const auto &LI : MatchesByLength) {
+  for (const auto &[Length, Matches] : MatchesByLength) {
     OS.indent(Indent * 2 + 2)
-        << "case " << LI.first << ":\t // " << LI.second.size() << " string"
-        << (LI.second.size() == 1 ? "" : "s") << " to match.\n";
-    if (EmitStringMatcherForChar(LI.second, 0, Indent, IgnoreDuplicates))
+        << "case " << Length << ":\t // " << Matches.size() << " string"
+        << (Matches.size() == 1 ? "" : "s") << " to match.\n";
+    if (EmitStringMatcherForChar(Matches, 0, Indent, IgnoreDuplicates))
       OS.indent(Indent*2+4) << "break;\n";
   }
 

>From c47260efccf10279b120dbfc516264b39ebaa277 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 22 May 2025 15:59:10 -0700
Subject: [PATCH 067/105] [CIR][NFC] Fix failing OpenACC NYI test (#141155)

A recent change to the error message produced for unhandled compound
statements without scope introduced a failure in an OpenACC test that
was checking for the old error message. This change updates the test to
check for the new message.
---
 clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp b/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp
index 95b04a314ad8e..1dfb2edd128f8 100644
--- a/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp
@@ -3,7 +3,7 @@
 void HelloWorld(int *A, int *B, int *C, int N) {
 
 // expected-error at +2{{ClangIR code gen Not Yet Implemented: OpenACC Atomic Construct}}
-// expected-error at +1{{ClangIR code gen Not Yet Implemented: statement}}
+// expected-error at +1{{ClangIR code gen Not Yet Implemented: emitCompoundStmtWithoutScope: OpenACCAtomicConstruct}}
 #pragma acc atomic
   N = N + 1;
 

>From d0acddbdd615f1503e88903570ee7484bd217615 Mon Sep 17 00:00:00 2001
From: Mingming Liu <mingmingl at google.com>
Date: Thu, 22 May 2025 16:14:36 -0700
Subject: [PATCH 068/105] Revert "[StaticDataLayout][PGO]Implement reader and
 writer change for data access profiles" (#141157)

Reverts llvm/llvm-project#139997

Sanitizer failures
(https://lab.llvm.org/buildbot/#/builders/94/builds/7373)

Will fix forward later.
---
 .../include/llvm/ProfileData/DataAccessProf.h | 22 ++---
 .../llvm/ProfileData/IndexedMemProfData.h     | 12 +--
 .../llvm/ProfileData/InstrProfReader.h        |  6 +-
 .../llvm/ProfileData/InstrProfWriter.h        |  6 --
 llvm/include/llvm/ProfileData/MemProfReader.h | 14 ---
 llvm/include/llvm/ProfileData/MemProfYAML.h   | 61 -------------
 llvm/lib/ProfileData/DataAccessProf.cpp       |  7 +-
 llvm/lib/ProfileData/IndexedMemProfData.cpp   | 62 +++----------
 llvm/lib/ProfileData/InstrProfReader.cpp      | 14 ---
 llvm/lib/ProfileData/InstrProfWriter.cpp      | 13 +--
 llvm/lib/ProfileData/MemProfReader.cpp        | 29 ------
 .../tools/llvm-profdata/memprof-yaml.test     | 91 +------------------
 llvm/tools/llvm-profdata/llvm-profdata.cpp    |  4 -
 .../ProfileData/DataAccessProfTest.cpp        |  4 +-
 14 files changed, 32 insertions(+), 313 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/DataAccessProf.h b/llvm/include/llvm/ProfileData/DataAccessProf.h
index cd4b200486a3f..3cc8835a776dd 100644
--- a/llvm/include/llvm/ProfileData/DataAccessProf.h
+++ b/llvm/include/llvm/ProfileData/DataAccessProf.h
@@ -17,8 +17,10 @@
 #ifndef LLVM_PROFILEDATA_DATAACCESSPROF_H_
 #define LLVM_PROFILEDATA_DATAACCESSPROF_H_
 
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseMapInfoVariant.h"
 #include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -33,15 +35,12 @@
 
 namespace llvm {
 
-namespace memprof {
+namespace data_access_prof {
 
 /// The location of data in the source code. Used by profile lookup API.
 struct SourceLocation {
   SourceLocation(StringRef FileNameRef, uint32_t Line)
       : FileName(FileNameRef.str()), Line(Line) {}
-
-  // Empty constructor is used in yaml conversion.
-  SourceLocation() {}
   /// The filename where the data is located.
   std::string FileName;
   /// The line number in the source code.
@@ -54,8 +53,6 @@ namespace internal {
 // which strings are owned by `DataAccessProfData`. Used by `DataAccessProfData`
 // to represent data locations internally.
 struct SourceLocationRef {
-  SourceLocationRef(StringRef FileNameRef, uint32_t Line)
-      : FileName(FileNameRef), Line(Line) {}
   // The filename where the data is located.
   StringRef FileName;
   // The line number in the source code.
@@ -103,21 +100,18 @@ using SymbolHandle = std::variant<std::string, uint64_t>;
 /// The data access profiles for a symbol.
 struct DataAccessProfRecord {
 public:
-  DataAccessProfRecord(SymbolHandleRef SymHandleRef, uint64_t AccessCount,
-                       ArrayRef<internal::SourceLocationRef> LocRefs)
-      : AccessCount(AccessCount) {
+  DataAccessProfRecord(SymbolHandleRef SymHandleRef,
+                       ArrayRef<internal::SourceLocationRef> LocRefs) {
     if (std::holds_alternative<StringRef>(SymHandleRef)) {
       SymHandle = std::get<StringRef>(SymHandleRef).str();
     } else
       SymHandle = std::get<uint64_t>(SymHandleRef);
 
     for (auto Loc : LocRefs)
-      Locations.emplace_back(Loc.FileName, Loc.Line);
+      Locations.push_back(SourceLocation(Loc.FileName, Loc.Line));
   }
-  // Empty constructor is used in yaml conversion.
-  DataAccessProfRecord() {}
   SymbolHandle SymHandle;
-  uint64_t AccessCount;
+
   // The locations of data in the source code. Optional.
   SmallVector<SourceLocation> Locations;
 };
@@ -214,7 +208,7 @@ class DataAccessProfData {
   llvm::SetVector<StringRef> KnownColdSymbols;
 };
 
-} // namespace memprof
+} // namespace data_access_prof
 } // namespace llvm
 
 #endif // LLVM_PROFILEDATA_DATAACCESSPROF_H_
diff --git a/llvm/include/llvm/ProfileData/IndexedMemProfData.h b/llvm/include/llvm/ProfileData/IndexedMemProfData.h
index 2b40094a9bc21..f33b160e0b6a9 100644
--- a/llvm/include/llvm/ProfileData/IndexedMemProfData.h
+++ b/llvm/include/llvm/ProfileData/IndexedMemProfData.h
@@ -15,13 +15,9 @@
 #ifndef LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H
 #define LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H
 
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/MemProf.h"
 
-#include <functional>
-#include <optional>
-
 namespace llvm {
 namespace memprof {
 struct IndexedMemProfData {
@@ -86,10 +82,8 @@ struct IndexedMemProfData {
 } // namespace memprof
 
 // Write the MemProf data to OS.
-Error writeMemProf(
-    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-    memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
-    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData);
-
+Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
+                   memprof::IndexedVersion MemProfVersionRequested,
+                   bool MemProfFullSchema);
 } // namespace llvm
 #endif
diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h
index d104ab51430d1..c250a9ede39bc 100644
--- a/llvm/include/llvm/ProfileData/InstrProfReader.h
+++ b/llvm/include/llvm/ProfileData/InstrProfReader.h
@@ -18,7 +18,6 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
 #include "llvm/Object/BuildID.h"
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/MemProf.h"
@@ -704,13 +703,10 @@ class IndexedMemProfReader {
   const unsigned char *CallStackBase = nullptr;
   // The number of elements in the radix tree array.
   unsigned RadixTreeSize = 0;
-  /// The data access profiles, deserialized from binary data.
-  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
 
   Error deserializeV2(const unsigned char *Start, const unsigned char *Ptr);
   Error deserializeRadixTreeBased(const unsigned char *Start,
-                                  const unsigned char *Ptr,
-                                  memprof::IndexedVersion Version);
+                                  const unsigned char *Ptr);
 
 public:
   IndexedMemProfReader() = default;
diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h
index cdb7afb623378..b72c901dbb5b2 100644
--- a/llvm/include/llvm/ProfileData/InstrProfWriter.h
+++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h
@@ -19,7 +19,6 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/Object/BuildID.h"
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/Support/Error.h"
@@ -82,8 +81,6 @@ class InstrProfWriter {
   // Whether to generated random memprof hotness for testing.
   bool MemprofGenerateRandomHotness;
 
-  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
-
 public:
   // For memprof testing, random hotness can be assigned to the contexts if
   // MemprofGenerateRandomHotness is enabled. The random seed can be either
@@ -125,9 +122,6 @@ class InstrProfWriter {
   // Add a binary id to the binary ids list.
   void addBinaryIds(ArrayRef<llvm::object::BuildID> BIs);
 
-  void addDataAccessProfData(
-      std::unique_ptr<memprof::DataAccessProfData> DataAccessProfile);
-
   /// Merge existing function counts from the given writer.
   void mergeRecordsFromWriter(InstrProfWriter &&IPW,
                               function_ref<void(Error)> Warn);
diff --git a/llvm/include/llvm/ProfileData/MemProfReader.h b/llvm/include/llvm/ProfileData/MemProfReader.h
index 3bfcdf0f42cde..130493ec77c08 100644
--- a/llvm/include/llvm/ProfileData/MemProfReader.h
+++ b/llvm/include/llvm/ProfileData/MemProfReader.h
@@ -229,20 +229,6 @@ class YAMLMemProfReader final : public MemProfReader {
   create(std::unique_ptr<MemoryBuffer> Buffer);
 
   void parse(StringRef YAMLData);
-
-  std::unique_ptr<memprof::DataAccessProfData> takeDataAccessProfData() {
-    return std::move(DataAccessProfileData);
-  }
-
-private:
-  // Called by `parse` to set data access profiles after parsing them from Yaml
-  // files.
-  void
-  setDataAccessProfileData(std::unique_ptr<memprof::DataAccessProfData> Data) {
-    DataAccessProfileData = std::move(Data);
-  }
-
-  std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData;
 };
 } // namespace memprof
 } // namespace llvm
diff --git a/llvm/include/llvm/ProfileData/MemProfYAML.h b/llvm/include/llvm/ProfileData/MemProfYAML.h
index f8dc659f66662..b642e3098aa0e 100644
--- a/llvm/include/llvm/ProfileData/MemProfYAML.h
+++ b/llvm/include/llvm/ProfileData/MemProfYAML.h
@@ -2,7 +2,6 @@
 #define LLVM_PROFILEDATA_MEMPROFYAML_H_
 
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/MemProf.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -21,24 +20,9 @@ struct GUIDMemProfRecordPair {
   MemProfRecord Record;
 };
 
-// Helper struct to yamlify memprof::DataAccessProfData. The struct
-// members use owned strings. This is for simplicity and assumes that most real
-// world use cases do look-ups and regression test scale is small.
-struct YamlDataAccessProfData {
-  std::vector<memprof::DataAccessProfRecord> Records;
-  std::vector<uint64_t> KnownColdStrHashes;
-  std::vector<std::string> KnownColdSymbols;
-
-  bool isEmpty() const {
-    return Records.empty() && KnownColdStrHashes.empty() &&
-           KnownColdSymbols.empty();
-  }
-};
-
 // The top-level data structure, only used with YAML for now.
 struct AllMemProfData {
   std::vector<GUIDMemProfRecordPair> HeapProfileRecords;
-  YamlDataAccessProfData YamlifiedDataAccessProfiles;
 };
 } // namespace memprof
 
@@ -222,52 +206,9 @@ template <> struct MappingTraits<memprof::GUIDMemProfRecordPair> {
   }
 };
 
-template <> struct MappingTraits<memprof::SourceLocation> {
-  static void mapping(IO &Io, memprof::SourceLocation &Loc) {
-    Io.mapOptional("FileName", Loc.FileName);
-    Io.mapOptional("Line", Loc.Line);
-  }
-};
-
-template <> struct MappingTraits<memprof::DataAccessProfRecord> {
-  static void mapping(IO &Io, memprof::DataAccessProfRecord &Rec) {
-    if (Io.outputting()) {
-      if (std::holds_alternative<std::string>(Rec.SymHandle)) {
-        Io.mapOptional("Symbol", std::get<std::string>(Rec.SymHandle));
-      } else {
-        Io.mapOptional("Hash", std::get<uint64_t>(Rec.SymHandle));
-      }
-    } else {
-      std::string SymName;
-      uint64_t Hash = 0;
-      Io.mapOptional("Symbol", SymName);
-      Io.mapOptional("Hash", Hash);
-      if (!SymName.empty()) {
-        Rec.SymHandle = SymName;
-      } else {
-        Rec.SymHandle = Hash;
-      }
-    }
-
-    Io.mapOptional("Locations", Rec.Locations);
-  }
-};
-
-template <> struct MappingTraits<memprof::YamlDataAccessProfData> {
-  static void mapping(IO &Io, memprof::YamlDataAccessProfData &Data) {
-    Io.mapOptional("SampledRecords", Data.Records);
-    Io.mapOptional("KnownColdSymbols", Data.KnownColdSymbols);
-    Io.mapOptional("KnownColdStrHashes", Data.KnownColdStrHashes);
-  }
-};
-
 template <> struct MappingTraits<memprof::AllMemProfData> {
   static void mapping(IO &Io, memprof::AllMemProfData &Data) {
     Io.mapRequired("HeapProfileRecords", Data.HeapProfileRecords);
-    // Map data access profiles if reading input, or if writing output &&
-    // the struct is populated.
-    if (!Io.outputting() || !Data.YamlifiedDataAccessProfiles.isEmpty())
-      Io.mapOptional("DataAccessProfiles", Data.YamlifiedDataAccessProfiles);
   }
 };
 
@@ -293,7 +234,5 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::AllocationInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::CallSiteInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDMemProfRecordPair)
 LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::GUIDHex64) // Used for CalleeGuids
-LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::DataAccessProfRecord)
-LLVM_YAML_IS_SEQUENCE_VECTOR(memprof::SourceLocation)
 
 #endif // LLVM_PROFILEDATA_MEMPROFYAML_H_
diff --git a/llvm/lib/ProfileData/DataAccessProf.cpp b/llvm/lib/ProfileData/DataAccessProf.cpp
index 090dcb3dcc1b9..a31f3db0621fb 100644
--- a/llvm/lib/ProfileData/DataAccessProf.cpp
+++ b/llvm/lib/ProfileData/DataAccessProf.cpp
@@ -11,7 +11,7 @@
 #include <sys/types.h>
 
 namespace llvm {
-namespace memprof {
+namespace data_access_prof {
 
 // If `Map` has an entry keyed by `Str`, returns the entry iterator. Otherwise,
 // creates an owned copy of `Str`, adds a map entry for it and returns the
@@ -48,8 +48,7 @@ DataAccessProfData::getProfileRecord(const SymbolHandleRef SymbolID) const {
 
   auto It = Records.find(Key);
   if (It != Records.end()) {
-    return DataAccessProfRecord(Key, It->second.AccessCount,
-                                It->second.Locations);
+    return DataAccessProfRecord(Key, It->second.Locations);
   }
 
   return std::nullopt;
@@ -262,5 +261,5 @@ Error DataAccessProfData::deserializeRecords(const unsigned char *&Ptr) {
   }
   return Error::success();
 }
-} // namespace memprof
+} // namespace data_access_prof
 } // namespace llvm
diff --git a/llvm/lib/ProfileData/IndexedMemProfData.cpp b/llvm/lib/ProfileData/IndexedMemProfData.cpp
index 7398e4c468bbe..59e59720179af 100644
--- a/llvm/lib/ProfileData/IndexedMemProfData.cpp
+++ b/llvm/lib/ProfileData/IndexedMemProfData.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/MemProf.h"
@@ -218,9 +217,7 @@ static Error writeMemProfV2(ProfOStream &OS,
 
 static Error writeMemProfRadixTreeBased(
     ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-    memprof::IndexedVersion Version, bool MemProfFullSchema,
-    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData =
-        nullptr) {
+    memprof::IndexedVersion Version, bool MemProfFullSchema) {
   assert((Version == memprof::Version3 || Version == memprof::Version4) &&
          "Unsupported version for radix tree format");
 
@@ -229,8 +226,6 @@ static Error writeMemProfRadixTreeBased(
   OS.write(0ULL); // Reserve space for the memprof call stack payload offset.
   OS.write(0ULL); // Reserve space for the memprof record payload offset.
   OS.write(0ULL); // Reserve space for the memprof record table offset.
-  if (Version >= memprof::Version4)
-    OS.write(0ULL); // Reserve space for the data access profile offset.
 
   auto Schema = memprof::getHotColdSchema();
   if (MemProfFullSchema)
@@ -257,29 +252,17 @@ static Error writeMemProfRadixTreeBased(
   uint64_t RecordTableOffset = writeMemProfRecords(
       OS, MemProfData.Records, &Schema, Version, &MemProfCallStackIndexes);
 
-  uint64_t DataAccessProfOffset = 0;
-  if (DataAccessProfileData != nullptr) {
-    assert(Version >= memprof::Version4 &&
-           "Data access profiles are added starting from v4");
-    DataAccessProfOffset = OS.tell();
-    if (Error E = DataAccessProfileData->serialize(OS))
-      return E;
-  }
-
   // Verify that the computation for the number of elements in the call stack
   // array works.
   assert(CallStackPayloadOffset +
              NumElements * sizeof(memprof::LinearFrameId) ==
          RecordPayloadOffset);
 
-  SmallVector<uint64_t, 4> Header = {
+  uint64_t Header[] = {
       CallStackPayloadOffset,
       RecordPayloadOffset,
       RecordTableOffset,
   };
-  if (Version >= memprof::Version4)
-    Header.push_back(DataAccessProfOffset);
-
   OS.patch({{HeaderUpdatePos, Header}});
 
   return Error::success();
@@ -294,28 +277,24 @@ static Error writeMemProfV3(ProfOStream &OS,
 }
 
 // Write out MemProf Version4
-static Error writeMemProfV4(
-    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-    bool MemProfFullSchema,
-    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData) {
+static Error writeMemProfV4(ProfOStream &OS,
+                            memprof::IndexedMemProfData &MemProfData,
+                            bool MemProfFullSchema) {
   return writeMemProfRadixTreeBased(OS, MemProfData, memprof::Version4,
-                                    MemProfFullSchema,
-                                    std::move(DataAccessProfileData));
+                                    MemProfFullSchema);
 }
 
 // Write out the MemProf data in a requested version.
-Error writeMemProf(
-    ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
-    memprof::IndexedVersion MemProfVersionRequested, bool MemProfFullSchema,
-    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfileData) {
+Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData,
+                   memprof::IndexedVersion MemProfVersionRequested,
+                   bool MemProfFullSchema) {
   switch (MemProfVersionRequested) {
   case memprof::Version2:
     return writeMemProfV2(OS, MemProfData, MemProfFullSchema);
   case memprof::Version3:
     return writeMemProfV3(OS, MemProfData, MemProfFullSchema);
   case memprof::Version4:
-    return writeMemProfV4(OS, MemProfData, MemProfFullSchema,
-                          std::move(DataAccessProfileData));
+    return writeMemProfV4(OS, MemProfData, MemProfFullSchema);
   }
 
   return make_error<InstrProfError>(
@@ -379,10 +358,7 @@ Error IndexedMemProfReader::deserializeV2(const unsigned char *Start,
 }
 
 Error IndexedMemProfReader::deserializeRadixTreeBased(
-    const unsigned char *Start, const unsigned char *Ptr,
-    memprof::IndexedVersion Version) {
-  assert((Version == memprof::Version3 || Version == memprof::Version4) &&
-         "Unsupported version for radix tree format");
+    const unsigned char *Start, const unsigned char *Ptr) {
   // The offset in the stream right before invoking
   // CallStackTableGenerator.Emit.
   const uint64_t CallStackPayloadOffset =
@@ -394,11 +370,6 @@ Error IndexedMemProfReader::deserializeRadixTreeBased(
   const uint64_t RecordTableOffset =
       support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
 
-  uint64_t DataAccessProfOffset = 0;
-  if (Version == memprof::Version4)
-    DataAccessProfOffset =
-        support::endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
-
   // Read the schema.
   auto SchemaOr = memprof::readMemProfSchema(Ptr);
   if (!SchemaOr)
@@ -420,15 +391,6 @@ Error IndexedMemProfReader::deserializeRadixTreeBased(
       /*Payload=*/Start + RecordPayloadOffset,
       /*Base=*/Start, memprof::RecordLookupTrait(Version, Schema)));
 
-  assert((!DataAccessProfOffset || DataAccessProfOffset > RecordTableOffset) &&
-         "Data access profile is either empty or after the record table");
-  if (DataAccessProfOffset > RecordTableOffset) {
-    DataAccessProfileData = std::make_unique<memprof::DataAccessProfData>();
-    const unsigned char *DAPPtr = Start + DataAccessProfOffset;
-    if (Error E = DataAccessProfileData->deserialize(DAPPtr))
-      return E;
-  }
-
   return Error::success();
 }
 
@@ -462,7 +424,7 @@ Error IndexedMemProfReader::deserialize(const unsigned char *Start,
   case memprof::Version3:
   case memprof::Version4:
     // V3 and V4 share the same high-level structure (radix tree, linear IDs).
-    if (Error E = deserializeRadixTreeBased(Start, Ptr, Version))
+    if (Error E = deserializeRadixTreeBased(Start, Ptr))
       return E;
     break;
   }
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index ab109cd5b13a7..a1eb08362087f 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -1552,20 +1552,6 @@ memprof::AllMemProfData IndexedMemProfReader::getAllMemProfData() const {
     Pair.Record = std::move(*Record);
     AllMemProfData.HeapProfileRecords.push_back(std::move(Pair));
   }
-  // Populate the data access profiles for yaml output.
-  if (DataAccessProfileData != nullptr) {
-    for (const auto &[SymHandleRef, RecordRef] :
-         DataAccessProfileData->getRecords())
-      AllMemProfData.YamlifiedDataAccessProfiles.Records.push_back(
-          memprof::DataAccessProfRecord(SymHandleRef, RecordRef.AccessCount,
-                                        RecordRef.Locations));
-    for (StringRef ColdSymbol : DataAccessProfileData->getKnownColdSymbols())
-      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdSymbols.push_back(
-          ColdSymbol.str());
-    for (uint64_t Hash : DataAccessProfileData->getKnownColdHashes())
-      AllMemProfData.YamlifiedDataAccessProfiles.KnownColdStrHashes.push_back(
-          Hash);
-  }
   return AllMemProfData;
 }
 
diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp
index 039e1bc955cd4..2c6640eedebd9 100644
--- a/llvm/lib/ProfileData/InstrProfWriter.cpp
+++ b/llvm/lib/ProfileData/InstrProfWriter.cpp
@@ -16,7 +16,6 @@
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/ProfileSummary.h"
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/IndexedMemProfData.h"
 #include "llvm/ProfileData/InstrProf.h"
 #include "llvm/ProfileData/ProfileCommon.h"
@@ -321,11 +320,6 @@ void InstrProfWriter::addBinaryIds(ArrayRef<llvm::object::BuildID> BIs) {
   llvm::append_range(BinaryIds, BIs);
 }
 
-void InstrProfWriter::addDataAccessProfData(
-    std::unique_ptr<memprof::DataAccessProfData> DataAccessProfDataIn) {
-  DataAccessProfileData = std::move(DataAccessProfDataIn);
-}
-
 void InstrProfWriter::addTemporalProfileTrace(TemporalProfTraceTy Trace) {
   assert(Trace.FunctionNameRefs.size() <= MaxTemporalProfTraceLength);
   assert(!Trace.FunctionNameRefs.empty());
@@ -611,11 +605,8 @@ Error InstrProfWriter::writeImpl(ProfOStream &OS) {
   uint64_t MemProfSectionStart = 0;
   if (static_cast<bool>(ProfileKind & InstrProfKind::MemProf)) {
     MemProfSectionStart = OS.tell();
-
-    if (auto E =
-            writeMemProf(OS, MemProfData, MemProfVersionRequested,
-                         MemProfFullSchema, std::move(DataAccessProfileData)))
-
+    if (auto E = writeMemProf(OS, MemProfData, MemProfVersionRequested,
+                              MemProfFullSchema))
       return E;
   }
 
diff --git a/llvm/lib/ProfileData/MemProfReader.cpp b/llvm/lib/ProfileData/MemProfReader.cpp
index 9c723e495e7f9..d6bc4fdf5e448 100644
--- a/llvm/lib/ProfileData/MemProfReader.cpp
+++ b/llvm/lib/ProfileData/MemProfReader.cpp
@@ -37,7 +37,6 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 
@@ -823,34 +822,6 @@ void YAMLMemProfReader::parse(StringRef YAMLData) {
 
     MemProfData.Records.try_emplace(GUID, std::move(IndexedRecord));
   }
-
-  if (Doc.YamlifiedDataAccessProfiles.isEmpty())
-    return;
-
-  auto ToSymHandleRef =
-      [](const memprof::SymbolHandle &Handle) -> memprof::SymbolHandleRef {
-    if (std::holds_alternative<std::string>(Handle))
-      return StringRef(std::get<std::string>(Handle));
-    return std::get<uint64_t>(Handle);
-  };
-
-  auto DataAccessProfileData = std::make_unique<memprof::DataAccessProfData>();
-  for (const auto &Record : Doc.YamlifiedDataAccessProfiles.Records)
-    if (Error E = DataAccessProfileData->setDataAccessProfile(
-            ToSymHandleRef(Record.SymHandle), Record.AccessCount,
-            Record.Locations))
-      reportFatalInternalError(std::move(E));
-
-  for (const uint64_t Hash : Doc.YamlifiedDataAccessProfiles.KnownColdStrHashes)
-    if (Error E = DataAccessProfileData->addKnownSymbolWithoutSamples(Hash))
-      reportFatalInternalError(std::move(E));
-
-  for (const std::string &Sym :
-       Doc.YamlifiedDataAccessProfiles.KnownColdSymbols)
-    if (Error E = DataAccessProfileData->addKnownSymbolWithoutSamples(Sym))
-      reportFatalInternalError(std::move(E));
-
-  setDataAccessProfileData(std::move(DataAccessProfileData));
 }
 } // namespace memprof
 } // namespace llvm
diff --git a/llvm/test/tools/llvm-profdata/memprof-yaml.test b/llvm/test/tools/llvm-profdata/memprof-yaml.test
index 5beda8c036a12..9766cc50f37d7 100644
--- a/llvm/test/tools/llvm-profdata/memprof-yaml.test
+++ b/llvm/test/tools/llvm-profdata/memprof-yaml.test
@@ -1,101 +1,12 @@
 ; RUN: split-file %s %t
 ; COM: The text format only supports the latest version.
-
-; Verify that the YAML output is identical to the YAML input.
-; memprof-in.yaml has both heap profile records and data access profiles.
 ; RUN: llvm-profdata merge --memprof-version=4 %t/memprof-in.yaml -o %t/memprof-out.indexed
 ; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out.yaml
 ; RUN: diff -b %t/memprof-in.yaml %t/memprof-out.yaml
 
-; Merge text profile as v3 binary profile. Test that the merged v3 profile
-; are identical to memprof-in-v3.yaml, and doesn't have callee guids or dap.
-; RUN: llvm-profdata merge --memprof-version=3 %t/memprof-in.yaml -o %t/memprof-out-v3.indexed
-; RUN: llvm-profdata show --memory %t/memprof-out-v3.indexed > %t/memprof-out-v3.yaml
-; RUN: diff -b %t/memprof-out-v3.yaml %t/memprof-in-v3.yaml
-
-; memprof-in-no-dap.yaml has empty data access profiles.
-; RUN: llvm-profdata merge --memprof-version=4 %t/memprof-in-no-dap.yaml -o %t/memprof-out.indexed
-; RUN: llvm-profdata show --memory %t/memprof-out.indexed > %t/memprof-out-no-dap.yaml
-; RUN: diff -b %t/memprof-in-no-dap.yaml %t/memprof-out-no-dap.yaml
-
+; Verify that the YAML output is identical to the YAML input.
 ;--- memprof-in.yaml
 ---
-HeapProfileRecords:
-  - GUID:            0xdeadbeef12345678
-    AllocSites:
-      - Callstack:
-          - { Function: 0x1111111111111111, LineOffset: 11, Column: 10, IsInlineFrame: true }
-          - { Function: 0x2222222222222222, LineOffset: 22, Column: 20, IsInlineFrame: false }
-        MemInfoBlock:
-          AllocCount:      111
-          TotalSize:       222
-          TotalLifetime:   333
-          TotalLifetimeAccessDensity: 444
-      - Callstack:
-          - { Function: 0x3333333333333333, LineOffset: 33, Column: 30, IsInlineFrame: false }
-          - { Function: 0x4444444444444444, LineOffset: 44, Column: 40, IsInlineFrame: true }
-        MemInfoBlock:
-          AllocCount:      555
-          TotalSize:       666
-          TotalLifetime:   777
-          TotalLifetimeAccessDensity: 888
-    CallSites:
-      - Frames:
-        - { Function: 0x5555555555555555, LineOffset: 55, Column: 50, IsInlineFrame: true }
-        - { Function: 0x6666666666666666, LineOffset: 66, Column: 60, IsInlineFrame: false }
-        CalleeGuids: [ 0x100, 0x200 ]
-      - Frames:
-        - { Function: 0x7777777777777777, LineOffset: 77, Column: 70, IsInlineFrame: true }
-        - { Function: 0x8888888888888888, LineOffset: 88, Column: 80, IsInlineFrame: false }
-        CalleeGuids: [ 0x300 ]
-DataAccessProfiles:
-  SampledRecords:
-    - Symbol:          abcde
-      Locations:
-      - FileName:      file2.h
-        Line:          123
-      - FileName:      file3.cpp
-        Line:          456
-    - Hash:            101010
-      Locations:
-        - FileName:        file.cpp
-          Line:            233
-  KnownColdSymbols:
-    - foo
-    - bar
-  KnownColdStrHashes: [ 999, 1001 ]
-...
-;--- memprof-in-v3.yaml
----
-HeapProfileRecords:
-  - GUID:            0xdeadbeef12345678
-    AllocSites:
-      - Callstack:
-          - { Function: 0x1111111111111111, LineOffset: 11, Column: 10, IsInlineFrame: true }
-          - { Function: 0x2222222222222222, LineOffset: 22, Column: 20, IsInlineFrame: false }
-        MemInfoBlock:
-          AllocCount:      111
-          TotalSize:       222
-          TotalLifetime:   333
-          TotalLifetimeAccessDensity: 444
-      - Callstack:
-          - { Function: 0x3333333333333333, LineOffset: 33, Column: 30, IsInlineFrame: false }
-          - { Function: 0x4444444444444444, LineOffset: 44, Column: 40, IsInlineFrame: true }
-        MemInfoBlock:
-          AllocCount:      555
-          TotalSize:       666
-          TotalLifetime:   777
-          TotalLifetimeAccessDensity: 888
-    CallSites:
-      - Frames:
-        - { Function: 0x5555555555555555, LineOffset: 55, Column: 50, IsInlineFrame: true }
-        - { Function: 0x6666666666666666, LineOffset: 66, Column: 60, IsInlineFrame: false }
-      - Frames:
-        - { Function: 0x7777777777777777, LineOffset: 77, Column: 70, IsInlineFrame: true }
-        - { Function: 0x8888888888888888, LineOffset: 88, Column: 80, IsInlineFrame: false }
-...
-;--- memprof-in-no-dap.yaml
----
 HeapProfileRecords:
   - GUID:            0xdeadbeef12345678
     AllocSites:
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 8660eed6be2bf..885e06df6c390 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -16,7 +16,6 @@
 #include "llvm/Debuginfod/HTTPClient.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/Object/Binary.h"
-#include "llvm/ProfileData/DataAccessProf.h"
 #include "llvm/ProfileData/InstrProfCorrelator.h"
 #include "llvm/ProfileData/InstrProfReader.h"
 #include "llvm/ProfileData/InstrProfWriter.h"
@@ -757,8 +756,6 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
 
     auto MemProfData = Reader->takeMemProfData();
 
-    auto DataAccessProfData = Reader->takeDataAccessProfData();
-
     // Check for the empty input in case the YAML file is invalid.
     if (MemProfData.Records.empty()) {
       WC->Errors.emplace_back(
@@ -767,7 +764,6 @@ loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
     }
 
     WC->Writer.addMemProfData(std::move(MemProfData), MemProfError);
-    WC->Writer.addDataAccessProfData(std::move(DataAccessProfData));
     return;
   }
 
diff --git a/llvm/unittests/ProfileData/DataAccessProfTest.cpp b/llvm/unittests/ProfileData/DataAccessProfTest.cpp
index 13af3390557d7..8866c16fe292a 100644
--- a/llvm/unittests/ProfileData/DataAccessProfTest.cpp
+++ b/llvm/unittests/ProfileData/DataAccessProfTest.cpp
@@ -14,7 +14,7 @@
 #include "gtest/gtest.h"
 
 namespace llvm {
-namespace memprof {
+namespace data_access_prof {
 namespace {
 
 using ::llvm::StringRef;
@@ -177,5 +177,5 @@ TEST(MemProf, DataAccessProfile) {
   }
 }
 } // namespace
-} // namespace memprof
+} // namespace data_access_prof
 } // namespace llvm

>From 1a4d5887386d98573bee895f762997abc5b4499c Mon Sep 17 00:00:00 2001
From: Adam Nemet <anemet at apple.com>
Date: Thu, 22 May 2025 16:21:19 -0700
Subject: [PATCH 069/105] [TableGen] Add missing $ before the dag operator name
 (#140969)

This way the dump output is roundtripable.
---
 llvm/lib/TableGen/Record.cpp     | 2 +-
 llvm/test/TableGen/usevalname.td | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 2f991d5fec165..12f5ce6175dbf 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -2786,7 +2786,7 @@ bool DagInit::isConcrete() const {
 std::string DagInit::getAsString() const {
   std::string Result = "(" + Val->getAsString();
   if (ValName)
-    Result += ":" + ValName->getAsUnquotedString();
+    Result += ":$" + ValName->getAsUnquotedString();
   if (!arg_empty()) {
     Result += " ";
     ListSeparator LS;
diff --git a/llvm/test/TableGen/usevalname.td b/llvm/test/TableGen/usevalname.td
index d85b98ac33e64..ab90398cde49c 100644
--- a/llvm/test/TableGen/usevalname.td
+++ b/llvm/test/TableGen/usevalname.td
@@ -20,5 +20,5 @@ multiclass shuffle<Reg RC> {
                                        RC:$src1, RC:$src2))]>;
 }
 
-// CHECK: shufp:src3
+// CHECK: shufp:$src3
 defm ADD : shuffle<VR128>;

>From e9304cb7bbe2991a11bc9a3e234cb69f202dd804 Mon Sep 17 00:00:00 2001
From: Steven Wu <stevenwu at apple.com>
Date: Thu, 22 May 2025 16:22:21 -0700
Subject: [PATCH 070/105] [TSan][Test] Disable signal_recursive.cpp test on
 Darwin (#141135)

Mark signal_recursive.cpp test as unsupported on Darwin due to
deprecated API `sem_init` and test receives error:

`sem_init failed (errno=78)`
---
 compiler-rt/test/tsan/signal_recursive.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/compiler-rt/test/tsan/signal_recursive.cpp b/compiler-rt/test/tsan/signal_recursive.cpp
index fca8757d2a952..189c35a299dcd 100644
--- a/compiler-rt/test/tsan/signal_recursive.cpp
+++ b/compiler-rt/test/tsan/signal_recursive.cpp
@@ -3,6 +3,8 @@
 // Test case for recursive signal handlers, adopted from:
 // https://github.com/google/sanitizers/issues/478
 
+// UNSUPPORTED: darwin
+
 #include "test.h"
 #include <semaphore.h>
 #include <signal.h>

>From d6596482ef277269dd35b5ea0c0439173cba7636 Mon Sep 17 00:00:00 2001
From: "S. VenkataKeerthy" <31350914+svkeerthy at users.noreply.github.com>
Date: Thu, 22 May 2025 16:49:21 -0700
Subject: [PATCH 071/105] Minor typo fix in IR2Vec section of MLGO doc
 (#141162)

Co-authored-by: svkeerthy <venkatakeerthy at google.com>
---
 llvm/docs/MLGO.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/MLGO.rst b/llvm/docs/MLGO.rst
index 43b45d505ea3a..15d71c9d77506 100644
--- a/llvm/docs/MLGO.rst
+++ b/llvm/docs/MLGO.rst
@@ -471,7 +471,7 @@ embeddings can be computed and accessed via an ``ir2vec::Embedder`` instance.
       const ir2vec::Vocab &Vocabulary = VocabRes.getVocabulary();
       unsigned Dimension = VocabRes.getDimension();
 
-    Note that ``IR2VecVocabAnalysis`` pass is immutable.
+   Note that ``IR2VecVocabAnalysis`` pass is immutable.
 
 2. **Create Embedder instance**:
    With the vocabulary, create an embedder for a specific function:

>From 34e63be925cc91d13f8c57c42664d9a678328f7c Mon Sep 17 00:00:00 2001
From: Jie Fu <jiefu at tencent.com>
Date: Fri, 23 May 2025 09:00:19 +0800
Subject: [PATCH 072/105] [clang-doc] Prevent copying loop variables (NFC)

/llvm-project/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp:86:19:
error: loop variable '[Name, FileName]' creates a copy from type 'std::pair<llvm::StringRef, llvm::StringRef> const' [-Werror,-Wrange-loop-construct]
  for (const auto [Name, FileName] : Partials)
                  ^
/llvm-project/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp:86:8:
note: use reference type 'std::pair<llvm::StringRef, llvm::StringRef> const &' to prevent copying
  for (const auto [Name, FileName] : Partials)
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  &
1 error generated.
---
 clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index fd68b2e08ad98..6f51add830ed6 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -83,7 +83,7 @@ setupTemplate(std::unique_ptr<MustacheTemplateFile> &Template,
   if (Error Err = T.takeError())
     return Err;
   Template = std::move(T.get());
-  for (const auto [Name, FileName] : Partials)
+  for (const auto &[Name, FileName] : Partials)
     if (auto Err = Template->registerPartialFile(Name, FileName))
       return Err;
   return Error::success();

>From 0635ef8240ffe493169fb353fb004df2fb20353b Mon Sep 17 00:00:00 2001
From: hev <wangrui at loongson.cn>
Date: Fri, 23 May 2025 09:30:29 +0800
Subject: [PATCH 073/105] [LoongArch][NFC] Improve csrxchg instrinsic test case
 (#141060)

Took xry's idea [^1] to improve the csrxchg instrinsic test case.

[^1]:
https://github.com/llvm/llvm-project/pull/141037#issuecomment-2900955906
---
 llvm/test/CodeGen/LoongArch/csrxchg-intrinsic.ll | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/llvm/test/CodeGen/LoongArch/csrxchg-intrinsic.ll b/llvm/test/CodeGen/LoongArch/csrxchg-intrinsic.ll
index 2f38b3a8c7ad1..cdeb7a008b848 100644
--- a/llvm/test/CodeGen/LoongArch/csrxchg-intrinsic.ll
+++ b/llvm/test/CodeGen/LoongArch/csrxchg-intrinsic.ll
@@ -13,12 +13,11 @@ entry:
 }
 
 ;; Check that the rj operand of csrxchg is not R1.
-define i32 @csrxchg_w_rj_not_r1() {
+define i32 @csrxchg_w_rj_not_r1(i32 %0) {
 ; CHECK-NOT:    csrxchg ${{[a-z]*}}, $r1, 0
 ; CHECK-NOT:    csrxchg ${{[a-z]*}}, $ra, 0
 entry:
-  %0 = tail call i32 asm "", "=r,r,i,{r4},{r5},{r6},{r7},{r8},{r9},{r10},{r11},{r12},{r13},{r14},{r15},{r16},{r17},{r18},{r19},{r20},{r23},{r24},{r25},{r26},{r27},{r28},{r29},{r30},{r31},0"(i32 4, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0)
-  %1 = tail call i32 @llvm.loongarch.csrxchg.w(i32 %0, i32 4, i32 0)
-  %2 = tail call i32 asm "", "=r,r,i,{r4},{r5},{r6},{r7},{r8},{r9},{r10},{r11},{r12},{r13},{r14},{r15},{r16},{r17},{r18},{r19},{r20},{r23},{r24},{r25},{r26},{r27},{r28},{r29},{r30},{r31},0"(i32 4, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 0, i32 %1)
-  ret i32 %2
+  %2 = tail call i32 asm "", "={$r1},{$r1}"(i32 0)
+  %3 = tail call i32 @llvm.loongarch.csrxchg.w(i32 %0, i32 %2, i32 0)
+  ret i32 %3
 }

>From 720014f70841f0284d21ef8100c406d6c864ac9c Mon Sep 17 00:00:00 2001
From: Volodymyr Sapsai <vsapsai at apple.com>
Date: Thu, 22 May 2025 18:34:30 -0700
Subject: [PATCH 074/105] Revert "[Modules] Don't fail when an unused textual
 header is missing. (#138227)"

This reverts commit 64bb60a471a5ddc9c9bec413c65fdab730a1e4b0.

Revert to give more time affected parties to adjust to the change.
---
 clang/lib/Lex/ModuleMap.cpp                           | 6 ++----
 clang/test/Modules/Inputs/submodules/module.modulemap | 4 ----
 clang/test/Modules/missing-header.m                   | 3 ---
 3 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 4175959d8f55b..e899e0cbc6f35 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -310,10 +310,8 @@ void ModuleMap::resolveHeader(Module *Mod,
   } else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
     // There's a builtin header but no corresponding on-disk header. Assume
     // this was supposed to modularize the builtin header alone.
-  } else if ((Header.Kind == Module::HK_Excluded) ||
-             (Header.Kind == Module::HK_Textual)) {
-    // Ignore excluded and textual header files as a module can be built with
-    // such headers missing.
+  } else if (Header.Kind == Module::HK_Excluded) {
+    // Ignore missing excluded header files. They're optional anyway.
   } else {
     // If we find a module that has a missing header, we mark this module as
     // unavailable and store the header directive for displaying diagnostics.
diff --git a/clang/test/Modules/Inputs/submodules/module.modulemap b/clang/test/Modules/Inputs/submodules/module.modulemap
index 9e8143b8101de..1c1b76a08969e 100644
--- a/clang/test/Modules/Inputs/submodules/module.modulemap
+++ b/clang/test/Modules/Inputs/submodules/module.modulemap
@@ -30,7 +30,3 @@ module missing_umbrella_with_inferred_submodules {
   module * { export * }
   export *
 }
-
-module missing_textual_header {
-  textual header "missing_textual.h"
-}
diff --git a/clang/test/Modules/missing-header.m b/clang/test/Modules/missing-header.m
index 84d82e5ceda32..c162e1b5f08b3 100644
--- a/clang/test/Modules/missing-header.m
+++ b/clang/test/Modules/missing-header.m
@@ -8,9 +8,6 @@
 @import missing_unavailable_headers.not_missing; // OK
 // CHECK-NOT: missing_unavailable_headers
 
- at import missing_textual_header; // OK
-// CHECK-NOT: missing_textual_header
-
 @import missing_headers;
 // CHECK: module.modulemap:15:27: error: header 'missing.h' not found
 // CHECK: could not build module 'missing_headers'

>From b79a624cd601723f9e55a7b1bad9fbaa060d803e Mon Sep 17 00:00:00 2001
From: Yuta Saito <kateinoigakukun at gmail.com>
Date: Fri, 23 May 2025 10:58:28 +0900
Subject: [PATCH 075/105] [clang] Support ASan on WASI (#139014)

I'm working on porting ASan to Wasm/WASI targets, and this is the first
part of the change sets. I'll post runtime changes separately.

This change makes `-fsanitize=address` available for WASI target by
replicating what we do for Emscripten because they share the same memory
model.
---
 clang/lib/Driver/ToolChains/WebAssembly.cpp              | 7 ++++++-
 llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp | 8 ++++----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index cd12f2ae5a6de..9fcc33728c1ad 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -545,8 +545,13 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args,
 SanitizerMask WebAssembly::getSupportedSanitizers() const {
   SanitizerMask Res = ToolChain::getSupportedSanitizers();
   if (getTriple().isOSEmscripten()) {
-    Res |= SanitizerKind::Vptr | SanitizerKind::Leak | SanitizerKind::Address;
+    Res |= SanitizerKind::Vptr | SanitizerKind::Leak;
   }
+
+  if (getTriple().isOSEmscripten() || getTriple().isOSWASI()) {
+    Res |= SanitizerKind::Address;
+  }
+
   // -fsanitize=function places two words before the function label, which are
   // -unsupported.
   Res &= ~SanitizerKind::Function;
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index c1dba77c3532b..840a5e3f31dfd 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -118,7 +118,7 @@ static const uint64_t kNetBSD_ShadowOffset64 = 1ULL << 46;
 static const uint64_t kNetBSDKasan_ShadowOffset64 = 0xdfff900000000000;
 static const uint64_t kPS_ShadowOffset64 = 1ULL << 40;
 static const uint64_t kWindowsShadowOffset32 = 3ULL << 28;
-static const uint64_t kEmscriptenShadowOffset = 0;
+static const uint64_t kWebAssemblyShadowOffset = 0;
 
 // The shadow memory space is dynamically allocated.
 static const uint64_t kWindowsShadowOffset64 = kDynamicShadowSentinel;
@@ -499,9 +499,9 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize,
   bool IsRISCV64 = TargetTriple.getArch() == Triple::riscv64;
   bool IsWindows = TargetTriple.isOSWindows();
   bool IsFuchsia = TargetTriple.isOSFuchsia();
-  bool IsEmscripten = TargetTriple.isOSEmscripten();
   bool IsAMDGPU = TargetTriple.isAMDGPU();
   bool IsHaiku = TargetTriple.isOSHaiku();
+  bool IsWasm = TargetTriple.isWasm();
 
   ShadowMapping Mapping;
 
@@ -525,8 +525,8 @@ static ShadowMapping getShadowMapping(const Triple &TargetTriple, int LongSize,
       Mapping.Offset = kDynamicShadowSentinel;
     else if (IsWindows)
       Mapping.Offset = kWindowsShadowOffset32;
-    else if (IsEmscripten)
-      Mapping.Offset = kEmscriptenShadowOffset;
+    else if (IsWasm)
+      Mapping.Offset = kWebAssemblyShadowOffset;
     else
       Mapping.Offset = kDefaultShadowOffset32;
   } else {  // LongSize == 64

>From 8268794cc5da06dfe911a40e5b20506c54e65b1b Mon Sep 17 00:00:00 2001
From: Erick Velez <erickvelez7 at gmail.com>
Date: Fri, 23 May 2025 02:05:52 +0000
Subject: [PATCH 076/105] [clang-doc] Precommit test for correct conversion
 function names (#141168)

---
 .../test/clang-doc/conversion_function.cpp    | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 clang-tools-extra/test/clang-doc/conversion_function.cpp

diff --git a/clang-tools-extra/test/clang-doc/conversion_function.cpp b/clang-tools-extra/test/clang-doc/conversion_function.cpp
new file mode 100644
index 0000000000000..ebde35e38278d
--- /dev/null
+++ b/clang-tools-extra/test/clang-doc/conversion_function.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t && mkdir -p %t
+
+// RUN: clang-doc --output=%t --executor=standalone %s 
+// RUN: find %t/ -regex ".*/[0-9A-F]*.yaml" -exec cat {} ";" | FileCheck %s --check-prefix=CHECK-YAML
+
+// RUN: clang-doc --format=html --output=%t --executor=standalone %s 
+// FileCheck %s --check-prefix=CHECK-HTML
+
+template <typename T>
+struct MyStruct {
+  operator T();
+};
+
+// Output incorrect conversion names.
+// CHECK-YAML:         Name:            'operator type-parameter-0-0'
+// CHECK-YAML-NOT:     Name:            'operator T'
+
+// CHECK-HTML-NOT: <h3 id='{{[0-9A-F]*}}'>operator T</h3>
+// CHECK-HTML-NOT: <p>public T operator T()</p>

>From 2b64b1566c2b62e46b2e2268c78aab204eccb9a1 Mon Sep 17 00:00:00 2001
From: Finn Plummer <finn.c.plum at gmail.com>
Date: Thu, 22 May 2025 19:20:34 -0700
Subject: [PATCH 077/105] [HLSL][RootSignature] Add parsing of optional
 parameters for RootDescriptor (#140151)

- define in-memory representation of optional non-flag parameters to
`RootDescriptor`
- fill in data to parse these params in `parseRootDescriptorParams`
- add unit tests

Part 3 of https://github.com/llvm/llvm-project/issues/126577
---
 .../clang/Parse/ParseHLSLRootSignature.h      |  2 +
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 40 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 11 ++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  2 +
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 0d56d2a16a268..739a14d43584e 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -91,6 +91,8 @@ class RootSignatureParser {
 
   struct ParsedRootDescriptorParams {
     std::optional<llvm::hlsl::rootsig::Register> Reg;
+    std::optional<uint32_t> Space;
+    std::optional<llvm::hlsl::rootsig::ShaderVisibility> Visibility;
   };
   std::optional<ParsedRootDescriptorParams>
   parseRootDescriptorParams(RootSignatureToken::Kind RegType);
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index da01df04ac78e..92be49b8a96b2 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -207,6 +207,13 @@ std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() {
 
   Descriptor.Reg = Params->Reg.value();
 
+  // Fill in optional values
+  if (Params->Space.has_value())
+    Descriptor.Space = Params->Space.value();
+
+  if (Params->Visibility.has_value())
+    Descriptor.Visibility = Params->Visibility.value();
+
   if (consumeExpectedToken(TokenKind::pu_r_paren,
                            diag::err_hlsl_unexpected_end_of_params,
                            /*param of=*/TokenKind::kw_RootConstants))
@@ -435,6 +442,39 @@ RootSignatureParser::parseRootDescriptorParams(TokenKind RegType) {
       Params.Reg = Reg;
     }
 
+    // `space` `=` POS_INT
+    if (tryConsumeExpectedToken(TokenKind::kw_space)) {
+      if (Params.Space.has_value()) {
+        getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
+            << CurToken.TokKind;
+        return std::nullopt;
+      }
+
+      if (consumeExpectedToken(TokenKind::pu_equal))
+        return std::nullopt;
+
+      auto Space = parseUIntParam();
+      if (!Space.has_value())
+        return std::nullopt;
+      Params.Space = Space;
+    }
+
+    // `visibility` `=` SHADER_VISIBILITY
+    if (tryConsumeExpectedToken(TokenKind::kw_visibility)) {
+      if (Params.Visibility.has_value()) {
+        getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
+            << CurToken.TokKind;
+        return std::nullopt;
+      }
+
+      if (consumeExpectedToken(TokenKind::pu_equal))
+        return std::nullopt;
+
+      auto Visibility = parseShaderVisibility();
+      if (!Visibility.has_value())
+        return std::nullopt;
+      Params.Visibility = Visibility;
+    }
   } while (tryConsumeExpectedToken(TokenKind::pu_comma));
 
   return Params;
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 665ef5b518be7..07b4f625a2e05 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -347,8 +347,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) {
 TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) {
   const llvm::StringLiteral Source = R"cc(
     CBV(b0),
-    SRV(t42),
-    UAV(u34893247)
+    SRV(space = 4, t42, visibility = SHADER_VISIBILITY_GEOMETRY),
+    UAV(visibility = SHADER_VISIBILITY_HULL, u34893247)
   )cc";
 
   TrivialModuleLoader ModLoader;
@@ -371,18 +371,25 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) {
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::BReg);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::All);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::SRV);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::TReg);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 42u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 4u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility,
+            ShaderVisibility::Geometry);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem));
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::UAV);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::UReg);
   ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 34893247u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u);
+  ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::Hull);
 
   ASSERT_TRUE(Consumer->isSatisfied());
 }
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 4b1bbd0e3bd12..7c496844ab7a6 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -90,6 +90,8 @@ using DescriptorType = llvm::dxil::ResourceClass;
 struct RootDescriptor {
   DescriptorType Type;
   Register Reg;
+  uint32_t Space = 0;
+  ShaderVisibility Visibility = ShaderVisibility::All;
 };
 
 // Models the end of a descriptor table and stores its visibility

>From 5d76555f935cfe75d1e45bd56544786cc56718c3 Mon Sep 17 00:00:00 2001
From: Finn Plummer <finn.c.plum at gmail.com>
Date: Thu, 22 May 2025 19:21:40 -0700
Subject: [PATCH 078/105] [NFC][HLSL][RootSignature] Use `operator<<` overload
 instead of dump method (#141127)

- we will need to provide a way to dump `RootFlags` for serialization
and by using operator overloads we can maintain a consistent interface

This is an NFC to allow for
https://github.com/llvm/llvm-project/issues/138192 to be more
straightforwardly implemented.
---
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  8 ++---
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp  | 33 +++++++++++--------
 .../Frontend/HLSLRootSignatureDumpTest.cpp    | 10 +++---
 3 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 7c496844ab7a6..cc3d96f1757bc 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -100,10 +100,10 @@ struct DescriptorTable {
   // Denotes that the previous NumClauses in the RootElement array
   // are the clauses in the table.
   uint32_t NumClauses = 0;
-
-  void dump(raw_ostream &OS) const;
 };
 
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable &Table);
+
 static const uint32_t NumDescriptorsUnbounded = 0xffffffff;
 static const uint32_t DescriptorTableOffsetAppend = 0xffffffff;
 // Models DTClause : CBV | SRV | UAV | Sampler, by collecting like parameters
@@ -130,10 +130,10 @@ struct DescriptorTableClause {
       break;
     }
   }
-
-  void dump(raw_ostream &OS) const;
 };
 
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTableClause &Clause);
+
 /// Models RootElement : RootFlags | RootConstants | RootDescriptor
 ///  | DescriptorTable | DescriptorTableClause
 ///
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
index abf076944b273..ec0d130a6767c 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -71,11 +71,6 @@ static raw_ostream &operator<<(raw_ostream &OS,
   return OS;
 }
 
-void DescriptorTable::dump(raw_ostream &OS) const {
-  OS << "DescriptorTable(numClauses = " << NumClauses
-     << ", visibility = " << Visibility << ")";
-}
-
 static raw_ostream &operator<<(raw_ostream &OS, const ClauseType &Type) {
   switch (Type) {
   case ClauseType::CBuffer:
@@ -137,14 +132,24 @@ static raw_ostream &operator<<(raw_ostream &OS,
   return OS;
 }
 
-void DescriptorTableClause::dump(raw_ostream &OS) const {
-  OS << Type << "(" << Reg << ", numDescriptors = " << NumDescriptors
-     << ", space = " << Space << ", offset = ";
-  if (Offset == DescriptorTableOffsetAppend)
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable &Table) {
+  OS << "DescriptorTable(numClauses = " << Table.NumClauses
+     << ", visibility = " << Table.Visibility << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTableClause &Clause) {
+  OS << Clause.Type << "(" << Clause.Reg
+     << ", numDescriptors = " << Clause.NumDescriptors
+     << ", space = " << Clause.Space << ", offset = ";
+  if (Clause.Offset == DescriptorTableOffsetAppend)
     OS << "DescriptorTableOffsetAppend";
   else
-    OS << Offset;
-  OS << ", flags = " << Flags << ")";
+    OS << Clause.Offset;
+  OS << ", flags = " << Clause.Flags << ")";
+
+  return OS;
 }
 
 void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
@@ -154,11 +159,11 @@ void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
     if (!First)
       OS << ",";
     OS << " ";
-    First = false;
     if (const auto &Clause = std::get_if<DescriptorTableClause>(&Element))
-      Clause->dump(OS);
+      OS << *Clause;
     if (const auto &Table = std::get_if<DescriptorTable>(&Element))
-      Table->dump(OS);
+      OS << *Table;
+    First = false;
   }
   OS << "}";
 }
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
index ba1fbfd1f8708..3f92fa0f05794 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
@@ -21,7 +21,7 @@ TEST(HLSLRootSignatureTest, DescriptorCBVClauseDump) {
 
   std::string Out;
   llvm::raw_string_ostream OS(Out);
-  Clause.dump(OS);
+  OS << Clause;
   OS.flush();
 
   std::string Expected = "CBV(b0, numDescriptors = 1, space = 0, "
@@ -41,7 +41,7 @@ TEST(HLSLRootSignatureTest, DescriptorSRVClauseDump) {
 
   std::string Out;
   llvm::raw_string_ostream OS(Out);
-  Clause.dump(OS);
+  OS << Clause;
   OS.flush();
 
   std::string Expected =
@@ -60,7 +60,7 @@ TEST(HLSLRootSignatureTest, DescriptorUAVClauseDump) {
 
   std::string Out;
   llvm::raw_string_ostream OS(Out);
-  Clause.dump(OS);
+  OS << Clause;
   OS.flush();
 
   std::string Expected =
@@ -84,7 +84,7 @@ TEST(HLSLRootSignatureTest, DescriptorSamplerClauseDump) {
 
   std::string Out;
   llvm::raw_string_ostream OS(Out);
-  Clause.dump(OS);
+  OS << Clause;
   OS.flush();
 
   std::string Expected = "Sampler(s0, numDescriptors = 2, space = 42, offset = "
@@ -100,7 +100,7 @@ TEST(HLSLRootSignatureTest, DescriptorTableDump) {
 
   std::string Out;
   llvm::raw_string_ostream OS(Out);
-  Table.dump(OS);
+  OS << Table;
   OS.flush();
 
   std::string Expected =

>From 3a84a4e55d896e573fe175f34c793b0c294dec6b Mon Sep 17 00:00:00 2001
From: Alex MacLean <amaclean at nvidia.com>
Date: Thu, 22 May 2025 19:38:10 -0700
Subject: [PATCH 079/105] Reland "[NVPTX] Unify and extend barrier{.cta}
 intrinsic support" (#141143)

Note: This relands #140615 adding a ".count" suffix to the non-".all"
variants.

Our current intrinsic support for barrier intrinsics is confusing and
incomplete, with multiple intrinsics mapping to the same instruction and
intrinsic names not clearly conveying intrinsic semantics. Further, we
lack support for some variants. This change unifies the IR
representation to a single consistently named set of intrinsics.

- llvm.nvvm.barrier.cta.sync.aligned.all(i32)
- llvm.nvvm.barrier.cta.sync.aligned.count(i32, i32)
- llvm.nvvm.barrier.cta.arrive.aligned.count(i32, i32)
- llvm.nvvm.barrier.cta.sync.all(i32)
- llvm.nvvm.barrier.cta.sync.count(i32, i32)
- llvm.nvvm.barrier.cta.arrive.count(i32, i32)

The following Auto-Upgrade rules are used to maintain compatibility with
IR using the legacy intrinsics:

* llvm.nvvm.barrier0 --> llvm.nvvm.barrier.cta.sync.aligned.all(0)
* llvm.nvvm.barrier.n --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
* llvm.nvvm.bar.sync --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
* llvm.nvvm.barrier --> llvm.nvvm.barrier.cta.sync.aligned.count(x, y)
* llvm.nvvm.barrier.sync --> llvm.nvvm.barrier.cta.sync.all(x)
* llvm.nvvm.barrier.sync.cnt --> llvm.nvvm.barrier.cta.sync.count(x, y)
---
 clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp    |  16 ++
 clang/test/CodeGen/builtins-nvptx-ptx60.cu    |   4 +-
 clang/test/CodeGen/builtins-nvptx.c           |   4 +-
 clang/test/Headers/gpuintrin.c                |   2 +-
 llvm/docs/NVPTXUsage.rst                      |  48 +++++-
 llvm/include/llvm/IR/IntrinsicsNVVM.td        |  37 +++--
 llvm/lib/IR/AutoUpgrade.cpp                   |  35 +++-
 llvm/lib/Target/NVPTX/NVPTXIntrinsics.td      |  71 ++++----
 .../Transforms/IPO/AttributorAttributes.cpp   |   3 +-
 .../GlobalsModRef/functions_without_nosync.ll |  19 +--
 .../Assembler/auto_upgrade_nvvm_intrinsics.ll |  22 +++
 llvm/test/CodeGen/NVPTX/barrier.ll            | 153 +++++++++++++++---
 llvm/test/CodeGen/NVPTX/named-barriers.ll     |  42 -----
 .../CodeGen/NVPTX/noduplicate-syncthreads.ll  |   6 +-
 llvm/test/Feature/intrinsic-noduplicate.ll    |   6 +-
 .../Transforms/FunctionAttrs/convergent.ll    |   6 +-
 .../JumpThreading/thread-two-bbs-cuda.ll      |   8 +-
 .../test/Transforms/OpenMP/barrier_removal.ll |  28 ++--
 mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td   |  24 +--
 mlir/test/Target/LLVMIR/Import/nvvmir.ll      |   3 +-
 mlir/test/Target/LLVMIR/nvvmir.mlir           |  10 +-
 21 files changed, 350 insertions(+), 197 deletions(-)
 delete mode 100644 llvm/test/CodeGen/NVPTX/named-barriers.ll

diff --git a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
index 002af4f931c09..6da65b681df1e 100644
--- a/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
@@ -1160,6 +1160,22 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID,
   case NVPTX::BI__nvvm_fence_sc_cluster:
     return Builder.CreateCall(
         CGM.getIntrinsic(Intrinsic::nvvm_fence_sc_cluster));
+  case NVPTX::BI__nvvm_bar_sync:
+    return Builder.CreateCall(
+        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all),
+        EmitScalarExpr(E->getArg(0)));
+  case NVPTX::BI__syncthreads:
+    return Builder.CreateCall(
+        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all),
+        Builder.getInt32(0));
+  case NVPTX::BI__nvvm_barrier_sync:
+    return Builder.CreateCall(
+        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_all),
+        EmitScalarExpr(E->getArg(0)));
+  case NVPTX::BI__nvvm_barrier_sync_cnt:
+    return Builder.CreateCall(
+        CGM.getIntrinsic(Intrinsic::nvvm_barrier_cta_sync_count),
+        {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});
   default:
     return nullptr;
   }
diff --git a/clang/test/CodeGen/builtins-nvptx-ptx60.cu b/clang/test/CodeGen/builtins-nvptx-ptx60.cu
index 599d09a20e04a..8b2514a183221 100644
--- a/clang/test/CodeGen/builtins-nvptx-ptx60.cu
+++ b/clang/test/CodeGen/builtins-nvptx-ptx60.cu
@@ -32,10 +32,10 @@ __device__ void nvvm_sync(unsigned mask, int i, float f, int a, int b,
   // CHECK: call void @llvm.nvvm.bar.warp.sync(i32
   // expected-error at +1 {{'__nvvm_bar_warp_sync' needs target feature ptx60}}
   __nvvm_bar_warp_sync(mask);
-  // CHECK: call void @llvm.nvvm.barrier.sync(i32
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.all(i32
   // expected-error at +1 {{'__nvvm_barrier_sync' needs target feature ptx60}}
   __nvvm_barrier_sync(mask);
-  // CHECK: call void @llvm.nvvm.barrier.sync.cnt(i32
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.count(i32
   // expected-error at +1 {{'__nvvm_barrier_sync_cnt' needs target feature ptx60}}
   __nvvm_barrier_sync_cnt(mask, i);
 
diff --git a/clang/test/CodeGen/builtins-nvptx.c b/clang/test/CodeGen/builtins-nvptx.c
index 7904762709df6..cef529163bb39 100644
--- a/clang/test/CodeGen/builtins-nvptx.c
+++ b/clang/test/CodeGen/builtins-nvptx.c
@@ -198,7 +198,7 @@ __device__ int read_pms() {
 
 __device__ void sync() {
 
-// CHECK: call void @llvm.nvvm.bar.sync(i32 0)
+// CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
 
   __nvvm_bar_sync(0);
 
@@ -259,7 +259,7 @@ __device__ void nvvm_math(float f1, float f2, double d1, double d2) {
   __nvvm_membar_gl();
 // CHECK: call void @llvm.nvvm.membar.sys()
   __nvvm_membar_sys();
-// CHECK: call void @llvm.nvvm.barrier0()
+// CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   __syncthreads();
 }
 
diff --git a/clang/test/Headers/gpuintrin.c b/clang/test/Headers/gpuintrin.c
index f7dfb86ac4652..b254423ec4a1e 100644
--- a/clang/test/Headers/gpuintrin.c
+++ b/clang/test/Headers/gpuintrin.c
@@ -887,7 +887,7 @@ __gpu_kernel void foo() {
 // NVPTX-LABEL: define internal void @__gpu_sync_threads(
 // NVPTX-SAME: ) #[[ATTR0]] {
 // NVPTX-NEXT:  [[ENTRY:.*:]]
-// NVPTX-NEXT:    call void @llvm.nvvm.barrier0()
+// NVPTX-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
 // NVPTX-NEXT:    ret void
 //
 //
diff --git a/llvm/docs/NVPTXUsage.rst b/llvm/docs/NVPTXUsage.rst
index 6f230a1635f3b..8bb0f2ed17c32 100644
--- a/llvm/docs/NVPTXUsage.rst
+++ b/llvm/docs/NVPTXUsage.rst
@@ -199,21 +199,59 @@ map in the following way to CUDA builtins:
 Barriers
 --------
 
-'``llvm.nvvm.barrier0``'
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
+'``llvm.nvvm.barrier.cta.*``'
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 Syntax:
 """""""
 
 .. code-block:: llvm
 
-  declare void @llvm.nvvm.barrier0()
+  declare void @llvm.nvvm.barrier.cta.sync.count(i32 %id, i32 %n)
+  declare void @llvm.nvvm.barrier.cta.sync.all(i32 %id)
+  declare void @llvm.nvvm.barrier.cta.arrive.count(i32 %id, i32 %n)
+
+  declare void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 %id, i32 %n)
+  declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %id)
+  declare void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32 %id, i32 %n)
 
 Overview:
 """""""""
 
-The '``@llvm.nvvm.barrier0()``' intrinsic emits a PTX ``bar.sync 0``
-instruction, equivalent to the ``__syncthreads()`` call in CUDA.
+The '``@llvm.nvvm.barrier.cta.*``' family of intrinsics perform barrier
+synchronization and communication within a CTA. They can be used by the threads
+within the CTA for synchronization and communication.
+
+Semantics:
+""""""""""
+
+Operand %id specifies a logical barrier resource and must fall within the range
+0 through 15. When present, operand %n specifies the number of threads
+participating in the barrier. When specifying a thread count, the value must be
+a multiple of the warp size. With the '``@llvm.nvvm.barrier.cta.sync.*``'
+variants, the '``.all``' suffix indicates that all threads in the CTA should
+participate in the barrier while the '``.count``' suffix indicates that only
+the threads specified by the %n operand should participate in the barrier.
+
+All forms of the '``@llvm.nvvm.barrier.cta.*``' intrinsic cause the executing
+thread to wait for all non-exited threads from its warp and then marks the
+warp's arrival at the barrier. In addition to signaling its arrival at the 
+barrier, the '``@llvm.nvvm.barrier.cta.sync.*``' intrinsics cause the executing
+thread to wait for non-exited threads of all other warps participating in the
+barrier to arrive. On the other hand, the '``@llvm.nvvm.barrier.cta.arrive.*``'
+intrinsic does not cause the executing thread to wait for threads of other
+participating warps.
+
+When a barrier completes, the waiting threads are restarted without delay,
+and the barrier is reinitialized so that it can be immediately reused.
+
+The '``@llvm.nvvm.barrier.cta.*``' intrinsic has an optional '``.aligned``'
+modifier to indicate textual alignment of the barrier. When specified, it
+indicates that all threads in the CTA will execute the same
+'``@llvm.nvvm.barrier.cta.*``' instruction. In conditionally executed code, an
+aligned '``@llvm.nvvm.barrier.cta.*``' instruction should only be used if it is
+known that all threads in the CTA evaluate the condition identically, otherwise
+behavior is undefined.
 
 Electing a thread
 -----------------
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index 50dc1fd0f8ab0..91e7d188c8533 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -128,6 +128,12 @@
 //   * llvm.nvvm.swap.lo.hi.b64      --> llvm.fshl(x, x, 32)
 //   * llvm.nvvm.atomic.load.inc.32  --> atomicrmw uinc_wrap
 //   * llvm.nvvm.atomic.load.dec.32  --> atomicrmw udec_wrap
+// * llvm.nvvm.barrier0              --> llvm.nvvm.barrier.cta.sync.aligned.all(0)
+// * llvm.nvvm.barrier.n             --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
+// * llvm.nvvm.bar.sync              --> llvm.nvvm.barrier.cta.sync.aligned.all(x)
+// * llvm.nvvm.barrier               --> llvm.nvvm.barrier.cta.sync.aligned(x, y)
+// * llvm.nvvm.barrier.sync          --> llvm.nvvm.barrier.cta.sync.all(x)
+// * llvm.nvvm.barrier.sync.cnt      --> llvm.nvvm.barrier.cta.sync(x, y)
 
 def llvm_global_ptr_ty  : LLVMQualPointerType<1>;         // (global)ptr
 def llvm_shared_ptr_ty  : LLVMQualPointerType<3>;         // (shared)ptr
@@ -1278,18 +1284,6 @@ let TargetPrefix = "nvvm" in {
   defm int_nvvm_atomic_cas_gen_i  : PTXAtomicWithScope3<llvm_anyint_ty>;
 
 // Bar.Sync
-
-  // The builtin for "bar.sync 0" is called __syncthreads.  Unlike most of the
-  // intrinsics in this file, this one is a user-facing API.
-  def int_nvvm_barrier0 : ClangBuiltin<"__syncthreads">,
-      Intrinsic<[], [], [IntrConvergent, IntrNoCallback]>;
-  // Synchronize all threads in the CTA at barrier 'n'.
-  def int_nvvm_barrier_n : ClangBuiltin<"__nvvm_bar_n">,
-      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
-  // Synchronize 'm', a multiple of warp size, (arg 2) threads in
-  // the CTA at barrier 'n' (arg 1).
-  def int_nvvm_barrier : ClangBuiltin<"__nvvm_bar">,
-      Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_barrier0_popc : ClangBuiltin<"__nvvm_bar0_popc">,
       Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_barrier0_and : ClangBuiltin<"__nvvm_bar0_and">,
@@ -1297,16 +1291,21 @@ let TargetPrefix = "nvvm" in {
   def int_nvvm_barrier0_or : ClangBuiltin<"__nvvm_bar0_or">,
       Intrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
 
-  def int_nvvm_bar_sync : NVVMBuiltin,
-      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
   def int_nvvm_bar_warp_sync : NVVMBuiltin,
       Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
 
-  // barrier.sync id[, cnt]
-  def int_nvvm_barrier_sync : NVVMBuiltin,
-      Intrinsic<[], [llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
-  def int_nvvm_barrier_sync_cnt : NVVMBuiltin,
-      Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], [IntrConvergent, IntrNoCallback]>;
+  // barrier{.cta}.sync{.aligned}      a{, b};
+  // barrier{.cta}.arrive{.aligned}    a, b;
+  let IntrProperties = [IntrConvergent, IntrNoCallback] in {
+    foreach align = ["", "_aligned"] in {
+      def int_nvvm_barrier_cta_sync # align # _all :
+          Intrinsic<[], [llvm_i32_ty]>;
+      def int_nvvm_barrier_cta_sync # align # _count :
+          Intrinsic<[], [llvm_i32_ty, llvm_i32_ty]>;
+      def int_nvvm_barrier_cta_arrive # align # _count :
+          Intrinsic<[], [llvm_i32_ty, llvm_i32_ty]>;
+    }
+  }
 
   // barrier.cluster.[wait, arrive, arrive.relaxed]
   def int_nvvm_barrier_cluster_arrive :
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 7157baf394e3f..7ba6d411bc7b5 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1343,12 +1343,9 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
         // nvvm.abs.{i,ii}
         Expand =
             Name == "i" || Name == "ll" || Name == "bf16" || Name == "bf16x2";
-      else if (Name == "fabs.f" || Name == "fabs.ftz.f" || Name == "fabs.d")
+      else if (Name.consume_front("fabs."))
         // nvvm.fabs.{f,ftz.f,d}
-        Expand = true;
-      else if (Name == "clz.ll" || Name == "popc.ll" || Name == "h2f" ||
-               Name == "swap.lo.hi.b64")
-        Expand = true;
+        Expand = Name == "f" || Name == "ftz.f" || Name == "d";
       else if (Name.consume_front("max.") || Name.consume_front("min."))
         // nvvm.{min,max}.{i,ii,ui,ull}
         Expand = Name == "s" || Name == "i" || Name == "ll" || Name == "us" ||
@@ -1380,7 +1377,18 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
         Expand = (Name.starts_with("i.") || Name.starts_with("f.") ||
                   Name.starts_with("p."));
       else
-        Expand = false;
+        Expand = StringSwitch<bool>(Name)
+                     .Case("barrier0", true)
+                     .Case("barrier.n", true)
+                     .Case("barrier.sync.cnt", true)
+                     .Case("barrier.sync", true)
+                     .Case("barrier", true)
+                     .Case("bar.sync", true)
+                     .Case("clz.ll", true)
+                     .Case("popc.ll", true)
+                     .Case("h2f", true)
+                     .Case("swap.lo.hi.b64", true)
+                     .Default(false);
 
       if (Expand) {
         NewFn = nullptr;
@@ -2478,6 +2486,21 @@ static Value *upgradeNVVMIntrinsicCall(StringRef Name, CallBase *CI,
     MDNode *MD = MDNode::get(Builder.getContext(), {});
     LD->setMetadata(LLVMContext::MD_invariant_load, MD);
     return LD;
+  } else if (Name == "barrier0" || Name == "barrier.n" || Name == "bar.sync") {
+    Value *Arg =
+        Name.ends_with('0') ? Builder.getInt32(0) : CI->getArgOperand(0);
+    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_aligned_all,
+                                  {}, {Arg});
+  } else if (Name == "barrier") {
+    Rep = Builder.CreateIntrinsic(
+        Intrinsic::nvvm_barrier_cta_sync_aligned_count, {},
+        {CI->getArgOperand(0), CI->getArgOperand(1)});
+  } else if (Name == "barrier.sync") {
+    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_all, {},
+                                  {CI->getArgOperand(0)});
+  } else if (Name == "barrier.sync.cnt") {
+    Rep = Builder.CreateIntrinsic(Intrinsic::nvvm_barrier_cta_sync_count, {},
+                                  {CI->getArgOperand(0), CI->getArgOperand(1)});
   } else {
     Intrinsic::ID IID = shouldUpgradeNVPTXBF16Intrinsic(Name);
     if (IID != Intrinsic::not_intrinsic &&
diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index 56b5fde652e2c..8fb5884fa2a20 100644
--- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -67,15 +67,6 @@ class THREADMASK_INFO<bit sync> {
 // Synchronization and shuffle functions
 //-----------------------------------
 let isConvergent = true in {
-def INT_BARRIER0 : NVPTXInst<(outs), (ins),
-                  "bar.sync \t0;",
-      [(int_nvvm_barrier0)]>;
-def INT_BARRIERN : NVPTXInst<(outs), (ins Int32Regs:$src1),
-                  "bar.sync \t$src1;",
-      [(int_nvvm_barrier_n i32:$src1)]>;
-def INT_BARRIER : NVPTXInst<(outs), (ins Int32Regs:$src1, Int32Regs:$src2),
-                  "bar.sync \t$src1, $src2;",
-      [(int_nvvm_barrier i32:$src1, i32:$src2)]>;
 def INT_BARRIER0_POPC : NVPTXInst<(outs Int32Regs:$dst), (ins Int32Regs:$pred),
   !strconcat("{{ \n\t",
              ".reg .pred \t%p1; \n\t",
@@ -102,9 +93,6 @@ def INT_BARRIER0_OR : NVPTXInst<(outs Int32Regs:$dst), (ins Int32Regs:$pred),
              "}}"),
       [(set i32:$dst, (int_nvvm_barrier0_or i32:$pred))]>;
 
-def INT_BAR_SYNC : NVPTXInst<(outs), (ins i32imm:$i), "bar.sync \t$i;",
-                             [(int_nvvm_bar_sync imm:$i)]>;
-
 def INT_BAR_WARP_SYNC_I : NVPTXInst<(outs), (ins i32imm:$i), "bar.warp.sync \t$i;",
                              [(int_nvvm_bar_warp_sync imm:$i)]>,
         Requires<[hasPTX<60>, hasSM<30>]>;
@@ -112,29 +100,44 @@ def INT_BAR_WARP_SYNC_R : NVPTXInst<(outs), (ins Int32Regs:$i), "bar.warp.sync \
                              [(int_nvvm_bar_warp_sync i32:$i)]>,
         Requires<[hasPTX<60>, hasSM<30>]>;
 
-def INT_BARRIER_SYNC_I : NVPTXInst<(outs), (ins i32imm:$i), "barrier.sync \t$i;",
-                                   [(int_nvvm_barrier_sync imm:$i)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
-def INT_BARRIER_SYNC_R : NVPTXInst<(outs), (ins Int32Regs:$i), "barrier.sync \t$i;",
-                                   [(int_nvvm_barrier_sync i32:$i)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
+multiclass BARRIER1<string asmstr, Intrinsic intrinsic, list<Predicate> requires = []> {
+  def _i : BasicNVPTXInst<(outs), (ins i32imm:$i), asmstr,
+                          [(intrinsic imm:$i)]>,
+           Requires<requires>;
 
-def INT_BARRIER_SYNC_CNT_RR : NVPTXInst<(outs), (ins Int32Regs:$id, Int32Regs:$cnt),
-                 "barrier.sync \t$id, $cnt;",
-                 [(int_nvvm_barrier_sync_cnt i32:$id, i32:$cnt)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
-def INT_BARRIER_SYNC_CNT_RI : NVPTXInst<(outs), (ins Int32Regs:$id, i32imm:$cnt),
-                 "barrier.sync \t$id, $cnt;",
-                 [(int_nvvm_barrier_sync_cnt i32:$id, imm:$cnt)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
-def INT_BARRIER_SYNC_CNT_IR : NVPTXInst<(outs), (ins i32imm:$id, Int32Regs:$cnt),
-                 "barrier.sync \t$id, $cnt;",
-                 [(int_nvvm_barrier_sync_cnt imm:$id, i32:$cnt)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
-def INT_BARRIER_SYNC_CNT_II : NVPTXInst<(outs), (ins i32imm:$id, i32imm:$cnt),
-                 "barrier.sync \t$id, $cnt;",
-                 [(int_nvvm_barrier_sync_cnt imm:$id, imm:$cnt)]>,
-        Requires<[hasPTX<60>, hasSM<30>]>;
+  def _r : BasicNVPTXInst<(outs), (ins Int32Regs:$i), asmstr,
+                          [(intrinsic i32:$i)]>,
+           Requires<requires>;
+}
+
+multiclass BARRIER2<string asmstr, Intrinsic intrinsic, list<Predicate> requires = []> {
+  def _rr : BasicNVPTXInst<(outs), (ins Int32Regs:$i, Int32Regs:$j), asmstr,
+                          [(intrinsic i32:$i, i32:$j)]>,
+            Requires<requires>;
+
+  def _ri : BasicNVPTXInst<(outs), (ins Int32Regs:$i, i32imm:$j), asmstr,
+                          [(intrinsic i32:$i, imm:$j)]>,
+            Requires<requires>;
+
+  def _ir : BasicNVPTXInst<(outs), (ins i32imm:$i, Int32Regs:$j), asmstr,
+                          [(intrinsic imm:$i, i32:$j)]>,
+            Requires<requires>;
+
+  def _ii : BasicNVPTXInst<(outs), (ins i32imm:$i, i32imm:$j), asmstr,
+                          [(intrinsic imm:$i, imm:$j)]>,
+            Requires<requires>;
+}
+
+// Note the "bar.sync" variants could be renamed to the equivalent corresponding
+// "barrier.*.aligned" variants. We use the older syntax for compatibility with
+// older versions of the PTX ISA.
+defm BARRIER_CTA_SYNC_ALIGNED_ALL : BARRIER1<"bar.sync", int_nvvm_barrier_cta_sync_aligned_all>;
+defm BARRIER_CTA_SYNC_ALIGNED : BARRIER2<"bar.sync", int_nvvm_barrier_cta_sync_aligned_count>;
+defm BARRIER_CTA_ARRIVE_ALIGNED : BARRIER2<"bar.arrive", int_nvvm_barrier_cta_arrive_aligned_count>;
+
+defm BARRIER_CTA_SYNC_ALL : BARRIER1<"barrier.sync", int_nvvm_barrier_cta_sync_all, [hasPTX<60>]>;
+defm BARRIER_CTA_SYNC : BARRIER2<"barrier.sync", int_nvvm_barrier_cta_sync_count, [hasPTX<60>]>;
+defm BARRIER_CTA_ARRIVE : BARRIER2<"barrier.arrive", int_nvvm_barrier_cta_arrive_count, [hasPTX<60>]>;
 
 class INT_BARRIER_CLUSTER<string variant, Intrinsic Intr,
                           list<Predicate> Preds = [hasPTX<78>, hasSM<90>]>:
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 8b843634600be..470c5308edca4 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -2150,7 +2150,8 @@ struct AANoUnwindCallSite final
 
 bool AANoSync::isAlignedBarrier(const CallBase &CB, bool ExecutedAligned) {
   switch (CB.getIntrinsicID()) {
-  case Intrinsic::nvvm_barrier0:
+  case Intrinsic::nvvm_barrier_cta_sync_aligned_all:
+  case Intrinsic::nvvm_barrier_cta_sync_aligned_count:
   case Intrinsic::nvvm_barrier0_and:
   case Intrinsic::nvvm_barrier0_or:
   case Intrinsic::nvvm_barrier0_popc:
diff --git a/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll b/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
index e92a45807ed9c..7019694439bb8 100644
--- a/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
+++ b/llvm/test/Analysis/GlobalsModRef/functions_without_nosync.ll
@@ -11,28 +11,15 @@ target triple = "nvptx64-nvidia-cuda"
 
 ; CHECK-LABEL: @bar_sync
 ; CHECK: store
-; CHECK: tail call void @llvm.nvvm.bar.sync(i32 0)
+; CHECK: tail call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
 ; CHECK: load
 define dso_local i32 @bar_sync(i32 %0) local_unnamed_addr {
   store i32 %0, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
-  tail call void @llvm.nvvm.bar.sync(i32 0)
+  tail call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   %2 = load i32, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
   ret i32 %2
 }
 
-declare void @llvm.nvvm.bar.sync(i32) #0
-
-; CHECK-LABEL: @barrier0
-; CHECK: store
-; CHECK: tail call void @llvm.nvvm.barrier0()
-; CHECK: load
-define dso_local i32 @barrier0(i32 %0) local_unnamed_addr  {
-  store i32 %0, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
-  tail call void @llvm.nvvm.barrier0()
-  %2 = load i32, ptr addrspacecast (ptr addrspace(3) @s to ptr), align 4
-  ret i32 %2
-}
-
-declare void @llvm.nvvm.barrier0() #0
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #0
 
 attributes #0 = { convergent nounwind }
diff --git a/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll b/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
index 2bfa1c2dfba7a..b7bdca42d5596 100644
--- a/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
+++ b/llvm/test/Assembler/auto_upgrade_nvvm_intrinsics.ll
@@ -78,6 +78,13 @@ declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.3d(ptr addrspace(3) %d,
 declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.4d(ptr addrspace(3) %d, ptr addrspace(3) %bar, ptr %tm, i32 %d0, i32 %d1, i32 %d2, i32 %d3, i16 %im2col0, i16 %im2col1, i16 %mc, i64 %ch, i1 %f1, i1 %f2);
 declare void @llvm.nvvm.cp.async.bulk.tensor.g2s.im2col.5d(ptr addrspace(3) %d, ptr addrspace(3) %bar, ptr %tm, i32 %d0, i32 %d1, i32 %d2, i32 %d3, i32 %d4, i16 %im2col0, i16 %im2col1, i16 %im2col2, i16 %mc, i64 %ch, i1 %f1, i1 %f2);
 
+declare void @llvm.nvvm.barrier0()
+declare void @llvm.nvvm.barrier.n(i32)
+declare void @llvm.nvvm.bar.sync(i32)
+declare void @llvm.nvvm.barrier(i32, i32)
+declare void @llvm.nvvm.barrier.sync(i32)
+declare void @llvm.nvvm.barrier.sync.cnt(i32, i32)
+
 ; CHECK-LABEL: @simple_upgrade
 define void @simple_upgrade(i32 %a, i64 %b, i16 %c) {
 ; CHECK: call i32 @llvm.bitreverse.i32(i32 %a)
@@ -324,3 +331,18 @@ define void @nvvm_cp_async_bulk_tensor_g2s_tile(ptr addrspace(3) %d, ptr addrspa
   ret void
 }
 
+define void @cta_barriers(i32 %x, i32 %y) {
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %x)
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %x)
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 %x, i32 %y)
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.all(i32 %x)
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.count(i32 %x, i32 %y)
+  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.n(i32 %x)
+  call void @llvm.nvvm.bar.sync(i32 %x)
+  call void @llvm.nvvm.barrier(i32 %x, i32 %y)
+  call void @llvm.nvvm.barrier.sync(i32 %x)
+  call void @llvm.nvvm.barrier.sync.cnt(i32 %x, i32 %y)
+  ret void
+}
diff --git a/llvm/test/CodeGen/NVPTX/barrier.ll b/llvm/test/CodeGen/NVPTX/barrier.ll
index 05bdc9087f572..a3b0d21f098f2 100644
--- a/llvm/test/CodeGen/NVPTX/barrier.ll
+++ b/llvm/test/CodeGen/NVPTX/barrier.ll
@@ -1,33 +1,136 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_30 -mattr=+ptx60 | FileCheck %s
 ; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_30 -mattr=+ptx60 | %ptxas-verify %}
 
 declare void @llvm.nvvm.bar.warp.sync(i32)
-declare void @llvm.nvvm.barrier.sync(i32)
-declare void @llvm.nvvm.barrier.sync.cnt(i32, i32)
-
-; CHECK-LABEL: .func{{.*}}barrier_sync
-define void @barrier_sync(i32 %id, i32 %cnt) {
-  ; CHECK: ld.param.b32 	[[ID:%r[0-9]+]], [barrier_sync_param_0];
-  ; CHECK: ld.param.b32 	[[CNT:%r[0-9]+]], [barrier_sync_param_1];
-
-  ; CHECK:  barrier.sync [[ID]], [[CNT]];
-  call void @llvm.nvvm.barrier.sync.cnt(i32 %id, i32 %cnt)
-  ; CHECK:  barrier.sync [[ID]], 32;
-  call void @llvm.nvvm.barrier.sync.cnt(i32 %id, i32 32)
-  ; CHECK:  barrier.sync 3, [[CNT]];
-  call void @llvm.nvvm.barrier.sync.cnt(i32 3, i32 %cnt)
-  ; CHECK:  barrier.sync 4, 64;
-  call void @llvm.nvvm.barrier.sync.cnt(i32 4, i32 64)
-
-  ; CHECK: barrier.sync [[ID]];
-  call void @llvm.nvvm.barrier.sync(i32 %id)
-  ; CHECK: barrier.sync 1;
-  call void @llvm.nvvm.barrier.sync(i32 1)
-
-  ; CHECK: bar.warp.sync [[ID]];
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
+declare void @llvm.nvvm.barrier.cta.sync.aligned.count(i32, i32)
+declare void @llvm.nvvm.barrier.cta.sync.all(i32)
+declare void @llvm.nvvm.barrier.cta.sync.count(i32, i32)
+declare void @llvm.nvvm.barrier.cta.arrive.count(i32, i32)
+declare void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32, i32)
+
+define void @barrier_warp_sync(i32 %id) {
+; CHECK-LABEL: barrier_warp_sync(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<2>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_warp_sync_param_0];
+; CHECK-NEXT:    bar.warp.sync %r1;
+; CHECK-NEXT:    bar.warp.sync 6;
+; CHECK-NEXT:    ret;
   call void @llvm.nvvm.bar.warp.sync(i32 %id)
-  ; CHECK: bar.warp.sync 6;
   call void @llvm.nvvm.bar.warp.sync(i32 6)
-  ret void;
+  ret void
+}
+
+define void @barrier_cta_sync_aligned_all(i32 %id) {
+; CHECK-LABEL: barrier_cta_sync_aligned_all(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<2>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_aligned_all_param_0];
+; CHECK-NEXT:    bar.sync %r1;
+; CHECK-NEXT:    bar.sync 3;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %id)
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 3)
+  ret void
+}
+
+define void @barrier_cta_sync_aligned(i32 %id, i32 %cnt) {
+; CHECK-LABEL: barrier_cta_sync_aligned(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_aligned_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_sync_aligned_param_1];
+; CHECK-NEXT:    bar.sync %r1, %r2;
+; CHECK-NEXT:    bar.sync 3, %r2;
+; CHECK-NEXT:    bar.sync %r1, 64;
+; CHECK-NEXT:    bar.sync 4, 64;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 %id, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 3, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 %id, i32 64)
+  call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 4, i32 64)
+  ret void
+}
+
+define void @barrier_cta_arrive_aligned(i32 %id, i32 %cnt) {
+; CHECK-LABEL: barrier_cta_arrive_aligned(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_arrive_aligned_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_arrive_aligned_param_1];
+; CHECK-NEXT:    bar.arrive %r1, %r2;
+; CHECK-NEXT:    bar.arrive 3, %r2;
+; CHECK-NEXT:    bar.arrive %r1, 64;
+; CHECK-NEXT:    bar.arrive 4, 64;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32 %id, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32 3, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32 %id, i32 64)
+  call void @llvm.nvvm.barrier.cta.arrive.aligned.count(i32 4, i32 64)
+  ret void
+}
+
+define void @barrier_cta_sync_all(i32 %id) {
+; CHECK-LABEL: barrier_cta_sync_all(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<2>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_all_param_0];
+; CHECK-NEXT:    barrier.sync %r1;
+; CHECK-NEXT:    barrier.sync 3;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.sync.all(i32 %id)
+  call void @llvm.nvvm.barrier.cta.sync.all(i32 3)
+  ret void
 }
 
+define void @barrier_cta_sync(i32 %id, i32 %cnt) {
+; CHECK-LABEL: barrier_cta_sync(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_sync_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_sync_param_1];
+; CHECK-NEXT:    barrier.sync %r1, %r2;
+; CHECK-NEXT:    barrier.sync 3, %r2;
+; CHECK-NEXT:    barrier.sync %r1, 64;
+; CHECK-NEXT:    barrier.sync 4, 64;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.sync.count(i32 %id, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.sync.count(i32 3, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.sync.count(i32 %id, i32 64)
+  call void @llvm.nvvm.barrier.cta.sync.count(i32 4, i32 64)
+  ret void
+}
+
+define void @barrier_cta_arrive(i32 %id, i32 %cnt) {
+; CHECK-LABEL: barrier_cta_arrive(
+; CHECK:       {
+; CHECK-NEXT:    .reg .b32 %r<3>;
+; CHECK-EMPTY:
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    ld.param.b32 %r1, [barrier_cta_arrive_param_0];
+; CHECK-NEXT:    ld.param.b32 %r2, [barrier_cta_arrive_param_1];
+; CHECK-NEXT:    barrier.arrive %r1, %r2;
+; CHECK-NEXT:    barrier.arrive 3, %r2;
+; CHECK-NEXT:    barrier.arrive %r1, 64;
+; CHECK-NEXT:    barrier.arrive 4, 64;
+; CHECK-NEXT:    ret;
+  call void @llvm.nvvm.barrier.cta.arrive.count(i32 %id, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.arrive.count(i32 3, i32 %cnt)
+  call void @llvm.nvvm.barrier.cta.arrive.count(i32 %id, i32 64)
+  call void @llvm.nvvm.barrier.cta.arrive.count(i32 4, i32 64)
+  ret void
+}
diff --git a/llvm/test/CodeGen/NVPTX/named-barriers.ll b/llvm/test/CodeGen/NVPTX/named-barriers.ll
deleted file mode 100644
index 34e93cef6aaa4..0000000000000
--- a/llvm/test/CodeGen/NVPTX/named-barriers.ll
+++ /dev/null
@@ -1,42 +0,0 @@
-; RUN: llc < %s -mtriple=nvptx -mcpu=sm_20 | FileCheck %s
-; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 | FileCheck %s
-; RUN: %if ptxas && !ptxas-12.0 %{ llc < %s -mtriple=nvptx -mcpu=sm_20 | %ptxas-verify %}
-; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 | %ptxas-verify %}
-
-; Use bar.sync to arrive at a pre-computed barrier number and
-; wait for all threads in CTA to also arrive:
-define ptx_device void @test_barrier_named_cta() {
-; CHECK: mov.b32  %r[[REG0:[0-9]+]], 0;
-; CHECK: bar.sync %r[[REG0]];
-; CHECK: mov.b32  %r[[REG1:[0-9]+]], 10;
-; CHECK: bar.sync %r[[REG1]];
-; CHECK: mov.b32  %r[[REG2:[0-9]+]], 15;
-; CHECK: bar.sync %r[[REG2]];
-; CHECK: ret;
-  call void @llvm.nvvm.barrier.n(i32 0)
-  call void @llvm.nvvm.barrier.n(i32 10)
-  call void @llvm.nvvm.barrier.n(i32 15)
-  ret void
-}
-
-; Use bar.sync to arrive at a pre-computed barrier number and
-; wait for fixed number of cooperating threads to arrive:
-define ptx_device void @test_barrier_named() {
-; CHECK: mov.b32  %r[[REG0A:[0-9]+]], 32;
-; CHECK: mov.b32  %r[[REG0B:[0-9]+]], 0;
-; CHECK: bar.sync %r[[REG0B]], %r[[REG0A]];
-; CHECK: mov.b32  %r[[REG1A:[0-9]+]], 352;
-; CHECK: mov.b32  %r[[REG1B:[0-9]+]], 10;
-; CHECK: bar.sync %r[[REG1B]], %r[[REG1A]];
-; CHECK: mov.b32  %r[[REG2A:[0-9]+]], 992;
-; CHECK: mov.b32  %r[[REG2B:[0-9]+]], 15;
-; CHECK: bar.sync %r[[REG2B]], %r[[REG2A]];
-; CHECK: ret;
-  call void @llvm.nvvm.barrier(i32 0, i32 32)
-  call void @llvm.nvvm.barrier(i32 10, i32 352)
-  call void @llvm.nvvm.barrier(i32 15, i32 992)
-  ret void
-}
-
-declare void @llvm.nvvm.barrier(i32, i32)
-declare void @llvm.nvvm.barrier.n(i32)
diff --git a/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll b/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
index 2a0c5ab7299ba..02abae0c8f9c5 100644
--- a/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
+++ b/llvm/test/CodeGen/NVPTX/noduplicate-syncthreads.ll
@@ -3,8 +3,8 @@
 ; Make sure the call to syncthreads is not duplicate here by the LLVM
 ; optimizations, because it has the noduplicate attribute set.
 
-; CHECK: call void @llvm.nvvm.barrier0
-; CHECK-NOT: call void @llvm.nvvm.barrier0
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all
+; CHECK-NOT: call void @llvm.nvvm.barrier.cta.sync.aligned.all
 
 ; Function Attrs: nounwind
 define void @foo(ptr %output) #1 {
@@ -36,7 +36,7 @@ if.else:                                          ; preds = %entry
   br label %if.end
 
 if.end:                                           ; preds = %if.else, %if.then
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   %6 = load ptr, ptr %output.addr, align 8
   %7 = load float, ptr %6, align 4
   %conv7 = fpext float %7 to double
diff --git a/llvm/test/Feature/intrinsic-noduplicate.ll b/llvm/test/Feature/intrinsic-noduplicate.ll
index ecdb381b7920b..42264ef909e8a 100644
--- a/llvm/test/Feature/intrinsic-noduplicate.ll
+++ b/llvm/test/Feature/intrinsic-noduplicate.ll
@@ -2,9 +2,9 @@
 ; REQUIRES: nvptx-registered-target
 
 ; Make sure LLVM knows about the convergent attribute on the
-; llvm.nvvm.barrier0 intrinsic.
+; llvm.nvvm.barrier.cta.sync.aligned.all intrinsic.
 
-declare void @llvm.nvvm.barrier0()
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
 
-; CHECK: declare void @llvm.nvvm.barrier0() #[[ATTRNUM:[0-9]+]]
+; CHECK: declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #[[ATTRNUM:[0-9]+]]
 ; CHECK: attributes #[[ATTRNUM]] = { convergent nocallback nounwind }
diff --git a/llvm/test/Transforms/FunctionAttrs/convergent.ll b/llvm/test/Transforms/FunctionAttrs/convergent.ll
index 49c357bd6bc86..e2581b2b418fe 100644
--- a/llvm/test/Transforms/FunctionAttrs/convergent.ll
+++ b/llvm/test/Transforms/FunctionAttrs/convergent.ll
@@ -70,17 +70,17 @@ define i32 @indirect_non_convergent_call(ptr %f) convergent norecurse {
   ret i32 %a
 }
 
-declare void @llvm.nvvm.barrier0() convergent
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) convergent
 
 define i32 @intrinsic() convergent {
   ; Implicitly convergent, because the intrinsic is convergent.
 ; CHECK: Function Attrs: convergent norecurse nounwind
 ; CHECK-LABEL: define {{[^@]+}}@intrinsic
 ; CHECK-SAME: () #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT:    call void @llvm.nvvm.barrier0()
+; CHECK-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
 ; CHECK-NEXT:    ret i32 0
 ;
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   ret i32 0
 }
 
diff --git a/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll b/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
index 8a9e6f728936f..1671baaaa0876 100644
--- a/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
+++ b/llvm/test/Transforms/JumpThreading/thread-two-bbs-cuda.ll
@@ -12,7 +12,7 @@ define i32 @wrapped_tid() #0 comdat align 32 {
   ret i32 %1
 }
 
-declare void @llvm.nvvm.barrier0() #1
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32) #1
 
 ; We had a bug where we duplicated basic blocks containing convergent
 ; functions like @llvm.nvvm.barrier0 below.  Verify that we don't do
@@ -32,9 +32,9 @@ define void @foo() local_unnamed_addr #2 comdat align 32 {
   br label %6
 
 6:
-; CHECK: call void @llvm.nvvm.barrier0()
-; CHECK-NOT: call void @llvm.nvvm.barrier0()
-  call void @llvm.nvvm.barrier0()
+; CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+; CHECK-NOT: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   %7 = icmp eq i32 %2, 0
   br i1 %7, label %11, label %8
 
diff --git a/llvm/test/Transforms/OpenMP/barrier_removal.ll b/llvm/test/Transforms/OpenMP/barrier_removal.ll
index 5b7544b1a7961..f662d5dd85b2b 100644
--- a/llvm/test/Transforms/OpenMP/barrier_removal.ll
+++ b/llvm/test/Transforms/OpenMP/barrier_removal.ll
@@ -8,7 +8,7 @@ target triple = "amdgcn-amd-amdhsa"
 declare void @useI32(i32)
 declare void @unknown()
 declare void @aligned_barrier() "llvm.assume"="ompx_aligned_barrier"
-declare void @llvm.nvvm.barrier0()
+declare void @llvm.nvvm.barrier.cta.sync.aligned.all(i32)
 declare i32 @llvm.nvvm.barrier0.and(i32)
 declare i32 @llvm.nvvm.barrier0.or(i32)
 declare i32 @llvm.nvvm.barrier0.popc(i32)
@@ -58,7 +58,7 @@ define amdgpu_kernel void @pos_empty_3() "kernel" {
 ; CHECK-SAME: () #[[ATTR4]] {
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   ret void
 }
 define amdgpu_kernel void @pos_empty_4() "kernel" {
@@ -393,12 +393,12 @@ define amdgpu_kernel void @pos_multiple() "kernel" {
 ; CHECK-SAME: () #[[ATTR4]] {
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   call void @aligned_barrier()
   call void @aligned_barrier()
   call void @llvm.amdgcn.s.barrier()
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   call void @aligned_barrier()
   call void @aligned_barrier()
   ret void
@@ -422,7 +422,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_1(i1 %c0, i1 %c1) "kernel" {
 ; CHECK-NEXT:    ret void
 ;
   fence acquire
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   fence release
   call void @aligned_barrier()
   fence seq_cst
@@ -441,7 +441,7 @@ f0:
   fence release
   call void @aligned_barrier()
   fence acquire
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   fence acquire
   br i1 %c1, label %t1, label %f1
 t1:
@@ -473,7 +473,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_2(i1 %c0, i1 %c1, ptr %p) "ker
 ; CHECK-NEXT:    br label [[M:%.*]]
 ; CHECK:       f0:
 ; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
-; CHECK-NEXT:    call void @llvm.nvvm.barrier0()
+; CHECK-NEXT:    call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
 ; CHECK-NEXT:    br i1 [[C1]], label [[T1:%.*]], label [[F1:%.*]]
 ; CHECK:       t1:
 ; CHECK-NEXT:    br label [[M]]
@@ -483,7 +483,7 @@ define amdgpu_kernel void @multiple_blocks_kernel_2(i1 %c0, i1 %c1, ptr %p) "ker
 ; CHECK-NEXT:    store i32 4, ptr [[P]], align 4
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   store i32 4, ptr %p
   call void @aligned_barrier()
   br i1 %c0, label %t0, label %f0
@@ -496,7 +496,7 @@ t0b:
 f0:
   call void @aligned_barrier()
   store i32 4, ptr %p
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -527,7 +527,7 @@ define void @multiple_blocks_non_kernel_1(i1 %c0, i1 %c1) "kernel" {
 ; CHECK:       m:
 ; CHECK-NEXT:    ret void
 ;
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   call void @aligned_barrier()
   br i1 %c0, label %t0, label %f0
 t0:
@@ -538,7 +538,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -577,7 +577,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -614,7 +614,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   br i1 %c1, label %t1, label %f1
 t1:
   call void @aligned_barrier()
@@ -665,7 +665,7 @@ t0b:
   br label %m
 f0:
   call void @aligned_barrier()
-  call void @llvm.nvvm.barrier0()
+  call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   store i32 2, ptr %p
   br i1 %c1, label %t1, label %f1
 t1:
diff --git a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
index e4a44f698b622..96a344b689488 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
@@ -535,8 +535,13 @@ def NVVM_MBarrierTestWaitSharedOp : NVVM_Op<"mbarrier.test.wait.shared">,
 // NVVM synchronization op definitions
 //===----------------------------------------------------------------------===//
 
-def NVVM_Barrier0Op : NVVM_IntrOp<"barrier0"> {
+def NVVM_Barrier0Op : NVVM_Op<"barrier0"> {
   let assemblyFormat = "attr-dict";
+  string llvmBuilder = [{
+      createIntrinsicCall(
+          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_all,
+          {builder.getInt32(0)});
+  }];
 }
 
 def NVVM_BarrierOp : NVVM_Op<"barrier", [AttrSizedOperandSegments]> {
@@ -544,15 +549,14 @@ def NVVM_BarrierOp : NVVM_Op<"barrier", [AttrSizedOperandSegments]> {
     Optional<I32>:$barrierId,
     Optional<I32>:$numberOfThreads);
   string llvmBuilder = [{
-    if ($numberOfThreads && $barrierId) {
-      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier,
-                {$barrierId, $numberOfThreads});
-    } else if($barrierId) {
-      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier_n,
-                {$barrierId});   
-    } else {
-      createIntrinsicCall(builder, llvm::Intrinsic::nvvm_barrier0);
-    }
+    llvm::Value *id = $barrierId ? $barrierId : builder.getInt32(0);
+    if ($numberOfThreads)
+      createIntrinsicCall(
+          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_count,
+          {id, $numberOfThreads});
+    else
+      createIntrinsicCall(
+          builder, llvm::Intrinsic::nvvm_barrier_cta_sync_aligned_all, {id});
   }];
   let hasVerifier = 1;
 
diff --git a/mlir/test/Target/LLVMIR/Import/nvvmir.ll b/mlir/test/Target/LLVMIR/Import/nvvmir.ll
index c8b7b82f47fd9..2da0b0ceb2cfe 100644
--- a/mlir/test/Target/LLVMIR/Import/nvvmir.ll
+++ b/mlir/test/Target/LLVMIR/Import/nvvmir.ll
@@ -73,12 +73,11 @@ define float @nvvm_rcp(float %0) {
 
 ; CHECK-LABEL: @llvm_nvvm_barrier0()
 define void @llvm_nvvm_barrier0() {
-  ; CHECK: nvvm.barrier0
+  ; CHECK: llvm.nvvm.barrier.cta.sync.aligned.all
   call void @llvm.nvvm.barrier0()
   ret void
 }
 
-
 ; TODO: Support the intrinsics below once they derive from NVVM_IntrOp rather than from NVVM_Op.
 ;
 ; define i32 @nvvm_shfl(i32 %0, i32 %1, i32 %2, i32 %3, float %4) {
diff --git a/mlir/test/Target/LLVMIR/nvvmir.mlir b/mlir/test/Target/LLVMIR/nvvmir.mlir
index 894b72733a46a..c6def56199f37 100644
--- a/mlir/test/Target/LLVMIR/nvvmir.mlir
+++ b/mlir/test/Target/LLVMIR/nvvmir.mlir
@@ -162,7 +162,7 @@ llvm.func @nvvm_rcp(%0: f32) -> f32 {
 
 // CHECK-LABEL: @llvm_nvvm_barrier0
 llvm.func @llvm_nvvm_barrier0() {
-  // CHECK: call void @llvm.nvvm.barrier0()
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
   nvvm.barrier0
   llvm.return
 }
@@ -170,11 +170,11 @@ llvm.func @llvm_nvvm_barrier0() {
 // CHECK-LABEL: @llvm_nvvm_barrier(
 // CHECK-SAME: i32 %[[barId:.*]], i32 %[[numThreads:.*]])
 llvm.func @llvm_nvvm_barrier(%barID : i32, %numberOfThreads : i32) {
-  // CHECK: call void @llvm.nvvm.barrier0()
-  nvvm.barrier 
-  // CHECK: call void @llvm.nvvm.barrier.n(i32 %[[barId]])
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 0)
+  nvvm.barrier
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.all(i32 %[[barId]])
   nvvm.barrier id = %barID
-  // CHECK: call void @llvm.nvvm.barrier(i32 %[[barId]], i32 %[[numThreads]])
+  // CHECK: call void @llvm.nvvm.barrier.cta.sync.aligned.count(i32 %[[barId]], i32 %[[numThreads]])
   nvvm.barrier id = %barID number_of_threads = %numberOfThreads
   llvm.return
 }

>From 73b833005445b21886557aac3382d7fb429f8fdb Mon Sep 17 00:00:00 2001
From: "S. VenkataKeerthy" <31350914+svkeerthy at users.noreply.github.com>
Date: Thu, 22 May 2025 20:10:30 -0700
Subject: [PATCH 080/105] [MLInlineAdvisor] Changing creation of TensorSpec in
 a type agnostic manner. (#141161)

This change would enable using `ir2vec::Embedding` which are float
vectors in ML Inliner.

Co-authored-by: svkeerthy <venkatakeerthy at google.com>
---
 llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp b/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp
index 2feedd2ff40af..e7e8f2ac1ff25 100644
--- a/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp
+++ b/llvm/lib/Analysis/DevelopmentModeInlineAdvisor.cpp
@@ -261,8 +261,8 @@ static const std::vector<TensorSpec> TrainingOnlyFeatures{
 static const std::vector<TensorSpec> getInputFeatures() {
   std::vector<TensorSpec> InputSpecs;
   for (size_t I = 0; I < NumberOfFeatures; ++I)
-    InputSpecs.push_back(TensorSpec::createSpec<int64_t>(
-        TFFeedPrefix + FeatureMap[I].name(), FeatureMap[I].shape()));
+    InputSpecs.push_back(
+        TensorSpec(TFFeedPrefix + FeatureMap[I].name(), FeatureMap[I]));
   append_range(InputSpecs, TrainingOnlyFeatures);
   return InputSpecs;
 }

>From 689342de25e65597583805eecd367c4982fd53b8 Mon Sep 17 00:00:00 2001
From: hev <wangrui at loongson.cn>
Date: Fri, 23 May 2025 11:14:41 +0800
Subject: [PATCH 081/105] [Clang][LoongArch] Add inline asm support for the `q`
 constraint (#141037)

This patch adds support for the `q` constraint:
a general-purpose register except for $r0 and $r1 (for the csrxchg
instruction)

Link: https://gcc.gnu.org/pipermail/gcc-patches/2025-May/684339.html
---
 clang/lib/Basic/Targets/LoongArch.cpp         |  5 +++++
 .../LoongArch/inline-asm-constraints.c        |  6 ++++++
 .../LoongArch/LoongArchISelLowering.cpp       |  5 +++++
 .../LoongArch/inline-asm-constraint-q.ll      | 21 +++++++++++++++++++
 4 files changed, 37 insertions(+)
 create mode 100644 llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll

diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
index ca742797d7a3b..f4bcb54bd470d 100644
--- a/clang/lib/Basic/Targets/LoongArch.cpp
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -139,6 +139,11 @@ bool LoongArchTargetInfo::validateAsmConstraint(
     // A signed 16-bit constant.
     Info.setRequiresImmediate(-32768, 32767);
     return true;
+  case 'q':
+    // A general-purpose register except for $r0 and $r1 (for the csrxchg
+    // instruction)
+    Info.setAllowsRegister();
+    return true;
   case 'I':
     // A signed 12-bit constant (for arithmetic instructions).
     Info.setRequiresImmediate(-2048, 2047);
diff --git a/clang/test/CodeGen/LoongArch/inline-asm-constraints.c b/clang/test/CodeGen/LoongArch/inline-asm-constraints.c
index b19494284bd99..ded21206d63bf 100644
--- a/clang/test/CodeGen/LoongArch/inline-asm-constraints.c
+++ b/clang/test/CodeGen/LoongArch/inline-asm-constraints.c
@@ -35,6 +35,12 @@ void test_m(int *p) {
   asm volatile("" :: "m"(*(p+4)));
 }
 
+void test_q(void) {
+// CHECK-LABEL: define{{.*}} void @test_q()
+// CHECK: call void asm sideeffect "", "q"(i32 0)
+  asm volatile ("" :: "q"(0));
+}
+
 void test_I(void) {
 // CHECK-LABEL: define{{.*}} void @test_I()
 // CHECK: call void asm sideeffect "", "I"(i32 2047)
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 9774683e16291..50ec0b2e3ca78 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -7276,6 +7276,8 @@ LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
   // 'm':  A memory operand whose address is formed by a base register and
   //       offset that is suitable for use in instructions with the same
   //       addressing mode as st.w and ld.w.
+  // 'q':  A general-purpose register except for $r0 and $r1 (for the csrxchg
+  //       instruction)
   // 'I':  A signed 12-bit constant (for arithmetic instructions).
   // 'J':  Integer zero.
   // 'K':  An unsigned 12-bit constant (for logic instructions).
@@ -7289,6 +7291,7 @@ LoongArchTargetLowering::getConstraintType(StringRef Constraint) const {
     default:
       break;
     case 'f':
+    case 'q':
       return C_RegisterClass;
     case 'l':
     case 'I':
@@ -7328,6 +7331,8 @@ LoongArchTargetLowering::getRegForInlineAsmConstraint(
       if (VT.isVector())
         break;
       return std::make_pair(0U, &LoongArch::GPRRegClass);
+    case 'q':
+      return std::make_pair(0U, &LoongArch::GPRNoR0R1RegClass);
     case 'f':
       if (Subtarget.hasBasicF() && VT == MVT::f32)
         return std::make_pair(0U, &LoongArch::FPR32RegClass);
diff --git a/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll
new file mode 100644
index 0000000000000..e16bd1d8aacf3
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-q.ll
@@ -0,0 +1,21 @@
+; RUN: llc --mtriple=loongarch32 --mattr=+f --verify-machineinstrs < %s | FileCheck %s
+; RUN: llc --mtriple=loongarch64 --mattr=+f --verify-machineinstrs < %s | FileCheck %s
+
+;; Check that the "q" operand is not R0.
+define i32 @constraint_q_not_r0() {
+; CHECK-NOT:    csrxchg ${{[a-z]*}}, $r0, 0
+; CHECK-NOT:    csrxchg ${{[a-z]*}}, $zero, 0
+entry:
+  %2 = tail call i32 asm "csrxchg $0, $1, 0", "=r,q,0"(i32 0, i32 0)
+  ret i32 %2
+}
+
+;; Check that the "q" operand is not R1.
+define i32 @constraint_q_not_r1(i32 %0) {
+; CHECK-NOT:    csrxchg ${{[a-z]*}}, $r1, 0
+; CHECK-NOT:    csrxchg ${{[a-z]*}}, $ra, 0
+entry:
+  %2 = tail call i32 asm "", "={$r1},{$r1}"(i32 0)
+  %3 = tail call i32 asm "csrxchg $0, $1, 0", "=r,q,0"(i32 %2, i32 %0)
+  ret i32 %3
+}

>From 695d725edfb71e3e048229b96a5b3e9c2adad048 Mon Sep 17 00:00:00 2001
From: Hu Jialun <hujialun at outlook.sg>
Date: Fri, 23 May 2025 11:20:35 +0800
Subject: [PATCH 082/105] [lldb-dap] Assorted small fixes for runInTerminal
 (#140908)

- `CreateRunInTerminalReverseRequest` is passed a `StringMap` by value,
whose keys are owned and deallocated after return.
- Target args are wrongly specified as reverse request (launcher) args.
- Test case error message did not catch up with a0aa5f8.

All runInTerminal tests are passing with this applied.
---
 .../API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py | 4 ++--
 lldb/tools/lldb-dap/JSONUtils.cpp                             | 4 ++--
 lldb/tools/lldb-dap/JSONUtils.h                               | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
index 9aab7ca3293db..65c931210d400 100644
--- a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
+++ b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py
@@ -128,8 +128,8 @@ def test_runInTerminalInvalidTarget(self):
         )
         self.assertFalse(response["success"])
         self.assertIn(
-            "Could not create a target for a program 'INVALIDPROGRAM': 'INVALIDPROGRAM' does not exist",
-            response["message"],
+            "'INVALIDPROGRAM' does not exist",
+            response["body"]["error"]["format"],
         )
 
     @skipIfWindows
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index dcc25c9212432..c9c6f4554c325 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -1335,7 +1335,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
 /// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
-    const llvm::StringMap<std::string> env, llvm::StringRef cwd,
+    const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
     llvm::StringRef comm_file, lldb::pid_t debugger_pid) {
   llvm::json::Object run_in_terminal_args;
   // This indicates the IDE to open an embedded terminal, instead of opening
@@ -1352,7 +1352,7 @@ llvm::json::Object CreateRunInTerminalReverseRequest(
   req_args.push_back("--launch-target");
   req_args.push_back(program.str());
   req_args.insert(req_args.end(), args.begin(), args.end());
-  run_in_terminal_args.try_emplace("args", args);
+  run_in_terminal_args.try_emplace("args", req_args);
 
   if (!cwd.empty())
     run_in_terminal_args.try_emplace("cwd", cwd);
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index ac9b39739104f..5758c3d56ec90 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -544,7 +544,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
 ///     Microsoft.
 llvm::json::Object CreateRunInTerminalReverseRequest(
     llvm::StringRef program, const std::vector<std::string> &args,
-    const llvm::StringMap<std::string> env, llvm::StringRef cwd,
+    const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
     llvm::StringRef comm_file, lldb::pid_t debugger_pid);
 
 /// Create a "Terminated" JSON object that contains statistics

>From 8d30c73505d3e3f87a4ace7d81ebaa96f5689e7f Mon Sep 17 00:00:00 2001
From: csstormq <swust_xiaoqiangxu at 163.com>
Date: Fri, 23 May 2025 11:25:23 +0800
Subject: [PATCH 083/105] [mlir][docs] Fix typo in PassManagement.md (NFC)
 (#140891)

---
 mlir/docs/PassManagement.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/docs/PassManagement.md b/mlir/docs/PassManagement.md
index eda48a44cf023..a920d57c7cd25 100644
--- a/mlir/docs/PassManagement.md
+++ b/mlir/docs/PassManagement.md
@@ -878,7 +878,7 @@ struct MyPassOptions {
 #endif // GEN_PASS_DECL_MYPASS
 ```
 
-The utogenerated file will also contain the declarations of the default
+The autogenerated file will also contain the declarations of the default
 constructors.
 
 ```c++

>From 835bba973d7a5f539967cdae2dc4bd3fc4a904f9 Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Thu, 22 May 2025 21:44:34 -0700
Subject: [PATCH 084/105] [clang][Darwin] Add test checking for tls support on
 xros target triples (#141170)

---
 clang/test/Sema/darwin-tls.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/Sema/darwin-tls.c b/clang/test/Sema/darwin-tls.c
index 9a41c5c6a995a..4f80cb72779d8 100644
--- a/clang/test/Sema/darwin-tls.c
+++ b/clang/test/Sema/darwin-tls.c
@@ -13,6 +13,8 @@
 // RUN: %clang_cc1 -fsyntax-only -Wno-error=implicit-int -triple thumbv7k-apple-watchos2.0 %s 2>&1 | FileCheck %s --check-prefix TLS
 // RUN: not %clang_cc1 -fsyntax-only -triple i386-apple-watchos2.0-simulator %s 2>&1 | FileCheck %s --check-prefix NO-TLS
 // RUN: %clang_cc1 -fsyntax-only -Wno-error=implicit-int -triple i386-apple-watchos3.0-simulator %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: %clang_cc1 -fsyntax-only -Wno-error=implicit-int -triple arm64-apple-xros %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: %clang_cc1 -fsyntax-only -Wno-error=implicit-int -triple arm64-apple-xros-simulator %s 2>&1 | FileCheck %s --check-prefix TLS
 
 
 __thread int a;

>From c0e7a59204660e8609ae18cfb7e0c7912bf058cf Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 22:36:23 -0700
Subject: [PATCH 085/105] [BOLT] Remove redundant control flow statements (NFC)
 (#141182)

---
 bolt/lib/Core/DIEBuilder.cpp                 | 2 --
 bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 1 -
 2 files changed, 3 deletions(-)

diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp
index 072a152119ae2..d36dbb3459249 100644
--- a/bolt/lib/Core/DIEBuilder.cpp
+++ b/bolt/lib/Core/DIEBuilder.cpp
@@ -175,8 +175,6 @@ void DIEBuilder::updateReferences() {
     LocExpr.Die.replaceValue(getState().DIEAlloc, LocExpr.Attr, LocExpr.Form,
                              Value);
   }
-
-  return;
 }
 
 uint32_t DIEBuilder::allocDIE(const DWARFUnit &DU, const DWARFDie &DDie,
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index ae9b22e4051dc..581f22f2a2b75 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -783,7 +783,6 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
     Inst.setOpcode(RISCV::ADD);
     Inst.insert(Inst.begin(), MCOperand::createReg(Reg));
     Inst.insert(Inst.begin() + 1, MCOperand::createReg(RISCV::X0));
-    return;
   }
 
   InstructionListType createLoadImmediate(const MCPhysReg Dest,

>From 6979ab26555a8640a0470410c2c040fd68bf68ce Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 22:36:26 -0700
Subject: [PATCH 086/105] [lldb] Remove redundant control flow statements (NFC)
 (#141183)

---
 lldb/include/lldb/Interpreter/ScriptInterpreter.h           | 6 ++----
 lldb/include/lldb/Target/Process.h                          | 2 +-
 lldb/source/Commands/CommandObjectDiagnostics.cpp           | 1 -
 lldb/source/Commands/CommandObjectTarget.cpp                | 2 --
 .../Python/Interfaces/ScriptedPythonInterface.h             | 1 -
 lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp    | 1 -
 6 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 3a4a7ae924584..f1c3eefdcd874 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -500,10 +500,8 @@ class ScriptInterpreter : public PluginInterface {
     return false;
   }
 
-  virtual void OptionParsingStartedForCommandObject(
-      StructuredData::GenericSP cmd_obj_sp) {
-    return;
-  }
+  virtual void
+  OptionParsingStartedForCommandObject(StructuredData::GenericSP cmd_obj_sp) {}
 
   virtual uint32_t
   GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 536a69fb89759..a8892e9c43225 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -605,7 +605,7 @@ class Process : public std::enable_shared_from_this<Process>,
 
   /// The underlying plugin might store the low-level communication history for
   /// this session.  Dump it into the provided stream.
-  virtual void DumpPluginHistory(Stream &s) { return; }
+  virtual void DumpPluginHistory(Stream &s) {}
 
   /// Launch a new process.
   ///
diff --git a/lldb/source/Commands/CommandObjectDiagnostics.cpp b/lldb/source/Commands/CommandObjectDiagnostics.cpp
index ac87f869f0127..b565e16e76b53 100644
--- a/lldb/source/Commands/CommandObjectDiagnostics.cpp
+++ b/lldb/source/Commands/CommandObjectDiagnostics.cpp
@@ -96,7 +96,6 @@ class CommandObjectDiagnosticsDump : public CommandObjectParsed {
     result.GetOutputStream() << "diagnostics written to " << *directory << '\n';
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
-    return;
   }
 
   CommandOptions m_options;
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 8c877fc971056..e2ba0008badd3 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -649,8 +649,6 @@ class CommandObjectTargetDelete : public CommandObjectParsed {
     result.GetOutputStream().Printf("%u targets deleted.\n",
                                     (uint32_t)num_targets_to_delete);
     result.SetStatus(eReturnStatusSuccessFinishResult);
-
-    return;
   }
 
   OptionGroupOptions m_option_group;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 4b9f463ef5605..b38b65e3545c4 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -463,7 +463,6 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
   template <typename T, typename U>
   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
     // If U is not a PythonObject, don't touch it!
-    return;
   }
 
   template <typename T>
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
index 1703597a7cd2f..a00127b8e5580 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
@@ -263,7 +263,6 @@ void AppleDWARFIndex::GetTypes(
     m_module.LogMessage(log, "FindByNameAndTag()");
   const dw_tag_t expected_tag = context[0].tag;
   SearchFor(*m_apple_types_up, expected_name, callback, expected_tag);
-  return;
 }
 
 void AppleDWARFIndex::GetNamespaces(

>From 9c62446024f50cbf3f8722d11f71e31baae3a051 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 22:36:29 -0700
Subject: [PATCH 087/105] [mlir] Remove redundant control flow statements (NFC)
 (#141184)

---
 mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h           | 4 ++--
 mlir/include/mlir/Analysis/DataFlowFramework.h                | 2 +-
 mlir/lib/Dialect/Mesh/IR/MeshOps.cpp                          | 1 -
 mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp           | 1 -
 .../lib/Dialect/Linalg/TestLinalgRankReduceContractionOps.cpp | 1 -
 5 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h b/mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h
index 7ecde7f39415c..8bcfe51ad7cd1 100644
--- a/mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h
+++ b/mlir/include/mlir/Analysis/DataFlow/DenseAnalysis.h
@@ -125,7 +125,7 @@ class AbstractDenseForwardDataFlowAnalysis : public DataFlowAnalysis {
   /// Visit an operation. If this analysis can confirm that lattice content
   /// of lattice anchors around operation are necessarily identical, join
   /// them into the same equivalent class.
-  virtual void buildOperationEquivalentLatticeAnchor(Operation *op) { return; }
+  virtual void buildOperationEquivalentLatticeAnchor(Operation *op) {}
 
   /// Propagate the dense lattice forward along the control flow edge from
   /// `regionFrom` to `regionTo` regions of the `branch` operation. `nullopt`
@@ -386,7 +386,7 @@ class AbstractDenseBackwardDataFlowAnalysis : public DataFlowAnalysis {
   /// Visit an operation. If this analysis can confirm that lattice content
   /// of lattice anchors around operation are necessarily identical, join
   /// them into the same equivalent class.
-  virtual void buildOperationEquivalentLatticeAnchor(Operation *op) { return; }
+  virtual void buildOperationEquivalentLatticeAnchor(Operation *op) {}
 
   /// Propagate the dense lattice backwards along the control flow edge from
   /// `regionFrom` to `regionTo` regions of the `branch` operation. `nullopt`
diff --git a/mlir/include/mlir/Analysis/DataFlowFramework.h b/mlir/include/mlir/Analysis/DataFlowFramework.h
index caf978a51fd8e..49862927caff2 100644
--- a/mlir/include/mlir/Analysis/DataFlowFramework.h
+++ b/mlir/include/mlir/Analysis/DataFlowFramework.h
@@ -622,7 +622,7 @@ class DataFlowAnalysis {
   /// This function will union lattice anchor to same equivalent class if the
   /// analysis can determine the lattice content of lattice anchor is
   /// necessarily identical under the corrensponding lattice type.
-  virtual void initializeEquivalentLatticeAnchor(Operation *top) { return; }
+  virtual void initializeEquivalentLatticeAnchor(Operation *top) {}
 
 protected:
   /// Create a dependency between the given analysis state and lattice anchor
diff --git a/mlir/lib/Dialect/Mesh/IR/MeshOps.cpp b/mlir/lib/Dialect/Mesh/IR/MeshOps.cpp
index 2bdb58892937f..304cb55a35086 100644
--- a/mlir/lib/Dialect/Mesh/IR/MeshOps.cpp
+++ b/mlir/lib/Dialect/Mesh/IR/MeshOps.cpp
@@ -314,7 +314,6 @@ void mlir::mesh::maybeInsertTargetShardingAnnotation(MeshSharding sharding,
                                              newShardOp.getSharding(),
                                              /*annotate_for_users*/ true);
   rewriter.replaceAllUsesExcept(newShardOp, newShardOp2, newShardOp2);
-  return;
 }
 
 void mlir::mesh::maybeInsertTargetShardingAnnotation(MeshSharding sharding,
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
index 9227b0f8fd5b9..f9db5dcb88b4c 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaValidation.cpp
@@ -463,7 +463,6 @@ struct TosaValidation : public tosa::impl::TosaValidationBase<TosaValidation> {
 
     depth++;
     getMaxNestedDepth(op, depth);
-    return;
   }
 
   bool levelCheckMaxNesting(Operation *op) {
diff --git a/mlir/test/lib/Dialect/Linalg/TestLinalgRankReduceContractionOps.cpp b/mlir/test/lib/Dialect/Linalg/TestLinalgRankReduceContractionOps.cpp
index 750ba6b5d9872..d7b7c6fe90c90 100644
--- a/mlir/test/lib/Dialect/Linalg/TestLinalgRankReduceContractionOps.cpp
+++ b/mlir/test/lib/Dialect/Linalg/TestLinalgRankReduceContractionOps.cpp
@@ -51,7 +51,6 @@ struct TestLinalgRankReduceContractionOps
     linalg::populateContractionOpRankReducingPatterns(patterns);
     if (failed(applyPatternsGreedily(funcOp.getBody(), std::move(patterns))))
       return signalPassFailure();
-    return;
   }
 };
 

>From 6464238dc0d0517f3a786b28ced3f3a65db91c21 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 22:36:32 -0700
Subject: [PATCH 088/105] [mlir] Use llvm::stable_sort (NFC) (#141186)

---
 .../Transforms/Utils/LoopEmitter.cpp          |  2 +-
 mlir/lib/IR/Diagnostics.cpp                   |  2 +-
 mlir/lib/Rewrite/ByteCode.cpp                 |  8 +++---
 mlir/lib/Rewrite/PatternApplicator.cpp        |  2 +-
 .../Transforms/Utils/CommutativityUtils.cpp   |  3 +--
 .../Transforms/Utils/DialectConversion.cpp    | 26 +++++++++----------
 6 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/Utils/LoopEmitter.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/Utils/LoopEmitter.cpp
index 3a77ce347b1c0..84129edee3753 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/Utils/LoopEmitter.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/Utils/LoopEmitter.cpp
@@ -404,7 +404,7 @@ void LoopEmitter::categorizeIterators(
       spIters.push_back(it);
   }
 
-  std::stable_sort(spIters.begin(), spIters.end(), [](auto lhs, auto rhs) {
+  llvm::stable_sort(spIters, [](auto lhs, auto rhs) {
     // AffineUnRed > Affine > Slice > Trivial
     return static_cast<uint8_t>(lhs->kind) > static_cast<uint8_t>(rhs->kind);
   });
diff --git a/mlir/lib/IR/Diagnostics.cpp b/mlir/lib/IR/Diagnostics.cpp
index 79697be2b45ea..3a0f81d240336 100644
--- a/mlir/lib/IR/Diagnostics.cpp
+++ b/mlir/lib/IR/Diagnostics.cpp
@@ -979,7 +979,7 @@ struct ParallelDiagnosticHandlerImpl : public llvm::PrettyStackTraceEntry {
     // Stable sort all of the diagnostics that were emitted. This creates a
     // deterministic ordering for the diagnostics based upon which order id they
     // were emitted for.
-    std::stable_sort(diagnostics.begin(), diagnostics.end());
+    llvm::stable_sort(diagnostics);
 
     // Emit each diagnostic to the context again.
     for (ThreadDiagnostic &diag : diagnostics)
diff --git a/mlir/lib/Rewrite/ByteCode.cpp b/mlir/lib/Rewrite/ByteCode.cpp
index 5939d0d00d328..ae3f22dec9f2c 100644
--- a/mlir/lib/Rewrite/ByteCode.cpp
+++ b/mlir/lib/Rewrite/ByteCode.cpp
@@ -2346,10 +2346,10 @@ void PDLByteCode::match(Operation *op, PatternRewriter &rewriter,
   assert(succeeded(executeResult) && "unexpected matcher execution failure");
 
   // Order the found matches by benefit.
-  std::stable_sort(matches.begin(), matches.end(),
-                   [](const MatchResult &lhs, const MatchResult &rhs) {
-                     return lhs.benefit > rhs.benefit;
-                   });
+  llvm::stable_sort(matches,
+                    [](const MatchResult &lhs, const MatchResult &rhs) {
+                      return lhs.benefit > rhs.benefit;
+                    });
 }
 
 LogicalResult PDLByteCode::rewrite(PatternRewriter &rewriter,
diff --git a/mlir/lib/Rewrite/PatternApplicator.cpp b/mlir/lib/Rewrite/PatternApplicator.cpp
index ea43f8a147d47..4a12183492fd4 100644
--- a/mlir/lib/Rewrite/PatternApplicator.cpp
+++ b/mlir/lib/Rewrite/PatternApplicator.cpp
@@ -103,7 +103,7 @@ void PatternApplicator::applyCostModel(CostModel model) {
 
     // Sort patterns with highest benefit first, and remove those that are
     // impossible to match.
-    std::stable_sort(list.begin(), list.end(), cmp);
+    llvm::stable_sort(list, cmp);
     while (!list.empty() && benefits[list.back()].isImpossibleToMatch()) {
       LLVM_DEBUG(logImpossibleToMatch(*list.back()));
       list.pop_back();
diff --git a/mlir/lib/Transforms/Utils/CommutativityUtils.cpp b/mlir/lib/Transforms/Utils/CommutativityUtils.cpp
index 5ba6e4747cb57..8b132b5e484bb 100644
--- a/mlir/lib/Transforms/Utils/CommutativityUtils.cpp
+++ b/mlir/lib/Transforms/Utils/CommutativityUtils.cpp
@@ -297,8 +297,7 @@ class SortCommutativeOperands : public RewritePattern {
     }
 
     // Sort the operands.
-    std::stable_sort(commOperands.begin(), commOperands.end(),
-                     commutativeOperandComparator);
+    llvm::stable_sort(commOperands, commutativeOperandComparator);
     SmallVector<Value, 2> sortedOperands;
     for (const std::unique_ptr<CommutativeOperand> &commOperand : commOperands)
       sortedOperands.push_back(commOperand->operand);
diff --git a/mlir/lib/Transforms/Utils/DialectConversion.cpp b/mlir/lib/Transforms/Utils/DialectConversion.cpp
index bd11bbe58a3f6..02657b500ebfa 100644
--- a/mlir/lib/Transforms/Utils/DialectConversion.cpp
+++ b/mlir/lib/Transforms/Utils/DialectConversion.cpp
@@ -2520,19 +2520,19 @@ unsigned OperationLegalizer::applyCostModelToPatterns(
     return minDepth;
 
   // Sort the patterns by those likely to be the most beneficial.
-  std::stable_sort(patternsByDepth.begin(), patternsByDepth.end(),
-                   [](const std::pair<const Pattern *, unsigned> &lhs,
-                      const std::pair<const Pattern *, unsigned> &rhs) {
-                     // First sort by the smaller pattern legalization
-                     // depth.
-                     if (lhs.second != rhs.second)
-                       return lhs.second < rhs.second;
-
-                     // Then sort by the larger pattern benefit.
-                     auto lhsBenefit = lhs.first->getBenefit();
-                     auto rhsBenefit = rhs.first->getBenefit();
-                     return lhsBenefit > rhsBenefit;
-                   });
+  llvm::stable_sort(patternsByDepth,
+                    [](const std::pair<const Pattern *, unsigned> &lhs,
+                       const std::pair<const Pattern *, unsigned> &rhs) {
+                      // First sort by the smaller pattern legalization
+                      // depth.
+                      if (lhs.second != rhs.second)
+                        return lhs.second < rhs.second;
+
+                      // Then sort by the larger pattern benefit.
+                      auto lhsBenefit = lhs.first->getBenefit();
+                      auto rhsBenefit = rhs.first->getBenefit();
+                      return lhsBenefit > rhsBenefit;
+                    });
 
   // Update the legalization pattern to use the new sorted list.
   patterns.clear();

>From 02ed6d82f66f79b0f546c3af37252d6753228451 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 22:36:36 -0700
Subject: [PATCH 089/105] [AST] Simplify string comparisons (NFC) (#141189)

---
 clang/unittests/AST/DeclTest.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 16aa2b50b7a06..ed635da683aab 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -104,8 +104,9 @@ TEST(Decl, AsmLabelAttr) {
     MC->mangleName(DeclG, OS_G);
   }
 
-  ASSERT_TRUE(0 == MangleF.compare("\x01" "foo"));
-  ASSERT_TRUE(0 == MangleG.compare("goo"));
+  ASSERT_EQ(MangleF, "\x01"
+                     "foo");
+  ASSERT_EQ(MangleG, "goo");
 }
 
 TEST(Decl, MangleDependentSizedArray) {
@@ -138,8 +139,8 @@ TEST(Decl, MangleDependentSizedArray) {
   MC->mangleCanonicalTypeName(DeclA->getType(), OS_A);
   MC->mangleCanonicalTypeName(DeclB->getType(), OS_B);
 
-  ASSERT_TRUE(0 == MangleA.compare("_ZTSA_i"));
-  ASSERT_TRUE(0 == MangleB.compare("_ZTSAT0__T_"));
+  ASSERT_EQ(MangleA, "_ZTSA_i");
+  ASSERT_EQ(MangleB, "_ZTSAT0__T_");
 }
 
 TEST(Decl, ConceptDecl) {

>From 32805964fcc2d5ad6296aae91e18053720e7a8a0 Mon Sep 17 00:00:00 2001
From: Timm Baeder <tbaeder at redhat.com>
Date: Fri, 23 May 2025 08:17:22 +0200
Subject: [PATCH 090/105] [clang][bytecode] Diagnose placement-new'ing to a
 temporary (#141099)

... that's been created in a different evaluation.
---
 clang/lib/AST/ByteCode/Interp.cpp         | 2 ++
 clang/test/AST/ByteCode/placement-new.cpp | 9 ++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 7cc0d2a526480..17660570d24cd 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1703,6 +1703,8 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
                           std::optional<uint64_t> ArraySize) {
   const Pointer &Ptr = S.Stk.peek<Pointer>();
 
+  if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
+    return false;
   if (!CheckStore(S, OpPC, Ptr))
     return false;
 
diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp
index 14b893c7e587b..9015690256458 100644
--- a/clang/test/AST/ByteCode/placement-new.cpp
+++ b/clang/test/AST/ByteCode/placement-new.cpp
@@ -15,7 +15,8 @@ namespace std {
   constexpr void construct_at(void *p, Args &&...args) {
     new (p) T((Args&&)args...); // both-note {{in call to}} \
                                 // both-note {{placement new would change type of storage from 'int' to 'float'}} \
-                                // both-note {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}}
+                                // both-note {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}} \
+                                // both-note {{construction of temporary is not allowed}}
 
   }
 }
@@ -391,3 +392,9 @@ namespace MemMove {
 
   static_assert(foo() == 123);
 }
+
+namespace Temp {
+  constexpr int &&temporary = 0; // both-note {{created here}}
+  static_assert((std::construct_at<int>(&temporary, 1), true)); // both-error{{not an integral constant expression}} \
+                                                                // both-note {{in call}}
+}

>From 044929d075cff7883a020526ec8b795b30f9f086 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Fri, 23 May 2025 08:26:46 +0200
Subject: [PATCH 091/105] [lldb] Change synthetic symbol names to have file
 address (#138416)

* Changes the default synthetic symbol names to contain their file
address

This is a new PR after the first PR (#137512) was reverted because it
didn't update the way unnamed symbols were searched in the symbol table,
which relied on the index being in the name.

This time also added extra test to make sure the symbol is found as
expected
---
 lldb/include/lldb/Symbol/Symbol.h             |  2 +-
 lldb/source/Symbol/Symbol.cpp                 |  4 +-
 lldb/source/Symbol/Symtab.cpp                 | 13 +++---
 .../python_api/unnamed_symbol_lookup/Makefile | 23 +++++++++++
 .../TestUnnamedSymbolLookup.py                | 40 +++++++++++++++++++
 .../python_api/unnamed_symbol_lookup/main.c   |  6 +++
 .../ObjectFile/ELF/eh_frame-symbols.yaml      |  4 +-
 .../Breakpad/symtab-sorted-by-size.test       |  2 +-
 .../Shell/SymbolFile/Breakpad/symtab.test     |  2 +-
 9 files changed, 84 insertions(+), 12 deletions(-)
 create mode 100644 lldb/test/API/python_api/unnamed_symbol_lookup/Makefile
 create mode 100644 lldb/test/API/python_api/unnamed_symbol_lookup/TestUnnamedSymbolLookup.py
 create mode 100644 lldb/test/API/python_api/unnamed_symbol_lookup/main.c

diff --git a/lldb/include/lldb/Symbol/Symbol.h b/lldb/include/lldb/Symbol/Symbol.h
index e05c845a69f3e..688c8a5931feb 100644
--- a/lldb/include/lldb/Symbol/Symbol.h
+++ b/lldb/include/lldb/Symbol/Symbol.h
@@ -258,7 +258,7 @@ class Symbol : public SymbolContextScope {
   bool ContainsFileAddress(lldb::addr_t file_addr) const;
 
   static llvm::StringRef GetSyntheticSymbolPrefix() {
-    return "___lldb_unnamed_symbol";
+    return "___lldb_unnamed_symbol_";
   }
 
   /// Decode a serialized version of this object from data.
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 4828de4fdfa37..d6689a647062a 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -639,7 +639,9 @@ void Symbol::SynthesizeNameIfNeeded() const {
     // breakpoints on them.
     llvm::SmallString<256> name;
     llvm::raw_svector_ostream os(name);
-    os << GetSyntheticSymbolPrefix() << GetID();
+    os << GetSyntheticSymbolPrefix()
+       << llvm::format_hex_no_prefix(
+              m_addr_range.GetBaseAddress().GetFileAddress(), 0);
     m_mangled.SetDemangledName(ConstString(os.str()));
   }
 }
diff --git a/lldb/source/Symbol/Symtab.cpp b/lldb/source/Symbol/Symtab.cpp
index 9aee5d3e813d8..9a3e8476fa356 100644
--- a/lldb/source/Symbol/Symtab.cpp
+++ b/lldb/source/Symbol/Symtab.cpp
@@ -654,8 +654,8 @@ uint32_t Symtab::GetNameIndexes(ConstString symbol_name,
   if (count)
     return count;
   // Synthetic symbol names are not added to the name indexes, but they start
-  // with a prefix and end with a the symbol UserID. This allows users to find
-  // these symbols without having to add them to the name indexes. These
+  // with a prefix and end with the symbol file address. This allows users to
+  // find these symbols without having to add them to the name indexes. These
   // queries will not happen very often since the names don't mean anything, so
   // performance is not paramount in this case.
   llvm::StringRef name = symbol_name.GetStringRef();
@@ -663,11 +663,12 @@ uint32_t Symtab::GetNameIndexes(ConstString symbol_name,
   if (!name.consume_front(Symbol::GetSyntheticSymbolPrefix()))
     return 0; // Not a synthetic symbol name
 
-  // Extract the user ID from the symbol name
-  unsigned long long uid = 0;
-  if (getAsUnsignedInteger(name, /*Radix=*/10, uid))
+  // Extract the file address from the symbol name
+  unsigned long long file_address = 0;
+  if (getAsUnsignedInteger(name, /*Radix=*/16, file_address))
     return 0; // Failed to extract the user ID as an integer
-  Symbol *symbol = FindSymbolByID(uid);
+
+  Symbol *symbol = FindSymbolAtFileAddress(static_cast<addr_t>(file_address));
   if (symbol == nullptr)
     return 0;
   const uint32_t symbol_idx = GetIndexForSymbol(symbol);
diff --git a/lldb/test/API/python_api/unnamed_symbol_lookup/Makefile b/lldb/test/API/python_api/unnamed_symbol_lookup/Makefile
new file mode 100644
index 0000000000000..4e29185e9dd59
--- /dev/null
+++ b/lldb/test/API/python_api/unnamed_symbol_lookup/Makefile
@@ -0,0 +1,23 @@
+C_SOURCES := main.c
+
+include Makefile.rules
+
+all: a.out.stripped
+
+ifeq "$(OS)" "Darwin"
+STRIP_COMMAND = $(STRIP) -s keep_symbols.txt
+else
+STRIP_COMMAND = $(STRIP) --keep-symbol=main
+endif
+
+a.out.stripped: a.out
+ifeq "$(OS)" "Darwin"
+	echo "_main" > keep_symbols.txt
+	$(STRIP) -s keep_symbols.txt -o a.out.stripped a.out
+else
+	$(STRIP) --keep-symbol=main -o a.out.stripped a.out
+endif
+
+ifneq "$(CODESIGN)" ""
+	$(CODESIGN) -fs - a.out.stripped
+endif
diff --git a/lldb/test/API/python_api/unnamed_symbol_lookup/TestUnnamedSymbolLookup.py b/lldb/test/API/python_api/unnamed_symbol_lookup/TestUnnamedSymbolLookup.py
new file mode 100644
index 0000000000000..09d43a34c7e30
--- /dev/null
+++ b/lldb/test/API/python_api/unnamed_symbol_lookup/TestUnnamedSymbolLookup.py
@@ -0,0 +1,40 @@
+"""
+Test lookup unnamed symbols.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestUnnamedSymbolLookup(TestBase):
+    def test_unnamed_symbol_lookup(self):
+        """Test looking up unnamed symbol synthetic name"""
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_name_breakpoint(
+            self, "main", exe_name="a.out.stripped"
+        )
+
+        main_frame = thread.GetFrameAtIndex(0)
+
+        # Step until reaching the unnamed symbol called from main
+        for _ in range(100):
+            thread.StepInto()
+            if thread.GetFrameAtIndex(0) != main_frame:
+                break
+
+            thread.StepInto()
+
+        self.assertEqual(
+            main_frame, thread.GetFrameAtIndex(1), "Expected to be called from main"
+        )
+        symbol = thread.GetFrameAtIndex(0).GetSymbol()
+        self.assertIsNotNone(symbol, "unnamed symbol called from main not reached")
+        self.assertTrue(symbol.name.startswith("___lldb_unnamed_symbol"))
+
+        exe_module = symbol.GetStartAddress().GetModule()
+        found_symbols = exe_module.FindSymbols(symbol.name)
+        self.assertIsNotNone(found_symbols)
+        self.assertEqual(found_symbols.GetSize(), 1)
diff --git a/lldb/test/API/python_api/unnamed_symbol_lookup/main.c b/lldb/test/API/python_api/unnamed_symbol_lookup/main.c
new file mode 100644
index 0000000000000..ec8350706b3c9
--- /dev/null
+++ b/lldb/test/API/python_api/unnamed_symbol_lookup/main.c
@@ -0,0 +1,6 @@
+__attribute__((nodebug)) int stripped_function(int val) { return val * val; }
+
+int main(void) {
+  stripped_function(10);
+  return 0;
+}
diff --git a/lldb/test/Shell/ObjectFile/ELF/eh_frame-symbols.yaml b/lldb/test/Shell/ObjectFile/ELF/eh_frame-symbols.yaml
index 0dcc9fb76bd4f..709c37e79d878 100644
--- a/lldb/test/Shell/ObjectFile/ELF/eh_frame-symbols.yaml
+++ b/lldb/test/Shell/ObjectFile/ELF/eh_frame-symbols.yaml
@@ -3,8 +3,8 @@
 
 # CHECK: Index   UserID DSX Type            File Address/Value Load Address       Size               Flags      Name
 # CHECK: [    0]      1     SourceFile      0x0000000000000000                    0x0000000000000000 0x00000004 -
-# CHECK: [    1]      2  SX Code            0x0000000000201180                    0x0000000000000010 0x00000000 ___lldb_unnamed_symbol{{[0-9]*}}
-# CHECK: [    2]      3  SX Code            0x0000000000201190                    0x0000000000000006 0x00000000 ___lldb_unnamed_symbol{{[0-9]*}}
+# CHECK: [    1]      2  SX Code            0x0000000000201180                    0x0000000000000010 0x00000000 ___lldb_unnamed_symbol_{{[0-9a-f]*}}
+# CHECK: [    2]      3  SX Code            0x0000000000201190                    0x0000000000000006 0x00000000 ___lldb_unnamed_symbol_{{[0-9a-f]*}}
 
 --- !ELF
 FileHeader:
diff --git a/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test b/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test
index 98052ea20bedd..00e04eb39a98e 100644
--- a/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test
+++ b/lldb/test/Shell/SymbolFile/Breakpad/symtab-sorted-by-size.test
@@ -3,7 +3,7 @@
 # RUN:   -s %s | FileCheck %s
 
 # CHECK: num_symbols = 4 (sorted by size):
-# CHECK: [    0]      0  SX Code            0x0000000000400000                    0x00000000000000b0 0x00000000 ___lldb_unnamed_symbol0
+# CHECK: [    0]      0  SX Code            0x0000000000400000                    0x00000000000000b0 0x00000000 ___lldb_unnamed_symbol_400000
 # CHECK: [    1]      0   X Code            0x00000000004000d0                    0x0000000000000022 0x00000000 _start
 # CHECK: [    2]      0   X Code            0x00000000004000b0                    0x0000000000000010 0x00000000 f1
 # CHECK: [    3]      0   X Code            0x00000000004000c0                    0x0000000000000010 0x00000000 f2
diff --git a/lldb/test/Shell/SymbolFile/Breakpad/symtab.test b/lldb/test/Shell/SymbolFile/Breakpad/symtab.test
index ef41bb3bea955..a32eb5808426f 100644
--- a/lldb/test/Shell/SymbolFile/Breakpad/symtab.test
+++ b/lldb/test/Shell/SymbolFile/Breakpad/symtab.test
@@ -5,7 +5,7 @@
 # CHECK-LABEL: (lldb) image dump symtab symtab.out
 # CHECK: Symtab, file = {{.*}}symtab.out, num_symbols = 4:
 # CHECK: Index   UserID DSX Type            File Address/Value Load Address       Size               Flags      Name
-# CHECK: [    0]      0  SX Code            0x0000000000400000                    0x00000000000000b0 0x00000000 ___lldb_unnamed_symbol{{[0-9]*}}
+# CHECK: [    0]      0  SX Code            0x0000000000400000                    0x00000000000000b0 0x00000000 ___lldb_unnamed_symbol_{{[0-9a-f]*}}
 # CHECK: [    1]      0   X Code            0x00000000004000b0                    0x0000000000000010 0x00000000 f1
 # CHECK: [    2]      0   X Code            0x00000000004000c0                    0x0000000000000010 0x00000000 f2
 # CHECK: [    3]      0   X Code            0x00000000004000d0                    0x0000000000000022 0x00000000 _start

>From 782c066b69832d0691b6e4b8d5c18175e05d5c10 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 23:50:51 -0700
Subject: [PATCH 092/105] [MCA] Use a range-based for loop (NFC) (#141187)

---
 llvm/lib/MCA/Stages/ExecuteStage.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/MCA/Stages/ExecuteStage.cpp b/llvm/lib/MCA/Stages/ExecuteStage.cpp
index 7714d4ff8aede..49e0b8ee35e84 100644
--- a/llvm/lib/MCA/Stages/ExecuteStage.cpp
+++ b/llvm/lib/MCA/Stages/ExecuteStage.cpp
@@ -275,9 +275,9 @@ void ExecuteStage::notifyReservedOrReleasedBuffers(const InstRef &IR,
     return;
 
   SmallVector<unsigned, 4> BufferIDs(llvm::popcount(UsedBuffers), 0);
-  for (unsigned I = 0, E = BufferIDs.size(); I < E; ++I) {
+  for (unsigned &ID : BufferIDs) {
     uint64_t CurrentBufferMask = UsedBuffers & (-UsedBuffers);
-    BufferIDs[I] = HWS.getResourceID(CurrentBufferMask);
+    ID = HWS.getResourceID(CurrentBufferMask);
     UsedBuffers ^= CurrentBufferMask;
   }
 

>From 05674b21fed51a940b93e09b38d1833010f3f694 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 23:50:55 -0700
Subject: [PATCH 093/105] [clang-tidy] Use std:::string::find with
 std::string_view (NFC) (#141188)

std::string::rfind accepts anything that can be converted to
std::string_view starting in C++17.  Since StringRef can be converted
to std::string_view, we do not need to create a temporary instance of
std::string here.
---
 clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp
index ba89070be59cc..3ea235b1fed7f 100644
--- a/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/HeaderGuardCheck.cpp
@@ -40,7 +40,7 @@ std::string LLVMHeaderGuardCheck::getHeaderGuard(StringRef Filename,
   // Unlike LLVM svn, LLVM git monorepo is named llvm-project, so we replace
   // "/llvm-project/" with the canonical "/llvm/".
   const static StringRef LLVMProject = "/llvm-project/";
-  size_t PosLLVMProject = Guard.rfind(std::string(LLVMProject));
+  size_t PosLLVMProject = Guard.rfind(LLVMProject);
   if (PosLLVMProject != StringRef::npos)
     Guard = Guard.replace(PosLLVMProject, LLVMProject.size(), "/llvm/");
 

>From cc78177e8f50f1d217b2fba5677fc1664aabd91e Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 23:50:58 -0700
Subject: [PATCH 094/105] [llvm] Use *Map::try_emplace (NFC) (#141190)

try_emplace can default-construct values, so we do not need to do so
on our own.  Plus, try_emplace(Key) is much simpler/shorter than
insert({Key, LongValueType()}).
---
 llvm/lib/Analysis/ScalarEvolution.cpp                  | 4 ++--
 llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp          | 6 +++---
 llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp | 3 +--
 llvm/lib/CodeGen/NonRelocatableStringpool.cpp          | 2 +-
 llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp            | 2 +-
 5 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 5e01c29615fab..b0975df6ed39e 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -8371,7 +8371,7 @@ ScalarEvolution::getPredicatedBackedgeTakenInfo(const Loop *L) {
   if (BTI.hasFullInfo())
     return BTI;
 
-  auto Pair = PredicatedBackedgeTakenCounts.insert({L, BackedgeTakenInfo()});
+  auto Pair = PredicatedBackedgeTakenCounts.try_emplace(L);
 
   if (!Pair.second)
     return Pair.first->second;
@@ -8390,7 +8390,7 @@ ScalarEvolution::getBackedgeTakenInfo(const Loop *L) {
   // code elsewhere that it shouldn't attempt to request a new
   // backedge-taken count, which could result in infinite recursion.
   std::pair<DenseMap<const Loop *, BackedgeTakenInfo>::iterator, bool> Pair =
-      BackedgeTakenCounts.insert({L, BackedgeTakenInfo()});
+      BackedgeTakenCounts.try_emplace(L);
   if (!Pair.second)
     return Pair.first->second;
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index df4e48571692c..fc43bc6f7776d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -234,7 +234,7 @@ unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
 CodeViewDebug::InlineSite &
 CodeViewDebug::getInlineSite(const DILocation *InlinedAt,
                              const DISubprogram *Inlinee) {
-  auto SiteInsertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()});
+  auto SiteInsertion = CurFn->InlineSites.try_emplace(InlinedAt);
   InlineSite *Site = &SiteInsertion.first->second;
   if (SiteInsertion.second) {
     unsigned ParentFuncId = CurFn->FuncId;
@@ -2743,7 +2743,7 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) {
   // Check if we've already translated the complete record type.
   // Insert the type with a null TypeIndex to signify that the type is currently
   // being lowered.
-  auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()});
+  auto InsertResult = CompleteTypeIndices.try_emplace(CTy);
   if (!InsertResult.second)
     return InsertResult.first->second;
 
@@ -3005,7 +3005,7 @@ void CodeViewDebug::collectLexicalBlockInfo(
   // Create a new CodeView lexical block for this lexical scope.  If we've
   // seen this DILexicalBlock before then the scope tree is malformed and
   // we can handle this gracefully by not processing it a second time.
-  auto BlockInsertion = CurFn->LexicalBlocks.insert({DILB, LexicalBlock()});
+  auto BlockInsertion = CurFn->LexicalBlocks.try_emplace(DILB);
   if (!BlockInsertion.second)
     return;
 
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index a1fd5a71df93d..fdf50188fbcd8 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -1691,8 +1691,7 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
   // filled in later.
   for (const DbgOp &Op : DbgOps) {
     if (!Op.IsConst)
-      if (FoundLocs.insert({Op.ID, TransferTracker::LocationAndQuality()})
-              .second)
+      if (FoundLocs.try_emplace(Op.ID).second)
         ValuesToFind.push_back(Op.ID);
   }
 
diff --git a/llvm/lib/CodeGen/NonRelocatableStringpool.cpp b/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
index 26857c6a40889..087ac622ffdce 100644
--- a/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
+++ b/llvm/lib/CodeGen/NonRelocatableStringpool.cpp
@@ -12,7 +12,7 @@
 namespace llvm {
 
 DwarfStringPoolEntryRef NonRelocatableStringpool::getEntry(StringRef S) {
-  auto I = Strings.insert({S, DwarfStringPoolEntry()});
+  auto I = Strings.try_emplace(S);
   auto &Entry = I.first->second;
   if (I.second || !Entry.isIndexed()) {
     Entry.Index = NumEntries++;
diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
index dc11e0a4e012b..99c00e149c140 100644
--- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
@@ -2656,7 +2656,7 @@ bool SIInsertWaitcnts::run(MachineFunction &MF) {
   // Keep iterating over the blocks in reverse post order, inserting and
   // updating s_waitcnt where needed, until a fix point is reached.
   for (auto *MBB : ReversePostOrderTraversal<MachineFunction *>(&MF))
-    BlockInfos.insert({MBB, BlockInfo()});
+    BlockInfos.try_emplace(MBB);
 
   std::unique_ptr<WaitcntBrackets> Brackets;
   bool Repeat;

>From 3d028348ce0d6fa531ba7dad8fd38893019dc609 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Thu, 22 May 2025 23:52:07 -0700
Subject: [PATCH 095/105] [CodeGen] Remove redundant calls to
 std::unique_ptr<T>::get (NFC) (#141191)

---
 clang/lib/CodeGen/CGDebugInfo.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 3d20756774708..21896c94c86b4 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -134,10 +134,9 @@ void CGDebugInfo::addInstSourceAtomMetadata(llvm::Instruction *I,
   // Each instruction can only be attributed to one source atom (a limitation of
   // the implementation). If this instruction is already part of a source atom,
   // pick the group in which it has highest precedence (lowest rank).
-  if (DL.get()->getAtomGroup() && DL.get()->getAtomRank() &&
-      DL.get()->getAtomRank() < Rank) {
-    Group = DL.get()->getAtomGroup();
-    Rank = DL.get()->getAtomRank();
+  if (DL->getAtomGroup() && DL->getAtomRank() && DL->getAtomRank() < Rank) {
+    Group = DL->getAtomGroup();
+    Rank = DL->getAtomRank();
   }
 
   // Update the function-local watermark so we don't reuse this number for

>From 61d5fdf50c78810972f5984473600fd917ccaff5 Mon Sep 17 00:00:00 2001
From: Michele Scuttari <michele.scuttari at outlook.com>
Date: Fri, 23 May 2025 09:21:35 +0200
Subject: [PATCH 096/105] [MLIR] Add bufferization state class to
 OneShotBufferization pass (#141019)

Follow-up on #138143, which was reverted due to a missing update a method signature (more specifically, the bufferization interface for `tensor::ConcatOp`) that was not catched before merging. The old PR description is reported in the next lines.

This PR is a follow-up on https://github.com/llvm/llvm-project/pull/138125, and adds a bufferization state class providing information about the IR. The information currently consists of a cached list of symbol tables, which aims to solve the quadratic scaling of the bufferization task with respect to the number of symbols. The PR breaks API compatibility: the bufferize method of the BufferizableOpInterface has been enriched with a reference to a BufferizationState object.

The bufferization state must be kept in a valid state by the interface implementations. For example, if an operation with the Symbol trait is inserted or replaced, its parent SymbolTable must be updated accordingly (see, for example, the bufferization of arith::ConstantOp, where the symbol table of the module gets the new global symbol inserted). Similarly, the invalidation of a symbol table must be performed if an operation with the SymbolTable trait is removed (this can be performed using the invalidateSymbolTable method, introduced in https://github.com/llvm/llvm-project/pull/138014).
---
 .../IR/BufferizableOpInterface.h              | 14 +++++
 .../IR/BufferizableOpInterface.td             |  3 +-
 .../Bufferization/IR/BufferizationOps.td      | 15 ++++--
 .../Bufferization/Transforms/BufferUtils.h    |  6 +++
 .../Bufferization/Transforms/Bufferize.h      |  1 +
 .../Transforms/OneShotAnalysis.h              |  1 +
 .../Transforms/OneShotModuleBufferize.h       |  4 +-
 .../Dialect/Linalg/Transforms/Transforms.h    |  1 +
 .../BufferizableOpInterfaceImpl.cpp           | 12 +++--
 .../IR/BufferizableOpInterface.cpp            |  4 ++
 .../Bufferization/IR/BufferizationOps.cpp     | 12 +++--
 .../BufferizationTransformOps.cpp             |  9 +++-
 .../Bufferization/Transforms/BufferUtils.cpp  | 23 +++++++--
 .../Bufferization/Transforms/Bufferize.cpp    | 10 ++--
 .../FuncBufferizableOpInterfaceImpl.cpp       |  9 ++--
 .../Transforms/OneShotAnalysis.cpp            |  9 ++--
 .../Transforms/OneShotModuleBufferize.cpp     | 12 ++---
 .../BufferizableOpInterfaceImpl.cpp           |  3 +-
 .../BufferizableOpInterfaceImpl.cpp           |  7 ++-
 .../Transforms/ConvertToDestinationStyle.cpp  | 25 ++++++---
 .../BufferizableOpInterfaceImpl.cpp           | 15 ++++--
 .../BufferizableOpInterfaceImpl.cpp           | 27 ++++++----
 .../BufferizableOpInterfaceImpl.cpp           |  6 ++-
 .../BufferizableOpInterfaceImpl.cpp           |  3 +-
 .../SparsificationAndBufferizationPass.cpp    |  5 +-
 .../BufferizableOpInterfaceImpl.cpp           | 51 ++++++++++++-------
 .../BufferizableOpInterfaceImpl.cpp           | 15 ++++--
 27 files changed, 215 insertions(+), 87 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
index cb6ef8bc17220..43c97d57e1834 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
@@ -578,6 +578,20 @@ class AnalysisState {
       insideMutuallyExclusiveRegionsCache;
 };
 
+/// BufferizationState provides information about the state of the IR during the
+/// bufferization process.
+class BufferizationState {
+public:
+  /// Get a reference to the collection of cached symbol tables.
+  SymbolTableCollection &getSymbolTables();
+
+private:
+  /// The cached symbol tables.
+  /// The user is expected to update / invalidate the cached symbol tables if
+  /// the bufferized operation has the Symbol or SymbolTable traits.
+  SymbolTableCollection symbolTables;
+};
+
 /// Create an AllocTensorOp for the given shaped value (memref or tensor).
 /// If `copy` is set, the shaped value is copied. Otherwise, a tensor with
 /// undefined contents is allocated.
diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td
index 95022d7d665d2..b599a9f053215 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td
@@ -426,7 +426,8 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
         /*retType=*/"::llvm::LogicalResult",
         /*methodName=*/"bufferize",
         /*args=*/(ins "::mlir::RewriterBase &":$rewriter,
-                      "const ::mlir::bufferization::BufferizationOptions &":$options),
+                      "const ::mlir::bufferization::BufferizationOptions &":$options,
+                      "::mlir::bufferization::BufferizationState &":$state),
         /*methodBody=*/"",
         /*defaultImplementation=*/[{
           llvm_unreachable("bufferize not implemented");
diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td
index 7a1a701bea6dc..dafa4b9b183f2 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td
@@ -93,7 +93,8 @@ def Bufferization_AllocTensorOp : Bufferization_Op<"alloc_tensor",
 
   let extraClassDeclaration = [{
     LogicalResult bufferize(RewriterBase &rewriter,
-                            const BufferizationOptions &options);
+                            const BufferizationOptions &options,
+                            BufferizationState &state);
 
     bool resultBufferizesToMemoryWrite(OpResult opResult,
                                        const AnalysisState &state);
@@ -282,7 +283,8 @@ def Bufferization_MaterializeInDestinationOp
 
   let extraClassDeclaration = [{
     LogicalResult bufferize(RewriterBase &rewriter,
-                            const BufferizationOptions &options);
+                            const BufferizationOptions &options,
+                            BufferizationState &state);
 
     bool bufferizesToMemoryRead(OpOperand &opOperand,
                                 const AnalysisState &state);
@@ -375,7 +377,8 @@ def Bufferization_DeallocTensorOp : Bufferization_Op<"dealloc_tensor",
     }
 
     LogicalResult bufferize(RewriterBase &rewriter,
-                            const BufferizationOptions &options);
+                            const BufferizationOptions &options,
+                            BufferizationState &state);
   }];
 }
 
@@ -458,7 +461,8 @@ def Bufferization_ToTensorOp : Bufferization_Op<"to_tensor", [
     //===------------------------------------------------------------------===//
 
     LogicalResult bufferize(RewriterBase &rewriter,
-                            const BufferizationOptions &options) const {
+                            const BufferizationOptions &options,
+                            BufferizationState &state) const {
       // to_tensor/to_buffer pairs fold away after bufferization.
       return success();
     }
@@ -550,7 +554,8 @@ def Bufferization_ToBufferOp : Bufferization_Op<"to_buffer", [
     }
 
     LogicalResult bufferize(RewriterBase &rewriter,
-                            const BufferizationOptions &options);
+                            const BufferizationOptions &options,
+                            BufferizationState &state);
   }];
 
   let assemblyFormat = [{
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/BufferUtils.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/BufferUtils.h
index e5f3b6d571f43..c08bd6c436133 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/BufferUtils.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/BufferUtils.h
@@ -29,6 +29,7 @@ class GlobalOp;
 } // namespace memref
 
 namespace bufferization {
+class BufferizationState;
 
 /// A simple analysis that detects allocation operations.
 class BufferPlacementAllocs {
@@ -122,9 +123,14 @@ class BufferPlacementTransformationBase {
 // Globals are created lazily at the top of the enclosing ModuleOp with pretty
 // names. Duplicates are avoided.
 FailureOr<memref::GlobalOp> getGlobalFor(arith::ConstantOp constantOp,
+                                         SymbolTableCollection &symbolTables,
                                          uint64_t alignment,
                                          Attribute memorySpace = {});
 
+void removeSymbol(Operation *op, BufferizationState &state);
+
+void insertSymbol(Operation *op, BufferizationState &state);
+
 } // namespace bufferization
 } // namespace mlir
 
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Bufferize.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/Bufferize.h
index d5cb8d8eb673c..70e3defee0867 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Bufferize.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Bufferize.h
@@ -45,6 +45,7 @@ struct BufferizationStatistics {
 /// additional buffer copies or set "options.copyBeforeWrite = true". The
 /// general bufferization entry point is `runOneShotBufferize`.
 LogicalResult bufferizeOp(Operation *op, const BufferizationOptions &options,
+                          BufferizationState &bufferizationState,
                           BufferizationStatistics *statistics = nullptr);
 
 /// Bufferize the signature of `block` and its callers (i.e., ops that have the
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
index 673027f76190d..15189d2c1cb87 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
@@ -270,6 +270,7 @@ LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state,
 /// Run One-Shot Bufferize on the given op: Analysis + Bufferization
 LogicalResult
 runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options,
+                    BufferizationState &state,
                     BufferizationStatistics *statistics = nullptr);
 
 } // namespace bufferization
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotModuleBufferize.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotModuleBufferize.h
index 4e5f5e9c730fa..2cf801dd1d951 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotModuleBufferize.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotModuleBufferize.h
@@ -20,6 +20,7 @@ namespace bufferization {
 struct BufferizationStatistics;
 class OneShotAnalysisState;
 struct OneShotBufferizationOptions;
+class BufferizationState;
 
 /// Analyze `moduleOp` and its nested ops. Bufferization decisions are stored in
 /// `state`.
@@ -38,6 +39,7 @@ analyzeModuleOp(ModuleOp moduleOp, OneShotAnalysisState &state,
 ///   will be inserted only to these FuncOps.
 llvm::LogicalResult
 bufferizeModuleOp(ModuleOp moduleOp, const OneShotBufferizationOptions &options,
+                  BufferizationState &state,
                   BufferizationStatistics *statistics = nullptr);
 
 /// Remove bufferization attributes on every FuncOp arguments in the ModuleOp.
@@ -50,7 +52,7 @@ void removeBufferizationAttributesInModule(ModuleOp moduleOp);
 llvm::LogicalResult runOneShotModuleBufferize(
     ModuleOp moduleOp,
     const bufferization::OneShotBufferizationOptions &options,
-    BufferizationStatistics *statistics = nullptr);
+    BufferizationState &state, BufferizationStatistics *statistics = nullptr);
 
 } // namespace bufferization
 } // namespace mlir
diff --git a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
index 4f90fc8831bc6..2eef0a06d0eb4 100644
--- a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h
@@ -30,6 +30,7 @@ namespace mlir {
 namespace bufferization {
 class AllocTensorOp;
 class OneShotAnalysisState;
+class BufferizationState;
 } // namespace bufferization
 
 namespace linalg {
diff --git a/mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp
index 5e69a98db8f1e..f646326ffc58f 100644
--- a/mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -24,7 +24,8 @@ struct ConstantOpInterface
     : public BufferizableOpInterface::ExternalModel<ConstantOpInterface,
                                                     arith::ConstantOp> {
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto constantOp = cast<arith::ConstantOp>(op);
     auto type = dyn_cast<RankedTensorType>(constantOp.getType());
 
@@ -46,7 +47,8 @@ struct ConstantOpInterface
     // Create global memory segment and replace tensor with memref pointing to
     // that memory segment.
     FailureOr<memref::GlobalOp> globalOp =
-        getGlobalFor(constantOp, options.bufferAlignment, memorySpace);
+        getGlobalFor(constantOp, state.getSymbolTables(),
+                     options.bufferAlignment, memorySpace);
     if (failed(globalOp))
       return failure();
     memref::GlobalOp globalMemref = *globalOp;
@@ -83,7 +85,8 @@ struct IndexCastOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto castOp = cast<arith::IndexCastOp>(op);
     auto resultTensorType = cast<TensorType>(castOp.getType());
 
@@ -131,7 +134,8 @@ struct SelectOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto selectOp = cast<arith::SelectOp>(op);
     Location loc = selectOp.getLoc();
 
diff --git a/mlir/lib/Dialect/Bufferization/IR/BufferizableOpInterface.cpp b/mlir/lib/Dialect/Bufferization/IR/BufferizableOpInterface.cpp
index 1fc34051680f1..14fa4c1ed8159 100644
--- a/mlir/lib/Dialect/Bufferization/IR/BufferizableOpInterface.cpp
+++ b/mlir/lib/Dialect/Bufferization/IR/BufferizableOpInterface.cpp
@@ -125,6 +125,10 @@ void AnalysisState::resetCache() {
   insideMutuallyExclusiveRegionsCache.clear();
 }
 
+SymbolTableCollection &BufferizationState::getSymbolTables() {
+  return symbolTables;
+}
+
 Region *bufferization::getNextEnclosingRepetitiveRegion(
     Region *region, const BufferizationOptions &options) {
   assert(isRepetitiveRegion(region, options) && "expected repetitive region");
diff --git a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
index ecd2ef15546a4..91eccb0ab7430 100644
--- a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
@@ -149,7 +149,8 @@ void mlir::bufferization::populateDynamicDimSizes(
 //===----------------------------------------------------------------------===//
 
 LogicalResult AllocTensorOp::bufferize(RewriterBase &rewriter,
-                                       const BufferizationOptions &options) {
+                                       const BufferizationOptions &options,
+                                       BufferizationState &state) {
   OpBuilder::InsertionGuard g(rewriter);
   Location loc = getLoc();
 
@@ -529,7 +530,8 @@ void CloneOp::getCanonicalizationPatterns(RewritePatternSet &results,
 //===----------------------------------------------------------------------===//
 
 LogicalResult DeallocTensorOp::bufferize(RewriterBase &rewriter,
-                                         const BufferizationOptions &options) {
+                                         const BufferizationOptions &options,
+                                         BufferizationState &state) {
   FailureOr<Value> buffer = getBuffer(rewriter, getTensor(), options);
   if (failed(buffer))
     return failure();
@@ -576,7 +578,8 @@ MaterializeInDestinationOp::getAliasingValues(OpOperand &opOperand,
 
 LogicalResult
 MaterializeInDestinationOp::bufferize(RewriterBase &rewriter,
-                                      const BufferizationOptions &options) {
+                                      const BufferizationOptions &options,
+                                      BufferizationState &state) {
   bool tensorDest = isa<TensorType>(getDest().getType());
   Value buffer;
   if (tensorDest) {
@@ -861,7 +864,8 @@ void ToBufferOp::getCanonicalizationPatterns(RewritePatternSet &results,
 }
 
 LogicalResult ToBufferOp::bufferize(RewriterBase &rewriter,
-                                    const BufferizationOptions &options) {
+                                    const BufferizationOptions &options,
+                                    BufferizationState &state) {
   // Fold to_buffer(to_tensor(x)) to x. Insert a cast if necessary.
   (void)foldToBufferToTensorPair(rewriter, *this, options);
   // Note: The return value of `bufferize` indicates whether there was an error
diff --git a/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp b/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
index a1d7bb995fc73..db1eb20512033 100644
--- a/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp
@@ -83,6 +83,8 @@ transform::OneShotBufferizeOp::apply(transform::TransformRewriter &rewriter,
   }
 
   auto payloadOps = state.getPayloadOps(getTarget());
+  BufferizationState bufferizationState;
+
   for (Operation *target : payloadOps) {
     if (!isa<ModuleOp, FunctionOpInterface>(target))
       return emitSilenceableError() << "expected module or function target";
@@ -90,10 +92,12 @@ transform::OneShotBufferizeOp::apply(transform::TransformRewriter &rewriter,
     if (options.bufferizeFunctionBoundaries) {
       if (!moduleOp)
         return emitSilenceableError() << "expected module target";
-      if (failed(bufferization::runOneShotModuleBufferize(moduleOp, options)))
+      if (failed(bufferization::runOneShotModuleBufferize(moduleOp, options,
+                                                          bufferizationState)))
         return emitSilenceableError() << "bufferization failed";
     } else {
-      if (failed(bufferization::runOneShotBufferize(target, options)))
+      if (failed(bufferization::runOneShotBufferize(target, options,
+                                                    bufferizationState)))
         return emitSilenceableError() << "bufferization failed";
     }
   }
@@ -162,6 +166,7 @@ class BufferizationTransformDialectExtension
     registerTransformOps<
 #define GET_OP_LIST
 #include "mlir/Dialect/Bufferization/TransformOps/BufferizationTransformOps.cpp.inc"
+
         >();
   }
 };
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/BufferUtils.cpp b/mlir/lib/Dialect/Bufferization/Transforms/BufferUtils.cpp
index c2e90764b1335..ff2c83d228dbb 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/BufferUtils.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/BufferUtils.cpp
@@ -103,8 +103,9 @@ BufferPlacementTransformationBase::BufferPlacementTransformationBase(
 //===----------------------------------------------------------------------===//
 
 FailureOr<memref::GlobalOp>
-bufferization::getGlobalFor(arith::ConstantOp constantOp, uint64_t alignment,
-                            Attribute memorySpace) {
+bufferization::getGlobalFor(arith::ConstantOp constantOp,
+                            SymbolTableCollection &symbolTables,
+                            uint64_t alignment, Attribute memorySpace) {
   auto type = cast<RankedTensorType>(constantOp.getType());
   auto moduleOp = constantOp->getParentOfType<ModuleOp>();
   if (!moduleOp)
@@ -127,7 +128,7 @@ bufferization::getGlobalFor(arith::ConstantOp constantOp, uint64_t alignment,
   // Create a builder without an insertion point. We will insert using the
   // symbol table to guarantee unique names.
   OpBuilder globalBuilder(moduleOp.getContext());
-  SymbolTable symbolTable(moduleOp);
+  SymbolTable &symbolTable = symbolTables.getSymbolTable(moduleOp);
 
   // Create a pretty name.
   SmallString<64> buf;
@@ -158,3 +159,19 @@ bufferization::getGlobalFor(arith::ConstantOp constantOp, uint64_t alignment,
   global->moveBefore(&moduleOp.front());
   return global;
 }
+
+namespace mlir::bufferization {
+void removeSymbol(Operation *op, BufferizationState &state) {
+  SymbolTable &symbolTable = state.getSymbolTables().getSymbolTable(
+      op->getParentWithTrait<OpTrait::SymbolTable>());
+
+  symbolTable.remove(op);
+}
+
+void insertSymbol(Operation *op, BufferizationState &state) {
+  SymbolTable &symbolTable = state.getSymbolTables().getSymbolTable(
+      op->getParentWithTrait<OpTrait::SymbolTable>());
+
+  symbolTable.insert(op);
+}
+} // namespace mlir::bufferization
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
index 824b505517119..67f373d912dd4 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
@@ -161,10 +161,12 @@ struct OneShotBufferizePass
       return signalPassFailure();
     }
 
+    BufferizationState state;
     BufferizationStatistics statistics;
     ModuleOp moduleOp = getOperation();
     if (opt.bufferizeFunctionBoundaries) {
-      if (failed(runOneShotModuleBufferize(moduleOp, opt, &statistics))) {
+      if (failed(
+              runOneShotModuleBufferize(moduleOp, opt, state, &statistics))) {
         signalPassFailure();
         return;
       }
@@ -175,7 +177,7 @@ struct OneShotBufferizePass
                   "'bufferize-function-boundaries'");
         return signalPassFailure();
       }
-      if (failed(runOneShotBufferize(moduleOp, opt, &statistics))) {
+      if (failed(runOneShotBufferize(moduleOp, opt, state, &statistics))) {
         signalPassFailure();
         return;
       }
@@ -275,6 +277,7 @@ class BufferizationRewriter : public IRRewriter, public RewriterBase::Listener {
 
 LogicalResult bufferization::bufferizeOp(Operation *op,
                                          const BufferizationOptions &options,
+                                         BufferizationState &bufferizationState,
                                          BufferizationStatistics *statistics) {
   if (options.copyBeforeWrite) {
     AnalysisState state(options);
@@ -331,7 +334,8 @@ LogicalResult bufferization::bufferizeOp(Operation *op,
                << "//===-------------------------------------------===//\n"
                << "IR after bufferizing: " << nextOp->getName() << "\n");
     rewriter.setInsertionPoint(nextOp);
-    if (failed(bufferizableOp.bufferize(rewriter, options))) {
+    if (failed(
+            bufferizableOp.bufferize(rewriter, options, bufferizationState))) {
       LLVM_DEBUG(llvm::dbgs()
                  << "failed to bufferize\n"
                  << "//===-------------------------------------------===//\n");
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.cpp
index 755477713668e..080796208bfc1 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.cpp
@@ -239,7 +239,8 @@ struct CallOpInterface
   /// All function arguments are writable. It is the responsibility of the
   /// CallOp to insert buffer copies where necessary.
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     func::CallOp callOp = cast<func::CallOp>(op);
 
     // 1. Compute the result types of the new CallOp.
@@ -349,7 +350,8 @@ struct ReturnOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
 #ifndef NDEBUG
     auto returnOp = cast<func::ReturnOp>(op);
     assert(isa<FuncOp>(returnOp->getParentOp()) &&
@@ -418,7 +420,8 @@ struct FuncOpInterface
   /// All function bbArgs are writable unless they are explicitly marked as
   /// read-only. Callers must insert copies when needed.
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto funcOp = cast<FuncOp>(op);
     FunctionType funcType = funcOp.getFunctionType();
 
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
index 6e93b36d2d5a2..de820e9c8f8af 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
@@ -1365,10 +1365,9 @@ LogicalResult bufferization::analyzeOp(Operation *op,
   return success(!failedAnalysis);
 }
 
-LogicalResult
-bufferization::runOneShotBufferize(Operation *op,
-                                   const OneShotBufferizationOptions &options,
-                                   BufferizationStatistics *statistics) {
+LogicalResult bufferization::runOneShotBufferize(
+    Operation *op, const OneShotBufferizationOptions &options,
+    BufferizationState &state, BufferizationStatistics *statistics) {
   // copy-before-write deactivates the analysis. It cannot be used together with
   // test-analysis-only.
   assert(!(options.copyBeforeWrite && options.testAnalysisOnly) &&
@@ -1391,5 +1390,5 @@ bufferization::runOneShotBufferize(Operation *op,
 
   // Bufferize the op and its nested ops. If options.copyBeforeWrite is set,
   // a new buffer copy is allocated every time a buffer is written to.
-  return bufferizeOp(op, options, statistics);
+  return bufferizeOp(op, options, state, statistics);
 }
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OneShotModuleBufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OneShotModuleBufferize.cpp
index a025da8635135..90ceea4d69680 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OneShotModuleBufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OneShotModuleBufferize.cpp
@@ -512,7 +512,7 @@ void mlir::bufferization::removeBufferizationAttributesInModule(
 
 LogicalResult mlir::bufferization::bufferizeModuleOp(
     ModuleOp moduleOp, const OneShotBufferizationOptions &options,
-    BufferizationStatistics *statistics) {
+    BufferizationState &state, BufferizationStatistics *statistics) {
   assert(options.bufferizeFunctionBoundaries &&
          "expected that function boundary bufferization is activated");
   IRRewriter rewriter(moduleOp.getContext());
@@ -548,10 +548,10 @@ LogicalResult mlir::bufferization::bufferizeModuleOp(
       // Buffer copies must be inserted before every write.
       OneShotBufferizationOptions updatedOptions = options;
       updatedOptions.copyBeforeWrite = true;
-      if (failed(bufferizeOp(funcOp, updatedOptions, statistics)))
+      if (failed(bufferizeOp(funcOp, updatedOptions, state, statistics)))
         return failure();
     } else {
-      if (failed(bufferizeOp(funcOp, options, statistics)))
+      if (failed(bufferizeOp(funcOp, options, state, statistics)))
         return failure();
     }
 
@@ -565,7 +565,7 @@ LogicalResult mlir::bufferization::bufferizeModuleOp(
     // Functions were already bufferized.
     if (isa<func::FuncOp>(&op) || op.hasTrait<OpTrait::SymbolTable>())
       continue;
-    if (failed(bufferizeOp(&op, options, statistics)))
+    if (failed(bufferizeOp(&op, options, state, statistics)))
       return failure();
   }
 
@@ -577,7 +577,7 @@ LogicalResult mlir::bufferization::bufferizeModuleOp(
 
 LogicalResult mlir::bufferization::runOneShotModuleBufferize(
     ModuleOp moduleOp, const OneShotBufferizationOptions &options,
-    BufferizationStatistics *statistics) {
+    BufferizationState &state, BufferizationStatistics *statistics) {
   assert(options.bufferizeFunctionBoundaries &&
          "expected that function boundary bufferization is activated");
   assert(!(options.copyBeforeWrite && options.testAnalysisOnly) &&
@@ -606,7 +606,7 @@ LogicalResult mlir::bufferization::runOneShotModuleBufferize(
   }
   if (options.testAnalysisOnly)
     return success();
-  if (failed(bufferizeModuleOp(moduleOp, options, statistics)))
+  if (failed(bufferizeModuleOp(moduleOp, options, state, statistics)))
     return failure();
   return success();
 }
diff --git a/mlir/lib/Dialect/ControlFlow/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/ControlFlow/Transforms/BufferizableOpInterfaceImpl.cpp
index 72f4a1a4f4c66..6a1546fb48683 100644
--- a/mlir/lib/Dialect/ControlFlow/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/ControlFlow/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -43,7 +43,8 @@ struct BranchLikeOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     // The operands of this op are bufferized together with the block signature.
     return success();
   }
diff --git a/mlir/lib/Dialect/Linalg/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/Transforms/BufferizableOpInterfaceImpl.cpp
index be158af09d398..b6a498a57c036 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -148,7 +148,8 @@ struct LinalgOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     return bufferizeDestinationStyleOpInterface(
         rewriter, cast<DestinationStyleOpInterface>(op), options);
   }
@@ -174,7 +175,8 @@ struct SoftmaxOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto softmaxOp = cast<linalg::SoftmaxOp>(op);
     FailureOr<Value> inputBuffer =
         getBuffer(rewriter, softmaxOp.getInput(), options);
@@ -202,6 +204,7 @@ void mlir::linalg::registerBufferizableOpInterfaceExternalModels(
     LinalgOpInterfaceHelper<
 #define GET_OP_LIST
 #include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
+
         >::registerOpInterface(ctx);
 
     SoftmaxOp::attachInterface<SoftmaxOpInterface>(*ctx);
diff --git a/mlir/lib/Dialect/Linalg/Transforms/ConvertToDestinationStyle.cpp b/mlir/lib/Dialect/Linalg/Transforms/ConvertToDestinationStyle.cpp
index a62510deefc4a..94a4b9011c16b 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/ConvertToDestinationStyle.cpp
+++ b/mlir/lib/Dialect/Linalg/Transforms/ConvertToDestinationStyle.cpp
@@ -263,7 +263,11 @@ Value linalg::bufferizeToAllocation(
   assert(llvm::range_size(maskOp.getMaskBlock()->without_terminator()) == 1 &&
          "expected single masked op");
   OpBuilder::InsertionGuard g(rewriter);
+
+  // Should the bufferization options and state be function arguments?
   bufferization::BufferizationOptions bufferizationOptions;
+  bufferization::BufferizationState bufferizationState;
+
   Operation *yieldOp = maskOp.getMaskRegion().front().getTerminator();
   assert(isa<vector::YieldOp>(yieldOp) && "expected yield op terminator");
 
@@ -279,7 +283,7 @@ Value linalg::bufferizeToAllocation(
   // Bufferize terminator.
   rewriter.setInsertionPoint(yieldOp);
   if (failed(cast<bufferization::BufferizableOpInterface>(yieldOp).bufferize(
-          rewriter, bufferizationOptions)))
+          rewriter, bufferizationOptions, bufferizationState)))
     return nullptr;
 
   // Erase dead to_tensor ops inside of the mask op. This is necessary because
@@ -300,8 +304,9 @@ Value linalg::bufferizeToAllocation(
       for (OpOperand &use : result.getUses())
         resultUses.push_back(&use);
   rewriter.setInsertionPoint(maskOp);
-  if (failed(cast<bufferization::BufferizableOpInterface>(maskOp.getOperation())
-                 .bufferize(rewriter, bufferizationOptions)))
+  if (failed(
+          cast<bufferization::BufferizableOpInterface>(maskOp.getOperation())
+              .bufferize(rewriter, bufferizationOptions, bufferizationState)))
     return nullptr;
 
   // Set "restrict" attribute, indicating that no other tensor aliases with
@@ -484,8 +489,11 @@ Value linalg::bufferizeToAllocation(
   auto bufferizableOp = dyn_cast<BufferizableOpInterface>(op);
   if (!bufferizableOp)
     return nullptr;
+
+  // Should the bufferization options and states be function arguments?
   BufferizationOptions bufferizationOptions;
-  AnalysisState state(bufferizationOptions);
+  AnalysisState analysisState(bufferizationOptions);
+  BufferizationState bufferizationState;
 
 #ifndef NDEBUG
   if (!options.bufferizeDestinationOnly) {
@@ -527,7 +535,7 @@ Value linalg::bufferizeToAllocation(
   };
   for (OpResult result : tensorResults) {
     AliasingOpOperandList aliasingOperands =
-        state.getAliasingOpOperands(result);
+        analysisState.getAliasingOpOperands(result);
     for (const AliasingOpOperand &operand : aliasingOperands) {
       addOutOfPlaceOperand(operand.opOperand);
       for (OpOperand &resultUse : result.getUses())
@@ -535,7 +543,7 @@ Value linalg::bufferizeToAllocation(
     }
   }
   for (OpOperand &operand : op->getOpOperands()) {
-    if (!state.bufferizesToMemoryWrite(operand))
+    if (!analysisState.bufferizesToMemoryWrite(operand))
       continue;
     if (!isa<RankedTensorType>(operand.get().getType()))
       continue;
@@ -553,7 +561,7 @@ Value linalg::bufferizeToAllocation(
     Value alloc = createAllocationForTensor(
         rewriter, op->getLoc(), operand->get(), options, memorySpace);
     allocs.push_back(alloc);
-    if (!state.findDefinitions(operand).empty()) {
+    if (!analysisState.findDefinitions(operand).empty()) {
       // Initialize buffer with a copy of the operand data. Not needed if the
       // tensor is uninitialized.
       createMemcpy(rewriter, op->getLoc(), operand->get(), alloc, options);
@@ -575,7 +583,8 @@ Value linalg::bufferizeToAllocation(
 
   // Bufferize the op.
   rewriter.setInsertionPoint(op);
-  if (failed(bufferizableOp.bufferize(rewriter, bufferizationOptions)))
+  if (failed(bufferizableOp.bufferize(rewriter, bufferizationOptions,
+                                      bufferizationState)))
     return nullptr;
 
   // Set "restrict" attribute, indicating that no other tensor aliases with
diff --git a/mlir/lib/Dialect/MLProgram/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/MLProgram/Transforms/BufferizableOpInterfaceImpl.cpp
index 926d580ac7852..a69bc9e5088ae 100644
--- a/mlir/lib/Dialect/MLProgram/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/MLProgram/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -9,6 +9,7 @@
 #include "mlir/Dialect/MLProgram/Transforms/BufferizableOpInterfaceImpl.h"
 
 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
+#include "mlir/Dialect/Bufferization/Transforms/BufferUtils.h"
 #include "mlir/Dialect/MLProgram/IR/MLProgram.h"
 #include "mlir/Dialect/MemRef/IR/MemRef.h"
 
@@ -52,15 +53,18 @@ struct GlobalOpInterface
   bool hasTensorSemantics(Operation *) const { return true; }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &) const {
+                          const BufferizationOptions &,
+                          BufferizationState &state) const {
     auto globalOp = cast<GlobalOp>(op);
     if (!globalOp.getValue().has_value())
       return globalOp.emitError("global op must have a value");
 
+    bufferization::removeSymbol(globalOp, state);
+
     auto tensorType = cast<TensorType>(globalOp.getType());
     auto memrefType = getMemRefTypeWithStaticIdentityLayout(tensorType);
 
-    replaceOpWithNewBufferizedOp<memref::GlobalOp>(
+    auto replacement = replaceOpWithNewBufferizedOp<memref::GlobalOp>(
         rewriter, globalOp, globalOp.getSymName(),
         /*sym_visibility=*/globalOp.getSymVisibilityAttr(),
         /*type=*/cast<MemRefType>(memrefType),
@@ -68,6 +72,7 @@ struct GlobalOpInterface
         /*constant=*/!globalOp.getIsMutable(),
         /*alignment=*/nullptr);
 
+    bufferization::insertSymbol(replacement, state);
     return success();
   }
 };
@@ -91,7 +96,8 @@ struct GlobalLoadOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &) const {
+                          const BufferizationOptions &,
+                          BufferizationState &state) const {
     auto globalLoadOp = cast<GlobalLoadOp>(op);
 
     auto tensorType = cast<TensorType>(globalLoadOp.getType());
@@ -121,7 +127,8 @@ struct GlobalStoreOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto globalStoreOp = cast<GlobalStoreOp>(op);
 
     auto tensorType = cast<TensorType>(globalStoreOp.getValue().getType());
diff --git a/mlir/lib/Dialect/SCF/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/SCF/Transforms/BufferizableOpInterfaceImpl.cpp
index d6a9d8f6401f1..3ff1f5c49aece 100644
--- a/mlir/lib/Dialect/SCF/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/SCF/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -95,7 +95,8 @@ struct ConditionOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto conditionOp = cast<scf::ConditionOp>(op);
     auto whileOp = cast<scf::WhileOp>(conditionOp->getParentOp());
 
@@ -181,7 +182,8 @@ struct ExecuteRegionOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto executeRegionOp = cast<scf::ExecuteRegionOp>(op);
     auto yieldOp = getUniqueYieldOp(executeRegionOp);
     TypeRange newResultTypes(yieldOp.getResults());
@@ -237,7 +239,8 @@ struct IfOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard g(rewriter);
     auto ifOp = cast<scf::IfOp>(op);
 
@@ -347,7 +350,8 @@ struct IndexSwitchOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard g(rewriter);
     auto switchOp = cast<scf::IndexSwitchOp>(op);
 
@@ -722,7 +726,8 @@ struct ForOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto forOp = cast<scf::ForOp>(op);
     Block *oldLoopBody = forOp.getBody();
 
@@ -939,7 +944,8 @@ struct WhileOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto whileOp = cast<scf::WhileOp>(op);
 
     // Indices of all bbArgs that have tensor type. These are the ones that
@@ -1144,7 +1150,8 @@ struct YieldOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto yieldOp = cast<scf::YieldOp>(op);
     if (!isa<scf::ExecuteRegionOp, scf::IfOp, scf::IndexSwitchOp, scf::ForOp,
              scf::WhileOp>(yieldOp->getParentOp()))
@@ -1220,7 +1227,8 @@ struct ForallOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard guard(rewriter);
     auto forallOp = cast<ForallOp>(op);
     int64_t rank = forallOp.getRank();
@@ -1327,7 +1335,8 @@ struct InParallelOpInterface
     : public BufferizableOpInterface::ExternalModel<InParallelOpInterface,
                                                     InParallelOp> {
   LogicalResult bufferize(Operation *op, RewriterBase &b,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     llvm_unreachable("op does not have any tensor OpOperands / OpResults");
     return failure();
   }
diff --git a/mlir/lib/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.cpp
index 6c3b23937f98f..e8cab76d3c753 100644
--- a/mlir/lib/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -47,7 +47,8 @@ struct AssumingOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto assumingOp = cast<shape::AssumingOp>(op);
     assert(llvm::hasSingleElement(assumingOp.getDoRegion().getBlocks()) &&
            "only 1 block supported");
@@ -112,7 +113,8 @@ struct AssumingYieldOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto yieldOp = cast<shape::AssumingYieldOp>(op);
     SmallVector<Value> newResults;
     for (Value value : yieldOp.getOperands()) {
diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/BufferizableOpInterfaceImpl.cpp
index 7734d1d258453..f952b68ba7e67 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -30,7 +30,8 @@ template <typename ConcreteModel, typename ConcreteOp>
 struct SparseBufferizableOpInterfaceExternalModel
     : public BufferizableOpInterface::ExternalModel<ConcreteModel, ConcreteOp> {
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     return op->emitError(
         "sparse_tensor ops must be bufferized with the sparsifier");
   }
diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/SparsificationAndBufferizationPass.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/SparsificationAndBufferizationPass.cpp
index 6e882a8d0ff30..7c7c64f2aef01 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/SparsificationAndBufferizationPass.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/SparsificationAndBufferizationPass.cpp
@@ -114,8 +114,11 @@ class SparsificationAndBufferizationPass
       return false;
     });
 
+    bufferization::BufferizationState bufferizationState;
+
     if (failed(bufferization::bufferizeModuleOp(cast<ModuleOp>(getOperation()),
-                                                updatedOptions)))
+                                                updatedOptions,
+                                                bufferizationState)))
       return failure();
 
     bufferization::removeBufferizationAttributesInModule(getOperation());
diff --git a/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
index b6843e560a899..630e970cd4b19 100644
--- a/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -83,7 +83,8 @@ struct CastOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto castOp = cast<tensor::CastOp>(op);
 
     // The result buffer still has the old (pre-cast) type.
@@ -162,7 +163,8 @@ struct CollapseShapeOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto collapseShapeOp = cast<tensor::CollapseShapeOp>(op);
     RankedTensorType tensorResultType = collapseShapeOp.getResultType();
     FailureOr<Value> maybeBuffer =
@@ -247,7 +249,8 @@ struct DimOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto dimOp = cast<tensor::DimOp>(op);
     FailureOr<Value> v = getBuffer(rewriter, dimOp.getSource(), options);
     if (failed(v))
@@ -271,7 +274,8 @@ struct EmptyOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto emptyOp = cast<tensor::EmptyOp>(op);
 
     // Optimization: Fold away the op if it has no uses.
@@ -329,7 +333,8 @@ struct ExpandShapeOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto expandShapeOp = cast<tensor::ExpandShapeOp>(op);
     auto tensorResultType = expandShapeOp.getResultType();
     FailureOr<Value> buffer =
@@ -367,7 +372,8 @@ struct ExtractSliceOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto extractSliceOp = cast<tensor::ExtractSliceOp>(op);
     SmallVector<OpFoldResult> mixedOffsets = extractSliceOp.getMixedOffsets();
     SmallVector<OpFoldResult> mixedSizes = extractSliceOp.getMixedSizes();
@@ -432,7 +438,8 @@ struct ExtractOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto extractOp = cast<tensor::ExtractOp>(op);
     FailureOr<Value> srcMemref =
         getBuffer(rewriter, extractOp.getTensor(), options);
@@ -474,7 +481,8 @@ struct FromElementsOpInterface
   bool bufferizesToAllocation(Operation *op, Value value) const { return true; }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto fromElementsOp = cast<tensor::FromElementsOp>(op);
     auto tensorType = cast<RankedTensorType>(fromElementsOp.getType());
 
@@ -586,7 +594,8 @@ struct GenerateOpInterface
   bool bufferizesToAllocation(Operation *op, Value value) const { return true; }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto generateOp = cast<tensor::GenerateOp>(op);
 
     auto type = generateOp.getResult().getType();
@@ -620,7 +629,8 @@ struct InsertOpInterface
     : public DstBufferizableOpInterfaceExternalModel<InsertOpInterface,
                                                      tensor::InsertOp> {
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto insertOp = cast<tensor::InsertOp>(op);
     FailureOr<Value> destMemref =
         getBuffer(rewriter, insertOp.getDest(), options);
@@ -670,7 +680,8 @@ struct InsertSliceOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     // insert_slice ops arise from tiling and bufferizing them out-of-place is
     // generally a deal breaker. When used with loops, this ends up cloning the
     // whole tensor on every single iteration and is a symptom of a
@@ -752,7 +763,8 @@ struct PadOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto padOp = cast<tensor::PadOp>(op);
     Location loc = padOp.getLoc();
     RankedTensorType resultType = padOp.getResultType();
@@ -831,7 +843,8 @@ struct RankOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto rankOp = cast<tensor::RankOp>(op);
     FailureOr<Value> v = getBuffer(rewriter, rankOp.getTensor(), options);
     if (failed(v))
@@ -868,7 +881,8 @@ struct ReshapeOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto reshapeOp = cast<tensor::ReshapeOp>(op);
     FailureOr<Value> srcBuffer =
         getBuffer(rewriter, reshapeOp.getSource(), options);
@@ -940,7 +954,8 @@ struct ParallelInsertSliceOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard g(rewriter);
     auto parallelInsertSliceOp = cast<ParallelInsertSliceOp>(op);
     ParallelCombiningOpInterface parallelCombiningParent =
@@ -1015,7 +1030,8 @@ struct SplatOpInterface
   bool bufferizesToAllocation(Operation *op, Value value) const { return true; }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard g(rewriter);
     auto splatOp = cast<tensor::SplatOp>(op);
 
@@ -1073,7 +1089,8 @@ struct ConcatOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     OpBuilder::InsertionGuard g(rewriter);
     auto concatOp = cast<tensor::ConcatOp>(op);
 
diff --git a/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp
index b2272c5fda876..45b6e7c512947 100644
--- a/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -48,7 +48,8 @@ struct TransferReadOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto readOp = cast<vector::TransferReadOp>(op);
     assert(isa<TensorType>(readOp.getShapedType()) &&
            "only tensor types expected");
@@ -103,7 +104,8 @@ struct TransferWriteOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto writeOp = cast<vector::TransferWriteOp>(op);
     assert(isa<TensorType>(writeOp.getShapedType()) &&
            "only tensor types expected");
@@ -148,7 +150,8 @@ struct GatherOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto gatherOp = cast<vector::GatherOp>(op);
     assert(isa<TensorType>(gatherOp.getBaseType()) &&
            "only tensor types expected");
@@ -202,7 +205,8 @@ struct MaskOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto maskOp = cast<vector::MaskOp>(op);
 
     // Do not bufferize if the masked op is not bufferizable.
@@ -279,7 +283,8 @@ struct YieldOpInterface
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
-                          const BufferizationOptions &options) const {
+                          const BufferizationOptions &options,
+                          BufferizationState &state) const {
     auto yieldOp = cast<vector::YieldOp>(op);
 
     // Only supported as a vector.mask terminator.

>From f1cf168a6fbfa28eca2bebb4493966dc63c925c5 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Fri, 23 May 2025 09:23:53 +0200
Subject: [PATCH 097/105] [lldb/cmake] Remove a no-op statement (#141063)

Like the comment says, this really is a no-op and has no effect on the
generated build commands.
---
 lldb/cmake/modules/AddLLDB.cmake | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/lldb/cmake/modules/AddLLDB.cmake b/lldb/cmake/modules/AddLLDB.cmake
index 0a81ec5092185..41f9b28a0ab39 100644
--- a/lldb/cmake/modules/AddLLDB.cmake
+++ b/lldb/cmake/modules/AddLLDB.cmake
@@ -93,13 +93,6 @@ function(add_lldb_library name)
     set(libkind STATIC)
   endif()
 
-  #PIC not needed on Win
-  # FIXME: Setting CMAKE_CXX_FLAGS here is a no-op, use target_compile_options
-  # or omit this logic instead.
-  if (NOT WIN32)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
-  endif()
-
   if (PARAM_OBJECT)
     add_library(${name} ${libkind} ${srcs})
   else()

>From be50ada9d008673a041a5e675f9d9d70a4572aaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Fri, 23 May 2025 09:26:31 +0200
Subject: [PATCH 098/105] [clang][analyzer] Refine modeling of 'getcwd' in
 StdCLibraryFunctions checker (#141076)

Add extra branches for the case when the buffer argument is NULL.

Fixes #135720
---
 .../Checkers/StdLibraryFunctionsChecker.cpp       | 14 ++++++++++----
 clang/test/Analysis/errno-stdlibraryfunctions.c   | 15 ++++++++++++++-
 2 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 3c6c3123f5cdd..6dae817fe89b5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -2651,16 +2651,22 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
     addToFunctionSummaryMap(
         "getcwd", Signature(ArgTypes{CharPtrTy, SizeTy}, RetType{CharPtrTy}),
         Summary(NoEvalCall)
-            .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
+            .Case({NotNull(0),
+                   ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
                    ReturnValueCondition(BO_EQ, ArgNo(0))},
                   ErrnoMustNotBeChecked, GenericSuccessMsg)
-            .Case({ArgumentCondition(1, WithinRange, SingleValue(0)),
+            .Case({NotNull(0),
+                   ArgumentCondition(1, WithinRange, SingleValue(0)),
                    IsNull(Ret)},
                   ErrnoNEZeroIrrelevant, "Assuming that argument 'size' is 0")
-            .Case({ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
+            .Case({NotNull(0),
+                   ArgumentCondition(1, WithinRange, Range(1, SizeMax)),
                    IsNull(Ret)},
                   ErrnoNEZeroIrrelevant, GenericFailureMsg)
-            .ArgConstraint(NotNull(ArgNo(0)))
+            .Case({IsNull(0), NotNull(Ret)}, ErrnoMustNotBeChecked,
+                  GenericSuccessMsg)
+            .Case({IsNull(0), IsNull(Ret)}, ErrnoNEZeroIrrelevant,
+                  GenericFailureMsg)
             .ArgConstraint(
                 BufferSize(/*Buffer*/ ArgNo(0), /*BufSize*/ ArgNo(1)))
             .ArgConstraint(
diff --git a/clang/test/Analysis/errno-stdlibraryfunctions.c b/clang/test/Analysis/errno-stdlibraryfunctions.c
index 657aa37a42670..72d167f68a1f4 100644
--- a/clang/test/Analysis/errno-stdlibraryfunctions.c
+++ b/clang/test/Analysis/errno-stdlibraryfunctions.c
@@ -99,7 +99,9 @@ void errno_mkdtemp3(CHAR_PTR template) {
   }
 }
 
-void errno_getcwd(char *Buf, size_t Sz) {
+void errno_getcwd_buf_nonnull(char *Buf, size_t Sz) {
+  if (Buf == NULL)
+    return;
   char *Path = getcwd(Buf, Sz);
   if (Sz == 0) {
     clang_analyzer_eval(errno != 0);   // expected-warning{{TRUE}}
@@ -114,6 +116,17 @@ void errno_getcwd(char *Buf, size_t Sz) {
   }
 }
 
+void errno_getcwd_buf_null() {
+  // POSIX does not mention this case but many implementations (Linux, FreeBSD) work this way.
+  char *Path = getcwd(NULL, 1);
+  if (Path == NULL) {
+    clang_analyzer_eval(errno != 0);   // expected-warning{{TRUE}}
+    if (errno) {}                      // no warning
+  } else {
+    if (errno) {}                      // expected-warning{{An undefined value may be read from 'errno'}}
+  }
+}
+
 void errno_execv(char *Path, char * Argv[]) {
   int Ret = execv(Path, Argv);
   clang_analyzer_eval(Ret == -1);  // expected-warning{{TRUE}}

>From f4e14bf213972053d6ee4ca0269e42ba2dd2ceba Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at hanshq.net>
Date: Fri, 23 May 2025 09:40:49 +0200
Subject: [PATCH 099/105] [Sema] Warn about omitting deprecated enumerator in
 switch (#138562)

This undoes part of 3e4e3b17c14c15c23c0ed18ca9165b42b1b13ae3 which added
the "Omitting a deprecated constant is ok; it should never materialize."
logic.

That seems wrong: deprecated means the enumerator is likely to be
removed in future versions, not that it cannot materialize.

Also move warnings about the use of deprecated enumerators in switch cases
behind a separate flag, -Wdeprecated-switch-case, for users who wish to
handle such enums explicitly and suppress the warning.
---
 clang/docs/ReleaseNotes.rst                   | 27 ++++++++++++++++
 clang/include/clang/Basic/DiagnosticGroups.td |  3 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 ++
 clang/include/clang/Sema/Sema.h               |  3 ++
 clang/lib/Parse/ParseExpr.cpp                 |  2 ++
 clang/lib/Sema/SemaAvailability.cpp           |  9 ++++--
 clang/lib/Sema/SemaStmt.cpp                   |  6 +++-
 clang/test/Sema/switch-availability.c         | 32 +++++++++++++++++--
 8 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 573ae97bff710..8a4ff6efc6860 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -565,6 +565,33 @@ Improvements to Clang's diagnostics
 
 - Clang now suggests corrections for unknown attribute names.
 
+- ``-Wswitch`` will now diagnose unhandled enumerators in switches also when
+  the enumerator is deprecated. Warnings about using deprecated enumerators in
+  switch cases have moved behind a new ``-Wdeprecated-switch-case`` flag.
+
+  For example:
+
+  .. code-block:: c
+
+    enum E {
+      Red,
+      Green,
+      Blue [[deprecated]]
+    };
+    void example(enum E e) {
+      switch (e) {
+      case Red:   // stuff...
+      case Green: // stuff...
+      }
+    }
+
+  will result in a warning about ``Blue`` not being handled in the switch.
+
+  The warning can be fixed either by adding a ``default:``, or by adding
+  ``case Blue:``. Since the enumerator is deprecated, the latter approach will
+  trigger a ``'Blue' is deprecated`` warning, which can be turned off with
+  ``-Wno-deprecated-switch-case``.
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 616f2555931f5..ff1dfc3e40d1a 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -234,7 +234,8 @@ def DeprecatedCopyWithDtor : DiagGroup<"deprecated-copy-with-dtor", [DeprecatedC
 def DeprecatedLiteralOperator : DiagGroup<"deprecated-literal-operator">;
 // For compatibility with GCC.
 def : DiagGroup<"deprecated-copy-dtor", [DeprecatedCopyWithDtor]>;
-def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
+def DeprecatedSwitchCase : DiagGroup<"deprecated-switch-case">;
+def DeprecatedDeclarations : DiagGroup<"deprecated-declarations", [DeprecatedSwitchCase]>;
 def DeprecatedRedundantConstexprStaticDef : DiagGroup<"deprecated-redundant-constexpr-static-def">;
 def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
 def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 78b36ceb88125..2835e3a9d9960 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6038,6 +6038,8 @@ def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to th
 def err_undeclared_use : Error<"use of undeclared %0">;
 def warn_deprecated : Warning<"%0 is deprecated">,
     InGroup<DeprecatedDeclarations>;
+def warn_deprecated_switch_case : Warning<warn_deprecated.Summary>,
+    InGroup<DeprecatedSwitchCase>;
 def note_from_diagnose_if : Note<"from 'diagnose_if' attribute on %0:">;
 def warn_property_method_deprecated :
     Warning<"property access is using %0 method which is deprecated">,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fe93df94438cb..1091a7f504b57 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6761,6 +6761,9 @@ class Sema final : public SemaBase {
     /// example, in a for-range initializer).
     bool InLifetimeExtendingContext = false;
 
+    /// Whether evaluating an expression for a switch case label.
+    bool IsCaseExpr = false;
+
     /// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
     bool RebuildDefaultArgOrDefaultInit = false;
 
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 11cfbbe790418..951a157305ddc 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -169,6 +169,8 @@ ExprResult Parser::ParseArrayBoundExpression() {
 ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
   EnterExpressionEvaluationContext ConstantEvaluated(
       Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+  Actions.currentEvaluationContext().IsCaseExpr = true;
+
   ExprResult LHS(ParseCastExpression(CastParseKind::AnyCastExpr, false,
                                      TypeCastState::NotTypeCast));
   ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 2e97035d29743..8c6a17301fba6 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -547,8 +547,13 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
     return;
   }
   case AR_Deprecated:
-    diag = !ObjCPropertyAccess ? diag::warn_deprecated
-                               : diag::warn_property_method_deprecated;
+    if (ObjCPropertyAccess)
+      diag = diag::warn_property_method_deprecated;
+    else if (S.currentEvaluationContext().IsCaseExpr)
+      diag = diag::warn_deprecated_switch_case;
+    else
+      diag = diag::warn_deprecated;
+
     diag_message = diag::warn_deprecated_message;
     diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
     property_note_select = /* deprecated */ 0;
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index e8c1f8490342a..b841f994601e3 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -1667,8 +1667,12 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
         // Don't warn about omitted unavailable EnumConstantDecls.
         switch (EI->second->getAvailability()) {
         case AR_Deprecated:
-          // Omitting a deprecated constant is ok; it should never materialize.
+          // Deprecated enumerators need to be handled: they may be deprecated,
+          // but can still occur.
+          break;
+
         case AR_Unavailable:
+          // Omitting an unavailable enumerator is ok; it should never occur.
           continue;
 
         case AR_NotYetIntroduced:
diff --git a/clang/test/Sema/switch-availability.c b/clang/test/Sema/switch-availability.c
index 888edddac463d..517b3f100b24c 100644
--- a/clang/test/Sema/switch-availability.c
+++ b/clang/test/Sema/switch-availability.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -Wswitch -triple x86_64-apple-macosx10.12 %s
+// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -triple x86_64-apple-macosx10.12 %s
+// RUN: %clang_cc1 -verify -Wswitch -Wreturn-type -Wno-deprecated-switch-case -DNO_DEPRECATED_CASE -triple x86_64-apple-macosx10.12 %s
 
 enum SwitchOne {
   Unavail __attribute__((availability(macos, unavailable))),
@@ -15,7 +16,7 @@ enum SwitchTwo {
 };
 
 void testSwitchTwo(enum SwitchTwo st) {
-  switch (st) {} // expected-warning{{enumeration values 'Vim' and 'Emacs' not handled in switch}}
+  switch (st) {} // expected-warning{{enumeration values 'Ed', 'Vim', and 'Emacs' not handled in switch}}
 }
 
 enum SwitchThree {
@@ -25,3 +26,30 @@ enum SwitchThree {
 void testSwitchThree(enum SwitchThree st) {
   switch (st) {} // expected-warning{{enumeration value 'New' not handled in switch}}
 }
+
+enum SwitchFour {
+  Red,
+  Green,
+#ifndef NO_DEPRECATED_CASE
+// expected-note at +2{{'Blue' has been explicitly marked deprecated here}}
+#endif
+  Blue [[deprecated]]
+};
+
+int testSwitchFour(enum SwitchFour e) {
+  switch (e) { // expected-warning{{enumeration value 'Blue' not handled in switch}}
+  case Red:   return 1;
+  case Green: return 2;
+  }
+} // expected-warning{{non-void function does not return a value in all control paths}}
+
+int testSwitchFourCovered(enum SwitchFour e) {
+  switch (e) {
+  case Red:   return 1;
+  case Green: return 2;
+#ifndef NO_DEPRECATED_CASE
+// expected-warning at +2{{'Blue' is deprecated}}
+#endif
+  case Blue:  return 3;
+  } // no warning
+}

>From 62cae9c3de6250476fe0937a4a184b6245ca9c95 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell <benjamin.maxwell at arm.com>
Date: Fri, 23 May 2025 08:43:10 +0100
Subject: [PATCH 100/105] [AArch64] Don't use LowerToPredicatedOp to
 shufflevector -> SVE lowerings (#140713)

The use of `LowerToPredicatedOp` here seems like a mistake as
`LowerToPredicatedOp` turns the SDValue passed to it into the desired
predicated node by copying over operands (and adding a predicate). This
results in two odd things here, the BITCASTs created and passed to
`LowerToPredicatedOp` are not used, only the operands of those bitcasts
are taken. Secondly, when a shuffle vector node is passed directly to
`LowerToPredicatedOp` to create a `REVD_MERGE_PASSTHRU` node an invalid
REV node is created as REV only takes one vector operand, but both
operands from the shuffle vector are copied to the new REV node. This is
not an issue in practice as the extra operand is ignored.

These issues were found by the verification added in #140472.

Part of #140472.

Note: Test changes only result in the vxf64 lowering matching the vxi64
lowering.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 32 +++++++++----------
 .../AArch64/sve-fixed-length-permute-rev.ll   |  3 +-
 ...streaming-mode-fixed-length-permute-rev.ll |  4 +--
 3 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b7f0bcfd015bc..cee27ccf88ef1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -29783,10 +29783,8 @@ SDValue AArch64TargetLowering::LowerFixedLengthVECTOR_SHUFFLEToSVE(
   }
 
   unsigned EltSize = VT.getScalarSizeInBits();
-  for (unsigned LaneSize : {64U, 32U, 16U}) {
-    if (isREVMask(ShuffleMask, EltSize, VT.getVectorNumElements(), LaneSize)) {
-      EVT NewVT =
-          getPackedSVEVectorVT(EVT::getIntegerVT(*DAG.getContext(), LaneSize));
+  for (unsigned BlockSize : {64U, 32U, 16U}) {
+    if (isREVMask(ShuffleMask, EltSize, VT.getVectorNumElements(), BlockSize)) {
       unsigned RevOp;
       if (EltSize == 8)
         RevOp = AArch64ISD::BSWAP_MERGE_PASSTHRU;
@@ -29794,24 +29792,24 @@ SDValue AArch64TargetLowering::LowerFixedLengthVECTOR_SHUFFLEToSVE(
         RevOp = AArch64ISD::REVH_MERGE_PASSTHRU;
       else
         RevOp = AArch64ISD::REVW_MERGE_PASSTHRU;
-
-      Op = DAG.getNode(ISD::BITCAST, DL, NewVT, Op1);
-      Op = LowerToPredicatedOp(Op, DAG, RevOp);
-      Op = DAG.getNode(ISD::BITCAST, DL, ContainerVT, Op);
-      return convertFromScalableVector(DAG, VT, Op);
+      EVT BlockedVT =
+          getPackedSVEVectorVT(EVT::getIntegerVT(*DAG.getContext(), BlockSize));
+      SDValue Pg = getPredicateForVector(DAG, DL, BlockedVT);
+      SDValue BlockedOp1 = DAG.getNode(ISD::BITCAST, DL, BlockedVT, Op1);
+      SDValue BlockedRev = DAG.getNode(RevOp, DL, BlockedVT, Pg, BlockedOp1,
+                                       DAG.getUNDEF(BlockedVT));
+      SDValue Container =
+          DAG.getNode(ISD::BITCAST, DL, ContainerVT, BlockedRev);
+      return convertFromScalableVector(DAG, VT, Container);
     }
   }
 
   if (Subtarget->hasSVE2p1() && EltSize == 64 &&
       isREVMask(ShuffleMask, EltSize, VT.getVectorNumElements(), 128)) {
-    if (!VT.isFloatingPoint())
-      return LowerToPredicatedOp(Op, DAG, AArch64ISD::REVD_MERGE_PASSTHRU);
-
-    EVT NewVT = getPackedSVEVectorVT(EVT::getIntegerVT(*DAG.getContext(), 64));
-    Op = DAG.getNode(ISD::BITCAST, DL, NewVT, Op1);
-    Op = LowerToPredicatedOp(Op, DAG, AArch64ISD::REVD_MERGE_PASSTHRU);
-    Op = DAG.getNode(ISD::BITCAST, DL, ContainerVT, Op);
-    return convertFromScalableVector(DAG, VT, Op);
+    SDValue Pg = getPredicateForVector(DAG, DL, VT);
+    SDValue Revd = DAG.getNode(AArch64ISD::REVD_MERGE_PASSTHRU, DL, ContainerVT,
+                               Pg, Op1, DAG.getUNDEF(ContainerVT));
+    return convertFromScalableVector(DAG, VT, Revd);
   }
 
   unsigned WhichResult;
diff --git a/llvm/test/CodeGen/AArch64/sve-fixed-length-permute-rev.ll b/llvm/test/CodeGen/AArch64/sve-fixed-length-permute-rev.ll
index 0cda4d94444e9..42f9bec94721e 100644
--- a/llvm/test/CodeGen/AArch64/sve-fixed-length-permute-rev.ll
+++ b/llvm/test/CodeGen/AArch64/sve-fixed-length-permute-rev.ll
@@ -227,9 +227,8 @@ define void @test_revdv4f64_sve2p1(ptr %a) #2 {
 ; CHECK-LABEL: test_revdv4f64_sve2p1:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ptrue p0.d, vl4
-; CHECK-NEXT:    ptrue p1.d
 ; CHECK-NEXT:    ld1d { z0.d }, p0/z, [x0]
-; CHECK-NEXT:    revd z0.q, p1/m, z0.q
+; CHECK-NEXT:    revd z0.q, p0/m, z0.q
 ; CHECK-NEXT:    st1d { z0.d }, p0, [x0]
 ; CHECK-NEXT:    ret
   %tmp1 = load <4 x double>, ptr %a
diff --git a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-permute-rev.ll b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-permute-rev.ll
index c364abf2916e8..890bc721128ff 100644
--- a/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-permute-rev.ll
+++ b/llvm/test/CodeGen/AArch64/sve-streaming-mode-fixed-length-permute-rev.ll
@@ -701,7 +701,7 @@ define void @test_revdv4f64_sve2p1(ptr %a) #1 {
 ; CHECK-LABEL: test_revdv4f64_sve2p1:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    ldp q0, q1, [x0]
-; CHECK-NEXT:    ptrue p0.d
+; CHECK-NEXT:    ptrue p0.d, vl2
 ; CHECK-NEXT:    revd z0.q, p0/m, z0.q
 ; CHECK-NEXT:    revd z1.q, p0/m, z1.q
 ; CHECK-NEXT:    stp q0, q1, [x0]
@@ -710,7 +710,7 @@ define void @test_revdv4f64_sve2p1(ptr %a) #1 {
 ; NONEON-NOSVE-LABEL: test_revdv4f64_sve2p1:
 ; NONEON-NOSVE:       // %bb.0:
 ; NONEON-NOSVE-NEXT:    ldp q0, q1, [x0]
-; NONEON-NOSVE-NEXT:    ptrue p0.d
+; NONEON-NOSVE-NEXT:    ptrue p0.d, vl2
 ; NONEON-NOSVE-NEXT:    revd z0.q, p0/m, z0.q
 ; NONEON-NOSVE-NEXT:    revd z1.q, p0/m, z1.q
 ; NONEON-NOSVE-NEXT:    stp q0, q1, [x0]

>From 6bb05ea4b888e7e65f7f4df7e6bb8fd156730404 Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 23 May 2025 09:54:48 +0200
Subject: [PATCH 101/105] [pdb] Tweak the message about overflowing the
 publics/globals record stream

Follow-up to https://github.com/llvm/llvm-project/pull/140884
---
 llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
index 8d684ab0aaf63..09cb355ca7319 100644
--- a/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
@@ -323,8 +323,8 @@ Error GSIStreamBuilder::finalizeMsfLayout() {
   uint64_t RecordBytes = PSH->RecordByteSize + GSH->RecordByteSize;
   if (RecordBytes > UINT32_MAX)
     return make_error<StringError>(
-        formatv("the public ({0} bytes) and global ({1} bytes) "
-                "symbols are too large to fit in a PDB file; "
+        formatv("the public symbols ({0} bytes) and global symbols ({1} bytes) "
+                "are too large to fit in a PDB file; "
                 "the maximum total is {2} bytes.",
                 PSH->RecordByteSize, GSH->RecordByteSize, UINT32_MAX),
         inconvertibleErrorCode());

>From 34deb764a718dd311577995a7aa9ba7d2668896c Mon Sep 17 00:00:00 2001
From: Simon Pilgrim <llvm-dev at redking.me.uk>
Date: Fri, 23 May 2025 09:12:29 +0100
Subject: [PATCH 102/105] [X86] IsElementEquivalent - add handling for
 ISD::BITCASTS from smaller vector elements (#139741)

Check if all smaller aliased source elements are equivalent
---
 llvm/lib/Target/X86/X86ISelLowering.cpp       | 22 ++++++++----
 .../CodeGen/X86/expand-vp-cast-intrinsics.ll  |  6 ++--
 llvm/test/CodeGen/X86/horizontal-sum.ll       | 15 ++++----
 .../CodeGen/X86/vector-half-conversions.ll    | 18 +++++-----
 llvm/test/CodeGen/X86/vector-mul.ll           | 18 ++++------
 .../zero_extend_vector_inreg_of_broadcast.ll  | 34 +++++++++++++------
 6 files changed, 64 insertions(+), 49 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 38be3a82af658..2ce4fa51692b3 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -9987,19 +9987,29 @@ static bool IsElementEquivalent(int MaskSize, SDValue Op, SDValue ExpectedOp,
         MaskSize == (int)ExpectedOp.getNumOperands())
       return Op.getOperand(Idx) == ExpectedOp.getOperand(ExpectedIdx);
     break;
-  case ISD::BITCAST:
-    if (Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize) {
-      SDValue Src = peekThroughBitcasts(Op);
-      EVT SrcVT = Src.getValueType();
-      if (SrcVT.isVector() &&
-          (SrcVT.getScalarSizeInBits() % VT.getScalarSizeInBits()) == 0) {
+  case ISD::BITCAST: {
+    SDValue Src = peekThroughBitcasts(Op);
+    EVT SrcVT = Src.getValueType();
+    if (Op == ExpectedOp && SrcVT.isVector() &&
+        (int)VT.getVectorNumElements() == MaskSize) {
+      if ((SrcVT.getScalarSizeInBits() % VT.getScalarSizeInBits()) == 0) {
         unsigned Scale = SrcVT.getScalarSizeInBits() / VT.getScalarSizeInBits();
         return (Idx % Scale) == (ExpectedIdx % Scale) &&
                IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src,
                                    Idx / Scale, ExpectedIdx / Scale);
       }
+      if ((VT.getScalarSizeInBits() % SrcVT.getScalarSizeInBits()) == 0) {
+        unsigned Scale = VT.getScalarSizeInBits() / SrcVT.getScalarSizeInBits();
+        for (unsigned I = 0; I != Scale; ++I)
+          if (!IsElementEquivalent(SrcVT.getVectorNumElements(), Src, Src,
+                                   (Idx * Scale) + I,
+                                   (ExpectedIdx * Scale) + I))
+            return false;
+        return true;
+      }
     }
     break;
+  }
   case ISD::VECTOR_SHUFFLE: {
     auto *SVN = cast<ShuffleVectorSDNode>(Op);
     return Op == ExpectedOp && (int)VT.getVectorNumElements() == MaskSize &&
diff --git a/llvm/test/CodeGen/X86/expand-vp-cast-intrinsics.ll b/llvm/test/CodeGen/X86/expand-vp-cast-intrinsics.ll
index 632f3c6c1e851..2609b06361af5 100644
--- a/llvm/test/CodeGen/X86/expand-vp-cast-intrinsics.ll
+++ b/llvm/test/CodeGen/X86/expand-vp-cast-intrinsics.ll
@@ -532,10 +532,10 @@ define <2 x half> @vfptrunc_v2f16_v2f64(<2 x double> %a, <2 x i1> %m, i32 zeroex
 ; AVX512-NEXT:    vmovdqa %xmm0, (%rsp) # 16-byte Spill
 ; AVX512-NEXT:    callq __truncdfhf2 at PLT
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vmovdqa (%rsp), %xmm1 # 16-byte Reload
-; AVX512-NEXT:    vpunpckldq {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
+; AVX512-NEXT:    vpblendd $13, (%rsp), %xmm0, %xmm1 # 16-byte Folded Reload
+; AVX512-NEXT:    # xmm1 = mem[0],xmm0[1],mem[2,3]
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vpblendd {{.*#+}} xmm0 = xmm1[0,1],xmm0[2,3]
 ; AVX512-NEXT:    addq $40, %rsp
 ; AVX512-NEXT:    .cfi_def_cfa_offset 8
 ; AVX512-NEXT:    retq
diff --git a/llvm/test/CodeGen/X86/horizontal-sum.ll b/llvm/test/CodeGen/X86/horizontal-sum.ll
index e2cc3ae0dca0a..443275e11459d 100644
--- a/llvm/test/CodeGen/X86/horizontal-sum.ll
+++ b/llvm/test/CodeGen/X86/horizontal-sum.ll
@@ -179,8 +179,8 @@ define <8 x float> @pair_sum_v8f32_v4f32(<4 x float> %0, <4 x float> %1, <4 x fl
 ; SSSE3-SLOW-NEXT:    movlhps {{.*#+}} xmm0 = xmm0[0],xmm2[0]
 ; SSSE3-SLOW-NEXT:    haddps %xmm7, %xmm6
 ; SSSE3-SLOW-NEXT:    haddps %xmm6, %xmm6
-; SSSE3-SLOW-NEXT:    shufps {{.*#+}} xmm2 = xmm2[2,3],xmm6[0,1]
-; SSSE3-SLOW-NEXT:    movaps %xmm2, %xmm1
+; SSSE3-SLOW-NEXT:    movhlps {{.*#+}} xmm6 = xmm2[1],xmm6[1]
+; SSSE3-SLOW-NEXT:    movaps %xmm6, %xmm1
 ; SSSE3-SLOW-NEXT:    retq
 ;
 ; SSSE3-FAST-LABEL: pair_sum_v8f32_v4f32:
@@ -345,8 +345,7 @@ define <8 x i32> @pair_sum_v8i32_v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2,
 ; SSSE3-SLOW-NEXT:    punpcklqdq {{.*#+}} xmm0 = xmm0[0],xmm1[0]
 ; SSSE3-SLOW-NEXT:    phaddd %xmm7, %xmm6
 ; SSSE3-SLOW-NEXT:    phaddd %xmm6, %xmm6
-; SSSE3-SLOW-NEXT:    palignr {{.*#+}} xmm6 = xmm1[8,9,10,11,12,13,14,15],xmm6[0,1,2,3,4,5,6,7]
-; SSSE3-SLOW-NEXT:    movdqa %xmm6, %xmm1
+; SSSE3-SLOW-NEXT:    punpckhqdq {{.*#+}} xmm1 = xmm1[1],xmm6[1]
 ; SSSE3-SLOW-NEXT:    retq
 ;
 ; SSSE3-FAST-LABEL: pair_sum_v8i32_v4i32:
@@ -374,7 +373,7 @@ define <8 x i32> @pair_sum_v8i32_v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2,
 ; AVX1-SLOW-NEXT:    vphaddd %xmm5, %xmm5, %xmm4
 ; AVX1-SLOW-NEXT:    vphaddd %xmm3, %xmm2, %xmm2
 ; AVX1-SLOW-NEXT:    vpshufd {{.*#+}} xmm3 = xmm2[0,2,2,3]
-; AVX1-SLOW-NEXT:    vpunpcklqdq {{.*#+}} xmm3 = xmm3[0],xmm1[0]
+; AVX1-SLOW-NEXT:    vpblendw {{.*#+}} xmm3 = xmm3[0,1,2,3],xmm1[4,5,6,7]
 ; AVX1-SLOW-NEXT:    vpshufd {{.*#+}} xmm5 = xmm4[0,0,0,0]
 ; AVX1-SLOW-NEXT:    vpblendw {{.*#+}} xmm3 = xmm3[0,1,2,3,4,5],xmm5[6,7]
 ; AVX1-SLOW-NEXT:    vshufps {{.*#+}} xmm1 = xmm2[1,3],xmm1[1,3]
@@ -397,7 +396,7 @@ define <8 x i32> @pair_sum_v8i32_v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2,
 ; AVX1-FAST-NEXT:    vphaddd %xmm5, %xmm5, %xmm4
 ; AVX1-FAST-NEXT:    vphaddd %xmm3, %xmm2, %xmm2
 ; AVX1-FAST-NEXT:    vpshufd {{.*#+}} xmm3 = xmm2[0,2,2,3]
-; AVX1-FAST-NEXT:    vpunpcklqdq {{.*#+}} xmm3 = xmm3[0],xmm1[0]
+; AVX1-FAST-NEXT:    vpblendw {{.*#+}} xmm3 = xmm3[0,1,2,3],xmm1[4,5,6,7]
 ; AVX1-FAST-NEXT:    vpshufd {{.*#+}} xmm5 = xmm4[0,0,0,0]
 ; AVX1-FAST-NEXT:    vpblendw {{.*#+}} xmm3 = xmm3[0,1,2,3,4,5],xmm5[6,7]
 ; AVX1-FAST-NEXT:    vshufps {{.*#+}} xmm1 = xmm2[1,3],xmm1[1,3]
@@ -422,7 +421,7 @@ define <8 x i32> @pair_sum_v8i32_v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2,
 ; AVX2-SLOW-NEXT:    vphaddd %xmm5, %xmm5, %xmm4
 ; AVX2-SLOW-NEXT:    vphaddd %xmm3, %xmm2, %xmm2
 ; AVX2-SLOW-NEXT:    vpshufd {{.*#+}} xmm3 = xmm2[0,2,2,3]
-; AVX2-SLOW-NEXT:    vpunpcklqdq {{.*#+}} xmm3 = xmm3[0],xmm1[0]
+; AVX2-SLOW-NEXT:    vpblendd {{.*#+}} xmm3 = xmm3[0,1],xmm1[2,3]
 ; AVX2-SLOW-NEXT:    vpbroadcastd %xmm4, %xmm5
 ; AVX2-SLOW-NEXT:    vpblendd {{.*#+}} xmm3 = xmm3[0,1,2],xmm5[3]
 ; AVX2-SLOW-NEXT:    vshufps {{.*#+}} xmm1 = xmm2[1,3],xmm1[1,1]
@@ -445,7 +444,7 @@ define <8 x i32> @pair_sum_v8i32_v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2,
 ; AVX2-FAST-NEXT:    vphaddd %xmm5, %xmm5, %xmm4
 ; AVX2-FAST-NEXT:    vphaddd %xmm3, %xmm2, %xmm2
 ; AVX2-FAST-NEXT:    vpshufd {{.*#+}} xmm3 = xmm2[0,2,2,3]
-; AVX2-FAST-NEXT:    vpunpcklqdq {{.*#+}} xmm3 = xmm3[0],xmm1[0]
+; AVX2-FAST-NEXT:    vpblendd {{.*#+}} xmm3 = xmm3[0,1],xmm1[2,3]
 ; AVX2-FAST-NEXT:    vpbroadcastd %xmm4, %xmm5
 ; AVX2-FAST-NEXT:    vpblendd {{.*#+}} xmm3 = xmm3[0,1,2],xmm5[3]
 ; AVX2-FAST-NEXT:    vshufps {{.*#+}} xmm1 = xmm2[1,3],xmm1[1,1]
diff --git a/llvm/test/CodeGen/X86/vector-half-conversions.ll b/llvm/test/CodeGen/X86/vector-half-conversions.ll
index 8510b1031d717..1bbf92e45fc6c 100644
--- a/llvm/test/CodeGen/X86/vector-half-conversions.ll
+++ b/llvm/test/CodeGen/X86/vector-half-conversions.ll
@@ -3138,10 +3138,10 @@ define <2 x i16> @cvt_2f64_to_2i16(<2 x double> %a0) nounwind {
 ; AVX512-NEXT:    vmovdqa %xmm0, (%rsp) # 16-byte Spill
 ; AVX512-NEXT:    callq __truncdfhf2 at PLT
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vmovdqa (%rsp), %xmm1 # 16-byte Reload
-; AVX512-NEXT:    vpunpckldq {{.*#+}} xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
+; AVX512-NEXT:    vpblendd $13, (%rsp), %xmm0, %xmm1 # 16-byte Folded Reload
+; AVX512-NEXT:    # xmm1 = mem[0],xmm0[1],mem[2,3]
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vpblendd {{.*#+}} xmm0 = xmm1[0,1],xmm0[2,3]
 ; AVX512-NEXT:    addq $40, %rsp
 ; AVX512-NEXT:    retq
   %1 = fptrunc <2 x double> %a0 to <2 x half>
@@ -3272,8 +3272,8 @@ define <4 x i16> @cvt_4f64_to_4i16(<4 x double> %a0) nounwind {
 ; AVX512-NEXT:    vmovdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; AVX512-NEXT:    callq __truncdfhf2 at PLT
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vmovdqa {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
-; AVX512-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vpblendd $3, {{[-0-9]+}}(%r{{[sb]}}p), %xmm0, %xmm0 # 16-byte Folded Reload
+; AVX512-NEXT:    # xmm0 = mem[0,1],xmm0[2,3]
 ; AVX512-NEXT:    addq $72, %rsp
 ; AVX512-NEXT:    retq
   %1 = fptrunc <4 x double> %a0 to <4 x half>
@@ -3404,8 +3404,8 @@ define <8 x i16> @cvt_4f64_to_8i16_undef(<4 x double> %a0) nounwind {
 ; AVX512-NEXT:    vmovdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; AVX512-NEXT:    callq __truncdfhf2 at PLT
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vmovdqa {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
-; AVX512-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vpblendd $3, {{[-0-9]+}}(%r{{[sb]}}p), %xmm0, %xmm0 # 16-byte Folded Reload
+; AVX512-NEXT:    # xmm0 = mem[0,1],xmm0[2,3]
 ; AVX512-NEXT:    addq $72, %rsp
 ; AVX512-NEXT:    retq
   %1 = fptrunc <4 x double> %a0 to <4 x half>
@@ -4107,8 +4107,8 @@ define void @store_cvt_4f64_to_8i16_undef(<4 x double> %a0, ptr %a1) nounwind {
 ; AVX512-NEXT:    vmovdqa %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
 ; AVX512-NEXT:    callq __truncdfhf2 at PLT
 ; AVX512-NEXT:    vpbroadcastw %xmm0, %xmm0
-; AVX512-NEXT:    vmovdqa {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
-; AVX512-NEXT:    vpunpcklqdq {{.*#+}} xmm0 = xmm1[0],xmm0[0]
+; AVX512-NEXT:    vpblendd $3, {{[-0-9]+}}(%r{{[sb]}}p), %xmm0, %xmm0 # 16-byte Folded Reload
+; AVX512-NEXT:    # xmm0 = mem[0,1],xmm0[2,3]
 ; AVX512-NEXT:    vmovdqa %xmm0, (%rbx)
 ; AVX512-NEXT:    addq $64, %rsp
 ; AVX512-NEXT:    popq %rbx
diff --git a/llvm/test/CodeGen/X86/vector-mul.ll b/llvm/test/CodeGen/X86/vector-mul.ll
index a166bebae721c..98b5bab98c4f9 100644
--- a/llvm/test/CodeGen/X86/vector-mul.ll
+++ b/llvm/test/CodeGen/X86/vector-mul.ll
@@ -1569,11 +1569,12 @@ define <2 x i64> @mul_v2i64_neg_17_65(<2 x i64> %a0) nounwind {
 }
 
 define <2 x i64> @mul_v2i64_0_1(<2 x i64> %a0) nounwind {
-; X86-SSE2-LABEL: mul_v2i64_0_1:
-; X86-SSE2:       # %bb.0:
-; X86-SSE2-NEXT:    xorpd %xmm1, %xmm1
-; X86-SSE2-NEXT:    movsd {{.*#+}} xmm0 = xmm1[0],xmm0[1]
-; X86-SSE2-NEXT:    retl
+; SSE2-LABEL: mul_v2i64_0_1:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    xorps %xmm1, %xmm1
+; SSE2-NEXT:    unpckhpd {{.*#+}} xmm1 = xmm1[1],xmm0[1]
+; SSE2-NEXT:    movaps %xmm1, %xmm0
+; SSE2-NEXT:    ret{{[l|q]}}
 ;
 ; SSE4-LABEL: mul_v2i64_0_1:
 ; SSE4:       # %bb.0:
@@ -1581,13 +1582,6 @@ define <2 x i64> @mul_v2i64_0_1(<2 x i64> %a0) nounwind {
 ; SSE4-NEXT:    blendps {{.*#+}} xmm0 = xmm1[0,1],xmm0[2,3]
 ; SSE4-NEXT:    ret{{[l|q]}}
 ;
-; X64-SSE2-LABEL: mul_v2i64_0_1:
-; X64-SSE2:       # %bb.0:
-; X64-SSE2-NEXT:    xorps %xmm1, %xmm1
-; X64-SSE2-NEXT:    unpckhpd {{.*#+}} xmm1 = xmm1[1],xmm0[1]
-; X64-SSE2-NEXT:    movaps %xmm1, %xmm0
-; X64-SSE2-NEXT:    retq
-;
 ; X64-AVX-LABEL: mul_v2i64_0_1:
 ; X64-AVX:       # %bb.0:
 ; X64-AVX-NEXT:    vxorps %xmm1, %xmm1, %xmm1
diff --git a/llvm/test/CodeGen/X86/zero_extend_vector_inreg_of_broadcast.ll b/llvm/test/CodeGen/X86/zero_extend_vector_inreg_of_broadcast.ll
index fed72ff5c2b39..7fbb211b69ccf 100644
--- a/llvm/test/CodeGen/X86/zero_extend_vector_inreg_of_broadcast.ll
+++ b/llvm/test/CodeGen/X86/zero_extend_vector_inreg_of_broadcast.ll
@@ -7065,17 +7065,29 @@ define void @vec512_i64_widen_to_i256_factor4_broadcast_to_v2i256_factor2(ptr %i
 ; AVX512DQ-NEXT:    vzeroupper
 ; AVX512DQ-NEXT:    retq
 ;
-; AVX512BW-LABEL: vec512_i64_widen_to_i256_factor4_broadcast_to_v2i256_factor2:
-; AVX512BW:       # %bb.0:
-; AVX512BW-NEXT:    vmovdqa (%rdi), %xmm0
-; AVX512BW-NEXT:    vpaddb (%rsi), %xmm0, %xmm0
-; AVX512BW-NEXT:    vpxor %xmm1, %xmm1, %xmm1
-; AVX512BW-NEXT:    vpmovsxbq {{.*#+}} zmm2 = [0,9,2,11,0,13,2,15]
-; AVX512BW-NEXT:    vpermi2q %zmm1, %zmm0, %zmm2
-; AVX512BW-NEXT:    vpaddb (%rdx), %zmm2, %zmm0
-; AVX512BW-NEXT:    vmovdqa64 %zmm0, (%rcx)
-; AVX512BW-NEXT:    vzeroupper
-; AVX512BW-NEXT:    retq
+; AVX512BW-SLOW-LABEL: vec512_i64_widen_to_i256_factor4_broadcast_to_v2i256_factor2:
+; AVX512BW-SLOW:       # %bb.0:
+; AVX512BW-SLOW-NEXT:    vmovdqa (%rdi), %xmm0
+; AVX512BW-SLOW-NEXT:    vpaddb (%rsi), %xmm0, %xmm0
+; AVX512BW-SLOW-NEXT:    vinserti64x4 $1, %ymm0, %zmm0, %zmm0
+; AVX512BW-SLOW-NEXT:    vpxor %xmm1, %xmm1, %xmm1
+; AVX512BW-SLOW-NEXT:    vpunpcklqdq {{.*#+}} zmm0 = zmm0[0],zmm1[0],zmm0[2],zmm1[2],zmm0[4],zmm1[4],zmm0[6],zmm1[6]
+; AVX512BW-SLOW-NEXT:    vpaddb (%rdx), %zmm0, %zmm0
+; AVX512BW-SLOW-NEXT:    vmovdqa64 %zmm0, (%rcx)
+; AVX512BW-SLOW-NEXT:    vzeroupper
+; AVX512BW-SLOW-NEXT:    retq
+;
+; AVX512BW-FAST-LABEL: vec512_i64_widen_to_i256_factor4_broadcast_to_v2i256_factor2:
+; AVX512BW-FAST:       # %bb.0:
+; AVX512BW-FAST-NEXT:    vmovdqa (%rdi), %xmm0
+; AVX512BW-FAST-NEXT:    vpaddb (%rsi), %xmm0, %xmm0
+; AVX512BW-FAST-NEXT:    vpxor %xmm1, %xmm1, %xmm1
+; AVX512BW-FAST-NEXT:    vpmovsxbq {{.*#+}} zmm2 = [0,9,2,11,0,13,2,15]
+; AVX512BW-FAST-NEXT:    vpermi2q %zmm1, %zmm0, %zmm2
+; AVX512BW-FAST-NEXT:    vpaddb (%rdx), %zmm2, %zmm0
+; AVX512BW-FAST-NEXT:    vmovdqa64 %zmm0, (%rcx)
+; AVX512BW-FAST-NEXT:    vzeroupper
+; AVX512BW-FAST-NEXT:    retq
   %in.vec.base = load <64 x i8>, ptr %in.vec.base.ptr, align 64
   %in.vec.bias = load <64 x i8>, ptr %in.vec.bias.ptr, align 64
   %in.vec = add <64 x i8> %in.vec.base, %in.vec.bias

>From f7315585839d834d68ba8efcc7b76e0a05f388bc Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Thu, 3 Apr 2025 13:36:59 +0100
Subject: [PATCH 103/105] [KeyInstr] Complex assignment atoms

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGExprComplex.cpp           | 10 ++++-
 .../test/DebugInfo/KeyInstructions/complex.c  | 40 +++++++++++++++++++
 2 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/complex.c

diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index f556594f4a9ec..600f61f1b325f 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -461,8 +461,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue,
   Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType());
   Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType());
 
-  Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
-  Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
+  auto *R =
+      Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
+  CGF.addInstToCurrentSourceAtom(R, Val.first);
+  auto *I =
+      Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
+  CGF.addInstToCurrentSourceAtom(I, Val.second);
 }
 
 
@@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter::
 EmitCompoundAssignLValue(const CompoundAssignOperator *E,
           ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
                          RValue &Val) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   TestAndClearIgnoreReal();
   TestAndClearIgnoreImag();
   QualType LHSTy = E->getLHS()->getType();
@@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
 }
 
 ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   ComplexPairTy Val;
   LValue LV = EmitBinAssignLValue(E, Val);
 
diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c
new file mode 100644
index 0000000000000..b97314e815bdc
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -0,0 +1,40 @@
+
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+_Complex float ci;
+void test() {
+// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]]
+// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]]
+  _Complex float lc = ci;
+
+// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]]
+// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]]
+  ci = ci;
+
+// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]]
+// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]]
+// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]]
+  ci += ci;
+
+// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]]
+// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]]
+  __imag ci = __imag ci + __imag ci;
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)

>From ec39f2c1ff4e0f8ffb5bedada80d240b8903c183 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Wed, 21 May 2025 14:58:42 +0100
Subject: [PATCH 104/105] cc1

---
 clang/test/DebugInfo/KeyInstructions/complex.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c
index b97314e815bdc..f922e5ff71a58 100644
--- a/clang/test/DebugInfo/KeyInstructions/complex.c
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -1,8 +1,8 @@
 
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o - -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c %s -debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
 
 _Complex float ci;

>From ebd8acdf4ad52d4412d7ed6e7b47ee6179004689 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hyams at sony.com>
Date: Wed, 21 May 2025 15:09:04 +0100
Subject: [PATCH 105/105] whitespace

---
 clang/test/DebugInfo/KeyInstructions/complex.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c b/clang/test/DebugInfo/KeyInstructions/complex.c
index f922e5ff71a58..ff8557afb91e7 100644
--- a/clang/test/DebugInfo/KeyInstructions/complex.c
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -1,4 +1,3 @@
-
 // RUN: %clang_cc1 -gkey-instructions -x c++ %s -debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
 



More information about the llvm-branch-commits mailing list