[clang] [flang] [libc] [llvm] AMDGPU: Add a subtarget feature for fine-grained remote memory support (PR #96442)

Matt Arsenault via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 27 02:10:32 PDT 2024


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/96442

>From f27377ec7f44d7f6c89786892e669fa8af6aa76f Mon Sep 17 00:00:00 2001
From: martinboehme <mboehme at google.com>
Date: Wed, 26 Jun 2024 15:01:57 +0200
Subject: [PATCH 01/19] [clang][dataflow] Teach `AnalysisASTVisitor` that
 `typeid()` can be evaluated. (#96731)

We were previously treating the operand of `typeid()` as being
definitely
unevaluated, but it can be evaluated if it is a glvalue of polymorphic
type.

This patch includes a test that fails without the fix.
---
 .../clang/Analysis/FlowSensitive/ASTOps.h     |  6 ++-
 .../Analysis/FlowSensitive/TransferTest.cpp   | 43 +++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
index 925b99af9141a..f9c923a36ad22 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
@@ -113,7 +113,11 @@ class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
   // nevertheless it appears in the Clang CFG, so we don't exclude it here.
   bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
   bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
-  bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
+  bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
+    if (TIE->isPotentiallyEvaluated())
+      return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE);
+    return true;
+  }
   bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
     return true;
   }
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index e743eefa5d458..39e7001393e5e 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1637,6 +1637,49 @@ TEST(TransferTest, StructModeledFieldsWithAccessor) {
       });
 }
 
+TEST(TransferTest, StructModeledFieldsInTypeid) {
+  // Test that we model fields mentioned inside a `typeid()` expression only if
+  // that expression is potentially evaluated -- i.e. if the expression inside
+  // `typeid()` is a glvalue of polymorphic type (see
+  // `CXXTypeidExpr::isPotentiallyEvaluated()` and [expr.typeid]p3).
+  std::string Code = R"(
+    // Definitions needed for `typeid`.
+    namespace std {
+      class type_info {};
+      class bad_typeid {};
+    }  // namespace std
+
+    struct NonPolymorphic {};
+
+    struct Polymorphic {
+      virtual ~Polymorphic() = default;
+    };
+
+    struct S {
+      NonPolymorphic *NonPoly;
+      Polymorphic *Poly;
+    };
+
+    void target(S &s) {
+      typeid(*s.NonPoly);
+      typeid(*s.Poly);
+      // [[p]]
+    }
+  )";
+  runDataflow(
+      Code,
+      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
+         ASTContext &ASTCtx) {
+        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
+        auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
+        std::vector<const ValueDecl *> Fields;
+        for (auto [Field, _] : SLoc.children())
+          Fields.push_back(Field);
+        EXPECT_THAT(Fields,
+                    UnorderedElementsAre(findValueDecl(ASTCtx, "Poly")));
+      });
+}
+
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = R"(
     struct Base1 {

>From 45af8b7957add870ed455f9e8b818ae4128578ed Mon Sep 17 00:00:00 2001
From: Lucas Duarte Prates <lucas.prates at arm.com>
Date: Wed, 26 Jun 2024 14:28:26 +0100
Subject: [PATCH 02/19] [AArch64] Add ability to list extensions enabled for a
 target (#95805)

This introduces the new `--print-enabled-extensions` command line option
to AArch64, which prints the list of extensions that are enabled for the
target specified by the combination of `--target`/`-march`/`-mcpu`
values.

The goal of the this option is both to enable the manual inspection of
the enabled extensions by users and to enhance the testability of
architecture versions and CPU targets implemented in the compiler.

As part of this change, a new field for `FEAT_*` architecture feature
names was added to the TableGen entries. The output of the existing
`--print-supported-extensions` option was updated accordingly to show
these in a separate column.
---
 clang/include/clang/Driver/Options.td         |   5 +
 .../include/clang/Frontend/FrontendOptions.h  |   4 +
 clang/lib/Driver/Driver.cpp                   |  19 +-
 clang/lib/Driver/ToolChain.cpp                |   8 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   2 +-
 clang/test/CodeGen/aarch64-targetattr.c       |   8 +-
 clang/test/Driver/aarch64-fp16.c              |  78 +--
 clang/test/Driver/aarch64-sve2.c              |   2 +-
 clang/test/Driver/aarch64-v81a.c              |  14 +
 clang/test/Driver/aarch64-v82a.c              |  18 +
 clang/test/Driver/aarch64-v83a.c              |  23 +
 clang/test/Driver/aarch64-v84a.c              |  34 ++
 clang/test/Driver/aarch64-v85a.c              |  42 ++
 clang/test/Driver/aarch64-v86a.c              |  47 ++
 clang/test/Driver/aarch64-v87a.c              |  50 ++
 clang/test/Driver/aarch64-v88a.c              |  53 ++
 clang/test/Driver/aarch64-v89a.c              |  59 ++
 clang/test/Driver/aarch64-v8a.c               |  29 +
 clang/test/Driver/aarch64-v91a.c              |  52 ++
 clang/test/Driver/aarch64-v92a.c              |  55 ++
 clang/test/Driver/aarch64-v93a.c              |  58 ++
 clang/test/Driver/aarch64-v94a.c              |  64 +++
 clang/test/Driver/aarch64-v95a.c              |  67 +++
 clang/test/Driver/aarch64-v9a.c               |  62 ++
 .../test/Driver/print-supported-extensions.c  |   4 +-
 .../Preprocessor/aarch64-target-features.c    |  52 +-
 clang/tools/driver/cc1_main.cpp               |  46 +-
 flang/test/Driver/target-cpu-features.f90     |   4 +-
 llvm/include/llvm/MC/MCSubtargetInfo.h        |   3 +
 .../llvm/TargetParser/AArch64TargetParser.h   |  23 +-
 llvm/lib/MC/MCSubtargetInfo.cpp               |  10 +
 llvm/lib/Target/AArch64/AArch64Features.td    | 542 +++++++++---------
 llvm/lib/TargetParser/AArch64TargetParser.cpp |  60 +-
 .../TargetParser/TargetParserTest.cpp         | 113 ++--
 llvm/utils/TableGen/ARMTargetDefEmitter.cpp   |  14 +-
 35 files changed, 1302 insertions(+), 422 deletions(-)
 create mode 100644 clang/test/Driver/aarch64-v8a.c
 create mode 100644 clang/test/Driver/aarch64-v9a.c

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index dd55838dcf384..724cf3351b88c 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5710,6 +5710,11 @@ def print_supported_extensions : Flag<["-", "--"], "print-supported-extensions">
   Visibility<[ClangOption, CC1Option, CLOption]>,
   HelpText<"Print supported -march extensions (RISC-V, AArch64 and ARM only)">,
   MarshallingInfoFlag<FrontendOpts<"PrintSupportedExtensions">>;
+def print_enabled_extensions : Flag<["-", "--"], "print-enabled-extensions">,
+  Visibility<[ClangOption, CC1Option, CLOption]>,
+  HelpText<"Print the extensions enabled by the given target and -march/-mcpu options."
+           " (AArch64 only)">,
+  MarshallingInfoFlag<FrontendOpts<"PrintEnabledExtensions">>;
 def : Flag<["-"], "mcpu=help">, Alias<print_supported_cpus>;
 def : Flag<["-"], "mtune=help">, Alias<print_supported_cpus>;
 def time : Flag<["-"], "time">,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index ebb8e9e59c6b6..5e5034fe01eb5 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -306,6 +306,10 @@ class FrontendOptions {
   LLVM_PREFERRED_TYPE(bool)
   unsigned PrintSupportedExtensions : 1;
 
+  /// Print the extensions enabled for the current target.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned PrintEnabledExtensions : 1;
+
   /// Show the -version text.
   LLVM_PREFERRED_TYPE(bool)
   unsigned ShowVersion : 1;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 6823f5424cef0..8fa8673b0fd69 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -363,6 +363,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
     // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
   } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) ||
+             (PhaseArg = DAL.getLastArg(options::OPT_print_enabled_extensions)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
@@ -2163,7 +2164,8 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
   if (C.getArgs().hasArg(options::OPT_v) ||
       C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) ||
       C.getArgs().hasArg(options::OPT_print_supported_cpus) ||
-      C.getArgs().hasArg(options::OPT_print_supported_extensions)) {
+      C.getArgs().hasArg(options::OPT_print_supported_extensions) ||
+      C.getArgs().hasArg(options::OPT_print_enabled_extensions)) {
     PrintVersion(C, llvm::errs());
     SuppressMissingInputWarning = true;
   }
@@ -4347,13 +4349,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
   }
 
   for (auto Opt : {options::OPT_print_supported_cpus,
-                   options::OPT_print_supported_extensions}) {
+                   options::OPT_print_supported_extensions,
+                   options::OPT_print_enabled_extensions}) {
     // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a
     // custom Compile phase that prints out supported cpu models and quits.
     //
-    // If --print-supported-extensions is specified, call the helper function
-    // RISCVMarchHelp in RISCVISAInfo.cpp that prints out supported extensions
-    // and quits.
+    // If either --print-supported-extensions or --print-enabled-extensions is
+    // specified, call the corresponding helper function that prints out the
+    // supported/enabled extensions and quits.
     if (Arg *A = Args.getLastArg(Opt)) {
       if (Opt == options::OPT_print_supported_extensions &&
           !C.getDefaultToolChain().getTriple().isRISCV() &&
@@ -4363,6 +4366,12 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
             << "--print-supported-extensions";
         return;
       }
+      if (Opt == options::OPT_print_enabled_extensions &&
+          !C.getDefaultToolChain().getTriple().isAArch64()) {
+        C.getDriver().Diag(diag::err_opt_not_valid_on_target)
+            << "--print-enabled-extensions";
+        return;
+      }
 
       // Use the -mcpu=? flag as the dummy input to cc1.
       Actions.clear();
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 40ab2e91125d1..8f4cc47e418b5 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -195,11 +195,11 @@ static void getAArch64MultilibFlags(const Driver &D,
                                        UnifiedFeatures.end());
   std::vector<std::string> MArch;
   for (const auto &Ext : AArch64::Extensions)
-    if (FeatureSet.contains(Ext.Feature))
-      MArch.push_back(Ext.Name.str());
+    if (FeatureSet.contains(Ext.PosTargetFeature))
+      MArch.push_back(Ext.UserVisibleName.str());
   for (const auto &Ext : AArch64::Extensions)
-    if (FeatureSet.contains(Ext.NegFeature))
-      MArch.push_back(("no" + Ext.Name).str());
+    if (FeatureSet.contains(Ext.NegTargetFeature))
+      MArch.push_back(("no" + Ext.UserVisibleName).str());
   StringRef ArchName;
   for (const auto &ArchInfo : AArch64::ArchInfos)
     if (FeatureSet.contains(ArchInfo->ArchFeature))
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index c0f6bc0c2e45a..1b7cc82ea816e 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1524,7 +1524,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
       auto isPAuthLR = [](const char *member) {
         llvm::AArch64::ExtensionInfo pauthlr_extension =
             llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
-        return pauthlr_extension.Feature == member;
+        return pauthlr_extension.PosTargetFeature == member;
       };
 
       if (std::any_of(CmdArgs.begin(), CmdArgs.end(), isPAuthLR))
diff --git a/clang/test/CodeGen/aarch64-targetattr.c b/clang/test/CodeGen/aarch64-targetattr.c
index 7aabecd1c07b8..e4e0ae7b66afc 100644
--- a/clang/test/CodeGen/aarch64-targetattr.c
+++ b/clang/test/CodeGen/aarch64-targetattr.c
@@ -196,14 +196,14 @@ void minusarch() {}
 // CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+v8.1a,+v8.2a,+v8a" }
 // CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8a" }
 // CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" }
-// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" }
+// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+ete,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+trbe,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" }
 // CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="cortex-a710" }
-// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a" }
+// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+ete,+fp-armv8,+neon,+trbe,+v8a" }
 // CHECK: attributes #[[ATTR7]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="generic" }
 // CHECK: attributes #[[ATTR8]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+v8.1a,+v8.2a,+v8a" "tune-cpu"="cortex-a710" }
 // CHECK: attributes #[[ATTR9]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" "tune-cpu"="cortex-a710" }
-// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" }
-// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" }
+// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" }
+// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" }
 // CHECK: attributes #[[ATTR12]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" }
 // CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16" }
 // CHECK: attributes #[[ATTR14]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
diff --git a/clang/test/Driver/aarch64-fp16.c b/clang/test/Driver/aarch64-fp16.c
index 4da1834cf6876..72ccd79850148 100644
--- a/clang/test/Driver/aarch64-fp16.c
+++ b/clang/test/Driver/aarch64-fp16.c
@@ -21,7 +21,7 @@
 
 // RUN: %clang --target=aarch64 -march=armv8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s
-// GENERICV8A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV8A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s
@@ -35,11 +35,11 @@
 // GENERICV82A-FP16-SAME: {{$}}
 
 // RUN: %clang --target=aarch64 -march=armv8.2-a+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-SPE %s
-// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon"
+// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s
-// GENERICV82A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV82A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s
@@ -51,15 +51,15 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s
-// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fullfp16"{{.*}} "-target-feature" "-fp16fml"
+// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fp16fml"{{.*}} "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s
-// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s
-// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}}  "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon"
+// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}}  "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe"
 // GENERICV82A-FP16-SPE-NOT:  "-target-feature" "{{[+-]}}fp16fml"
 // GENERICV82A-FP16-SPE-SAME: {{$}}
 
@@ -74,7 +74,7 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s
-// GENERICV83A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV83A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s
@@ -88,11 +88,11 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s
-// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s
-// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s
@@ -101,27 +101,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s
-// GENERICV84A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV84A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s
-// GENERICV84A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV84A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s
-// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
+// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s
-// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s
-// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s
-// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s
@@ -130,27 +130,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s
-// GENERICV85A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV85A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s
-// GENERICV85A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV85A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s
-// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
+// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s
-// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s
-// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s
-// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s
@@ -159,27 +159,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s
-// GENERICV86A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV86A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s
-// GENERICV86A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV86A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s
-// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
+// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s
-// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s
-// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s
-// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s
@@ -188,27 +188,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s
-// GENERICV87A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV87A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s
-// GENERICV87A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV87A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s
-// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
+// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s
-// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s
-// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s
-// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s
@@ -217,24 +217,24 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s
-// GENERICV88A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV88A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s
-// GENERICV88A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV88A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s
-// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
+// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s
-// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s
-// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
+// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s
-// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
+// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
diff --git a/clang/test/Driver/aarch64-sve2.c b/clang/test/Driver/aarch64-sve2.c
index c801f44d3cb84..389c3a52bde44 100644
--- a/clang/test/Driver/aarch64-sve2.c
+++ b/clang/test/Driver/aarch64-sve2.c
@@ -5,4 +5,4 @@
 // RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
 // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
 // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
-// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon" "-target-feature" "+sve" "-target-feature" "-sve2"
+// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+sve" "-target-feature" "-sve2"
diff --git a/clang/test/Driver/aarch64-v81a.c b/clang/test/Driver/aarch64-v81a.c
index e84652ec7f11e..b25d7f893cd70 100644
--- a/clang/test/Driver/aarch64-v81a.c
+++ b/clang/test/Driver/aarch64-v81a.c
@@ -19,3 +19,17 @@
 // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
 // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
 // ARM64-GENERICV81A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.1a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v82a.c b/clang/test/Driver/aarch64-v82a.c
index 9dd355934c105..ea599285eea73 100644
--- a/clang/test/Driver/aarch64-v82a.c
+++ b/clang/test/Driver/aarch64-v82a.c
@@ -13,3 +13,21 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s
 // GENERICV82A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v83a.c b/clang/test/Driver/aarch64-v83a.c
index b0ff9fb3abc24..97355c7afe078 100644
--- a/clang/test/Driver/aarch64-v83a.c
+++ b/clang/test/Driver/aarch64-v83a.c
@@ -13,3 +13,26 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s
 // GENERICV83A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.3a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v84a.c b/clang/test/Driver/aarch64-v84a.c
index 030990bfe5131..43790cead3c49 100644
--- a/clang/test/Driver/aarch64-v84a.c
+++ b/clang/test/Driver/aarch64-v84a.c
@@ -13,3 +13,37 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s
 // GENERICV84A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.4a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v85a.c b/clang/test/Driver/aarch64-v85a.c
index 3e1e921dcc013..c964641b580a4 100644
--- a/clang/test/Driver/aarch64-v85a.c
+++ b/clang/test/Driver/aarch64-v85a.c
@@ -13,3 +13,45 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s
 // GENERICV85A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.5a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v86a.c b/clang/test/Driver/aarch64-v86a.c
index ba2b57979b518..53bf8b44ae647 100644
--- a/clang/test/Driver/aarch64-v86a.c
+++ b/clang/test/Driver/aarch64-v86a.c
@@ -13,3 +13,50 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s
 // GENERICV86A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.6a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.6-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v87a.c b/clang/test/Driver/aarch64-v87a.c
index ee4b68882739a..d0c6aff950c95 100644
--- a/clang/test/Driver/aarch64-v87a.c
+++ b/clang/test/Driver/aarch64-v87a.c
@@ -13,3 +13,53 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s
 // GENERICV87A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.7a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.7-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v88a.c b/clang/test/Driver/aarch64-v88a.c
index b680c1f567134..4c1bb28c8b2dc 100644
--- a/clang/test/Driver/aarch64-v88a.c
+++ b/clang/test/Driver/aarch64-v88a.c
@@ -13,3 +13,56 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s
 // GENERICV88A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.8a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HBC
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MOPS
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v89a.c b/clang/test/Driver/aarch64-v89a.c
index 903b793d046ba..cc2021df6c325 100644
--- a/clang/test/Driver/aarch64-v89a.c
+++ b/clang/test/Driver/aarch64-v89a.c
@@ -12,3 +12,62 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s
 // GENERICV89A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.9a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8.9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CHK
+// ARCH-EXTENSION: FEAT_CLRBHB
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSSC
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HBC
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MOPS
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_PRFMSLC
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RASv2
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SPECRES2
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v8a.c b/clang/test/Driver/aarch64-v8a.c
new file mode 100644
index 0000000000000..8f5995f16f3d2
--- /dev/null
+++ b/clang/test/Driver/aarch64-v8a.c
@@ -0,0 +1,29 @@
+// RUN: %clang --target=aarch64_be -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// RUN: %clang --target=aarch64_be -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// RUN: %clang --target=aarch64 -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// RUN: %clang --target=aarch64 -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
+// GENERICV8A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"
+
+// RUN: %clang --target=aarch64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// RUN: %clang --target=aarch64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
+// GENERICV8A: "-cc1"{{.*}} "-triple" "aarch64{{(--)?}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"{{.*}}
+
+// RUN: %clang --target=arm64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
+// RUN: %clang --target=arm64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
+// RUN: %clang --target=arm64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
+// RUN: %clang --target=arm64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
+// ARM64-GENERICV8A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_TRBE
diff --git a/clang/test/Driver/aarch64-v91a.c b/clang/test/Driver/aarch64-v91a.c
index 80853a59d0153..2ea71c63b872c 100644
--- a/clang/test/Driver/aarch64-v91a.c
+++ b/clang/test/Driver/aarch64-v91a.c
@@ -13,3 +13,55 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s
 // GENERICV91A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.1a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v92a.c b/clang/test/Driver/aarch64-v92a.c
index ee644cc6f3c62..89710966d68f7 100644
--- a/clang/test/Driver/aarch64-v92a.c
+++ b/clang/test/Driver/aarch64-v92a.c
@@ -13,3 +13,58 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s
 // GENERICV92A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.2a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v93a.c b/clang/test/Driver/aarch64-v93a.c
index 817559e28ccf4..e048077fe3690 100644
--- a/clang/test/Driver/aarch64-v93a.c
+++ b/clang/test/Driver/aarch64-v93a.c
@@ -13,3 +13,61 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s
 // GENERICV93A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.3a"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HBC
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MOPS
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v94a.c b/clang/test/Driver/aarch64-v94a.c
index 9998cc8a4a216..c55b0fda2feb5 100644
--- a/clang/test/Driver/aarch64-v94a.c
+++ b/clang/test/Driver/aarch64-v94a.c
@@ -13,3 +13,67 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s
 // GENERICV94A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.4a"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CHK
+// ARCH-EXTENSION: FEAT_CLRBHB
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSSC
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HBC
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MOPS
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_PRFMSLC
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RASv2
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SPECRES2
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v95a.c b/clang/test/Driver/aarch64-v95a.c
index 62878f2127626..5d4801f119896 100644
--- a/clang/test/Driver/aarch64-v95a.c
+++ b/clang/test/Driver/aarch64-v95a.c
@@ -25,3 +25,70 @@
 // RUN: %clang -target aarch64 -march=armv9.5a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s
 // RUN: %clang -target aarch64 -march=armv9.5-a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s
 // V95A-TLBIW: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.5a"{{.*}} "-target-feature" "+tlbiw"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AMUv1p1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BF16
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CHK
+// ARCH-EXTENSION: FEAT_CLRBHB
+// ARCH-EXTENSION: FEAT_CPA
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSSC
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ECV
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FAMINMAX
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FGT
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_HBC
+// ARCH-EXTENSION: FEAT_HCX
+// ARCH-EXTENSION: FEAT_I8MM
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_LUT
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MOPS
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_PRFMSLC
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RASv2
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SPECRES2
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
+// ARCH-EXTENSION: FEAT_WFxT
+// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v9a.c b/clang/test/Driver/aarch64-v9a.c
new file mode 100644
index 0000000000000..798bc390086a9
--- /dev/null
+++ b/clang/test/Driver/aarch64-v9a.c
@@ -0,0 +1,62 @@
+// RUN: %clang --target=aarch64 -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// RUN: %clang --target=aarch64 -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
+// GENERICV9A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
+
+// RUN: %clang --target=aarch64_be -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// RUN: %clang --target=aarch64_be -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// RUN: %clang --target=aarch64 -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// RUN: %clang --target=aarch64 -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
+// GENERICV9A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
+
+// ===== Architecture extensions =====
+
+// RUN: %clang -target aarch64 -march=armv9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
+// ARCH-EXTENSION: FEAT_AMUv1
+// ARCH-EXTENSION: FEAT_AdvSIMD
+// ARCH-EXTENSION: FEAT_BTI
+// ARCH-EXTENSION: FEAT_CCIDX
+// ARCH-EXTENSION: FEAT_CRC32
+// ARCH-EXTENSION: FEAT_CSV2_2
+// ARCH-EXTENSION: FEAT_DIT
+// ARCH-EXTENSION: FEAT_DPB
+// ARCH-EXTENSION: FEAT_DPB2
+// ARCH-EXTENSION: FEAT_DotProd
+// ARCH-EXTENSION: FEAT_ETE
+// ARCH-EXTENSION: FEAT_FCMA
+// ARCH-EXTENSION: FEAT_FP
+// ARCH-EXTENSION: FEAT_FP16
+// ARCH-EXTENSION: FEAT_FRINTTS
+// ARCH-EXTENSION: FEAT_FlagM
+// ARCH-EXTENSION: FEAT_FlagM2
+// ARCH-EXTENSION: FEAT_JSCVT
+// ARCH-EXTENSION: FEAT_LOR
+// ARCH-EXTENSION: FEAT_LRCPC
+// ARCH-EXTENSION: FEAT_LRCPC2
+// ARCH-EXTENSION: FEAT_LSE
+// ARCH-EXTENSION: FEAT_LSE2
+// ARCH-EXTENSION: FEAT_MEC
+// ARCH-EXTENSION: FEAT_MPAM
+// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
+// ARCH-EXTENSION: FEAT_PAN
+// ARCH-EXTENSION: FEAT_PAN2
+// ARCH-EXTENSION: FEAT_PAuth
+// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
+// ARCH-EXTENSION: FEAT_RDM
+// ARCH-EXTENSION: FEAT_RME
+// ARCH-EXTENSION: FEAT_SB
+// ARCH-EXTENSION: FEAT_SEL2
+// ARCH-EXTENSION: FEAT_SPECRES
+// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
+// ARCH-EXTENSION: FEAT_SVE
+// ARCH-EXTENSION: FEAT_SVE2
+// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
+// ARCH-EXTENSION: FEAT_TRBE
+// ARCH-EXTENSION: FEAT_TRF
+// ARCH-EXTENSION: FEAT_UAO
+// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/print-supported-extensions.c b/clang/test/Driver/print-supported-extensions.c
index 17894fc0f7ee0..b9b16352f8295 100644
--- a/clang/test/Driver/print-supported-extensions.c
+++ b/clang/test/Driver/print-supported-extensions.c
@@ -4,8 +4,8 @@
 // RUN: %if aarch64-registered-target %{ %clang --target=aarch64-linux-gnu \
 // RUN:   --print-supported-extensions 2>&1 | FileCheck %s --check-prefix AARCH64 %}
 // AARCH64: All available -march extensions for AArch64
-// AARCH64:     Name                Description
-// AARCH64:     aes                 Enable AES support (FEAT_AES, FEAT_PMULL)
+// AARCH64:     Name                Architecture Feature(s)                                Description
+// AARCH64:     aes                 FEAT_AES, FEAT_PMULL                                   Enable AES support
 
 // RUN: %if riscv-registered-target %{ %clang --target=riscv64-linux-gnu \
 // RUN:   --print-supported-extensions 2>&1 | FileCheck %s --check-prefix RISCV %}
diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c
index 6f359461dea88..71cc36acf3f0e 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -315,37 +315,37 @@
 // RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s
 // RUN: %clang -target aarch64 -mcpu=a64fx -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A64FX %s
 // RUN: %clang -target aarch64 -mcpu=carmel -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CARMEL %s
-// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "apple-a13" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon"
-// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+neon" "-target-feature" "+ssbs"
-// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+sve"
-// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lor" "-target-feature" "+neon" "-target-feature" "+pan" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+vh"
+// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3"
+// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+ssbs"
+// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
+// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2
+// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sve"
+// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
 
 // RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s
-// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon" "-target-feature" "+ssbs"
+// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+altnzcv" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fptoint" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+specrestrict" "-target-feature" "+ssbs"
 
 // RUN: %clang -target x86_64-apple-macosx -arch arm64_32 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64_32 %s
-// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2"
 
 // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
 // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nosimd -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-3 %s
-// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+sha2"
 // CHECK-MARCH-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-fp-armv8"{{.*}} "-target-feature" "-neon"
 // CHECK-MARCH-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-neon"
 
@@ -463,8 +463,8 @@
 // RUN: %clang -target aarch64 -mcpu=GENERIC+nocrc+CRC -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-2 %s
 // RUN: %clang -target aarch64 -mcpu=cortex-a53+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-3 %s
 // CHECK-MCPU-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-aes"{{.*}} "-target-feature" "-sha2"
-// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon"
-// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "-sha2" "-target-feature" "-neon"
+// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc"{{.*}} "-target-feature" "+fp-armv8"{{.*}} "-target-feature" "+neon"
+// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "-neon" "-target-feature" "+perfmon" "-target-feature" "-sha2"
 
 // RUN: %clang -target aarch64 -mcpu=cyclone+nocrc+nocrypto -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s
 // RUN: %clang -target aarch64 -march=armv8-a -mcpu=cyclone+nocrc+nocrypto  -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s
@@ -492,9 +492,9 @@
 // RUN: %clang -target aarch64 -march=ARMV8.1A+CRYPTO -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-1 %s
 // RUN: %clang -target aarch64 -march=Armv8.1a+NOcrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-2 %s
 // RUN: %clang -target aarch64 -march=armv8.1a+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-3 %s
-// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
-// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+neon"
-// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-rdm" "-target-feature" "-neon"
+// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm"
+// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-neon" "-target-feature" "-rdm"
 
 // ================== Check Memory Tagging Extensions (MTE).
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8.5-a+memtag -x c -E -dM %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MEMTAG %s
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 2aebc6d3c0178..3c0599c2e5149 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -26,6 +26,7 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/LinkAllPasses.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -148,7 +149,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   if (MachineTriple.isRISCV())
     llvm::riscvExtensionsHelp(DescMap);
   else if (MachineTriple.isAArch64())
-    llvm::AArch64::PrintSupportedExtensions(DescMap);
+    llvm::AArch64::PrintSupportedExtensions();
   else if (MachineTriple.isARM())
     llvm::ARM::PrintSupportedExtensions(DescMap);
   else {
@@ -161,6 +162,45 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   return 0;
 }
 
+static int PrintEnabledExtensions(const TargetOptions& TargetOpts) {
+  std::string Error;
+  const llvm::Target *TheTarget =
+      llvm::TargetRegistry::lookupTarget(TargetOpts.Triple, Error);
+  if (!TheTarget) {
+    llvm::errs() << Error;
+    return 1;
+  }
+
+  // Create a target machine using the input features, the triple information
+  // and a dummy instance of llvm::TargetOptions. Note that this is _not_ the
+  // same as the `clang::TargetOptions` instance we have access to here.
+  llvm::TargetOptions BackendOptions;
+  std::string FeaturesStr = llvm::join(TargetOpts.FeaturesAsWritten, ",");
+  std::unique_ptr<llvm::TargetMachine> TheTargetMachine(
+      TheTarget->createTargetMachine(TargetOpts.Triple, TargetOpts.CPU, FeaturesStr, BackendOptions, std::nullopt));
+  const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
+  const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
+
+  // Extract the feature names that are enabled for the given target.
+  // We do that by capturing the key from the set of SubtargetFeatureKV entries
+  // provided by MCSubtargetInfo, which match the '-target-feature' values.
+  const std::vector<llvm::SubtargetFeatureKV> Features =
+    MCInfo->getEnabledProcessorFeatures();
+  std::set<llvm::StringRef> EnabledFeatureNames;
+  for (const llvm::SubtargetFeatureKV &feature : Features)
+    EnabledFeatureNames.insert(feature.Key);
+
+  if (!MachineTriple.isAArch64()) {
+    // The option was already checked in Driver::HandleImmediateArgs,
+    // so we do not expect to get here if we are not a supported architecture.
+    assert(0 && "Unhandled triple for --print-enabled-extensions option.");
+    return 1;
+  }
+  llvm::AArch64::printEnabledExtensions(EnabledFeatureNames);
+
+  return 0;
+}
+
 int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   ensureSufficientStack();
 
@@ -204,6 +244,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getFrontendOpts().PrintSupportedExtensions)
     return PrintSupportedExtensions(Clang->getTargetOpts().Triple);
 
+  // --print-enabled-extensions takes priority over the actual compilation.
+  if (Clang->getFrontendOpts().PrintEnabledExtensions)
+    return PrintEnabledExtensions(Clang->getTargetOpts());
+
   // Infer the builtin include path if unspecified.
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
diff --git a/flang/test/Driver/target-cpu-features.f90 b/flang/test/Driver/target-cpu-features.f90
index eea7a0f665b34..e78c3516db45a 100644
--- a/flang/test/Driver/target-cpu-features.f90
+++ b/flang/test/Driver/target-cpu-features.f90
@@ -31,11 +31,11 @@
 
 ! CHECK-A57: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-A57-SAME: "-target-cpu" "cortex-a57"
-! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2
 
 ! CHECK-A76: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-A76-SAME: "-target-cpu" "cortex-a76"
-! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+ssbs"
+! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+ssbs"
 
 ! CHECK-ARMV9: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-ARMV9-SAME: "-target-cpu" "generic"
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index ff76435d60843..deb7e2fd1c360 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -240,6 +240,9 @@ class MCSubtargetInfo {
     return ProcFeatures;
   }
 
+  /// Return the list of processor features currently enabled.
+  std::vector<SubtargetFeatureKV> getEnabledProcessorFeatures() const;
+
   /// HwMode IDs are stored and accessed in a bit set format, enabling
   /// users to efficiently retrieve specific IDs, such as the RegInfo
   /// HwMode ID, from the set as required. Using this approach, various
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index a40bca9563cdd..693759a1ccd82 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -22,6 +22,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
 #include <array>
+#include <set>
 #include <vector>
 
 namespace llvm {
@@ -116,12 +117,18 @@ using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
 // SubtargetFeature which may represent either an actual extension or some
 // internal LLVM property.
 struct ExtensionInfo {
-  StringRef Name;                 // Human readable name, e.g. "profile".
+  StringRef UserVisibleName;      // Human readable name used in -march, -cpu
+                                  // and target func attribute, e.g. "profile".
   std::optional<StringRef> Alias; // An alias for this extension, if one exists.
   ArchExtKind ID;                 // Corresponding to the ArchExtKind, this
                                   // extensions representation in the bitfield.
-  StringRef Feature;              // -mattr enable string, e.g. "+spe"
-  StringRef NegFeature;           // -mattr disable string, e.g. "-spe"
+  StringRef ArchFeatureName;      // The feature name defined by the
+                                  // Architecture, e.g. FEAT_AdvSIMD.
+  StringRef Description;          // The textual description of the extension.
+  StringRef PosTargetFeature;     // -target-feature/-mattr enable string,
+                                  // e.g. "+spe".
+  StringRef NegTargetFeature;     // -target-feature/-mattr disable string,
+                                  // e.g. "-spe".
 };
 
 #define EMIT_EXTENSIONS
@@ -286,12 +293,12 @@ struct ExtensionSet {
       Features.emplace_back(T(BaseArch->ArchFeature));
 
     for (const auto &E : Extensions) {
-      if (E.Feature.empty() || !Touched.test(E.ID))
+      if (E.PosTargetFeature.empty() || !Touched.test(E.ID))
         continue;
       if (Enabled.test(E.ID))
-        Features.emplace_back(T(E.Feature));
+        Features.emplace_back(T(E.PosTargetFeature));
       else
-        Features.emplace_back(T(E.NegFeature));
+        Features.emplace_back(T(E.NegTargetFeature));
     }
   }
 
@@ -343,7 +350,9 @@ bool isX18ReservedByDefault(const Triple &TT);
 // themselves, they are sequential (0, 1, 2, 3, ...).
 uint64_t getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
 
-void PrintSupportedExtensions(StringMap<StringRef> DescMap);
+void PrintSupportedExtensions();
+
+void printEnabledExtensions(std::set<StringRef> EnabledFeatureNames);
 
 } // namespace AArch64
 } // namespace llvm
diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp
index cf3aba17fc3d4..1de0a9f66669a 100644
--- a/llvm/lib/MC/MCSubtargetInfo.cpp
+++ b/llvm/lib/MC/MCSubtargetInfo.cpp
@@ -336,6 +336,16 @@ void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const {
                                   ForwardingPaths);
 }
 
+std::vector<SubtargetFeatureKV>
+MCSubtargetInfo::getEnabledProcessorFeatures() const {
+  std::vector<SubtargetFeatureKV> EnabledFeatures;
+  auto IsEnabled = [&](const SubtargetFeatureKV &FeatureKV) {
+    return FeatureBits.test(FeatureKV.Value);
+  };
+  llvm::copy_if(ProcFeatures, std::back_inserter(EnabledFeatures), IsEnabled);
+  return EnabledFeatures;
+}
+
 std::optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const {
   return std::nullopt;
 }
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 8c1003c085e63..8ec06ac0aef15 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -9,28 +9,46 @@
 //
 //===----------------------------------------------------------------------===//
 
-// A SubtargetFeature that can be toggled from the command line, and therefore
-// has an AEK_* entry in ArmExtKind.
+// A SubtargetFeature that represents one or more Architecture Extensions, as
+// defined by the Arm ARM and tipically identified by a 'FEAT_*' name.
+// Each Extension record defines an ExtensionInfo entry in the Target Parser
+// with a corresponding 'AEK_*' entry in the ArchExtKind enum.
 class Extension<
-  string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
+  string TargetFeatureName,            // String used for -target-feature, unless overridden.
   string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
+  string ArchitectureFeatureName,      // The extension's "FEAT_*"" name(s) defined by the architecture
   string Desc,                         // Description.
   list<SubtargetFeature> Implies = []  // List of dependent features.
 > : SubtargetFeature<TargetFeatureName, "Has" # Spelling, "true", Desc, Implies>
 {
     string ArchExtKindSpelling = "AEK_" # Spelling; // ArchExtKind enum name.
 
-    // In general, the name written on the command line should match the name
-    // used for -target-feature. However, there are exceptions. Therefore we
-    // add a separate field for this, to allow overriding it. Strongly prefer
-    // not doing so.
-    string MArchName = TargetFeatureName;
+    string ArchFeatureName = ArchitectureFeatureName;
+
+    // The user visible name used by -march/-mcpu modifiers and target attribute
+    // values. Extensions are not available on these by default.
+    string UserVisibleName = "";
 
     // An alias that can be used on the command line, if the extension has one.
     // Used for correcting historical names while remaining backwards compatible.
-    string MArchAlias = "";
+    string UserVisibleAlias = "";
 }
 
+// An Extension that can be toggled via a '-march'/'-mcpu' modifier or a target
+// attribute, e.g. '+sm4".
+class ExtensionWithMArch<
+  string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
+  string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
+  string ArchitectureFeatureName,      // The extension's "FEAT_*"" name(s) defined by the architecture
+  string Desc,                         // Description.
+  list<SubtargetFeature> Implies = []  // List of dependent features.
+> : Extension<TargetFeatureName, Spelling, ArchitectureFeatureName, Desc, Implies> {
+    // In general, the name written on the command line should match the name
+    // used for -target-feature. However, there are exceptions. Therefore we
+    // add a separate field for this, to allow overriding it. Strongly prefer
+    // not doing so.
+    let UserVisibleName = TargetFeatureName;
+}
 
 
 
@@ -45,21 +63,19 @@ class Extension<
 //  Armv8.0 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-let ArchExtKindSpelling = "AEK_FP", MArchName = "fp" in
-def FeatureFPARMv8 : Extension<"fp-armv8", "FPARMv8",
-  "Enable ARMv8 (FEAT_FP)">;
+let ArchExtKindSpelling = "AEK_FP", UserVisibleName = "fp" in
+def FeatureFPARMv8 : ExtensionWithMArch<"fp-armv8", "FPARMv8", "FEAT_FP",
+  "Enable ARMv8">;
 
-let ArchExtKindSpelling = "AEK_SIMD", MArchName = "simd" in
-def FeatureNEON : Extension<"neon", "NEON",
-  "Enable Advanced SIMD instructions (FEAT_AdvSIMD)", [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_SIMD", UserVisibleName = "simd" in
+def FeatureNEON : ExtensionWithMArch<"neon", "NEON", "FEAT_AdvSIMD",
+  "Enable Advanced SIMD instructions", [FeatureFPARMv8]>;
 
-def FeatureSHA2 : Extension<
-    "sha2", "SHA2",
-    "Enable SHA1 and SHA256 support (FEAT_SHA1, FEAT_SHA256)", [FeatureNEON]>;
+def FeatureSHA2 : ExtensionWithMArch<"sha2", "SHA2", "FEAT_SHA1, FEAT_SHA256",
+  "Enable SHA1 and SHA256 support", [FeatureNEON]>;
 
-def FeatureAES : Extension<
-    "aes", "AES",
-    "Enable AES support (FEAT_AES, FEAT_PMULL)", [FeatureNEON]>;
+def FeatureAES : ExtensionWithMArch<"aes", "AES", "FEAT_AES, FEAT_PMULL",
+  "Enable AES support", [FeatureNEON]>;
 
 // Crypto has been split up and any combination is now valid (see the
 // crypto definitions above). Also, crypto is now context sensitive:
@@ -69,289 +85,271 @@ def FeatureAES : Extension<
 // meaning anymore. We kept the Crypto definition here for backward
 // compatibility, and now imply features SHA2 and AES, which was the
 // "traditional" meaning of Crypto.
-def FeatureCrypto : Extension<"crypto", "Crypto",
+def FeatureCrypto : ExtensionWithMArch<"crypto", "Crypto", "FEAT_Crypto",
   "Enable cryptographic instructions", [FeatureNEON, FeatureSHA2, FeatureAES]>;
 
-def FeatureCRC : Extension<"crc", "CRC",
-  "Enable ARMv8 CRC-32 checksum instructions (FEAT_CRC32)">;
+def FeatureCRC : ExtensionWithMArch<"crc", "CRC", "FEAT_CRC32",
+  "Enable ARMv8 CRC-32 checksum instructions">;
 
 // This SubtargetFeature is special. It controls only whether codegen will turn
 // `llvm.readcyclecounter()` into an access to a PMUv3 System Register. The
 // `FEAT_PMUv3*` system registers are always available for assembly/disassembly.
-let MArchName = "pmuv3" in
-def FeaturePerfMon : Extension<"perfmon", "PerfMon",
-  "Enable Code Generation for ARMv8 PMUv3 Performance Monitors extension (FEAT_PMUv3)">;
+let UserVisibleName = "pmuv3" in
+def FeaturePerfMon : ExtensionWithMArch<"perfmon", "PerfMon", "FEAT_PMUv3",
+  "Enable Code Generation for ARMv8 PMUv3 Performance Monitors extension">;
 
-def FeatureSpecRestrict : SubtargetFeature<"specrestrict", "HasSpecRestrict",
-  "true", "Enable architectural speculation restriction (FEAT_CSV2_2)">;
+def FeatureSpecRestrict : Extension<"specrestrict", "SpecRestrict", "FEAT_CSV2_2",
+  "Enable architectural speculation restriction">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.1 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureLSE : Extension<"lse", "LSE",
-  "Enable ARMv8.1 Large System Extension (LSE) atomic instructions (FEAT_LSE)">;
+def FeatureLSE : ExtensionWithMArch<"lse", "LSE", "FEAT_LSE",
+  "Enable ARMv8.1 Large System Extension (LSE) atomic instructions">;
 
-let MArchAlias = "rdma" in
-def FeatureRDM : Extension<"rdm", "RDM",
-  "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions (FEAT_RDM)",
+let UserVisibleAlias = "rdma" in
+def FeatureRDM : ExtensionWithMArch<"rdm", "RDM", "FEAT_RDM",
+  "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions",
   [FeatureNEON]>;
 
-def FeaturePAN : SubtargetFeature<
-    "pan", "HasPAN", "true",
-    "Enables ARM v8.1 Privileged Access-Never extension (FEAT_PAN)">;
+def FeaturePAN : Extension<"pan", "PAN", "FEAT_PAN",
+  "Enables ARM v8.1 Privileged Access-Never extension">;
 
-def FeatureLOR : SubtargetFeature<
-    "lor", "HasLOR", "true",
-    "Enables ARM v8.1 Limited Ordering Regions extension (FEAT_LOR)">;
+def FeatureLOR : Extension<"lor", "LOR", "FEAT_LOR",
+  "Enables ARM v8.1 Limited Ordering Regions extension">;
 
 def FeatureCONTEXTIDREL2 : SubtargetFeature<"CONTEXTIDREL2", "HasCONTEXTIDREL2",
-    "true", "Enable RW operand CONTEXTIDR_EL2" >;
+  "true", "Enable RW operand CONTEXTIDR_EL2">;
 
-def FeatureVH : SubtargetFeature<"vh", "HasVH", "true",
-    "Enables ARM v8.1 Virtual Host extension (FEAT_VHE)", [FeatureCONTEXTIDREL2] >;
+def FeatureVH : Extension<"vh", "VH", "FEAT_VHE",
+  "Enables ARM v8.1 Virtual Host extension", [FeatureCONTEXTIDREL2]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.2 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSM4 : Extension<
-    "sm4", "SM4",
-    "Enable SM3 and SM4 support (FEAT_SM4, FEAT_SM3)", [FeatureNEON]>;
+def FeatureSM4 : ExtensionWithMArch<"sm4", "SM4", "FEAT_SM4, FEAT_SM3",
+  "Enable SM3 and SM4 support", [FeatureNEON]>;
 
-def FeatureSHA3 : Extension<
-    "sha3", "SHA3",
-    "Enable SHA512 and SHA3 support (FEAT_SHA3, FEAT_SHA512)", [FeatureNEON, FeatureSHA2]>;
+def FeatureSHA3 : ExtensionWithMArch<"sha3", "SHA3", "FEAT_SHA3, FEAT_SHA512",
+  "Enable SHA512 and SHA3 support", [FeatureNEON, FeatureSHA2]>;
 
-def FeatureRAS : Extension<"ras", "RAS",
-  "Enable ARMv8 Reliability, Availability and Serviceability Extensions (FEAT_RAS, FEAT_RASv1p1)">;
+def FeatureRAS : ExtensionWithMArch<"ras", "RAS", "FEAT_RAS, FEAT_RASv1p1",
+  "Enable ARMv8 Reliability, Availability and Serviceability Extensions">;
 
-let ArchExtKindSpelling = "AEK_FP16", MArchName = "fp16" in
-def FeatureFullFP16 : Extension<"fullfp16", "FullFP16",
-  "Full FP16 (FEAT_FP16)", [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_FP16", UserVisibleName = "fp16" in
+def FeatureFullFP16 : ExtensionWithMArch<"fullfp16", "FullFP16", "FEAT_FP16",
+  "Full FP16", [FeatureFPARMv8]>;
 
-let ArchExtKindSpelling = "AEK_PROFILE", MArchName = "profile" in
-def FeatureSPE : Extension<"spe", "SPE",
-  "Enable Statistical Profiling extension (FEAT_SPE)">;
+let ArchExtKindSpelling = "AEK_PROFILE", UserVisibleName = "profile" in
+def FeatureSPE : ExtensionWithMArch<"spe", "SPE", "FEAT_SPE",
+  "Enable Statistical Profiling extension">;
 
-def FeaturePAN_RWV : SubtargetFeature<
-    "pan-rwv", "HasPAN_RWV", "true",
-    "Enable v8.2 PAN s1e1R and s1e1W Variants (FEAT_PAN2)",
-    [FeaturePAN]>;
+def FeaturePAN_RWV : Extension<"pan-rwv", "PAN_RWV", "FEAT_PAN2",
+  "Enable v8.2 PAN s1e1R and s1e1W Variants", [FeaturePAN]>;
 
-def FeaturePsUAO : SubtargetFeature< "uaops", "HasPsUAO", "true",
-    "Enable v8.2 UAO PState (FEAT_UAO)">;
+def FeaturePsUAO : Extension<"uaops", "PsUAO", "FEAT_UAO",
+  "Enable v8.2 UAO PState">;
 
-def FeatureCCPP : SubtargetFeature<"ccpp", "HasCCPP",
-    "true", "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)" >;
+def FeatureCCPP : Extension<"ccpp", "CCPP", "FEAT_DPB",
+  "Enable v8.2 data Cache Clean to Point of Persistence">;
 
-def FeatureSVE : Extension<"sve", "SVE",
-  "Enable Scalable Vector Extension (SVE) instructions (FEAT_SVE)", [FeatureFullFP16]>;
+def FeatureSVE : ExtensionWithMArch<"sve", "SVE", "FEAT_SVE",
+  "Enable Scalable Vector Extension (SVE) instructions", [FeatureFullFP16]>;
 
 let ArchExtKindSpelling = "AEK_I8MM" in
-def FeatureMatMulInt8 : Extension<"i8mm", "MatMulInt8",
-    "Enable Matrix Multiply Int8 Extension (FEAT_I8MM)", []>;
+def FeatureMatMulInt8 : ExtensionWithMArch<"i8mm", "MatMulInt8", "FEAT_I8MM",
+  "Enable Matrix Multiply Int8 Extension">;
 
 let ArchExtKindSpelling = "AEK_F32MM" in
-def FeatureMatMulFP32 : Extension<"f32mm", "MatMulFP32",
-    "Enable Matrix Multiply FP32 Extension (FEAT_F32MM)", [FeatureSVE]>;
+def FeatureMatMulFP32 : ExtensionWithMArch<"f32mm", "MatMulFP32", "FEAT_F32MM",
+  "Enable Matrix Multiply FP32 Extension", [FeatureSVE]>;
 
 let ArchExtKindSpelling = "AEK_F64MM" in
-def FeatureMatMulFP64 : Extension<"f64mm", "MatMulFP64",
-    "Enable Matrix Multiply FP64 Extension (FEAT_F64MM)", [FeatureSVE]>;
+def FeatureMatMulFP64 : ExtensionWithMArch<"f64mm", "MatMulFP64", "FEAT_F64MM",
+  "Enable Matrix Multiply FP64 Extension", [FeatureSVE]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.3 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureRCPC : Extension<"rcpc", "RCPC",
-    "Enable support for RCPC extension (FEAT_LRCPC)", []>;
+def FeatureRCPC : ExtensionWithMArch<"rcpc", "RCPC", "FEAT_LRCPC",
+  "Enable support for RCPC extension">;
 
-def FeaturePAuth : Extension<
-    "pauth", "PAuth",
-    "Enable v8.3-A Pointer Authentication extension (FEAT_PAuth)">;
+def FeaturePAuth : ExtensionWithMArch<"pauth", "PAuth", "FEAT_PAuth",
+  "Enable v8.3-A Pointer Authentication extension">;
 
-let ArchExtKindSpelling = "AEK_JSCVT", MArchName = "jscvt" in
-def FeatureJS : Extension<
-    "jsconv", "JS",
-    "Enable v8.3-A JavaScript FP conversion instructions (FEAT_JSCVT)",
-    [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_JSCVT", UserVisibleName = "jscvt" in
+def FeatureJS : ExtensionWithMArch<"jsconv", "JS", "FEAT_JSCVT",
+  "Enable v8.3-A JavaScript FP conversion instructions",
+  [FeatureFPARMv8]>;
 
-def FeatureCCIDX : SubtargetFeature<
-    "ccidx", "HasCCIDX", "true",
-    "Enable v8.3-A Extend of the CCSIDR number of sets (FEAT_CCIDX)">;
+def FeatureCCIDX : Extension<"ccidx", "CCIDX", "FEAT_CCIDX",
+  "Enable v8.3-A Extend of the CCSIDR number of sets">;
 
-let ArchExtKindSpelling = "AEK_FCMA", MArchName = "fcma" in
-def FeatureComplxNum : Extension<
-    "complxnum", "ComplxNum",
-    "Enable v8.3-A Floating-point complex number support (FEAT_FCMA)",
-    [FeatureNEON]>;
+let ArchExtKindSpelling = "AEK_FCMA", UserVisibleName = "fcma" in
+def FeatureComplxNum : ExtensionWithMArch<"complxnum", "ComplxNum", "FEAT_FCMA",
+  "Enable v8.3-A Floating-point complex number support",
+  [FeatureNEON]>;
 
-def FeatureNV : SubtargetFeature<
-    "nv", "HasNV", "true",
-    "Enable v8.4-A Nested Virtualization Enchancement (FEAT_NV, FEAT_NV2)">;
+def FeatureNV : Extension<"nv", "NV", "FEAT_NV, FEAT_NV2",
+  "Enable v8.4-A Nested Virtualization Enchancement">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.4 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureLSE2 : SubtargetFeature<"lse2", "HasLSE2", "true",
-  "Enable ARMv8.4 Large System Extension 2 (LSE2) atomicity rules (FEAT_LSE2)">;
+def FeatureLSE2 : Extension<"lse2", "LSE2", "FEAT_LSE2",
+  "Enable ARMv8.4 Large System Extension 2 (LSE2) atomicity rules">;
 
-def FeatureFP16FML : Extension<"fp16fml", "FP16FML",
-  "Enable FP16 FML instructions (FEAT_FHM)", [FeatureFullFP16]>;
+def FeatureFP16FML : ExtensionWithMArch<"fp16fml", "FP16FML", "FEAT_FHM",
+  "Enable FP16 FML instructions", [FeatureFullFP16]>;
 
-def FeatureDotProd : Extension<
-    "dotprod", "DotProd",
-    "Enable dot product support (FEAT_DotProd)", [FeatureNEON]>;
+def FeatureDotProd : ExtensionWithMArch<"dotprod", "DotProd", "FEAT_DotProd",
+  "Enable dot product support", [FeatureNEON]>;
 
-def FeatureMPAM : SubtargetFeature<
-    "mpam", "HasMPAM", "true",
-    "Enable v8.4-A Memory system Partitioning and Monitoring extension (FEAT_MPAM)">;
+def FeatureMPAM : Extension<"mpam", "MPAM", "FEAT_MPAM",
+  "Enable v8.4-A Memory system Partitioning and Monitoring extension">;
 
-def FeatureDIT : SubtargetFeature<
-    "dit", "HasDIT", "true",
-    "Enable v8.4-A Data Independent Timing instructions (FEAT_DIT)">;
+def FeatureDIT : ExtensionWithMArch<"dit", "DIT", "FEAT_DIT",
+  "Enable v8.4-A Data Independent Timing instructions">;
 
-def FeatureTRACEV8_4 : SubtargetFeature<
-    "tracev8.4", "HasTRACEV8_4", "true",
-    "Enable v8.4-A Trace extension (FEAT_TRF)">;
+def FeatureTRACEV8_4 : Extension<"tracev8.4", "TRACEV8_4", "FEAT_TRF",
+  "Enable v8.4-A Trace extension">;
 
-def FeatureAM : SubtargetFeature<
-    "am", "HasAM", "true",
-    "Enable v8.4-A Activity Monitors extension (FEAT_AMUv1)">;
+def FeatureAM : Extension<"am", "AM", "FEAT_AMUv1",
+  "Enable v8.4-A Activity Monitors extension">;
 
-def FeatureSEL2 : SubtargetFeature<
-    "sel2", "HasSEL2", "true",
-    "Enable v8.4-A Secure Exception Level 2 extension (FEAT_SEL2)">;
+def FeatureSEL2 : Extension<"sel2", "SEL2", "FEAT_SEL2",
+  "Enable v8.4-A Secure Exception Level 2 extension">;
 
-def FeatureTLB_RMI : SubtargetFeature<
-    "tlb-rmi", "HasTLB_RMI", "true",
-    "Enable v8.4-A TLB Range and Maintenance Instructions (FEAT_TLBIOS, FEAT_TLBIRANGE)">;
+def FeatureTLB_RMI : Extension<"tlb-rmi", "TLB_RMI",
+  "FEAT_TLBIOS, FEAT_TLBIRANGE",
+  "Enable v8.4-A TLB Range and Maintenance Instructions">;
 
-def FeatureFlagM : Extension<
-    "flagm", "FlagM",
-    "Enable v8.4-A Flag Manipulation Instructions (FEAT_FlagM)", []>;
+def FeatureFlagM : ExtensionWithMArch<"flagm", "FlagM", "FEAT_FlagM",
+  "Enable v8.4-A Flag Manipulation Instructions">;
 
-def FeatureRCPC_IMMO : SubtargetFeature<"rcpc-immo", "HasRCPC_IMMO", "true",
-    "Enable v8.4-A RCPC instructions with Immediate Offsets (FEAT_LRCPC2)",
-    [FeatureRCPC]>;
+def FeatureRCPC_IMMO : Extension<"rcpc-immo", "RCPC_IMMO", "FEAT_LRCPC2",
+  "Enable v8.4-A RCPC instructions with Immediate Offsets",
+  [FeatureRCPC]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.5 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureAltFPCmp : SubtargetFeature<"altnzcv", "HasAlternativeNZCV", "true",
-  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)">;
+def FeatureAltFPCmp : Extension<"altnzcv", "AlternativeNZCV", "FEAT_FlagM2",
+  "Enable alternative NZCV format for floating point comparisons">;
 
-def FeatureFRInt3264 : SubtargetFeature<"fptoint", "HasFRInt3264", "true",
+def FeatureFRInt3264 : Extension<"fptoint", "FRInt3264", "FEAT_FRINTTS",
   "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to "
-  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)" >;
+  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int">;
 
-def FeatureSB : Extension<"sb", "SB",
-  "Enable v8.5 Speculation Barrier (FEAT_SB)", []>;
+def FeatureSB : ExtensionWithMArch<"sb", "SB", "FEAT_SB",
+  "Enable v8.5 Speculation Barrier">;
 
-def FeatureSSBS : Extension<"ssbs", "SSBS",
-  "Enable Speculative Store Bypass Safe bit (FEAT_SSBS, FEAT_SSBS2)", []>;
+def FeatureSSBS : ExtensionWithMArch<"ssbs", "SSBS", "FEAT_SSBS, FEAT_SSBS2",
+  "Enable Speculative Store Bypass Safe bit">;
 
-def FeaturePredRes : Extension<"predres", "PredRes",
-  "Enable v8.5a execution and data prediction invalidation instructions (FEAT_SPECRES)", []>;
+def FeaturePredRes : ExtensionWithMArch<"predres", "PredRes", "FEAT_SPECRES",
+  "Enable v8.5a execution and data prediction invalidation instructions">;
 
-def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "CCDP", "true",
-    "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)" >;
+def FeatureCacheDeepPersist : Extension<"ccdp", "CCDP", "FEAT_DPB2",
+  "Enable v8.5 Cache Clean to Point of Deep Persistence">;
 
-def FeatureBranchTargetId : SubtargetFeature<"bti", "BTI", "true",
-    "Enable Branch Target Identification (FEAT_BTI)">;
+def FeatureBranchTargetId : ExtensionWithMArch<"bti", "BTI", "FEAT_BTI",
+  "Enable Branch Target Identification">;
 
-let ArchExtKindSpelling = "AEK_RAND", MArchName = "rng" in
-def FeatureRandGen : Extension<"rand", "RandGen",
-    "Enable Random Number generation instructions (FEAT_RNG)", []>;
+let ArchExtKindSpelling = "AEK_RAND", UserVisibleName = "rng" in
+def FeatureRandGen : ExtensionWithMArch<"rand", "RandGen", "FEAT_RNG",
+  "Enable Random Number generation instructions">;
 
 // NOTE: "memtag" means FEAT_MTE + FEAT_MTE2 for -march or
 // __attribute((target(...))), but only FEAT_MTE for FMV.
-let MArchName = "memtag" in
-def FeatureMTE : Extension<"mte", "MTE",
-    "Enable Memory Tagging Extension (FEAT_MTE, FEAT_MTE2)", []>;
+let UserVisibleName = "memtag" in
+def FeatureMTE : ExtensionWithMArch<"mte", "MTE", "FEAT_MTE, FEAT_MTE2",
+  "Enable Memory Tagging Extension">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.6 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureBF16 : Extension<"bf16", "BF16",
-    "Enable BFloat16 Extension (FEAT_BF16)">;
+def FeatureBF16 : ExtensionWithMArch<"bf16", "BF16", "FEAT_BF16",
+  "Enable BFloat16 Extension">;
 
-def FeatureAMVS : SubtargetFeature<
-    "amvs", "HasAMVS", "true",
-    "Enable v8.6-A Activity Monitors Virtualization support (FEAT_AMUv1p1)",
-    [FeatureAM]>;
+def FeatureAMVS : Extension<"amvs", "AMVS", "FEAT_AMUv1p1",
+  "Enable v8.6-A Activity Monitors Virtualization support",
+  [FeatureAM]>;
 
-def FeatureFineGrainedTraps : SubtargetFeature<"fgt", "HasFineGrainedTraps",
-    "true", "Enable fine grained virtualization traps extension (FEAT_FGT)">;
+def FeatureFineGrainedTraps : Extension<"fgt", "FineGrainedTraps", "FEAT_FGT",
+  "Enable fine grained virtualization traps extension">;
 
 def FeatureEnhancedCounterVirtualization :
-      SubtargetFeature<"ecv", "HasEnhancedCounterVirtualization",
-      "true", "Enable enhanced counter virtualization extension (FEAT_ECV)">;
+    Extension<"ecv", "EnhancedCounterVirtualization", "FEAT_ECV",
+      "Enable enhanced counter virtualization extension">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.7 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureXS : SubtargetFeature<"xs", "HasXS",
-    "true", "Enable Armv8.7-A limited-TLB-maintenance instruction (FEAT_XS)">;
+def FeatureXS : Extension<"xs", "XS", "FEAT_XS",
+  "Enable Armv8.7-A limited-TLB-maintenance instruction">;
 
-def FeatureWFxT : SubtargetFeature<"wfxt", "WFxT", "true",
-    "Enable Armv8.7-A WFET and WFIT instruction (FEAT_WFxT)">;
+def FeatureWFxT : ExtensionWithMArch<"wfxt", "WFxT", "FEAT_WFxT",
+  "Enable Armv8.7-A WFET and WFIT instruction">;
 
-def FeatureHCX : SubtargetFeature<
-    "hcx", "HasHCX", "true", "Enable Armv8.7-A HCRX_EL2 system register (FEAT_HCX)">;
+def FeatureHCX : Extension<"hcx", "HCX", "FEAT_HCX",
+  "Enable Armv8.7-A HCRX_EL2 system register">;
 
-def FeatureLS64 : Extension<"ls64", "LS64",
-    "Enable Armv8.7-A LD64B/ST64B Accelerator Extension (FEAT_LS64, FEAT_LS64_V, FEAT_LS64_ACCDATA)", []>;
+def FeatureLS64 : ExtensionWithMArch<"ls64", "LS64",
+  "FEAT_LS64, FEAT_LS64_V, FEAT_LS64_ACCDATA",
+  "Enable Armv8.7-A LD64B/ST64B Accelerator Extension">;
 
-def FeatureSPE_EEF : SubtargetFeature<"spe-eef", "HasSPE_EEF",
-    "true", "Enable extra register in the Statistical Profiling Extension (FEAT_SPEv1p2)">;
+def FeatureSPE_EEF : Extension<"spe-eef", "SPE_EEF", "FEAT_SPEv1p2",
+  "Enable extra register in the Statistical Profiling Extension">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.8 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureHBC : Extension<"hbc", "HBC",
-    "Enable Armv8.8-A Hinted Conditional Branches Extension (FEAT_HBC)">;
+def FeatureHBC : ExtensionWithMArch<"hbc", "HBC", "FEAT_HBC",
+    "Enable Armv8.8-A Hinted Conditional Branches Extension">;
 
-def FeatureMOPS : Extension<"mops", "MOPS",
-    "Enable Armv8.8-A memcpy and memset acceleration instructions (FEAT_MOPS)", []>;
+def FeatureMOPS : ExtensionWithMArch<"mops", "MOPS", "FEAT_MOPS",
+    "Enable Armv8.8-A memcpy and memset acceleration instructions">;
 
-def FeatureNMI : SubtargetFeature<"nmi", "HasNMI",
-    "true", "Enable Armv8.8-A Non-maskable Interrupts (FEAT_NMI, FEAT_GICv3_NMI)">;
+def FeatureNMI : Extension<"nmi", "NMI", "FEAT_NMI, FEAT_GICv3_NMI",
+  "Enable Armv8.8-A Non-maskable Interrupts">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.9 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureRASv2 : Extension<"rasv2", "RASv2",
-  "Enable ARMv8.9-A Reliability, Availability and Serviceability Extensions (FEAT_RASv2)",
+def FeatureRASv2 : ExtensionWithMArch<"rasv2", "RASv2", "FEAT_RASv2",
+  "Enable ARMv8.9-A Reliability, Availability and Serviceability Extensions",
   [FeatureRAS]>;
 
-def FeatureCSSC : Extension<"cssc", "CSSC",
-  "Enable Common Short Sequence Compression (CSSC) instructions (FEAT_CSSC)">;
+def FeatureCSSC : ExtensionWithMArch<"cssc", "CSSC", "FEAT_CSSC",
+  "Enable Common Short Sequence Compression (CSSC) instructions">;
 
-def FeatureCLRBHB : SubtargetFeature<"clrbhb", "HasCLRBHB",
-    "true", "Enable Clear BHB instruction (FEAT_CLRBHB)">;
+def FeatureCLRBHB : Extension<"clrbhb", "CLRBHB", "FEAT_CLRBHB",
+  "Enable Clear BHB instruction">;
 
-def FeaturePRFM_SLC : SubtargetFeature<"prfm-slc-target", "HasPRFM_SLC",
-    "true", "Enable SLC target for PRFM instruction">;
+def FeaturePRFM_SLC : Extension<"prfm-slc-target", "PRFM_SLC", "FEAT_PRFMSLC",
+  "Enable SLC target for PRFM instruction">;
 
-let MArchName = "predres2" in
-def FeatureSPECRES2 : Extension<"specres2", "SPECRES2",
-    "Enable Speculation Restriction Instruction (FEAT_SPECRES2)",
-    [FeaturePredRes]>;
+let UserVisibleName = "predres2" in
+def FeatureSPECRES2 : ExtensionWithMArch<"specres2", "SPECRES2", "FEAT_SPECRES2",
+  "Enable Speculation Restriction Instruction",
+  [FeaturePredRes]>;
 
-def FeatureRCPC3 : Extension<"rcpc3", "RCPC3",
-    "Enable Armv8.9-A RCPC instructions for A64 and Advanced SIMD and floating-point instruction set (FEAT_LRCPC3)",
-    [FeatureRCPC_IMMO]>;
+def FeatureRCPC3 : ExtensionWithMArch<"rcpc3", "RCPC3", "FEAT_LRCPC3",
+  "Enable Armv8.9-A RCPC instructions for A64 and Advanced SIMD and floating-point instruction set",
+  [FeatureRCPC_IMMO]>;
 
-def FeatureTHE : Extension<"the", "THE",
-    "Enable Armv8.9-A Translation Hardening Extension (FEAT_THE)">;
+def FeatureTHE : ExtensionWithMArch<"the", "THE", "FEAT_THE",
+  "Enable Armv8.9-A Translation Hardening Extension">;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.0 Architecture Extensions
@@ -360,32 +358,32 @@ def FeatureTHE : Extension<"the", "THE",
 def FeatureUseScalarIncVL : SubtargetFeature<"use-scalar-inc-vl",
   "UseScalarIncVL", "true", "Prefer inc/dec over add+cnt">;
 
-def FeatureSVE2 : Extension<"sve2", "SVE2",
-  "Enable Scalable Vector Extension 2 (SVE2) instructions (FEAT_SVE2)",
+def FeatureSVE2 : ExtensionWithMArch<"sve2", "SVE2", "FEAT_SVE2",
+  "Enable Scalable Vector Extension 2 (SVE2) instructions",
   [FeatureSVE, FeatureUseScalarIncVL]>;
 
-def FeatureSVE2AES : Extension<"sve2-aes", "SVE2AES",
-  "Enable AES SVE2 instructions (FEAT_SVE_AES, FEAT_SVE_PMULL128)",
-  [FeatureSVE2, FeatureAES]>;
+def FeatureSVE2AES : ExtensionWithMArch<"sve2-aes", "SVE2AES",
+  "FEAT_SVE_AES, FEAT_SVE_PMULL128",
+  "Enable AES SVE2 instructions", [FeatureSVE2, FeatureAES]>;
 
-def FeatureSVE2SM4 : Extension<"sve2-sm4", "SVE2SM4",
-  "Enable SM4 SVE2 instructions (FEAT_SVE_SM4)", [FeatureSVE2, FeatureSM4]>;
+def FeatureSVE2SM4 : ExtensionWithMArch<"sve2-sm4", "SVE2SM4", "FEAT_SVE_SM4",
+  "Enable SM4 SVE2 instructions", [FeatureSVE2, FeatureSM4]>;
 
-def FeatureSVE2SHA3 : Extension<"sve2-sha3", "SVE2SHA3",
-  "Enable SHA3 SVE2 instructions (FEAT_SVE_SHA3)", [FeatureSVE2, FeatureSHA3]>;
+def FeatureSVE2SHA3 : ExtensionWithMArch<"sve2-sha3", "SVE2SHA3", "FEAT_SVE_SHA3",
+  "Enable SHA3 SVE2 instructions", [FeatureSVE2, FeatureSHA3]>;
 
-def FeatureSVE2BitPerm : Extension<"sve2-bitperm", "SVE2BitPerm",
-  "Enable bit permutation SVE2 instructions (FEAT_SVE_BitPerm)", [FeatureSVE2]>;
+def FeatureSVE2BitPerm : ExtensionWithMArch<"sve2-bitperm", "SVE2BitPerm",
+  "FEAT_SVE_BitPerm",
+  "Enable bit permutation SVE2 instructions", [FeatureSVE2]>;
 
-def FeatureTRBE : SubtargetFeature<"trbe", "TRBE", "true",
-    "Enable Trace Buffer Extension (FEAT_TRBE)">;
+def FeatureTRBE : Extension<"trbe", "TRBE", "FEAT_TRBE",
+  "Enable Trace Buffer Extension">;
 
-def FeatureETE : SubtargetFeature<"ete", "ETE", "true",
-    "Enable Embedded Trace Extension (FEAT_ETE)",
-    [FeatureTRBE]>;
+def FeatureETE : Extension<"ete", "ETE", "FEAT_ETE",
+  "Enable Embedded Trace Extension", [FeatureTRBE]>;
 
-def FeatureTME : Extension<"tme", "TME",
-    "Enable Transactional Memory Extension (FEAT_TME)" >;
+def FeatureTME : ExtensionWithMArch<"tme", "TME", "FEAT_TME",
+  "Enable Transactional Memory Extension">;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.1 Architecture Extensions
@@ -395,119 +393,119 @@ def FeatureTME : Extension<"tme", "TME",
 //  Armv9.2 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureBRBE : Extension<"brbe", "BRBE",
-    "Enable Branch Record Buffer Extension (FEAT_BRBE)">;
+def FeatureBRBE : ExtensionWithMArch<"brbe", "BRBE", "FEAT_BRBE",
+  "Enable Branch Record Buffer Extension">;
 
-def FeatureRME : SubtargetFeature<"rme", "HasRME",
-    "true", "Enable Realm Management Extension (FEAT_RME)">;
+def FeatureRME : Extension<"rme", "RME", "FEAT_RME",
+  "Enable Realm Management Extension">;
 
-def FeatureSME : Extension<"sme", "SME",
-  "Enable Scalable Matrix Extension (SME) (FEAT_SME)", [FeatureBF16, FeatureUseScalarIncVL]>;
+def FeatureSME : ExtensionWithMArch<"sme", "SME", "FEAT_SME",
+  "Enable Scalable Matrix Extension (SME)", [FeatureBF16, FeatureUseScalarIncVL]>;
 
-def FeatureSMEF64F64 : Extension<"sme-f64f64", "SMEF64F64",
-  "Enable Scalable Matrix Extension (SME) F64F64 instructions (FEAT_SME_F64F64)", [FeatureSME]>;
+def FeatureSMEF64F64 : ExtensionWithMArch<"sme-f64f64", "SMEF64F64", "FEAT_SME_F64F64",
+  "Enable Scalable Matrix Extension (SME) F64F64 instructions", [FeatureSME]>;
 
-def FeatureSMEI16I64 : Extension<"sme-i16i64", "SMEI16I64",
-  "Enable Scalable Matrix Extension (SME) I16I64 instructions (FEAT_SME_I16I64)", [FeatureSME]>;
+def FeatureSMEI16I64 : ExtensionWithMArch<"sme-i16i64", "SMEI16I64", "FEAT_SME_I16I64",
+  "Enable Scalable Matrix Extension (SME) I16I64 instructions", [FeatureSME]>;
 
-def FeatureSMEFA64 : Extension<"sme-fa64", "SMEFA64",
-  "Enable the full A64 instruction set in streaming SVE mode (FEAT_SME_FA64)", [FeatureSME, FeatureSVE2]>;
+def FeatureSMEFA64 : ExtensionWithMArch<"sme-fa64", "SMEFA64", "FEAT_SME_FA64",
+  "Enable the full A64 instruction set in streaming SVE mode", [FeatureSME, FeatureSVE2]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.3 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSME2 : Extension<"sme2", "SME2",
+def FeatureSME2 : ExtensionWithMArch<"sme2", "SME2", "FEAT_SME2",
   "Enable Scalable Matrix Extension 2 (SME2) instructions", [FeatureSME]>;
 
-def FeatureMEC : SubtargetFeature<"mec", "HasMEC",
-    "true", "Enable Memory Encryption Contexts Extension", [FeatureRME]>;
+def FeatureMEC : Extension<"mec", "MEC", "FEAT_MEC",
+  "Enable Memory Encryption Contexts Extension", [FeatureRME]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.4 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSVE2p1: Extension<"sve2p1", "SVE2p1",
+def FeatureSVE2p1: ExtensionWithMArch<"sve2p1", "SVE2p1", "FEAT_SVE2p1",
   "Enable Scalable Vector Extension 2.1 instructions", [FeatureSVE2]>;
 
-def FeatureB16B16 : Extension<"b16b16", "B16B16",
-  "Enable SVE2.1 or SME2.1 non-widening BFloat16 to BFloat16 instructions (FEAT_B16B16)", [FeatureBF16]>;
+def FeatureB16B16 : ExtensionWithMArch<"b16b16", "B16B16", "FEAT_SVE_B16B16",
+  "Enable SVE2.1 or SME2.1 non-widening BFloat16 to BFloat16 instructions", [FeatureBF16]>;
 
-def FeatureSMEF16F16 : Extension<"sme-f16f16", "SMEF16F16",
-  "Enable SME non-widening Float16 instructions (FEAT_SME_F16F16)", [FeatureSME2]>;
+def FeatureSMEF16F16 : ExtensionWithMArch<"sme-f16f16", "SMEF16F16", "FEAT_SME_F16F16",
+  "Enable SME non-widening Float16 instructions", [FeatureSME2]>;
 
-def FeatureSME2p1 : Extension<"sme2p1", "SME2p1",
-  "Enable Scalable Matrix Extension 2.1 (FEAT_SME2p1) instructions", [FeatureSME2]>;
+def FeatureSME2p1 : ExtensionWithMArch<"sme2p1", "SME2p1", "FEAT_SME2p1",
+  "Enable Scalable Matrix Extension 2.1 instructions", [FeatureSME2]>;
 
-def FeatureCHK : SubtargetFeature<"chk", "HasCHK",
-    "true", "Enable Armv8.0-A Check Feature Status Extension (FEAT_CHK)">;
+def FeatureCHK : Extension<"chk", "CHK", "FEAT_CHK",
+  "Enable Armv8.0-A Check Feature Status Extension">;
 
-def FeatureGCS : Extension<"gcs", "GCS",
-    "Enable Armv9.4-A Guarded Call Stack Extension", [FeatureCHK]>;
+def FeatureGCS : ExtensionWithMArch<"gcs", "GCS", "FEAT_GCS",
+  "Enable Armv9.4-A Guarded Call Stack Extension", [FeatureCHK]>;
 
-def FeatureITE : Extension<"ite", "ITE",
-    "Enable Armv9.4-A Instrumentation Extension FEAT_ITE", [FeatureETE,
-    FeatureTRBE]>;
+def FeatureITE : ExtensionWithMArch<"ite", "ITE", "FEAT_ITE",
+  "Enable Armv9.4-A Instrumentation Extension", [FeatureETE, FeatureTRBE]>;
 
-def FeatureLSE128 : Extension<"lse128", "LSE128",
-    "Enable Armv9.4-A 128-bit Atomic Instructions (FEAT_LSE128)",
-    [FeatureLSE]>;
+def FeatureLSE128 : ExtensionWithMArch<"lse128", "LSE128", "FEAT_LSE128",
+  "Enable Armv9.4-A 128-bit Atomic Instructions",
+  [FeatureLSE]>;
 
 // FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, and FEAT_SYSINSTR128 are mutually implicit.
 // Therefore group them all under a single feature flag, d128:
-def FeatureD128 : Extension<"d128", "D128",
-    "Enable Armv9.4-A 128-bit Page Table Descriptors, System Registers "
-    "and Instructions (FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, FEAT_SYSINSTR128)",
-    [FeatureLSE128]>;
+def FeatureD128 : ExtensionWithMArch<"d128", "D128",
+  "FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, FEAT_SYSINSTR128",
+  "Enable Armv9.4-A 128-bit Page Table Descriptors, System Registers "
+  "and Instructions",
+  [FeatureLSE128]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.5 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureFAMINMAX: Extension<"faminmax", "FAMINMAX",
-   "Enable FAMIN and FAMAX instructions (FEAT_FAMINMAX)">;
+def FeatureFAMINMAX: ExtensionWithMArch<"faminmax", "FAMINMAX", "FEAT_FAMINMAX",
+ "Enable FAMIN and FAMAX instructions">;
 
-def FeatureLUT: Extension<"lut", "LUT",
-   "Enable Lookup Table instructions (FEAT_LUT)">;
+def FeatureLUT: ExtensionWithMArch<"lut", "LUT", "FEAT_LUT",
+ "Enable Lookup Table instructions">;
    
-def FeatureFP8 : Extension<"fp8", "FP8",
-  "Enable FP8 instructions (FEAT_FP8)", [FeatureFAMINMAX, FeatureLUT, FeatureBF16]>;
+def FeatureFP8 : ExtensionWithMArch<"fp8", "FP8", "FEAT_FP8",
+  "Enable FP8 instructions", [FeatureFAMINMAX, FeatureLUT, FeatureBF16]>;
   
-def FeatureFP8FMA : Extension<"fp8fma", "FP8FMA",
-  "Enable fp8 multiply-add instructions (FEAT_FP8FMA)", [FeatureFP8]>;
+def FeatureFP8FMA : ExtensionWithMArch<"fp8fma", "FP8FMA", "FEAT_FP8FMA",
+  "Enable fp8 multiply-add instructions", [FeatureFP8]>;
 
-def FeatureSSVE_FP8FMA : Extension<"ssve-fp8fma", "SSVE_FP8FMA",
-  "Enable SVE2 fp8 multiply-add instructions (FEAT_SSVE_FP8FMA)", [FeatureSME2, FeatureFP8]>;
+def FeatureSSVE_FP8FMA : ExtensionWithMArch<"ssve-fp8fma", "SSVE_FP8FMA", "FEAT_SSVE_FP8FMA",
+  "Enable SVE2 fp8 multiply-add instructions", [FeatureSME2, FeatureFP8]>;
 
-def FeatureFP8DOT4: Extension<"fp8dot4", "FP8DOT4",
-   "Enable fp8 4-way dot instructions (FEAT_FP8DOT4)", [FeatureFP8FMA]>;
+def FeatureFP8DOT4: ExtensionWithMArch<"fp8dot4", "FP8DOT4", "FEAT_FP8DOT4",
+  "Enable fp8 4-way dot instructions", [FeatureFP8FMA]>;
   
-def FeatureFP8DOT2: Extension<"fp8dot2", "FP8DOT2",
-   "Enable fp8 2-way dot instructions (FEAT_FP8DOT2)", [FeatureFP8DOT4]>;
+def FeatureFP8DOT2: ExtensionWithMArch<"fp8dot2", "FP8DOT2", "FEAT_FP8DOT2",
+  "Enable fp8 2-way dot instructions", [FeatureFP8DOT4]>;
 
-def FeatureSSVE_FP8DOT4 : Extension<"ssve-fp8dot4", "SSVE_FP8DOT4",
-  "Enable SVE2 fp8 4-way dot product instructions (FEAT_SSVE_FP8DOT4)", [FeatureSSVE_FP8FMA]>;
+def FeatureSSVE_FP8DOT4 : ExtensionWithMArch<"ssve-fp8dot4", "SSVE_FP8DOT4", "FEAT_SSVE_FP8DOT4",
+  "Enable SVE2 fp8 4-way dot product instructions", [FeatureSSVE_FP8FMA]>;
 
-def FeatureSSVE_FP8DOT2 : Extension<"ssve-fp8dot2", "SSVE_FP8DOT2",
-  "Enable SVE2 fp8 2-way dot product instructions (FEAT_SSVE_FP8DOT2)", [FeatureSSVE_FP8DOT4]>;
+def FeatureSSVE_FP8DOT2 : ExtensionWithMArch<"ssve-fp8dot2", "SSVE_FP8DOT2", "FEAT_SSVE_FP8DOT2",
+  "Enable SVE2 fp8 2-way dot product instructions", [FeatureSSVE_FP8DOT4]>;
 
-def FeatureSME_LUTv2 : Extension<"sme-lutv2", "SME_LUTv2",
-  "Enable Scalable Matrix Extension (SME) LUTv2 instructions (FEAT_SME_LUTv2)">;
+def FeatureSME_LUTv2 : ExtensionWithMArch<"sme-lutv2", "SME_LUTv2", "FEAT_SME_LUTv2",
+  "Enable Scalable Matrix Extension (SME) LUTv2 instructions">;
 
-def FeatureSMEF8F32 : Extension<"sme-f8f32", "SMEF8F32",
-  "Enable Scalable Matrix Extension (SME) F8F32 instructions (FEAT_SME_F8F32)", [FeatureSME2, FeatureFP8]>;
+def FeatureSMEF8F32 : ExtensionWithMArch<"sme-f8f32", "SMEF8F32", "FEAT_SME_F8F32",
+  "Enable Scalable Matrix Extension (SME) F8F32 instructions", [FeatureSME2, FeatureFP8]>;
 
-def FeatureSMEF8F16 : Extension<"sme-f8f16", "SMEF8F16",
-  "Enable Scalable Matrix Extension (SME) F8F16 instructions(FEAT_SME_F8F16)", [FeatureSMEF8F32]>;
+def FeatureSMEF8F16 : ExtensionWithMArch<"sme-f8f16", "SMEF8F16", "FEAT_SME_F8F16",
+  "Enable Scalable Matrix Extension (SME) F8F16 instructions", [FeatureSMEF8F32]>;
 
-def FeatureCPA : Extension<"cpa", "CPA",
-    "Enable Armv9.5-A Checked Pointer Arithmetic (FEAT_CPA)">;
+def FeatureCPA : ExtensionWithMArch<"cpa", "CPA", "FEAT_CPA",
+  "Enable Armv9.5-A Checked Pointer Arithmetic">;
 
-def FeaturePAuthLR : Extension<"pauth-lr", "PAuthLR",
-    "Enable Armv9.5-A PAC enhancements (FEAT_PAuth_LR)">;
+def FeaturePAuthLR : ExtensionWithMArch<"pauth-lr", "PAuthLR", "FEAT_PAuth_LR",
+  "Enable Armv9.5-A PAC enhancements">;
 
-def FeatureTLBIW : Extension<"tlbiw", "TLBIW",
-  "Enable ARMv9.5-A TLBI VMALL for Dirty State (FEAT_TLBIW)">;
+def FeatureTLBIW : ExtensionWithMArch<"tlbiw", "TLBIW", "FEAT_TLBIW",
+  "Enable ARMv9.5-A TLBI VMALL for Dirty State">;
 
 //===----------------------------------------------------------------------===//
 //  Other Features
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index 7986f07538df7..2dde4d2b7e2a3 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -18,6 +18,7 @@
 #include "llvm/TargetParser/ARMTargetParserCommon.h"
 #include "llvm/TargetParser/Triple.h"
 #include <cctype>
+#include <vector>
 
 #define DEBUG_TYPE "target-parser"
 
@@ -61,8 +62,8 @@ bool AArch64::getExtensionFeatures(
     std::vector<StringRef> &Features) {
   for (const auto &E : Extensions)
     /* INVALID and NONE have no feature name. */
-    if (InputExts.test(E.ID) && !E.Feature.empty())
-      Features.push_back(E.Feature);
+    if (InputExts.test(E.ID) && !E.PosTargetFeature.empty())
+      Features.push_back(E.PosTargetFeature);
 
   return true;
 }
@@ -79,8 +80,8 @@ StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
   StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
 
   if (auto AE = parseArchExtension(ArchExtBase)) {
-    assert(!(AE.has_value() && AE->NegFeature.empty()));
-    return IsNegated ? AE->NegFeature : AE->Feature;
+    assert(!(AE.has_value() && AE->NegTargetFeature.empty()));
+    return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature;
   }
 
   return StringRef();
@@ -115,8 +116,10 @@ const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
 
 std::optional<AArch64::ExtensionInfo>
 AArch64::parseArchExtension(StringRef ArchExt) {
+  if (ArchExt.empty())
+    return {};
   for (const auto &A : Extensions) {
-    if (ArchExt == A.Name || ArchExt == A.Alias)
+    if (ArchExt == A.UserVisibleName || ArchExt == A.Alias)
       return A;
   }
   return {};
@@ -137,7 +140,7 @@ std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
 std::optional<AArch64::ExtensionInfo>
 AArch64::targetFeatureToExtension(StringRef TargetFeature) {
   for (const auto &E : Extensions)
-    if (TargetFeature == E.Feature)
+    if (TargetFeature == E.PosTargetFeature)
       return E;
   return {};
 }
@@ -154,21 +157,48 @@ std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) {
   return {};
 }
 
-void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) {
+void AArch64::PrintSupportedExtensions() {
   outs() << "All available -march extensions for AArch64\n\n"
          << "    " << left_justify("Name", 20)
-         << (DescMap.empty() ? "\n" : "Description\n");
+         << left_justify("Architecture Feature(s)", 55)
+         << "Description\n";
   for (const auto &Ext : Extensions) {
     // Extensions without a feature cannot be used with -march.
-    if (!Ext.Feature.empty()) {
-      std::string Description = DescMap[Ext.Name].str();
+    if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) {
       outs() << "    "
-             << format(Description.empty() ? "%s\n" : "%-20s%s\n",
-                       Ext.Name.str().c_str(), Description.c_str());
+             << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
+                       Ext.UserVisibleName.str().c_str(),
+                       Ext.ArchFeatureName.str().c_str(),
+                       Ext.Description.str().c_str());
     }
   }
 }
 
+void
+AArch64::printEnabledExtensions(std::set<StringRef> EnabledFeatureNames) {
+  outs() << "Extensions enabled for the given AArch64 target\n\n"
+         << "    " << left_justify("Architecture Feature(s)", 55)
+         << "Description\n";
+  std::vector<ExtensionInfo> EnabledExtensionsInfo;
+  for (const auto &FeatureName : EnabledFeatureNames) {
+    std::string PosFeatureName = '+' + FeatureName.str();
+    if (auto ExtInfo = targetFeatureToExtension(PosFeatureName))
+      EnabledExtensionsInfo.push_back(*ExtInfo);
+  }
+
+  std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(),
+            [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) {
+              return Lhs.ArchFeatureName < Rhs.ArchFeatureName;
+            });
+
+  for (const auto &Ext : EnabledExtensionsInfo) {
+    outs() << "    "
+           << format("%-55s%s\n",
+                     Ext.ArchFeatureName.str().c_str(),
+                     Ext.Description.str().c_str());
+  }
+}
+
 const llvm::AArch64::ExtensionInfo &
 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
   for (const auto &E : llvm::AArch64::Extensions)
@@ -181,7 +211,7 @@ void AArch64::ExtensionSet::enable(ArchExtKind E) {
   if (Enabled.test(E))
     return;
 
-  LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n");
+  LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n");
 
   Touched.set(E);
   Enabled.set(E);
@@ -222,7 +252,7 @@ void AArch64::ExtensionSet::disable(ArchExtKind E) {
   if (!Enabled.test(E))
     return;
 
-  LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n");
+  LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n");
 
   Touched.set(E);
   Enabled.reset(E);
@@ -266,7 +296,7 @@ bool AArch64::ExtensionSet::parseModifier(StringRef Modifier,
   StringRef ArchExt = Modifier.drop_front(NChars);
 
   if (auto AE = parseArchExtension(ArchExt)) {
-    if (AE->Feature.empty() || AE->NegFeature.empty())
+    if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty())
       return false;
     if (IsNegated)
       disable(AE->ID);
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 553f5df7827e2..fe20099382859 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1130,7 +1130,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_MTE,         AArch64::AEK_SSBS,
                  AArch64::AEK_FP16,        AArch64::AEK_FP16FML,
                  AArch64::AEK_SB,          AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_AM}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a520", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1147,7 +1148,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
+                 AArch64::AEK_ETE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a520ae", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1164,7 +1166,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
+                 AArch64::AEK_ETE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
@@ -1279,7 +1282,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PAUTH,   AArch64::AEK_FLAGM,
                  AArch64::AEK_SB,      AArch64::AEK_I8MM,
                  AArch64::AEK_BF16,    AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a715", "armv9-a", "neon-fp-armv8",
@@ -1296,7 +1300,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PREDRES, AArch64::AEK_PROFILE,
                  AArch64::AEK_FP16FML, AArch64::AEK_FP16,
                  AArch64::AEK_FLAGM,   AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,     AArch64::AEK_TRBE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a720", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1313,7 +1318,9 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
+                 AArch64::AEK_TRBE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a720ae", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1330,7 +1337,9 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
+                 AArch64::AEK_TRBE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a725", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1347,7 +1356,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_ETE,
+                 AArch64::AEK_SPE_EEF,     AArch64::AEK_TRBE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v1", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1364,7 +1374,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PROFILE, AArch64::AEK_RAND,
                  AArch64::AEK_FP16FML, AArch64::AEK_I8MM,
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
+                 AArch64::AEK_CCDP}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v2", "armv9-a", "neon-fp-armv8",
@@ -1380,7 +1391,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FP16FML,     AArch64::AEK_I8MM,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_RAND,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,       AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,       AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v3", "armv9.2-a", "neon-fp-armv8",
@@ -1399,7 +1411,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PERFMON,     AArch64::AEK_RAND,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FP16FML,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v3ae", "armv9.2-a", "neon-fp-armv8",
@@ -1418,7 +1431,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PERFMON,     AArch64::AEK_RAND,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FP16FML,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-r82", "armv8-r", "crypto-neon-fp-armv8",
@@ -1429,7 +1443,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC, AArch64::AEK_LSE, AArch64::AEK_SB,
                  AArch64::AEK_JSCVT, AArch64::AEK_FCMA, AArch64::AEK_PAUTH,
                  AArch64::AEK_FLAGM, AArch64::AEK_PERFMON,
-                 AArch64::AEK_PREDRES}),
+                 AArch64::AEK_PREDRES, AArch64::AEK_CCDP}),
             "8-R"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-r82ae", "armv8-r", "crypto-neon-fp-armv8",
@@ -1440,7 +1454,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC, AArch64::AEK_LSE, AArch64::AEK_SB,
                  AArch64::AEK_JSCVT, AArch64::AEK_FCMA, AArch64::AEK_PAUTH,
                  AArch64::AEK_FLAGM, AArch64::AEK_PERFMON,
-                 AArch64::AEK_PREDRES}),
+                 AArch64::AEK_PREDRES, AArch64::AEK_CCDP}),
             "8-R"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x1", "armv8.2-a", "crypto-neon-fp-armv8",
@@ -1459,7 +1473,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RAS, AArch64::AEK_LSE, AArch64::AEK_FP16,
                  AArch64::AEK_DOTPROD, AArch64::AEK_RCPC, AArch64::AEK_SSBS,
                  AArch64::AEK_PAUTH, AArch64::AEK_PROFILE, AArch64::AEK_FLAGM,
-                 AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PERFMON, AArch64::AEK_LSE2, AArch64::AEK_RCPC_IMMO}),
             "8.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x2", "armv9-a", "neon-fp-armv8",
@@ -1475,7 +1489,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SB,          AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML,     AArch64::AEK_FLAGM,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
+                 AArch64::AEK_ETE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x3", "armv9-a", "neon-fp-armv8",
@@ -1492,7 +1507,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FP16,    AArch64::AEK_FP16FML,
                  AArch64::AEK_PREDRES, AArch64::AEK_FLAGM,
                  AArch64::AEK_SSBS,    AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,     AArch64::AEK_TRBE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x4", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1509,7 +1525,9 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
+                 AArch64::AEK_TRBE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x925", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1526,7 +1544,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_ETE,
+                 AArch64::AEK_SPE_EEF,     AArch64::AEK_TRBE}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cyclone", "armv8-a", "crypto-neon-fp-armv8",
@@ -1557,7 +1576,8 @@ INSTANTIATE_TEST_SUITE_P(
             AArch64::ExtensionBitset({AArch64::AEK_CRC, AArch64::AEK_AES,
                                       AArch64::AEK_SHA2, AArch64::AEK_FP,
                                       AArch64::AEK_RDM, AArch64::AEK_SIMD,
-                                      AArch64::AEK_PERFMON}),
+                                      AArch64::AEK_PERFMON, AArch64::AEK_PAN,
+                                      AArch64::AEK_LOR, AArch64::AEK_VH}),
             "8-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a11", "armv8.2-a", "crypto-neon-fp-armv8",
@@ -1617,7 +1637,9 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
                  AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
                  AArch64::AEK_PREDRES, AArch64::AEK_SB,
-                 AArch64::AEK_SSBS}),
+                 AArch64::AEK_SSBS,    AArch64::AEK_CCDP,
+                 AArch64::AEK_FRINT3264, AArch64::AEK_SPECRESTRICT,
+                 AArch64::AEK_ALTERNATIVENZCV}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m1", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1632,7 +1654,9 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
                  AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
                  AArch64::AEK_PREDRES, AArch64::AEK_SB,
-                 AArch64::AEK_SSBS}),
+                 AArch64::AEK_SSBS,    AArch64::AEK_CCDP,
+                 AArch64::AEK_FRINT3264, AArch64::AEK_SPECRESTRICT,
+                 AArch64::AEK_ALTERNATIVENZCV}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a15", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1665,7 +1689,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m3", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1676,7 +1700,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a17", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1687,7 +1711,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m4", "armv8.7-a", "crypto-neon-fp-armv8",
@@ -1771,7 +1795,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,        AArch64::AEK_JSCVT,
                  AArch64::AEK_FCMA,        AArch64::AEK_PAUTH,
-                 AArch64::AEK_FP16FML,     AArch64::AEK_PERFMON}),
+                 AArch64::AEK_FP16FML,     AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,         AArch64::AEK_TRBE}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-n3", "armv9.2-a", "neon-fp-armv8",
@@ -1789,7 +1814,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FLAGM,   AArch64::AEK_PERFMON,
                  AArch64::AEK_RAND,    AArch64::AEK_SVE2BITPERM,
                  AArch64::AEK_FP16FML, AArch64::AEK_PROFILE,
-                 AArch64::AEK_JSCVT,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_JSCVT,   AArch64::AEK_PERFMON,
+                 AArch64::AEK_ETE,     AArch64::AEK_SPE_EEF}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "ampere1", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1824,7 +1850,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SHA2,  AArch64::AEK_AES,   AArch64::AEK_I8MM,
                  AArch64::AEK_SSBS,  AArch64::AEK_SB,    AArch64::AEK_RAND,
                  AArch64::AEK_MTE,   AArch64::AEK_JSCVT, AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH, AArch64::AEK_CSSC,  AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH, AArch64::AEK_CSSC,  AArch64::AEK_PERFMON,
+                 AArch64::AEK_WFXT}),
             "8.7-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-512tvb", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1841,7 +1868,8 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PROFILE, AArch64::AEK_RAND,
                  AArch64::AEK_FP16FML, AArch64::AEK_I8MM,
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
+                 AArch64::AEK_CCDP}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8",
@@ -2352,17 +2380,11 @@ TEST(TargetParserTest, AArch64ArchExtFeature) {
 TEST(TargetParserTest, AArch64PrintSupportedExtensions) {
   std::string expected =
       "All available -march extensions for AArch64\n\n"
-      "    Name                Description\n"
-      "    aes                 This is a long dummy description\n"
-      "    b16b16\n"
-      "    bf16\n";
-
-  StringMap<StringRef> DummyMap;
-  DummyMap["aes"] = "This is a long dummy description";
+      "    Name                Architecture Feature(s)                                Description\n";
 
   outs().flush();
   testing::internal::CaptureStdout();
-  AArch64::PrintSupportedExtensions(DummyMap);
+  AArch64::PrintSupportedExtensions();
   outs().flush();
   std::string captured = testing::internal::GetCapturedStdout();
 
@@ -2378,6 +2400,23 @@ TEST(TargetParserTest, AArch64PrintSupportedExtensions) {
   EXPECT_EQ(std::string::npos, captured.find("ssbs2"));
 }
 
+TEST(TargetParserTest, AArch64PrintEnabledExtensions) {
+  // Pick a single enabled extension to validate formatting
+  std::set<StringRef> EnabledExtensions = {"crc"};
+  std::string ExpectedOutput =
+      "Extensions enabled for the given AArch64 target\n\n"
+      "    Architecture Feature(s)                                Description\n"
+      "    FEAT_CRC32                                             Enable ARMv8 CRC-32 checksum instructions\n";
+
+  outs().flush();
+  testing::internal::CaptureStdout();
+  AArch64::printEnabledExtensions(EnabledExtensions);
+  outs().flush();
+  std::string CapturedOutput = testing::internal::GetCapturedStdout();
+
+  EXPECT_EQ(CapturedOutput, ExpectedOutput);
+}
+
 struct AArch64ExtensionDependenciesBaseArchTestParams {
   const llvm::AArch64::ArchInfo &Arch;
   std::vector<StringRef> Modifiers;
diff --git a/llvm/utils/TableGen/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
index e22f353b451f9..0a9370279410d 100644
--- a/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
@@ -41,9 +41,9 @@ static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
   std::vector<Record *> SortedExtensions =
       RK.getAllDerivedDefinitions("Extension");
   auto Alphabetical = [](Record *A, Record *B) -> bool {
-    const auto MarchA = A->getValueAsString("MArchName");
-    const auto MarchB = B->getValueAsString("MArchName");
-    return MarchA.compare(MarchB) < 0; // A lexographically less than B
+    const auto NameA = A->getValueAsString("Name");
+    const auto NameB = B->getValueAsString("Name");
+    return NameA.compare(NameB) < 0; // A lexographically less than B
   };
   std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
 
@@ -95,17 +95,19 @@ static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
   for (const Record *Rec : SortedExtensions) {
     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
     OS << "  ";
-    OS << "{\"" << Rec->getValueAsString("MArchName") << "\"";
-    if (auto Alias = Rec->getValueAsString("MArchAlias"); Alias.empty())
+    OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
+    if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
       OS << ", {}";
     else
       OS << ", \"" << Alias << "\"";
     OS << ", AArch64::" << AEK;
+    OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
+    OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
     OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
     OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
     OS << "},\n";
   };
-  OS << "  {\"none\", {}, AArch64::AEK_NONE, {}, {} },\n";
+  OS << "  {\"none\", {}, AArch64::AEK_NONE, {}, {}, {}, {} },\n";
   OS << "};\n"
      << "#undef EMIT_EXTENSIONS\n"
      << "#endif // EMIT_EXTENSIONS\n"

>From e6439369615dca4a891758e48c37caa55d7188f2 Mon Sep 17 00:00:00 2001
From: martinboehme <mboehme at google.com>
Date: Wed, 26 Jun 2024 15:40:42 +0200
Subject: [PATCH 03/19] Revert "[clang][dataflow] Teach `AnalysisASTVisitor`
 that `typeid()` can be evaluated." (#96766)

Reverts llvm/llvm-project#96731

It causes CI failures.
---
 .../clang/Analysis/FlowSensitive/ASTOps.h     |  6 +--
 .../Analysis/FlowSensitive/TransferTest.cpp   | 43 -------------------
 2 files changed, 1 insertion(+), 48 deletions(-)

diff --git a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
index f9c923a36ad22..925b99af9141a 100644
--- a/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
+++ b/clang/include/clang/Analysis/FlowSensitive/ASTOps.h
@@ -113,11 +113,7 @@ class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
   // nevertheless it appears in the Clang CFG, so we don't exclude it here.
   bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
   bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
-  bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
-    if (TIE->isPotentiallyEvaluated())
-      return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE);
-    return true;
-  }
+  bool TraverseCXXTypeidExpr(CXXTypeidExpr *) { return true; }
   bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
     return true;
   }
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 39e7001393e5e..e743eefa5d458 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1637,49 +1637,6 @@ TEST(TransferTest, StructModeledFieldsWithAccessor) {
       });
 }
 
-TEST(TransferTest, StructModeledFieldsInTypeid) {
-  // Test that we model fields mentioned inside a `typeid()` expression only if
-  // that expression is potentially evaluated -- i.e. if the expression inside
-  // `typeid()` is a glvalue of polymorphic type (see
-  // `CXXTypeidExpr::isPotentiallyEvaluated()` and [expr.typeid]p3).
-  std::string Code = R"(
-    // Definitions needed for `typeid`.
-    namespace std {
-      class type_info {};
-      class bad_typeid {};
-    }  // namespace std
-
-    struct NonPolymorphic {};
-
-    struct Polymorphic {
-      virtual ~Polymorphic() = default;
-    };
-
-    struct S {
-      NonPolymorphic *NonPoly;
-      Polymorphic *Poly;
-    };
-
-    void target(S &s) {
-      typeid(*s.NonPoly);
-      typeid(*s.Poly);
-      // [[p]]
-    }
-  )";
-  runDataflow(
-      Code,
-      [](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
-         ASTContext &ASTCtx) {
-        const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
-        auto &SLoc = getLocForDecl<RecordStorageLocation>(ASTCtx, Env, "s");
-        std::vector<const ValueDecl *> Fields;
-        for (auto [Field, _] : SLoc.children())
-          Fields.push_back(Field);
-        EXPECT_THAT(Fields,
-                    UnorderedElementsAre(findValueDecl(ASTCtx, "Poly")));
-      });
-}
-
 TEST(TransferTest, StructModeledFieldsWithComplicatedInheritance) {
   std::string Code = R"(
     struct Base1 {

>From 475e0bd4a9d963132704ccdc7da296e8e654e610 Mon Sep 17 00:00:00 2001
From: Lucas Duarte Prates <lucas.prates at arm.com>
Date: Wed, 26 Jun 2024 14:59:01 +0100
Subject: [PATCH 04/19] Revert "[AArch64] Add ability to list extensions
 enabled for a target" (#96768)

Reverts llvm/llvm-project#95805 due to test failures caught by the
buildbots.
---
 clang/include/clang/Driver/Options.td         |   5 -
 .../include/clang/Frontend/FrontendOptions.h  |   4 -
 clang/lib/Driver/Driver.cpp                   |  19 +-
 clang/lib/Driver/ToolChain.cpp                |   8 +-
 clang/lib/Driver/ToolChains/Clang.cpp         |   2 +-
 clang/test/CodeGen/aarch64-targetattr.c       |   8 +-
 clang/test/Driver/aarch64-fp16.c              |  78 +--
 clang/test/Driver/aarch64-sve2.c              |   2 +-
 clang/test/Driver/aarch64-v81a.c              |  14 -
 clang/test/Driver/aarch64-v82a.c              |  18 -
 clang/test/Driver/aarch64-v83a.c              |  23 -
 clang/test/Driver/aarch64-v84a.c              |  34 --
 clang/test/Driver/aarch64-v85a.c              |  42 --
 clang/test/Driver/aarch64-v86a.c              |  47 --
 clang/test/Driver/aarch64-v87a.c              |  50 --
 clang/test/Driver/aarch64-v88a.c              |  53 --
 clang/test/Driver/aarch64-v89a.c              |  59 --
 clang/test/Driver/aarch64-v8a.c               |  29 -
 clang/test/Driver/aarch64-v91a.c              |  52 --
 clang/test/Driver/aarch64-v92a.c              |  55 --
 clang/test/Driver/aarch64-v93a.c              |  58 --
 clang/test/Driver/aarch64-v94a.c              |  64 ---
 clang/test/Driver/aarch64-v95a.c              |  67 ---
 clang/test/Driver/aarch64-v9a.c               |  62 --
 .../test/Driver/print-supported-extensions.c  |   4 +-
 .../Preprocessor/aarch64-target-features.c    |  52 +-
 clang/tools/driver/cc1_main.cpp               |  46 +-
 flang/test/Driver/target-cpu-features.f90     |   4 +-
 llvm/include/llvm/MC/MCSubtargetInfo.h        |   3 -
 .../llvm/TargetParser/AArch64TargetParser.h   |  23 +-
 llvm/lib/MC/MCSubtargetInfo.cpp               |  10 -
 llvm/lib/Target/AArch64/AArch64Features.td    | 542 +++++++++---------
 llvm/lib/TargetParser/AArch64TargetParser.cpp |  60 +-
 .../TargetParser/TargetParserTest.cpp         | 113 ++--
 llvm/utils/TableGen/ARMTargetDefEmitter.cpp   |  14 +-
 35 files changed, 422 insertions(+), 1302 deletions(-)
 delete mode 100644 clang/test/Driver/aarch64-v8a.c
 delete mode 100644 clang/test/Driver/aarch64-v9a.c

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 724cf3351b88c..dd55838dcf384 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -5710,11 +5710,6 @@ def print_supported_extensions : Flag<["-", "--"], "print-supported-extensions">
   Visibility<[ClangOption, CC1Option, CLOption]>,
   HelpText<"Print supported -march extensions (RISC-V, AArch64 and ARM only)">,
   MarshallingInfoFlag<FrontendOpts<"PrintSupportedExtensions">>;
-def print_enabled_extensions : Flag<["-", "--"], "print-enabled-extensions">,
-  Visibility<[ClangOption, CC1Option, CLOption]>,
-  HelpText<"Print the extensions enabled by the given target and -march/-mcpu options."
-           " (AArch64 only)">,
-  MarshallingInfoFlag<FrontendOpts<"PrintEnabledExtensions">>;
 def : Flag<["-"], "mcpu=help">, Alias<print_supported_cpus>;
 def : Flag<["-"], "mtune=help">, Alias<print_supported_cpus>;
 def time : Flag<["-"], "time">,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 5e5034fe01eb5..ebb8e9e59c6b6 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -306,10 +306,6 @@ class FrontendOptions {
   LLVM_PREFERRED_TYPE(bool)
   unsigned PrintSupportedExtensions : 1;
 
-  /// Print the extensions enabled for the current target.
-  LLVM_PREFERRED_TYPE(bool)
-  unsigned PrintEnabledExtensions : 1;
-
   /// Show the -version text.
   LLVM_PREFERRED_TYPE(bool)
   unsigned ShowVersion : 1;
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 8fa8673b0fd69..6823f5424cef0 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -363,7 +363,6 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
     // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
   } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) ||
-             (PhaseArg = DAL.getLastArg(options::OPT_print_enabled_extensions)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_verify_pch)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
@@ -2164,8 +2163,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
   if (C.getArgs().hasArg(options::OPT_v) ||
       C.getArgs().hasArg(options::OPT__HASH_HASH_HASH) ||
       C.getArgs().hasArg(options::OPT_print_supported_cpus) ||
-      C.getArgs().hasArg(options::OPT_print_supported_extensions) ||
-      C.getArgs().hasArg(options::OPT_print_enabled_extensions)) {
+      C.getArgs().hasArg(options::OPT_print_supported_extensions)) {
     PrintVersion(C, llvm::errs());
     SuppressMissingInputWarning = true;
   }
@@ -4349,14 +4347,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
   }
 
   for (auto Opt : {options::OPT_print_supported_cpus,
-                   options::OPT_print_supported_extensions,
-                   options::OPT_print_enabled_extensions}) {
+                   options::OPT_print_supported_extensions}) {
     // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a
     // custom Compile phase that prints out supported cpu models and quits.
     //
-    // If either --print-supported-extensions or --print-enabled-extensions is
-    // specified, call the corresponding helper function that prints out the
-    // supported/enabled extensions and quits.
+    // If --print-supported-extensions is specified, call the helper function
+    // RISCVMarchHelp in RISCVISAInfo.cpp that prints out supported extensions
+    // and quits.
     if (Arg *A = Args.getLastArg(Opt)) {
       if (Opt == options::OPT_print_supported_extensions &&
           !C.getDefaultToolChain().getTriple().isRISCV() &&
@@ -4366,12 +4363,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
             << "--print-supported-extensions";
         return;
       }
-      if (Opt == options::OPT_print_enabled_extensions &&
-          !C.getDefaultToolChain().getTriple().isAArch64()) {
-        C.getDriver().Diag(diag::err_opt_not_valid_on_target)
-            << "--print-enabled-extensions";
-        return;
-      }
 
       // Use the -mcpu=? flag as the dummy input to cc1.
       Actions.clear();
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 8f4cc47e418b5..40ab2e91125d1 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -195,11 +195,11 @@ static void getAArch64MultilibFlags(const Driver &D,
                                        UnifiedFeatures.end());
   std::vector<std::string> MArch;
   for (const auto &Ext : AArch64::Extensions)
-    if (FeatureSet.contains(Ext.PosTargetFeature))
-      MArch.push_back(Ext.UserVisibleName.str());
+    if (FeatureSet.contains(Ext.Feature))
+      MArch.push_back(Ext.Name.str());
   for (const auto &Ext : AArch64::Extensions)
-    if (FeatureSet.contains(Ext.NegTargetFeature))
-      MArch.push_back(("no" + Ext.UserVisibleName).str());
+    if (FeatureSet.contains(Ext.NegFeature))
+      MArch.push_back(("no" + Ext.Name).str());
   StringRef ArchName;
   for (const auto &ArchInfo : AArch64::ArchInfos)
     if (FeatureSet.contains(ArchInfo->ArchFeature))
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 1b7cc82ea816e..c0f6bc0c2e45a 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1524,7 +1524,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
       auto isPAuthLR = [](const char *member) {
         llvm::AArch64::ExtensionInfo pauthlr_extension =
             llvm::AArch64::getExtensionByID(llvm::AArch64::AEK_PAUTHLR);
-        return pauthlr_extension.PosTargetFeature == member;
+        return pauthlr_extension.Feature == member;
       };
 
       if (std::any_of(CmdArgs.begin(), CmdArgs.end(), isPAuthLR))
diff --git a/clang/test/CodeGen/aarch64-targetattr.c b/clang/test/CodeGen/aarch64-targetattr.c
index e4e0ae7b66afc..7aabecd1c07b8 100644
--- a/clang/test/CodeGen/aarch64-targetattr.c
+++ b/clang/test/CodeGen/aarch64-targetattr.c
@@ -196,14 +196,14 @@ void minusarch() {}
 // CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+v8.1a,+v8.2a,+v8a" }
 // CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+fp-armv8,+fullfp16,+lse,+neon,+ras,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8a" }
 // CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+ras,+rcpc,+rdm,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" }
-// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+ete,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+trbe,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" }
+// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a710" "target-features"="+bf16,+complxnum,+crc,+dotprod,+flagm,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+mte,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sb,+sve,+sve2,+sve2-bitperm,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+v9a" }
 // CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="cortex-a710" }
-// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+ete,+fp-armv8,+neon,+trbe,+v8a" }
+// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+neon,+v8a" }
 // CHECK: attributes #[[ATTR7]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "tune-cpu"="generic" }
 // CHECK: attributes #[[ATTR8]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+crc,+dotprod,+fp-armv8,+fullfp16,+lse,+neon,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+v8.1a,+v8.2a,+v8a" "tune-cpu"="cortex-a710" }
 // CHECK: attributes #[[ATTR9]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" "tune-cpu"="cortex-a710" }
-// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" }
-// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+ccdp,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" }
+// CHECK: attributes #[[ATTR10]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" }
+// CHECK: attributes #[[ATTR11]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-v1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+rand,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+spe,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a,-sve" }
 // CHECK: attributes #[[ATTR12]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" }
 // CHECK: attributes #[[ATTR13]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16" }
 // CHECK: attributes #[[ATTR14]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+complxnum,+crc,+dotprod,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+ras,+rcpc,+rdm,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" }
diff --git a/clang/test/Driver/aarch64-fp16.c b/clang/test/Driver/aarch64-fp16.c
index 72ccd79850148..4da1834cf6876 100644
--- a/clang/test/Driver/aarch64-fp16.c
+++ b/clang/test/Driver/aarch64-fp16.c
@@ -21,7 +21,7 @@
 
 // RUN: %clang --target=aarch64 -march=armv8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-FP16FML %s
-// GENERICV8A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV8A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16FML %s
@@ -35,11 +35,11 @@
 // GENERICV82A-FP16-SAME: {{$}}
 
 // RUN: %clang --target=aarch64 -march=armv8.2-a+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-SPE %s
-// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe"
+// GENERICV82A-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML %s
-// GENERICV82A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV82A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-NO-FP16FML %s
@@ -51,15 +51,15 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16FML-NO-FP16 %s
-// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fp16fml"{{.*}} "-target-feature" "-fullfp16"
+// GENERICV82A-FP16FML-NO-FP16: "-target-feature" "-fullfp16"{{.*}} "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-NO-FP16-FP16FML %s
-// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV82A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.2a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s
 // RUN: %clang --target=aarch64 -march=armv8.2-a+fp16+profile -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-FP16-SPE %s
-// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}}  "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+spe"
+// GENERICV82A-FP16-SPE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.2a"{{.*}}  "-target-feature" "+fullfp16"{{.*}} "-target-feature" "+spe"{{.*}} "-target-feature" "+neon"
 // GENERICV82A-FP16-SPE-NOT:  "-target-feature" "{{[+-]}}fp16fml"
 // GENERICV82A-FP16-SPE-SAME: {{$}}
 
@@ -74,7 +74,7 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML %s
-// GENERICV83A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV83A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16-NO-FP16FML %s
@@ -88,11 +88,11 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-FP16FML-NO-FP16 %s
-// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV83A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.3a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.3-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-NO-FP16-FP16FML %s
-// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV83A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML %s
@@ -101,27 +101,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16 %s
-// GENERICV84A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV84A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML %s
-// GENERICV84A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV84A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16-NO-FP16FML %s
-// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
+// GENERICV84A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16FML-FP16 %s
-// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV84A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-FP16FML-NO-FP16 %s
-// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV84A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.4a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.4-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-NO-FP16-FP16FML %s
-// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV84A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML %s
@@ -130,27 +130,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16 %s
-// GENERICV85A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV85A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML %s
-// GENERICV85A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV85A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16-NO-FP16FML %s
-// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
+// GENERICV85A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16FML-FP16 %s
-// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV85A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-FP16FML-NO-FP16 %s
-// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV85A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.5a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.5-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-NO-FP16-FP16FML %s
-// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV85A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML %s
@@ -159,27 +159,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16 %s
-// GENERICV86A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV86A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML %s
-// GENERICV86A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV86A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16-NO-FP16FML %s
-// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
+// GENERICV86A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16FML-FP16 %s
-// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV86A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-FP16FML-NO-FP16 %s
-// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV86A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.6a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.6-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-NO-FP16-FP16FML %s
-// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV86A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML %s
@@ -188,27 +188,27 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16 %s
-// GENERICV87A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV87A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML %s
-// GENERICV87A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV87A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16-NO-FP16FML %s
-// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
+// GENERICV87A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16FML-FP16 %s
-// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV87A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-FP16FML-NO-FP16 %s
-// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV87A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.7a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.7-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-NO-FP16-FP16FML %s
-// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV87A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML %s
@@ -217,24 +217,24 @@
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16 %s
-// GENERICV88A-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV88A-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML %s
-// GENERICV88A-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV88A-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16+nofp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16-NO-FP16FML %s
-// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "-fp16fml" "-target-feature" "+fullfp16"
+// GENERICV88A-FP16-NO-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16fml+fp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16FML-FP16 %s
-// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV88A-NO-FP16FML-FP16: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+fp16fml+nofp16 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-FP16FML-NO-FP16 %s
-// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fp16fml" "-target-feature" "-fullfp16"
+// GENERICV88A-FP16FML-NO-FP16: "-target-feature" "-fullfp16" "-target-feature" "-fp16fml"
 
 // RUN: %clang --target=aarch64 -march=armv8.8a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s
 // RUN: %clang --target=aarch64 -march=armv8.8-a+nofp16+fp16fml -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-NO-FP16-FP16FML %s
-// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fp16fml" "-target-feature" "+fullfp16"
+// GENERICV88A-NO-FP16-FP16FML: "-target-feature" "+fullfp16" "-target-feature" "+fp16fml"
diff --git a/clang/test/Driver/aarch64-sve2.c b/clang/test/Driver/aarch64-sve2.c
index 389c3a52bde44..c801f44d3cb84 100644
--- a/clang/test/Driver/aarch64-sve2.c
+++ b/clang/test/Driver/aarch64-sve2.c
@@ -5,4 +5,4 @@
 // RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
 // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
 // RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a+nosve2 -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-NOSVE2 %s
-// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon"{{.*}} "-target-feature" "+sve" "-target-feature" "-sve2"
+// GENERICV9A-NOSVE2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+neon" "-target-feature" "+sve" "-target-feature" "-sve2"
diff --git a/clang/test/Driver/aarch64-v81a.c b/clang/test/Driver/aarch64-v81a.c
index b25d7f893cd70..e84652ec7f11e 100644
--- a/clang/test/Driver/aarch64-v81a.c
+++ b/clang/test/Driver/aarch64-v81a.c
@@ -19,17 +19,3 @@
 // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
 // RUN: %clang --target=arm64 -mlittle-endian -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV81A %s
 // ARM64-GENERICV81A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8.1a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v82a.c b/clang/test/Driver/aarch64-v82a.c
index ea599285eea73..9dd355934c105 100644
--- a/clang/test/Driver/aarch64-v82a.c
+++ b/clang/test/Driver/aarch64-v82a.c
@@ -13,21 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV82A-BE %s
 // GENERICV82A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.2a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v83a.c b/clang/test/Driver/aarch64-v83a.c
index 97355c7afe078..b0ff9fb3abc24 100644
--- a/clang/test/Driver/aarch64-v83a.c
+++ b/clang/test/Driver/aarch64-v83a.c
@@ -13,26 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV83A-BE %s
 // GENERICV83A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.3a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v84a.c b/clang/test/Driver/aarch64-v84a.c
index 43790cead3c49..030990bfe5131 100644
--- a/clang/test/Driver/aarch64-v84a.c
+++ b/clang/test/Driver/aarch64-v84a.c
@@ -13,37 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV84A-BE %s
 // GENERICV84A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.4a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v85a.c b/clang/test/Driver/aarch64-v85a.c
index c964641b580a4..3e1e921dcc013 100644
--- a/clang/test/Driver/aarch64-v85a.c
+++ b/clang/test/Driver/aarch64-v85a.c
@@ -13,45 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV85A-BE %s
 // GENERICV85A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.5a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v86a.c b/clang/test/Driver/aarch64-v86a.c
index 53bf8b44ae647..ba2b57979b518 100644
--- a/clang/test/Driver/aarch64-v86a.c
+++ b/clang/test/Driver/aarch64-v86a.c
@@ -13,50 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.6-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV86A-BE %s
 // GENERICV86A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.6a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.6-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v87a.c b/clang/test/Driver/aarch64-v87a.c
index d0c6aff950c95..ee4b68882739a 100644
--- a/clang/test/Driver/aarch64-v87a.c
+++ b/clang/test/Driver/aarch64-v87a.c
@@ -13,53 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.7-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV87A-BE %s
 // GENERICV87A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.7a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.7-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v88a.c b/clang/test/Driver/aarch64-v88a.c
index 4c1bb28c8b2dc..b680c1f567134 100644
--- a/clang/test/Driver/aarch64-v88a.c
+++ b/clang/test/Driver/aarch64-v88a.c
@@ -13,56 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV88A-BE %s
 // GENERICV88A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.8a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HBC
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MOPS
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v89a.c b/clang/test/Driver/aarch64-v89a.c
index cc2021df6c325..903b793d046ba 100644
--- a/clang/test/Driver/aarch64-v89a.c
+++ b/clang/test/Driver/aarch64-v89a.c
@@ -12,62 +12,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv8.9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV89A-BE %s
 // GENERICV89A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v8.9a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8.9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CHK
-// ARCH-EXTENSION: FEAT_CLRBHB
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSSC
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HBC
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MOPS
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_PRFMSLC
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RASv2
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SPECRES2
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v8a.c b/clang/test/Driver/aarch64-v8a.c
deleted file mode 100644
index 8f5995f16f3d2..0000000000000
--- a/clang/test/Driver/aarch64-v8a.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// RUN: %clang --target=aarch64_be -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// RUN: %clang --target=aarch64_be -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// RUN: %clang --target=aarch64 -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// RUN: %clang --target=aarch64 -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// RUN: %clang --target=aarch64_be -mbig-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A-BE %s
-// GENERICV8A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"
-
-// RUN: %clang --target=aarch64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// RUN: %clang --target=aarch64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// RUN: %clang --target=aarch64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV8A %s
-// GENERICV8A: "-cc1"{{.*}} "-triple" "aarch64{{(--)?}}"{{.*}} "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"{{.*}}
-
-// RUN: %clang --target=arm64 -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
-// RUN: %clang --target=arm64 -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
-// RUN: %clang --target=arm64 -mlittle-endian -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
-// RUN: %clang --target=arm64 -mlittle-endian -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERICV8A %s
-// ARM64-GENERICV8A: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"{{.*}} "-target-feature" "+v8a"{{.*}} "-target-feature" "+neon"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv8-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_TRBE
diff --git a/clang/test/Driver/aarch64-v91a.c b/clang/test/Driver/aarch64-v91a.c
index 2ea71c63b872c..80853a59d0153 100644
--- a/clang/test/Driver/aarch64-v91a.c
+++ b/clang/test/Driver/aarch64-v91a.c
@@ -13,55 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV91A-BE %s
 // GENERICV91A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.1a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9.1-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/aarch64-v92a.c b/clang/test/Driver/aarch64-v92a.c
index 89710966d68f7..ee644cc6f3c62 100644
--- a/clang/test/Driver/aarch64-v92a.c
+++ b/clang/test/Driver/aarch64-v92a.c
@@ -13,58 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.2-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV92A-BE %s
 // GENERICV92A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.2a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9.2-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v93a.c b/clang/test/Driver/aarch64-v93a.c
index e048077fe3690..817559e28ccf4 100644
--- a/clang/test/Driver/aarch64-v93a.c
+++ b/clang/test/Driver/aarch64-v93a.c
@@ -13,61 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.3-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV93A-BE %s
 // GENERICV93A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.3a"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9.3-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HBC
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MOPS
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v94a.c b/clang/test/Driver/aarch64-v94a.c
index c55b0fda2feb5..9998cc8a4a216 100644
--- a/clang/test/Driver/aarch64-v94a.c
+++ b/clang/test/Driver/aarch64-v94a.c
@@ -13,67 +13,3 @@
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s
 // RUN: %clang --target=aarch64_be -mbig-endian -march=armv9.4-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV94A-BE %s
 // GENERICV94A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.4a"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9.4-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CHK
-// ARCH-EXTENSION: FEAT_CLRBHB
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSSC
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HBC
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MOPS
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_PRFMSLC
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RASv2
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SPECRES2
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v95a.c b/clang/test/Driver/aarch64-v95a.c
index 5d4801f119896..62878f2127626 100644
--- a/clang/test/Driver/aarch64-v95a.c
+++ b/clang/test/Driver/aarch64-v95a.c
@@ -25,70 +25,3 @@
 // RUN: %clang -target aarch64 -march=armv9.5a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s
 // RUN: %clang -target aarch64 -march=armv9.5-a+tlbiw -### -c %s 2>&1 | FileCheck -check-prefix=V95A-TLBIW %s
 // V95A-TLBIW: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.5a"{{.*}} "-target-feature" "+tlbiw"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9.5-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AMUv1p1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BF16
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CHK
-// ARCH-EXTENSION: FEAT_CLRBHB
-// ARCH-EXTENSION: FEAT_CPA
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSSC
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ECV
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FAMINMAX
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FGT
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_HBC
-// ARCH-EXTENSION: FEAT_HCX
-// ARCH-EXTENSION: FEAT_I8MM
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_LUT
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MOPS
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NMI, FEAT_GICv3_NMI
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_PRFMSLC
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RASv2
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SPECRES2
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
-// ARCH-EXTENSION: FEAT_WFxT
-// ARCH-EXTENSION: FEAT_XS
diff --git a/clang/test/Driver/aarch64-v9a.c b/clang/test/Driver/aarch64-v9a.c
deleted file mode 100644
index 798bc390086a9..0000000000000
--- a/clang/test/Driver/aarch64-v9a.c
+++ /dev/null
@@ -1,62 +0,0 @@
-// RUN: %clang --target=aarch64 -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// RUN: %clang --target=aarch64 -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// RUN: %clang --target=aarch64 -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// RUN: %clang --target=aarch64_be -mlittle-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A %s
-// GENERICV9A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
-
-// RUN: %clang --target=aarch64_be -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// RUN: %clang --target=aarch64_be -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// RUN: %clang --target=aarch64 -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// RUN: %clang --target=aarch64 -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// RUN: %clang --target=aarch64_be -mbig-endian -march=armv9-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV9A-BE %s
-// GENERICV9A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9a"{{.*}} "-target-feature" "+sve" "-target-feature" "+sve2"
-
-// ===== Architecture extensions =====
-
-// RUN: %clang -target aarch64 -march=armv9-a --print-enabled-extensions | FileCheck -check-prefix=ARCH-EXTENSION --implicit-check-not FEAT_ %s
-// ARCH-EXTENSION: FEAT_AMUv1
-// ARCH-EXTENSION: FEAT_AdvSIMD
-// ARCH-EXTENSION: FEAT_BTI
-// ARCH-EXTENSION: FEAT_CCIDX
-// ARCH-EXTENSION: FEAT_CRC32
-// ARCH-EXTENSION: FEAT_CSV2_2
-// ARCH-EXTENSION: FEAT_DIT
-// ARCH-EXTENSION: FEAT_DPB
-// ARCH-EXTENSION: FEAT_DPB2
-// ARCH-EXTENSION: FEAT_DotProd
-// ARCH-EXTENSION: FEAT_ETE
-// ARCH-EXTENSION: FEAT_FCMA
-// ARCH-EXTENSION: FEAT_FP
-// ARCH-EXTENSION: FEAT_FP16
-// ARCH-EXTENSION: FEAT_FRINTTS
-// ARCH-EXTENSION: FEAT_FlagM
-// ARCH-EXTENSION: FEAT_FlagM2
-// ARCH-EXTENSION: FEAT_JSCVT
-// ARCH-EXTENSION: FEAT_LOR
-// ARCH-EXTENSION: FEAT_LRCPC
-// ARCH-EXTENSION: FEAT_LRCPC2
-// ARCH-EXTENSION: FEAT_LSE
-// ARCH-EXTENSION: FEAT_LSE2
-// ARCH-EXTENSION: FEAT_MEC
-// ARCH-EXTENSION: FEAT_MPAM
-// ARCH-EXTENSION: FEAT_NV, FEAT_NV2
-// ARCH-EXTENSION: FEAT_PAN
-// ARCH-EXTENSION: FEAT_PAN2
-// ARCH-EXTENSION: FEAT_PAuth
-// ARCH-EXTENSION: FEAT_RAS, FEAT_RASv1p1
-// ARCH-EXTENSION: FEAT_RDM
-// ARCH-EXTENSION: FEAT_RME
-// ARCH-EXTENSION: FEAT_SB
-// ARCH-EXTENSION: FEAT_SEL2
-// ARCH-EXTENSION: FEAT_SPECRES
-// ARCH-EXTENSION: FEAT_SSBS, FEAT_SSBS2
-// ARCH-EXTENSION: FEAT_SVE
-// ARCH-EXTENSION: FEAT_SVE2
-// ARCH-EXTENSION: FEAT_TLBIOS, FEAT_TLBIRANGE
-// ARCH-EXTENSION: FEAT_TRBE
-// ARCH-EXTENSION: FEAT_TRF
-// ARCH-EXTENSION: FEAT_UAO
-// ARCH-EXTENSION: FEAT_VHE
diff --git a/clang/test/Driver/print-supported-extensions.c b/clang/test/Driver/print-supported-extensions.c
index b9b16352f8295..17894fc0f7ee0 100644
--- a/clang/test/Driver/print-supported-extensions.c
+++ b/clang/test/Driver/print-supported-extensions.c
@@ -4,8 +4,8 @@
 // RUN: %if aarch64-registered-target %{ %clang --target=aarch64-linux-gnu \
 // RUN:   --print-supported-extensions 2>&1 | FileCheck %s --check-prefix AARCH64 %}
 // AARCH64: All available -march extensions for AArch64
-// AARCH64:     Name                Architecture Feature(s)                                Description
-// AARCH64:     aes                 FEAT_AES, FEAT_PMULL                                   Enable AES support
+// AARCH64:     Name                Description
+// AARCH64:     aes                 Enable AES support (FEAT_AES, FEAT_PMULL)
 
 // RUN: %if riscv-registered-target %{ %clang --target=riscv64-linux-gnu \
 // RUN:   --print-supported-extensions 2>&1 | FileCheck %s --check-prefix RISCV %}
diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c
index 71cc36acf3f0e..6f359461dea88 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -315,37 +315,37 @@
 // RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-THUNDERX2T99 %s
 // RUN: %clang -target aarch64 -mcpu=a64fx -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-A64FX %s
 // RUN: %clang -target aarch64 -mcpu=carmel -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-CARMEL %s
-// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lor" "-target-feature" "+neon" "-target-feature" "+pan" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+vh"
-// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
-// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2"
-// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3"
-// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+ssbs"
-// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
-// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2"
-// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2
-// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sve"
-// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-MCPU-APPLE-A7: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-APPLE-A10: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8a" "-target-feature" "+aes"{{.*}} "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-APPLE-A11: "-cc1"{{.*}} "-triple" "aarch64{{.*}}"{{.*}}"-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-APPLE-A12: "-cc1"{{.*}} "-triple" "aarch64"{{.*}} "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-A34: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-APPLE-A13: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "apple-a13" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon"
+// CHECK-MCPU-A35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-A53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-CORTEX-R82: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8r" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+flagm" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+neon" "-target-feature" "+ssbs"
+// CHECK-MCPU-M3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-M4: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-MCPU-A64FX: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+sve"
+// CHECK-MCPU-CARMEL: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+ras" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
 
 // RUN: %clang -target x86_64-apple-macosx -arch arm64 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64 %s
-// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+altnzcv" "-target-feature" "+ccdp" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fp16fml" "-target-feature" "+fptoint" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+specrestrict" "-target-feature" "+ssbs"
+// CHECK-ARCH-ARM64: "-target-cpu" "apple-m1" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.4a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+fp16fml" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+predres" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sb" "-target-feature" "+sha2" "-target-feature" "+sha3" "-target-feature" "+neon" "-target-feature" "+ssbs"
 
 // RUN: %clang -target x86_64-apple-macosx -arch arm64_32 -### -c %s 2>&1 | FileCheck --check-prefix=CHECK-ARCH-ARM64_32 %s
-// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+complxnum" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2"
+// CHECK-ARCH-ARM64_32: "-target-cpu" "apple-s4" "-target-feature" "+zcm" "-target-feature" "+zcz" "-target-feature" "+v8.3a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+complxnum" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+jsconv" "-target-feature" "+lse" "-target-feature" "+pauth" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
 
 // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto+fp+simd+crc+crypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-1 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
 // RUN: %clang -target aarch64 -march=armv8-a+fp+simd+crc+crypto+nofp+nosimd+nocrc+nocrypto -mabi=aapcs-soft -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-2 %s
 // RUN: %clang -target aarch64 -march=armv8-a+nosimd -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MARCH-3 %s
-// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+sha2"
+// CHECK-MARCH-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+sha2" "-target-feature" "+neon"
 // CHECK-MARCH-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-fp-armv8"{{.*}} "-target-feature" "-neon"
 // CHECK-MARCH-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-neon"
 
@@ -463,8 +463,8 @@
 // RUN: %clang -target aarch64 -mcpu=GENERIC+nocrc+CRC -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-2 %s
 // RUN: %clang -target aarch64 -mcpu=cortex-a53+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-3 %s
 // CHECK-MCPU-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "-aes"{{.*}} "-target-feature" "-sha2"
-// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc"{{.*}} "-target-feature" "+fp-armv8"{{.*}} "-target-feature" "+neon"
-// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "-neon" "-target-feature" "+perfmon" "-target-feature" "-sha2"
+// CHECK-MCPU-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon"
+// CHECK-MCPU-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8a" "-target-feature" "-aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "-sha2" "-target-feature" "-neon"
 
 // RUN: %clang -target aarch64 -mcpu=cyclone+nocrc+nocrypto -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s
 // RUN: %clang -target aarch64 -march=armv8-a -mcpu=cyclone+nocrc+nocrypto  -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MCPU-MARCH %s
@@ -492,9 +492,9 @@
 // RUN: %clang -target aarch64 -march=ARMV8.1A+CRYPTO -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-1 %s
 // RUN: %clang -target aarch64 -march=Armv8.1a+NOcrypto -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-2 %s
 // RUN: %clang -target aarch64 -march=armv8.1a+noSIMD -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V81A-FEATURE-3 %s
-// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm" "-target-feature" "+sha2"
-// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+rdm"
-// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-neon" "-target-feature" "-rdm"
+// CHECK-V81A-FEATURE-1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+crypto" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon"
+// CHECK-V81A-FEATURE-2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "+rdm" "-target-feature" "+neon"
+// CHECK-V81A-FEATURE-3: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-feature" "+v8.1a" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+lse" "-target-feature" "-rdm" "-target-feature" "-neon"
 
 // ================== Check Memory Tagging Extensions (MTE).
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8.5-a+memtag -x c -E -dM %s -o - 2>&1 | FileCheck -check-prefix=CHECK-MEMTAG %s
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 3c0599c2e5149..2aebc6d3c0178 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -26,7 +26,6 @@
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
 #include "llvm/ADT/Statistic.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/LinkAllPasses.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -149,7 +148,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   if (MachineTriple.isRISCV())
     llvm::riscvExtensionsHelp(DescMap);
   else if (MachineTriple.isAArch64())
-    llvm::AArch64::PrintSupportedExtensions();
+    llvm::AArch64::PrintSupportedExtensions(DescMap);
   else if (MachineTriple.isARM())
     llvm::ARM::PrintSupportedExtensions(DescMap);
   else {
@@ -162,45 +161,6 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   return 0;
 }
 
-static int PrintEnabledExtensions(const TargetOptions& TargetOpts) {
-  std::string Error;
-  const llvm::Target *TheTarget =
-      llvm::TargetRegistry::lookupTarget(TargetOpts.Triple, Error);
-  if (!TheTarget) {
-    llvm::errs() << Error;
-    return 1;
-  }
-
-  // Create a target machine using the input features, the triple information
-  // and a dummy instance of llvm::TargetOptions. Note that this is _not_ the
-  // same as the `clang::TargetOptions` instance we have access to here.
-  llvm::TargetOptions BackendOptions;
-  std::string FeaturesStr = llvm::join(TargetOpts.FeaturesAsWritten, ",");
-  std::unique_ptr<llvm::TargetMachine> TheTargetMachine(
-      TheTarget->createTargetMachine(TargetOpts.Triple, TargetOpts.CPU, FeaturesStr, BackendOptions, std::nullopt));
-  const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
-  const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
-
-  // Extract the feature names that are enabled for the given target.
-  // We do that by capturing the key from the set of SubtargetFeatureKV entries
-  // provided by MCSubtargetInfo, which match the '-target-feature' values.
-  const std::vector<llvm::SubtargetFeatureKV> Features =
-    MCInfo->getEnabledProcessorFeatures();
-  std::set<llvm::StringRef> EnabledFeatureNames;
-  for (const llvm::SubtargetFeatureKV &feature : Features)
-    EnabledFeatureNames.insert(feature.Key);
-
-  if (!MachineTriple.isAArch64()) {
-    // The option was already checked in Driver::HandleImmediateArgs,
-    // so we do not expect to get here if we are not a supported architecture.
-    assert(0 && "Unhandled triple for --print-enabled-extensions option.");
-    return 1;
-  }
-  llvm::AArch64::printEnabledExtensions(EnabledFeatureNames);
-
-  return 0;
-}
-
 int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   ensureSufficientStack();
 
@@ -244,10 +204,6 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getFrontendOpts().PrintSupportedExtensions)
     return PrintSupportedExtensions(Clang->getTargetOpts().Triple);
 
-  // --print-enabled-extensions takes priority over the actual compilation.
-  if (Clang->getFrontendOpts().PrintEnabledExtensions)
-    return PrintEnabledExtensions(Clang->getTargetOpts());
-
   // Infer the builtin include path if unspecified.
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
diff --git a/flang/test/Driver/target-cpu-features.f90 b/flang/test/Driver/target-cpu-features.f90
index e78c3516db45a..eea7a0f665b34 100644
--- a/flang/test/Driver/target-cpu-features.f90
+++ b/flang/test/Driver/target-cpu-features.f90
@@ -31,11 +31,11 @@
 
 ! CHECK-A57: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-A57-SAME: "-target-cpu" "cortex-a57"
-! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+sha2
+! CHECK-A57-SAME: "-target-feature" "+v8a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+fp-armv8" "-target-feature" "+perfmon" "-target-feature" "+sha2" "-target-feature" "+neon"
 
 ! CHECK-A76: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-A76-SAME: "-target-cpu" "cortex-a76"
-! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+neon" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+ssbs"
+! CHECK-A76-SAME: "-target-feature" "+v8.2a" "-target-feature" "+aes" "-target-feature" "+crc" "-target-feature" "+dotprod" "-target-feature" "+fp-armv8" "-target-feature" "+fullfp16" "-target-feature" "+lse" "-target-feature" "+perfmon" "-target-feature" "+ras" "-target-feature" "+rcpc" "-target-feature" "+rdm" "-target-feature" "+sha2" "-target-feature" "+neon" "-target-feature" "+ssbs"
 
 ! CHECK-ARMV9: "-fc1" "-triple" "aarch64-unknown-linux-gnu"
 ! CHECK-ARMV9-SAME: "-target-cpu" "generic"
diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h
index deb7e2fd1c360..ff76435d60843 100644
--- a/llvm/include/llvm/MC/MCSubtargetInfo.h
+++ b/llvm/include/llvm/MC/MCSubtargetInfo.h
@@ -240,9 +240,6 @@ class MCSubtargetInfo {
     return ProcFeatures;
   }
 
-  /// Return the list of processor features currently enabled.
-  std::vector<SubtargetFeatureKV> getEnabledProcessorFeatures() const;
-
   /// HwMode IDs are stored and accessed in a bit set format, enabling
   /// users to efficiently retrieve specific IDs, such as the RegInfo
   /// HwMode ID, from the set as required. Using this approach, various
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index 693759a1ccd82..a40bca9563cdd 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -22,7 +22,6 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
 #include <array>
-#include <set>
 #include <vector>
 
 namespace llvm {
@@ -117,18 +116,12 @@ using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
 // SubtargetFeature which may represent either an actual extension or some
 // internal LLVM property.
 struct ExtensionInfo {
-  StringRef UserVisibleName;      // Human readable name used in -march, -cpu
-                                  // and target func attribute, e.g. "profile".
+  StringRef Name;                 // Human readable name, e.g. "profile".
   std::optional<StringRef> Alias; // An alias for this extension, if one exists.
   ArchExtKind ID;                 // Corresponding to the ArchExtKind, this
                                   // extensions representation in the bitfield.
-  StringRef ArchFeatureName;      // The feature name defined by the
-                                  // Architecture, e.g. FEAT_AdvSIMD.
-  StringRef Description;          // The textual description of the extension.
-  StringRef PosTargetFeature;     // -target-feature/-mattr enable string,
-                                  // e.g. "+spe".
-  StringRef NegTargetFeature;     // -target-feature/-mattr disable string,
-                                  // e.g. "-spe".
+  StringRef Feature;              // -mattr enable string, e.g. "+spe"
+  StringRef NegFeature;           // -mattr disable string, e.g. "-spe"
 };
 
 #define EMIT_EXTENSIONS
@@ -293,12 +286,12 @@ struct ExtensionSet {
       Features.emplace_back(T(BaseArch->ArchFeature));
 
     for (const auto &E : Extensions) {
-      if (E.PosTargetFeature.empty() || !Touched.test(E.ID))
+      if (E.Feature.empty() || !Touched.test(E.ID))
         continue;
       if (Enabled.test(E.ID))
-        Features.emplace_back(T(E.PosTargetFeature));
+        Features.emplace_back(T(E.Feature));
       else
-        Features.emplace_back(T(E.NegTargetFeature));
+        Features.emplace_back(T(E.NegFeature));
     }
   }
 
@@ -350,9 +343,7 @@ bool isX18ReservedByDefault(const Triple &TT);
 // themselves, they are sequential (0, 1, 2, 3, ...).
 uint64_t getCpuSupportsMask(ArrayRef<StringRef> FeatureStrs);
 
-void PrintSupportedExtensions();
-
-void printEnabledExtensions(std::set<StringRef> EnabledFeatureNames);
+void PrintSupportedExtensions(StringMap<StringRef> DescMap);
 
 } // namespace AArch64
 } // namespace llvm
diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp
index 1de0a9f66669a..cf3aba17fc3d4 100644
--- a/llvm/lib/MC/MCSubtargetInfo.cpp
+++ b/llvm/lib/MC/MCSubtargetInfo.cpp
@@ -336,16 +336,6 @@ void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const {
                                   ForwardingPaths);
 }
 
-std::vector<SubtargetFeatureKV>
-MCSubtargetInfo::getEnabledProcessorFeatures() const {
-  std::vector<SubtargetFeatureKV> EnabledFeatures;
-  auto IsEnabled = [&](const SubtargetFeatureKV &FeatureKV) {
-    return FeatureBits.test(FeatureKV.Value);
-  };
-  llvm::copy_if(ProcFeatures, std::back_inserter(EnabledFeatures), IsEnabled);
-  return EnabledFeatures;
-}
-
 std::optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const {
   return std::nullopt;
 }
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 8ec06ac0aef15..8c1003c085e63 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -9,49 +9,31 @@
 //
 //===----------------------------------------------------------------------===//
 
-// A SubtargetFeature that represents one or more Architecture Extensions, as
-// defined by the Arm ARM and tipically identified by a 'FEAT_*' name.
-// Each Extension record defines an ExtensionInfo entry in the Target Parser
-// with a corresponding 'AEK_*' entry in the ArchExtKind enum.
+// A SubtargetFeature that can be toggled from the command line, and therefore
+// has an AEK_* entry in ArmExtKind.
 class Extension<
-  string TargetFeatureName,            // String used for -target-feature, unless overridden.
+  string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
   string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
-  string ArchitectureFeatureName,      // The extension's "FEAT_*"" name(s) defined by the architecture
   string Desc,                         // Description.
   list<SubtargetFeature> Implies = []  // List of dependent features.
 > : SubtargetFeature<TargetFeatureName, "Has" # Spelling, "true", Desc, Implies>
 {
     string ArchExtKindSpelling = "AEK_" # Spelling; // ArchExtKind enum name.
 
-    string ArchFeatureName = ArchitectureFeatureName;
-
-    // The user visible name used by -march/-mcpu modifiers and target attribute
-    // values. Extensions are not available on these by default.
-    string UserVisibleName = "";
-
-    // An alias that can be used on the command line, if the extension has one.
-    // Used for correcting historical names while remaining backwards compatible.
-    string UserVisibleAlias = "";
-}
-
-// An Extension that can be toggled via a '-march'/'-mcpu' modifier or a target
-// attribute, e.g. '+sm4".
-class ExtensionWithMArch<
-  string TargetFeatureName,            // String used for -target-feature and -march, unless overridden.
-  string Spelling,                     // The XYZ in HasXYZ and AEK_XYZ.
-  string ArchitectureFeatureName,      // The extension's "FEAT_*"" name(s) defined by the architecture
-  string Desc,                         // Description.
-  list<SubtargetFeature> Implies = []  // List of dependent features.
-> : Extension<TargetFeatureName, Spelling, ArchitectureFeatureName, Desc, Implies> {
     // In general, the name written on the command line should match the name
     // used for -target-feature. However, there are exceptions. Therefore we
     // add a separate field for this, to allow overriding it. Strongly prefer
     // not doing so.
-    let UserVisibleName = TargetFeatureName;
+    string MArchName = TargetFeatureName;
+
+    // An alias that can be used on the command line, if the extension has one.
+    // Used for correcting historical names while remaining backwards compatible.
+    string MArchAlias = "";
 }
 
 
 
+
 // Each SubtargetFeature which corresponds to an Arm Architecture feature should
 // be annotated with the respective FEAT_ feature name from the Architecture
 // Reference Manual. If a SubtargetFeature enables instructions from multiple
@@ -63,19 +45,21 @@ class ExtensionWithMArch<
 //  Armv8.0 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-let ArchExtKindSpelling = "AEK_FP", UserVisibleName = "fp" in
-def FeatureFPARMv8 : ExtensionWithMArch<"fp-armv8", "FPARMv8", "FEAT_FP",
-  "Enable ARMv8">;
+let ArchExtKindSpelling = "AEK_FP", MArchName = "fp" in
+def FeatureFPARMv8 : Extension<"fp-armv8", "FPARMv8",
+  "Enable ARMv8 (FEAT_FP)">;
 
-let ArchExtKindSpelling = "AEK_SIMD", UserVisibleName = "simd" in
-def FeatureNEON : ExtensionWithMArch<"neon", "NEON", "FEAT_AdvSIMD",
-  "Enable Advanced SIMD instructions", [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_SIMD", MArchName = "simd" in
+def FeatureNEON : Extension<"neon", "NEON",
+  "Enable Advanced SIMD instructions (FEAT_AdvSIMD)", [FeatureFPARMv8]>;
 
-def FeatureSHA2 : ExtensionWithMArch<"sha2", "SHA2", "FEAT_SHA1, FEAT_SHA256",
-  "Enable SHA1 and SHA256 support", [FeatureNEON]>;
+def FeatureSHA2 : Extension<
+    "sha2", "SHA2",
+    "Enable SHA1 and SHA256 support (FEAT_SHA1, FEAT_SHA256)", [FeatureNEON]>;
 
-def FeatureAES : ExtensionWithMArch<"aes", "AES", "FEAT_AES, FEAT_PMULL",
-  "Enable AES support", [FeatureNEON]>;
+def FeatureAES : Extension<
+    "aes", "AES",
+    "Enable AES support (FEAT_AES, FEAT_PMULL)", [FeatureNEON]>;
 
 // Crypto has been split up and any combination is now valid (see the
 // crypto definitions above). Also, crypto is now context sensitive:
@@ -85,271 +69,289 @@ def FeatureAES : ExtensionWithMArch<"aes", "AES", "FEAT_AES, FEAT_PMULL",
 // meaning anymore. We kept the Crypto definition here for backward
 // compatibility, and now imply features SHA2 and AES, which was the
 // "traditional" meaning of Crypto.
-def FeatureCrypto : ExtensionWithMArch<"crypto", "Crypto", "FEAT_Crypto",
+def FeatureCrypto : Extension<"crypto", "Crypto",
   "Enable cryptographic instructions", [FeatureNEON, FeatureSHA2, FeatureAES]>;
 
-def FeatureCRC : ExtensionWithMArch<"crc", "CRC", "FEAT_CRC32",
-  "Enable ARMv8 CRC-32 checksum instructions">;
+def FeatureCRC : Extension<"crc", "CRC",
+  "Enable ARMv8 CRC-32 checksum instructions (FEAT_CRC32)">;
 
 // This SubtargetFeature is special. It controls only whether codegen will turn
 // `llvm.readcyclecounter()` into an access to a PMUv3 System Register. The
 // `FEAT_PMUv3*` system registers are always available for assembly/disassembly.
-let UserVisibleName = "pmuv3" in
-def FeaturePerfMon : ExtensionWithMArch<"perfmon", "PerfMon", "FEAT_PMUv3",
-  "Enable Code Generation for ARMv8 PMUv3 Performance Monitors extension">;
+let MArchName = "pmuv3" in
+def FeaturePerfMon : Extension<"perfmon", "PerfMon",
+  "Enable Code Generation for ARMv8 PMUv3 Performance Monitors extension (FEAT_PMUv3)">;
 
-def FeatureSpecRestrict : Extension<"specrestrict", "SpecRestrict", "FEAT_CSV2_2",
-  "Enable architectural speculation restriction">;
+def FeatureSpecRestrict : SubtargetFeature<"specrestrict", "HasSpecRestrict",
+  "true", "Enable architectural speculation restriction (FEAT_CSV2_2)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.1 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureLSE : ExtensionWithMArch<"lse", "LSE", "FEAT_LSE",
-  "Enable ARMv8.1 Large System Extension (LSE) atomic instructions">;
+def FeatureLSE : Extension<"lse", "LSE",
+  "Enable ARMv8.1 Large System Extension (LSE) atomic instructions (FEAT_LSE)">;
 
-let UserVisibleAlias = "rdma" in
-def FeatureRDM : ExtensionWithMArch<"rdm", "RDM", "FEAT_RDM",
-  "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions",
+let MArchAlias = "rdma" in
+def FeatureRDM : Extension<"rdm", "RDM",
+  "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions (FEAT_RDM)",
   [FeatureNEON]>;
 
-def FeaturePAN : Extension<"pan", "PAN", "FEAT_PAN",
-  "Enables ARM v8.1 Privileged Access-Never extension">;
+def FeaturePAN : SubtargetFeature<
+    "pan", "HasPAN", "true",
+    "Enables ARM v8.1 Privileged Access-Never extension (FEAT_PAN)">;
 
-def FeatureLOR : Extension<"lor", "LOR", "FEAT_LOR",
-  "Enables ARM v8.1 Limited Ordering Regions extension">;
+def FeatureLOR : SubtargetFeature<
+    "lor", "HasLOR", "true",
+    "Enables ARM v8.1 Limited Ordering Regions extension (FEAT_LOR)">;
 
 def FeatureCONTEXTIDREL2 : SubtargetFeature<"CONTEXTIDREL2", "HasCONTEXTIDREL2",
-  "true", "Enable RW operand CONTEXTIDR_EL2">;
+    "true", "Enable RW operand CONTEXTIDR_EL2" >;
 
-def FeatureVH : Extension<"vh", "VH", "FEAT_VHE",
-  "Enables ARM v8.1 Virtual Host extension", [FeatureCONTEXTIDREL2]>;
+def FeatureVH : SubtargetFeature<"vh", "HasVH", "true",
+    "Enables ARM v8.1 Virtual Host extension (FEAT_VHE)", [FeatureCONTEXTIDREL2] >;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.2 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSM4 : ExtensionWithMArch<"sm4", "SM4", "FEAT_SM4, FEAT_SM3",
-  "Enable SM3 and SM4 support", [FeatureNEON]>;
+def FeatureSM4 : Extension<
+    "sm4", "SM4",
+    "Enable SM3 and SM4 support (FEAT_SM4, FEAT_SM3)", [FeatureNEON]>;
 
-def FeatureSHA3 : ExtensionWithMArch<"sha3", "SHA3", "FEAT_SHA3, FEAT_SHA512",
-  "Enable SHA512 and SHA3 support", [FeatureNEON, FeatureSHA2]>;
+def FeatureSHA3 : Extension<
+    "sha3", "SHA3",
+    "Enable SHA512 and SHA3 support (FEAT_SHA3, FEAT_SHA512)", [FeatureNEON, FeatureSHA2]>;
 
-def FeatureRAS : ExtensionWithMArch<"ras", "RAS", "FEAT_RAS, FEAT_RASv1p1",
-  "Enable ARMv8 Reliability, Availability and Serviceability Extensions">;
+def FeatureRAS : Extension<"ras", "RAS",
+  "Enable ARMv8 Reliability, Availability and Serviceability Extensions (FEAT_RAS, FEAT_RASv1p1)">;
 
-let ArchExtKindSpelling = "AEK_FP16", UserVisibleName = "fp16" in
-def FeatureFullFP16 : ExtensionWithMArch<"fullfp16", "FullFP16", "FEAT_FP16",
-  "Full FP16", [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_FP16", MArchName = "fp16" in
+def FeatureFullFP16 : Extension<"fullfp16", "FullFP16",
+  "Full FP16 (FEAT_FP16)", [FeatureFPARMv8]>;
 
-let ArchExtKindSpelling = "AEK_PROFILE", UserVisibleName = "profile" in
-def FeatureSPE : ExtensionWithMArch<"spe", "SPE", "FEAT_SPE",
-  "Enable Statistical Profiling extension">;
+let ArchExtKindSpelling = "AEK_PROFILE", MArchName = "profile" in
+def FeatureSPE : Extension<"spe", "SPE",
+  "Enable Statistical Profiling extension (FEAT_SPE)">;
 
-def FeaturePAN_RWV : Extension<"pan-rwv", "PAN_RWV", "FEAT_PAN2",
-  "Enable v8.2 PAN s1e1R and s1e1W Variants", [FeaturePAN]>;
+def FeaturePAN_RWV : SubtargetFeature<
+    "pan-rwv", "HasPAN_RWV", "true",
+    "Enable v8.2 PAN s1e1R and s1e1W Variants (FEAT_PAN2)",
+    [FeaturePAN]>;
 
-def FeaturePsUAO : Extension<"uaops", "PsUAO", "FEAT_UAO",
-  "Enable v8.2 UAO PState">;
+def FeaturePsUAO : SubtargetFeature< "uaops", "HasPsUAO", "true",
+    "Enable v8.2 UAO PState (FEAT_UAO)">;
 
-def FeatureCCPP : Extension<"ccpp", "CCPP", "FEAT_DPB",
-  "Enable v8.2 data Cache Clean to Point of Persistence">;
+def FeatureCCPP : SubtargetFeature<"ccpp", "HasCCPP",
+    "true", "Enable v8.2 data Cache Clean to Point of Persistence (FEAT_DPB)" >;
 
-def FeatureSVE : ExtensionWithMArch<"sve", "SVE", "FEAT_SVE",
-  "Enable Scalable Vector Extension (SVE) instructions", [FeatureFullFP16]>;
+def FeatureSVE : Extension<"sve", "SVE",
+  "Enable Scalable Vector Extension (SVE) instructions (FEAT_SVE)", [FeatureFullFP16]>;
 
 let ArchExtKindSpelling = "AEK_I8MM" in
-def FeatureMatMulInt8 : ExtensionWithMArch<"i8mm", "MatMulInt8", "FEAT_I8MM",
-  "Enable Matrix Multiply Int8 Extension">;
+def FeatureMatMulInt8 : Extension<"i8mm", "MatMulInt8",
+    "Enable Matrix Multiply Int8 Extension (FEAT_I8MM)", []>;
 
 let ArchExtKindSpelling = "AEK_F32MM" in
-def FeatureMatMulFP32 : ExtensionWithMArch<"f32mm", "MatMulFP32", "FEAT_F32MM",
-  "Enable Matrix Multiply FP32 Extension", [FeatureSVE]>;
+def FeatureMatMulFP32 : Extension<"f32mm", "MatMulFP32",
+    "Enable Matrix Multiply FP32 Extension (FEAT_F32MM)", [FeatureSVE]>;
 
 let ArchExtKindSpelling = "AEK_F64MM" in
-def FeatureMatMulFP64 : ExtensionWithMArch<"f64mm", "MatMulFP64", "FEAT_F64MM",
-  "Enable Matrix Multiply FP64 Extension", [FeatureSVE]>;
+def FeatureMatMulFP64 : Extension<"f64mm", "MatMulFP64",
+    "Enable Matrix Multiply FP64 Extension (FEAT_F64MM)", [FeatureSVE]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.3 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureRCPC : ExtensionWithMArch<"rcpc", "RCPC", "FEAT_LRCPC",
-  "Enable support for RCPC extension">;
+def FeatureRCPC : Extension<"rcpc", "RCPC",
+    "Enable support for RCPC extension (FEAT_LRCPC)", []>;
 
-def FeaturePAuth : ExtensionWithMArch<"pauth", "PAuth", "FEAT_PAuth",
-  "Enable v8.3-A Pointer Authentication extension">;
+def FeaturePAuth : Extension<
+    "pauth", "PAuth",
+    "Enable v8.3-A Pointer Authentication extension (FEAT_PAuth)">;
 
-let ArchExtKindSpelling = "AEK_JSCVT", UserVisibleName = "jscvt" in
-def FeatureJS : ExtensionWithMArch<"jsconv", "JS", "FEAT_JSCVT",
-  "Enable v8.3-A JavaScript FP conversion instructions",
-  [FeatureFPARMv8]>;
+let ArchExtKindSpelling = "AEK_JSCVT", MArchName = "jscvt" in
+def FeatureJS : Extension<
+    "jsconv", "JS",
+    "Enable v8.3-A JavaScript FP conversion instructions (FEAT_JSCVT)",
+    [FeatureFPARMv8]>;
 
-def FeatureCCIDX : Extension<"ccidx", "CCIDX", "FEAT_CCIDX",
-  "Enable v8.3-A Extend of the CCSIDR number of sets">;
+def FeatureCCIDX : SubtargetFeature<
+    "ccidx", "HasCCIDX", "true",
+    "Enable v8.3-A Extend of the CCSIDR number of sets (FEAT_CCIDX)">;
 
-let ArchExtKindSpelling = "AEK_FCMA", UserVisibleName = "fcma" in
-def FeatureComplxNum : ExtensionWithMArch<"complxnum", "ComplxNum", "FEAT_FCMA",
-  "Enable v8.3-A Floating-point complex number support",
-  [FeatureNEON]>;
+let ArchExtKindSpelling = "AEK_FCMA", MArchName = "fcma" in
+def FeatureComplxNum : Extension<
+    "complxnum", "ComplxNum",
+    "Enable v8.3-A Floating-point complex number support (FEAT_FCMA)",
+    [FeatureNEON]>;
 
-def FeatureNV : Extension<"nv", "NV", "FEAT_NV, FEAT_NV2",
-  "Enable v8.4-A Nested Virtualization Enchancement">;
+def FeatureNV : SubtargetFeature<
+    "nv", "HasNV", "true",
+    "Enable v8.4-A Nested Virtualization Enchancement (FEAT_NV, FEAT_NV2)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.4 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureLSE2 : Extension<"lse2", "LSE2", "FEAT_LSE2",
-  "Enable ARMv8.4 Large System Extension 2 (LSE2) atomicity rules">;
+def FeatureLSE2 : SubtargetFeature<"lse2", "HasLSE2", "true",
+  "Enable ARMv8.4 Large System Extension 2 (LSE2) atomicity rules (FEAT_LSE2)">;
 
-def FeatureFP16FML : ExtensionWithMArch<"fp16fml", "FP16FML", "FEAT_FHM",
-  "Enable FP16 FML instructions", [FeatureFullFP16]>;
+def FeatureFP16FML : Extension<"fp16fml", "FP16FML",
+  "Enable FP16 FML instructions (FEAT_FHM)", [FeatureFullFP16]>;
 
-def FeatureDotProd : ExtensionWithMArch<"dotprod", "DotProd", "FEAT_DotProd",
-  "Enable dot product support", [FeatureNEON]>;
+def FeatureDotProd : Extension<
+    "dotprod", "DotProd",
+    "Enable dot product support (FEAT_DotProd)", [FeatureNEON]>;
 
-def FeatureMPAM : Extension<"mpam", "MPAM", "FEAT_MPAM",
-  "Enable v8.4-A Memory system Partitioning and Monitoring extension">;
+def FeatureMPAM : SubtargetFeature<
+    "mpam", "HasMPAM", "true",
+    "Enable v8.4-A Memory system Partitioning and Monitoring extension (FEAT_MPAM)">;
 
-def FeatureDIT : ExtensionWithMArch<"dit", "DIT", "FEAT_DIT",
-  "Enable v8.4-A Data Independent Timing instructions">;
+def FeatureDIT : SubtargetFeature<
+    "dit", "HasDIT", "true",
+    "Enable v8.4-A Data Independent Timing instructions (FEAT_DIT)">;
 
-def FeatureTRACEV8_4 : Extension<"tracev8.4", "TRACEV8_4", "FEAT_TRF",
-  "Enable v8.4-A Trace extension">;
+def FeatureTRACEV8_4 : SubtargetFeature<
+    "tracev8.4", "HasTRACEV8_4", "true",
+    "Enable v8.4-A Trace extension (FEAT_TRF)">;
 
-def FeatureAM : Extension<"am", "AM", "FEAT_AMUv1",
-  "Enable v8.4-A Activity Monitors extension">;
+def FeatureAM : SubtargetFeature<
+    "am", "HasAM", "true",
+    "Enable v8.4-A Activity Monitors extension (FEAT_AMUv1)">;
 
-def FeatureSEL2 : Extension<"sel2", "SEL2", "FEAT_SEL2",
-  "Enable v8.4-A Secure Exception Level 2 extension">;
+def FeatureSEL2 : SubtargetFeature<
+    "sel2", "HasSEL2", "true",
+    "Enable v8.4-A Secure Exception Level 2 extension (FEAT_SEL2)">;
 
-def FeatureTLB_RMI : Extension<"tlb-rmi", "TLB_RMI",
-  "FEAT_TLBIOS, FEAT_TLBIRANGE",
-  "Enable v8.4-A TLB Range and Maintenance Instructions">;
+def FeatureTLB_RMI : SubtargetFeature<
+    "tlb-rmi", "HasTLB_RMI", "true",
+    "Enable v8.4-A TLB Range and Maintenance Instructions (FEAT_TLBIOS, FEAT_TLBIRANGE)">;
 
-def FeatureFlagM : ExtensionWithMArch<"flagm", "FlagM", "FEAT_FlagM",
-  "Enable v8.4-A Flag Manipulation Instructions">;
+def FeatureFlagM : Extension<
+    "flagm", "FlagM",
+    "Enable v8.4-A Flag Manipulation Instructions (FEAT_FlagM)", []>;
 
-def FeatureRCPC_IMMO : Extension<"rcpc-immo", "RCPC_IMMO", "FEAT_LRCPC2",
-  "Enable v8.4-A RCPC instructions with Immediate Offsets",
-  [FeatureRCPC]>;
+def FeatureRCPC_IMMO : SubtargetFeature<"rcpc-immo", "HasRCPC_IMMO", "true",
+    "Enable v8.4-A RCPC instructions with Immediate Offsets (FEAT_LRCPC2)",
+    [FeatureRCPC]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.5 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureAltFPCmp : Extension<"altnzcv", "AlternativeNZCV", "FEAT_FlagM2",
-  "Enable alternative NZCV format for floating point comparisons">;
+def FeatureAltFPCmp : SubtargetFeature<"altnzcv", "HasAlternativeNZCV", "true",
+  "Enable alternative NZCV format for floating point comparisons (FEAT_FlagM2)">;
 
-def FeatureFRInt3264 : Extension<"fptoint", "FRInt3264", "FEAT_FRINTTS",
+def FeatureFRInt3264 : SubtargetFeature<"fptoint", "HasFRInt3264", "true",
   "Enable FRInt[32|64][Z|X] instructions that round a floating-point number to "
-  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int">;
+  "an integer (in FP format) forcing it to fit into a 32- or 64-bit int (FEAT_FRINTTS)" >;
 
-def FeatureSB : ExtensionWithMArch<"sb", "SB", "FEAT_SB",
-  "Enable v8.5 Speculation Barrier">;
+def FeatureSB : Extension<"sb", "SB",
+  "Enable v8.5 Speculation Barrier (FEAT_SB)", []>;
 
-def FeatureSSBS : ExtensionWithMArch<"ssbs", "SSBS", "FEAT_SSBS, FEAT_SSBS2",
-  "Enable Speculative Store Bypass Safe bit">;
+def FeatureSSBS : Extension<"ssbs", "SSBS",
+  "Enable Speculative Store Bypass Safe bit (FEAT_SSBS, FEAT_SSBS2)", []>;
 
-def FeaturePredRes : ExtensionWithMArch<"predres", "PredRes", "FEAT_SPECRES",
-  "Enable v8.5a execution and data prediction invalidation instructions">;
+def FeaturePredRes : Extension<"predres", "PredRes",
+  "Enable v8.5a execution and data prediction invalidation instructions (FEAT_SPECRES)", []>;
 
-def FeatureCacheDeepPersist : Extension<"ccdp", "CCDP", "FEAT_DPB2",
-  "Enable v8.5 Cache Clean to Point of Deep Persistence">;
+def FeatureCacheDeepPersist : SubtargetFeature<"ccdp", "CCDP", "true",
+    "Enable v8.5 Cache Clean to Point of Deep Persistence (FEAT_DPB2)" >;
 
-def FeatureBranchTargetId : ExtensionWithMArch<"bti", "BTI", "FEAT_BTI",
-  "Enable Branch Target Identification">;
+def FeatureBranchTargetId : SubtargetFeature<"bti", "BTI", "true",
+    "Enable Branch Target Identification (FEAT_BTI)">;
 
-let ArchExtKindSpelling = "AEK_RAND", UserVisibleName = "rng" in
-def FeatureRandGen : ExtensionWithMArch<"rand", "RandGen", "FEAT_RNG",
-  "Enable Random Number generation instructions">;
+let ArchExtKindSpelling = "AEK_RAND", MArchName = "rng" in
+def FeatureRandGen : Extension<"rand", "RandGen",
+    "Enable Random Number generation instructions (FEAT_RNG)", []>;
 
 // NOTE: "memtag" means FEAT_MTE + FEAT_MTE2 for -march or
 // __attribute((target(...))), but only FEAT_MTE for FMV.
-let UserVisibleName = "memtag" in
-def FeatureMTE : ExtensionWithMArch<"mte", "MTE", "FEAT_MTE, FEAT_MTE2",
-  "Enable Memory Tagging Extension">;
+let MArchName = "memtag" in
+def FeatureMTE : Extension<"mte", "MTE",
+    "Enable Memory Tagging Extension (FEAT_MTE, FEAT_MTE2)", []>;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.6 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureBF16 : ExtensionWithMArch<"bf16", "BF16", "FEAT_BF16",
-  "Enable BFloat16 Extension">;
+def FeatureBF16 : Extension<"bf16", "BF16",
+    "Enable BFloat16 Extension (FEAT_BF16)">;
 
-def FeatureAMVS : Extension<"amvs", "AMVS", "FEAT_AMUv1p1",
-  "Enable v8.6-A Activity Monitors Virtualization support",
-  [FeatureAM]>;
+def FeatureAMVS : SubtargetFeature<
+    "amvs", "HasAMVS", "true",
+    "Enable v8.6-A Activity Monitors Virtualization support (FEAT_AMUv1p1)",
+    [FeatureAM]>;
 
-def FeatureFineGrainedTraps : Extension<"fgt", "FineGrainedTraps", "FEAT_FGT",
-  "Enable fine grained virtualization traps extension">;
+def FeatureFineGrainedTraps : SubtargetFeature<"fgt", "HasFineGrainedTraps",
+    "true", "Enable fine grained virtualization traps extension (FEAT_FGT)">;
 
 def FeatureEnhancedCounterVirtualization :
-    Extension<"ecv", "EnhancedCounterVirtualization", "FEAT_ECV",
-      "Enable enhanced counter virtualization extension">;
+      SubtargetFeature<"ecv", "HasEnhancedCounterVirtualization",
+      "true", "Enable enhanced counter virtualization extension (FEAT_ECV)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.7 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureXS : Extension<"xs", "XS", "FEAT_XS",
-  "Enable Armv8.7-A limited-TLB-maintenance instruction">;
+def FeatureXS : SubtargetFeature<"xs", "HasXS",
+    "true", "Enable Armv8.7-A limited-TLB-maintenance instruction (FEAT_XS)">;
 
-def FeatureWFxT : ExtensionWithMArch<"wfxt", "WFxT", "FEAT_WFxT",
-  "Enable Armv8.7-A WFET and WFIT instruction">;
+def FeatureWFxT : SubtargetFeature<"wfxt", "WFxT", "true",
+    "Enable Armv8.7-A WFET and WFIT instruction (FEAT_WFxT)">;
 
-def FeatureHCX : Extension<"hcx", "HCX", "FEAT_HCX",
-  "Enable Armv8.7-A HCRX_EL2 system register">;
+def FeatureHCX : SubtargetFeature<
+    "hcx", "HasHCX", "true", "Enable Armv8.7-A HCRX_EL2 system register (FEAT_HCX)">;
 
-def FeatureLS64 : ExtensionWithMArch<"ls64", "LS64",
-  "FEAT_LS64, FEAT_LS64_V, FEAT_LS64_ACCDATA",
-  "Enable Armv8.7-A LD64B/ST64B Accelerator Extension">;
+def FeatureLS64 : Extension<"ls64", "LS64",
+    "Enable Armv8.7-A LD64B/ST64B Accelerator Extension (FEAT_LS64, FEAT_LS64_V, FEAT_LS64_ACCDATA)", []>;
 
-def FeatureSPE_EEF : Extension<"spe-eef", "SPE_EEF", "FEAT_SPEv1p2",
-  "Enable extra register in the Statistical Profiling Extension">;
+def FeatureSPE_EEF : SubtargetFeature<"spe-eef", "HasSPE_EEF",
+    "true", "Enable extra register in the Statistical Profiling Extension (FEAT_SPEv1p2)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.8 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureHBC : ExtensionWithMArch<"hbc", "HBC", "FEAT_HBC",
-    "Enable Armv8.8-A Hinted Conditional Branches Extension">;
+def FeatureHBC : Extension<"hbc", "HBC",
+    "Enable Armv8.8-A Hinted Conditional Branches Extension (FEAT_HBC)">;
 
-def FeatureMOPS : ExtensionWithMArch<"mops", "MOPS", "FEAT_MOPS",
-    "Enable Armv8.8-A memcpy and memset acceleration instructions">;
+def FeatureMOPS : Extension<"mops", "MOPS",
+    "Enable Armv8.8-A memcpy and memset acceleration instructions (FEAT_MOPS)", []>;
 
-def FeatureNMI : Extension<"nmi", "NMI", "FEAT_NMI, FEAT_GICv3_NMI",
-  "Enable Armv8.8-A Non-maskable Interrupts">;
+def FeatureNMI : SubtargetFeature<"nmi", "HasNMI",
+    "true", "Enable Armv8.8-A Non-maskable Interrupts (FEAT_NMI, FEAT_GICv3_NMI)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv8.9 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureRASv2 : ExtensionWithMArch<"rasv2", "RASv2", "FEAT_RASv2",
-  "Enable ARMv8.9-A Reliability, Availability and Serviceability Extensions",
+def FeatureRASv2 : Extension<"rasv2", "RASv2",
+  "Enable ARMv8.9-A Reliability, Availability and Serviceability Extensions (FEAT_RASv2)",
   [FeatureRAS]>;
 
-def FeatureCSSC : ExtensionWithMArch<"cssc", "CSSC", "FEAT_CSSC",
-  "Enable Common Short Sequence Compression (CSSC) instructions">;
+def FeatureCSSC : Extension<"cssc", "CSSC",
+  "Enable Common Short Sequence Compression (CSSC) instructions (FEAT_CSSC)">;
 
-def FeatureCLRBHB : Extension<"clrbhb", "CLRBHB", "FEAT_CLRBHB",
-  "Enable Clear BHB instruction">;
+def FeatureCLRBHB : SubtargetFeature<"clrbhb", "HasCLRBHB",
+    "true", "Enable Clear BHB instruction (FEAT_CLRBHB)">;
 
-def FeaturePRFM_SLC : Extension<"prfm-slc-target", "PRFM_SLC", "FEAT_PRFMSLC",
-  "Enable SLC target for PRFM instruction">;
+def FeaturePRFM_SLC : SubtargetFeature<"prfm-slc-target", "HasPRFM_SLC",
+    "true", "Enable SLC target for PRFM instruction">;
 
-let UserVisibleName = "predres2" in
-def FeatureSPECRES2 : ExtensionWithMArch<"specres2", "SPECRES2", "FEAT_SPECRES2",
-  "Enable Speculation Restriction Instruction",
-  [FeaturePredRes]>;
+let MArchName = "predres2" in
+def FeatureSPECRES2 : Extension<"specres2", "SPECRES2",
+    "Enable Speculation Restriction Instruction (FEAT_SPECRES2)",
+    [FeaturePredRes]>;
 
-def FeatureRCPC3 : ExtensionWithMArch<"rcpc3", "RCPC3", "FEAT_LRCPC3",
-  "Enable Armv8.9-A RCPC instructions for A64 and Advanced SIMD and floating-point instruction set",
-  [FeatureRCPC_IMMO]>;
+def FeatureRCPC3 : Extension<"rcpc3", "RCPC3",
+    "Enable Armv8.9-A RCPC instructions for A64 and Advanced SIMD and floating-point instruction set (FEAT_LRCPC3)",
+    [FeatureRCPC_IMMO]>;
 
-def FeatureTHE : ExtensionWithMArch<"the", "THE", "FEAT_THE",
-  "Enable Armv8.9-A Translation Hardening Extension">;
+def FeatureTHE : Extension<"the", "THE",
+    "Enable Armv8.9-A Translation Hardening Extension (FEAT_THE)">;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.0 Architecture Extensions
@@ -358,32 +360,32 @@ def FeatureTHE : ExtensionWithMArch<"the", "THE", "FEAT_THE",
 def FeatureUseScalarIncVL : SubtargetFeature<"use-scalar-inc-vl",
   "UseScalarIncVL", "true", "Prefer inc/dec over add+cnt">;
 
-def FeatureSVE2 : ExtensionWithMArch<"sve2", "SVE2", "FEAT_SVE2",
-  "Enable Scalable Vector Extension 2 (SVE2) instructions",
+def FeatureSVE2 : Extension<"sve2", "SVE2",
+  "Enable Scalable Vector Extension 2 (SVE2) instructions (FEAT_SVE2)",
   [FeatureSVE, FeatureUseScalarIncVL]>;
 
-def FeatureSVE2AES : ExtensionWithMArch<"sve2-aes", "SVE2AES",
-  "FEAT_SVE_AES, FEAT_SVE_PMULL128",
-  "Enable AES SVE2 instructions", [FeatureSVE2, FeatureAES]>;
+def FeatureSVE2AES : Extension<"sve2-aes", "SVE2AES",
+  "Enable AES SVE2 instructions (FEAT_SVE_AES, FEAT_SVE_PMULL128)",
+  [FeatureSVE2, FeatureAES]>;
 
-def FeatureSVE2SM4 : ExtensionWithMArch<"sve2-sm4", "SVE2SM4", "FEAT_SVE_SM4",
-  "Enable SM4 SVE2 instructions", [FeatureSVE2, FeatureSM4]>;
+def FeatureSVE2SM4 : Extension<"sve2-sm4", "SVE2SM4",
+  "Enable SM4 SVE2 instructions (FEAT_SVE_SM4)", [FeatureSVE2, FeatureSM4]>;
 
-def FeatureSVE2SHA3 : ExtensionWithMArch<"sve2-sha3", "SVE2SHA3", "FEAT_SVE_SHA3",
-  "Enable SHA3 SVE2 instructions", [FeatureSVE2, FeatureSHA3]>;
+def FeatureSVE2SHA3 : Extension<"sve2-sha3", "SVE2SHA3",
+  "Enable SHA3 SVE2 instructions (FEAT_SVE_SHA3)", [FeatureSVE2, FeatureSHA3]>;
 
-def FeatureSVE2BitPerm : ExtensionWithMArch<"sve2-bitperm", "SVE2BitPerm",
-  "FEAT_SVE_BitPerm",
-  "Enable bit permutation SVE2 instructions", [FeatureSVE2]>;
+def FeatureSVE2BitPerm : Extension<"sve2-bitperm", "SVE2BitPerm",
+  "Enable bit permutation SVE2 instructions (FEAT_SVE_BitPerm)", [FeatureSVE2]>;
 
-def FeatureTRBE : Extension<"trbe", "TRBE", "FEAT_TRBE",
-  "Enable Trace Buffer Extension">;
+def FeatureTRBE : SubtargetFeature<"trbe", "TRBE", "true",
+    "Enable Trace Buffer Extension (FEAT_TRBE)">;
 
-def FeatureETE : Extension<"ete", "ETE", "FEAT_ETE",
-  "Enable Embedded Trace Extension", [FeatureTRBE]>;
+def FeatureETE : SubtargetFeature<"ete", "ETE", "true",
+    "Enable Embedded Trace Extension (FEAT_ETE)",
+    [FeatureTRBE]>;
 
-def FeatureTME : ExtensionWithMArch<"tme", "TME", "FEAT_TME",
-  "Enable Transactional Memory Extension">;
+def FeatureTME : Extension<"tme", "TME",
+    "Enable Transactional Memory Extension (FEAT_TME)" >;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.1 Architecture Extensions
@@ -393,119 +395,119 @@ def FeatureTME : ExtensionWithMArch<"tme", "TME", "FEAT_TME",
 //  Armv9.2 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureBRBE : ExtensionWithMArch<"brbe", "BRBE", "FEAT_BRBE",
-  "Enable Branch Record Buffer Extension">;
+def FeatureBRBE : Extension<"brbe", "BRBE",
+    "Enable Branch Record Buffer Extension (FEAT_BRBE)">;
 
-def FeatureRME : Extension<"rme", "RME", "FEAT_RME",
-  "Enable Realm Management Extension">;
+def FeatureRME : SubtargetFeature<"rme", "HasRME",
+    "true", "Enable Realm Management Extension (FEAT_RME)">;
 
-def FeatureSME : ExtensionWithMArch<"sme", "SME", "FEAT_SME",
-  "Enable Scalable Matrix Extension (SME)", [FeatureBF16, FeatureUseScalarIncVL]>;
+def FeatureSME : Extension<"sme", "SME",
+  "Enable Scalable Matrix Extension (SME) (FEAT_SME)", [FeatureBF16, FeatureUseScalarIncVL]>;
 
-def FeatureSMEF64F64 : ExtensionWithMArch<"sme-f64f64", "SMEF64F64", "FEAT_SME_F64F64",
-  "Enable Scalable Matrix Extension (SME) F64F64 instructions", [FeatureSME]>;
+def FeatureSMEF64F64 : Extension<"sme-f64f64", "SMEF64F64",
+  "Enable Scalable Matrix Extension (SME) F64F64 instructions (FEAT_SME_F64F64)", [FeatureSME]>;
 
-def FeatureSMEI16I64 : ExtensionWithMArch<"sme-i16i64", "SMEI16I64", "FEAT_SME_I16I64",
-  "Enable Scalable Matrix Extension (SME) I16I64 instructions", [FeatureSME]>;
+def FeatureSMEI16I64 : Extension<"sme-i16i64", "SMEI16I64",
+  "Enable Scalable Matrix Extension (SME) I16I64 instructions (FEAT_SME_I16I64)", [FeatureSME]>;
 
-def FeatureSMEFA64 : ExtensionWithMArch<"sme-fa64", "SMEFA64", "FEAT_SME_FA64",
-  "Enable the full A64 instruction set in streaming SVE mode", [FeatureSME, FeatureSVE2]>;
+def FeatureSMEFA64 : Extension<"sme-fa64", "SMEFA64",
+  "Enable the full A64 instruction set in streaming SVE mode (FEAT_SME_FA64)", [FeatureSME, FeatureSVE2]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.3 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSME2 : ExtensionWithMArch<"sme2", "SME2", "FEAT_SME2",
+def FeatureSME2 : Extension<"sme2", "SME2",
   "Enable Scalable Matrix Extension 2 (SME2) instructions", [FeatureSME]>;
 
-def FeatureMEC : Extension<"mec", "MEC", "FEAT_MEC",
-  "Enable Memory Encryption Contexts Extension", [FeatureRME]>;
+def FeatureMEC : SubtargetFeature<"mec", "HasMEC",
+    "true", "Enable Memory Encryption Contexts Extension", [FeatureRME]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.4 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureSVE2p1: ExtensionWithMArch<"sve2p1", "SVE2p1", "FEAT_SVE2p1",
+def FeatureSVE2p1: Extension<"sve2p1", "SVE2p1",
   "Enable Scalable Vector Extension 2.1 instructions", [FeatureSVE2]>;
 
-def FeatureB16B16 : ExtensionWithMArch<"b16b16", "B16B16", "FEAT_SVE_B16B16",
-  "Enable SVE2.1 or SME2.1 non-widening BFloat16 to BFloat16 instructions", [FeatureBF16]>;
+def FeatureB16B16 : Extension<"b16b16", "B16B16",
+  "Enable SVE2.1 or SME2.1 non-widening BFloat16 to BFloat16 instructions (FEAT_B16B16)", [FeatureBF16]>;
 
-def FeatureSMEF16F16 : ExtensionWithMArch<"sme-f16f16", "SMEF16F16", "FEAT_SME_F16F16",
-  "Enable SME non-widening Float16 instructions", [FeatureSME2]>;
+def FeatureSMEF16F16 : Extension<"sme-f16f16", "SMEF16F16",
+  "Enable SME non-widening Float16 instructions (FEAT_SME_F16F16)", [FeatureSME2]>;
 
-def FeatureSME2p1 : ExtensionWithMArch<"sme2p1", "SME2p1", "FEAT_SME2p1",
-  "Enable Scalable Matrix Extension 2.1 instructions", [FeatureSME2]>;
+def FeatureSME2p1 : Extension<"sme2p1", "SME2p1",
+  "Enable Scalable Matrix Extension 2.1 (FEAT_SME2p1) instructions", [FeatureSME2]>;
 
-def FeatureCHK : Extension<"chk", "CHK", "FEAT_CHK",
-  "Enable Armv8.0-A Check Feature Status Extension">;
+def FeatureCHK : SubtargetFeature<"chk", "HasCHK",
+    "true", "Enable Armv8.0-A Check Feature Status Extension (FEAT_CHK)">;
 
-def FeatureGCS : ExtensionWithMArch<"gcs", "GCS", "FEAT_GCS",
-  "Enable Armv9.4-A Guarded Call Stack Extension", [FeatureCHK]>;
+def FeatureGCS : Extension<"gcs", "GCS",
+    "Enable Armv9.4-A Guarded Call Stack Extension", [FeatureCHK]>;
 
-def FeatureITE : ExtensionWithMArch<"ite", "ITE", "FEAT_ITE",
-  "Enable Armv9.4-A Instrumentation Extension", [FeatureETE, FeatureTRBE]>;
+def FeatureITE : Extension<"ite", "ITE",
+    "Enable Armv9.4-A Instrumentation Extension FEAT_ITE", [FeatureETE,
+    FeatureTRBE]>;
 
-def FeatureLSE128 : ExtensionWithMArch<"lse128", "LSE128", "FEAT_LSE128",
-  "Enable Armv9.4-A 128-bit Atomic Instructions",
-  [FeatureLSE]>;
+def FeatureLSE128 : Extension<"lse128", "LSE128",
+    "Enable Armv9.4-A 128-bit Atomic Instructions (FEAT_LSE128)",
+    [FeatureLSE]>;
 
 // FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, and FEAT_SYSINSTR128 are mutually implicit.
 // Therefore group them all under a single feature flag, d128:
-def FeatureD128 : ExtensionWithMArch<"d128", "D128",
-  "FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, FEAT_SYSINSTR128",
-  "Enable Armv9.4-A 128-bit Page Table Descriptors, System Registers "
-  "and Instructions",
-  [FeatureLSE128]>;
+def FeatureD128 : Extension<"d128", "D128",
+    "Enable Armv9.4-A 128-bit Page Table Descriptors, System Registers "
+    "and Instructions (FEAT_D128, FEAT_LVA3, FEAT_SYSREG128, FEAT_SYSINSTR128)",
+    [FeatureLSE128]>;
 
 //===----------------------------------------------------------------------===//
 //  Armv9.5 Architecture Extensions
 //===----------------------------------------------------------------------===//
 
-def FeatureFAMINMAX: ExtensionWithMArch<"faminmax", "FAMINMAX", "FEAT_FAMINMAX",
- "Enable FAMIN and FAMAX instructions">;
+def FeatureFAMINMAX: Extension<"faminmax", "FAMINMAX",
+   "Enable FAMIN and FAMAX instructions (FEAT_FAMINMAX)">;
 
-def FeatureLUT: ExtensionWithMArch<"lut", "LUT", "FEAT_LUT",
- "Enable Lookup Table instructions">;
+def FeatureLUT: Extension<"lut", "LUT",
+   "Enable Lookup Table instructions (FEAT_LUT)">;
    
-def FeatureFP8 : ExtensionWithMArch<"fp8", "FP8", "FEAT_FP8",
-  "Enable FP8 instructions", [FeatureFAMINMAX, FeatureLUT, FeatureBF16]>;
+def FeatureFP8 : Extension<"fp8", "FP8",
+  "Enable FP8 instructions (FEAT_FP8)", [FeatureFAMINMAX, FeatureLUT, FeatureBF16]>;
   
-def FeatureFP8FMA : ExtensionWithMArch<"fp8fma", "FP8FMA", "FEAT_FP8FMA",
-  "Enable fp8 multiply-add instructions", [FeatureFP8]>;
+def FeatureFP8FMA : Extension<"fp8fma", "FP8FMA",
+  "Enable fp8 multiply-add instructions (FEAT_FP8FMA)", [FeatureFP8]>;
 
-def FeatureSSVE_FP8FMA : ExtensionWithMArch<"ssve-fp8fma", "SSVE_FP8FMA", "FEAT_SSVE_FP8FMA",
-  "Enable SVE2 fp8 multiply-add instructions", [FeatureSME2, FeatureFP8]>;
+def FeatureSSVE_FP8FMA : Extension<"ssve-fp8fma", "SSVE_FP8FMA",
+  "Enable SVE2 fp8 multiply-add instructions (FEAT_SSVE_FP8FMA)", [FeatureSME2, FeatureFP8]>;
 
-def FeatureFP8DOT4: ExtensionWithMArch<"fp8dot4", "FP8DOT4", "FEAT_FP8DOT4",
-  "Enable fp8 4-way dot instructions", [FeatureFP8FMA]>;
+def FeatureFP8DOT4: Extension<"fp8dot4", "FP8DOT4",
+   "Enable fp8 4-way dot instructions (FEAT_FP8DOT4)", [FeatureFP8FMA]>;
   
-def FeatureFP8DOT2: ExtensionWithMArch<"fp8dot2", "FP8DOT2", "FEAT_FP8DOT2",
-  "Enable fp8 2-way dot instructions", [FeatureFP8DOT4]>;
+def FeatureFP8DOT2: Extension<"fp8dot2", "FP8DOT2",
+   "Enable fp8 2-way dot instructions (FEAT_FP8DOT2)", [FeatureFP8DOT4]>;
 
-def FeatureSSVE_FP8DOT4 : ExtensionWithMArch<"ssve-fp8dot4", "SSVE_FP8DOT4", "FEAT_SSVE_FP8DOT4",
-  "Enable SVE2 fp8 4-way dot product instructions", [FeatureSSVE_FP8FMA]>;
+def FeatureSSVE_FP8DOT4 : Extension<"ssve-fp8dot4", "SSVE_FP8DOT4",
+  "Enable SVE2 fp8 4-way dot product instructions (FEAT_SSVE_FP8DOT4)", [FeatureSSVE_FP8FMA]>;
 
-def FeatureSSVE_FP8DOT2 : ExtensionWithMArch<"ssve-fp8dot2", "SSVE_FP8DOT2", "FEAT_SSVE_FP8DOT2",
-  "Enable SVE2 fp8 2-way dot product instructions", [FeatureSSVE_FP8DOT4]>;
+def FeatureSSVE_FP8DOT2 : Extension<"ssve-fp8dot2", "SSVE_FP8DOT2",
+  "Enable SVE2 fp8 2-way dot product instructions (FEAT_SSVE_FP8DOT2)", [FeatureSSVE_FP8DOT4]>;
 
-def FeatureSME_LUTv2 : ExtensionWithMArch<"sme-lutv2", "SME_LUTv2", "FEAT_SME_LUTv2",
-  "Enable Scalable Matrix Extension (SME) LUTv2 instructions">;
+def FeatureSME_LUTv2 : Extension<"sme-lutv2", "SME_LUTv2",
+  "Enable Scalable Matrix Extension (SME) LUTv2 instructions (FEAT_SME_LUTv2)">;
 
-def FeatureSMEF8F32 : ExtensionWithMArch<"sme-f8f32", "SMEF8F32", "FEAT_SME_F8F32",
-  "Enable Scalable Matrix Extension (SME) F8F32 instructions", [FeatureSME2, FeatureFP8]>;
+def FeatureSMEF8F32 : Extension<"sme-f8f32", "SMEF8F32",
+  "Enable Scalable Matrix Extension (SME) F8F32 instructions (FEAT_SME_F8F32)", [FeatureSME2, FeatureFP8]>;
 
-def FeatureSMEF8F16 : ExtensionWithMArch<"sme-f8f16", "SMEF8F16", "FEAT_SME_F8F16",
-  "Enable Scalable Matrix Extension (SME) F8F16 instructions", [FeatureSMEF8F32]>;
+def FeatureSMEF8F16 : Extension<"sme-f8f16", "SMEF8F16",
+  "Enable Scalable Matrix Extension (SME) F8F16 instructions(FEAT_SME_F8F16)", [FeatureSMEF8F32]>;
 
-def FeatureCPA : ExtensionWithMArch<"cpa", "CPA", "FEAT_CPA",
-  "Enable Armv9.5-A Checked Pointer Arithmetic">;
+def FeatureCPA : Extension<"cpa", "CPA",
+    "Enable Armv9.5-A Checked Pointer Arithmetic (FEAT_CPA)">;
 
-def FeaturePAuthLR : ExtensionWithMArch<"pauth-lr", "PAuthLR", "FEAT_PAuth_LR",
-  "Enable Armv9.5-A PAC enhancements">;
+def FeaturePAuthLR : Extension<"pauth-lr", "PAuthLR",
+    "Enable Armv9.5-A PAC enhancements (FEAT_PAuth_LR)">;
 
-def FeatureTLBIW : ExtensionWithMArch<"tlbiw", "TLBIW", "FEAT_TLBIW",
-  "Enable ARMv9.5-A TLBI VMALL for Dirty State">;
+def FeatureTLBIW : Extension<"tlbiw", "TLBIW",
+  "Enable ARMv9.5-A TLBI VMALL for Dirty State (FEAT_TLBIW)">;
 
 //===----------------------------------------------------------------------===//
 //  Other Features
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index 2dde4d2b7e2a3..7986f07538df7 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -18,7 +18,6 @@
 #include "llvm/TargetParser/ARMTargetParserCommon.h"
 #include "llvm/TargetParser/Triple.h"
 #include <cctype>
-#include <vector>
 
 #define DEBUG_TYPE "target-parser"
 
@@ -62,8 +61,8 @@ bool AArch64::getExtensionFeatures(
     std::vector<StringRef> &Features) {
   for (const auto &E : Extensions)
     /* INVALID and NONE have no feature name. */
-    if (InputExts.test(E.ID) && !E.PosTargetFeature.empty())
-      Features.push_back(E.PosTargetFeature);
+    if (InputExts.test(E.ID) && !E.Feature.empty())
+      Features.push_back(E.Feature);
 
   return true;
 }
@@ -80,8 +79,8 @@ StringRef AArch64::getArchExtFeature(StringRef ArchExt) {
   StringRef ArchExtBase = IsNegated ? ArchExt.drop_front(2) : ArchExt;
 
   if (auto AE = parseArchExtension(ArchExtBase)) {
-    assert(!(AE.has_value() && AE->NegTargetFeature.empty()));
-    return IsNegated ? AE->NegTargetFeature : AE->PosTargetFeature;
+    assert(!(AE.has_value() && AE->NegFeature.empty()));
+    return IsNegated ? AE->NegFeature : AE->Feature;
   }
 
   return StringRef();
@@ -116,10 +115,8 @@ const AArch64::ArchInfo *AArch64::parseArch(StringRef Arch) {
 
 std::optional<AArch64::ExtensionInfo>
 AArch64::parseArchExtension(StringRef ArchExt) {
-  if (ArchExt.empty())
-    return {};
   for (const auto &A : Extensions) {
-    if (ArchExt == A.UserVisibleName || ArchExt == A.Alias)
+    if (ArchExt == A.Name || ArchExt == A.Alias)
       return A;
   }
   return {};
@@ -140,7 +137,7 @@ std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
 std::optional<AArch64::ExtensionInfo>
 AArch64::targetFeatureToExtension(StringRef TargetFeature) {
   for (const auto &E : Extensions)
-    if (TargetFeature == E.PosTargetFeature)
+    if (TargetFeature == E.Feature)
       return E;
   return {};
 }
@@ -157,48 +154,21 @@ std::optional<AArch64::CpuInfo> AArch64::parseCpu(StringRef Name) {
   return {};
 }
 
-void AArch64::PrintSupportedExtensions() {
+void AArch64::PrintSupportedExtensions(StringMap<StringRef> DescMap) {
   outs() << "All available -march extensions for AArch64\n\n"
          << "    " << left_justify("Name", 20)
-         << left_justify("Architecture Feature(s)", 55)
-         << "Description\n";
+         << (DescMap.empty() ? "\n" : "Description\n");
   for (const auto &Ext : Extensions) {
     // Extensions without a feature cannot be used with -march.
-    if (!Ext.UserVisibleName.empty() && !Ext.PosTargetFeature.empty()) {
+    if (!Ext.Feature.empty()) {
+      std::string Description = DescMap[Ext.Name].str();
       outs() << "    "
-             << format(Ext.Description.empty() ? "%-20s%s\n" : "%-20s%-55s%s\n",
-                       Ext.UserVisibleName.str().c_str(),
-                       Ext.ArchFeatureName.str().c_str(),
-                       Ext.Description.str().c_str());
+             << format(Description.empty() ? "%s\n" : "%-20s%s\n",
+                       Ext.Name.str().c_str(), Description.c_str());
     }
   }
 }
 
-void
-AArch64::printEnabledExtensions(std::set<StringRef> EnabledFeatureNames) {
-  outs() << "Extensions enabled for the given AArch64 target\n\n"
-         << "    " << left_justify("Architecture Feature(s)", 55)
-         << "Description\n";
-  std::vector<ExtensionInfo> EnabledExtensionsInfo;
-  for (const auto &FeatureName : EnabledFeatureNames) {
-    std::string PosFeatureName = '+' + FeatureName.str();
-    if (auto ExtInfo = targetFeatureToExtension(PosFeatureName))
-      EnabledExtensionsInfo.push_back(*ExtInfo);
-  }
-
-  std::sort(EnabledExtensionsInfo.begin(), EnabledExtensionsInfo.end(),
-            [](const ExtensionInfo &Lhs, const ExtensionInfo &Rhs) {
-              return Lhs.ArchFeatureName < Rhs.ArchFeatureName;
-            });
-
-  for (const auto &Ext : EnabledExtensionsInfo) {
-    outs() << "    "
-           << format("%-55s%s\n",
-                     Ext.ArchFeatureName.str().c_str(),
-                     Ext.Description.str().c_str());
-  }
-}
-
 const llvm::AArch64::ExtensionInfo &
 lookupExtensionByID(llvm::AArch64::ArchExtKind ExtID) {
   for (const auto &E : llvm::AArch64::Extensions)
@@ -211,7 +181,7 @@ void AArch64::ExtensionSet::enable(ArchExtKind E) {
   if (Enabled.test(E))
     return;
 
-  LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).UserVisibleName << "\n");
+  LLVM_DEBUG(llvm::dbgs() << "Enable " << lookupExtensionByID(E).Name << "\n");
 
   Touched.set(E);
   Enabled.set(E);
@@ -252,7 +222,7 @@ void AArch64::ExtensionSet::disable(ArchExtKind E) {
   if (!Enabled.test(E))
     return;
 
-  LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).UserVisibleName << "\n");
+  LLVM_DEBUG(llvm::dbgs() << "Disable " << lookupExtensionByID(E).Name << "\n");
 
   Touched.set(E);
   Enabled.reset(E);
@@ -296,7 +266,7 @@ bool AArch64::ExtensionSet::parseModifier(StringRef Modifier,
   StringRef ArchExt = Modifier.drop_front(NChars);
 
   if (auto AE = parseArchExtension(ArchExt)) {
-    if (AE->PosTargetFeature.empty() || AE->NegTargetFeature.empty())
+    if (AE->Feature.empty() || AE->NegFeature.empty())
       return false;
     if (IsNegated)
       disable(AE->ID);
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index fe20099382859..553f5df7827e2 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1130,8 +1130,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_MTE,         AArch64::AEK_SSBS,
                  AArch64::AEK_FP16,        AArch64::AEK_FP16FML,
                  AArch64::AEK_SB,          AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_AM}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a520", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1148,8 +1147,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
-                 AArch64::AEK_ETE}),
+                 AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a520ae", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1166,8 +1164,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
-                 AArch64::AEK_ETE}),
+                 AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a57", "armv8-a", "crypto-neon-fp-armv8",
@@ -1282,8 +1279,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PAUTH,   AArch64::AEK_FLAGM,
                  AArch64::AEK_SB,      AArch64::AEK_I8MM,
                  AArch64::AEK_BF16,    AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a715", "armv9-a", "neon-fp-armv8",
@@ -1300,8 +1296,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PREDRES, AArch64::AEK_PROFILE,
                  AArch64::AEK_FP16FML, AArch64::AEK_FP16,
                  AArch64::AEK_FLAGM,   AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,     AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a720", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1318,9 +1313,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
-                 AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a720ae", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1337,9 +1330,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
-                 AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-a725", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1356,8 +1347,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_ETE,
-                 AArch64::AEK_SPE_EEF,     AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v1", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1374,8 +1364,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PROFILE, AArch64::AEK_RAND,
                  AArch64::AEK_FP16FML, AArch64::AEK_I8MM,
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
-                 AArch64::AEK_CCDP}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v2", "armv9-a", "neon-fp-armv8",
@@ -1391,8 +1380,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FP16FML,     AArch64::AEK_I8MM,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_RAND,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,       AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE}),
+                 AArch64::AEK_PAUTH,       AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v3", "armv9.2-a", "neon-fp-armv8",
@@ -1411,8 +1399,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PERFMON,     AArch64::AEK_RAND,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FP16FML,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-v3ae", "armv9.2-a", "neon-fp-armv8",
@@ -1431,8 +1418,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PERFMON,     AArch64::AEK_RAND,
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FP16FML,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-r82", "armv8-r", "crypto-neon-fp-armv8",
@@ -1443,7 +1429,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC, AArch64::AEK_LSE, AArch64::AEK_SB,
                  AArch64::AEK_JSCVT, AArch64::AEK_FCMA, AArch64::AEK_PAUTH,
                  AArch64::AEK_FLAGM, AArch64::AEK_PERFMON,
-                 AArch64::AEK_PREDRES, AArch64::AEK_CCDP}),
+                 AArch64::AEK_PREDRES}),
             "8-R"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-r82ae", "armv8-r", "crypto-neon-fp-armv8",
@@ -1454,7 +1440,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC, AArch64::AEK_LSE, AArch64::AEK_SB,
                  AArch64::AEK_JSCVT, AArch64::AEK_FCMA, AArch64::AEK_PAUTH,
                  AArch64::AEK_FLAGM, AArch64::AEK_PERFMON,
-                 AArch64::AEK_PREDRES, AArch64::AEK_CCDP}),
+                 AArch64::AEK_PREDRES}),
             "8-R"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x1", "armv8.2-a", "crypto-neon-fp-armv8",
@@ -1473,7 +1459,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RAS, AArch64::AEK_LSE, AArch64::AEK_FP16,
                  AArch64::AEK_DOTPROD, AArch64::AEK_RCPC, AArch64::AEK_SSBS,
                  AArch64::AEK_PAUTH, AArch64::AEK_PROFILE, AArch64::AEK_FLAGM,
-                 AArch64::AEK_PERFMON, AArch64::AEK_LSE2, AArch64::AEK_RCPC_IMMO}),
+                 AArch64::AEK_PERFMON}),
             "8.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x2", "armv9-a", "neon-fp-armv8",
@@ -1489,8 +1475,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SB,          AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML,     AArch64::AEK_FLAGM,
                  AArch64::AEK_JSCVT,       AArch64::AEK_FCMA,
-                 AArch64::AEK_PERFMON,     AArch64::AEK_AM,
-                 AArch64::AEK_ETE}),
+                 AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x3", "armv9-a", "neon-fp-armv8",
@@ -1507,8 +1492,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FP16,    AArch64::AEK_FP16FML,
                  AArch64::AEK_PREDRES, AArch64::AEK_FLAGM,
                  AArch64::AEK_SSBS,    AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,     AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA,    AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x4", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1525,9 +1509,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_SPE_EEF,
-                 AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA,        AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cortex-x925", "armv9.2-a", "crypto-neon-fp-armv8",
@@ -1544,8 +1526,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_FLAGM,
                  AArch64::AEK_PERFMON,     AArch64::AEK_PREDRES,
                  AArch64::AEK_PROFILE,     AArch64::AEK_JSCVT,
-                 AArch64::AEK_FCMA,        AArch64::AEK_ETE,
-                 AArch64::AEK_SPE_EEF,     AArch64::AEK_TRBE}),
+                 AArch64::AEK_FCMA}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "cyclone", "armv8-a", "crypto-neon-fp-armv8",
@@ -1576,8 +1557,7 @@ INSTANTIATE_TEST_SUITE_P(
             AArch64::ExtensionBitset({AArch64::AEK_CRC, AArch64::AEK_AES,
                                       AArch64::AEK_SHA2, AArch64::AEK_FP,
                                       AArch64::AEK_RDM, AArch64::AEK_SIMD,
-                                      AArch64::AEK_PERFMON, AArch64::AEK_PAN,
-                                      AArch64::AEK_LOR, AArch64::AEK_VH}),
+                                      AArch64::AEK_PERFMON}),
             "8-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a11", "armv8.2-a", "crypto-neon-fp-armv8",
@@ -1637,9 +1617,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
                  AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
                  AArch64::AEK_PREDRES, AArch64::AEK_SB,
-                 AArch64::AEK_SSBS,    AArch64::AEK_CCDP,
-                 AArch64::AEK_FRINT3264, AArch64::AEK_SPECRESTRICT,
-                 AArch64::AEK_ALTERNATIVENZCV}),
+                 AArch64::AEK_SSBS}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m1", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1654,9 +1632,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
                  AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
                  AArch64::AEK_PREDRES, AArch64::AEK_SB,
-                 AArch64::AEK_SSBS,    AArch64::AEK_CCDP,
-                 AArch64::AEK_FRINT3264, AArch64::AEK_SPECRESTRICT,
-                 AArch64::AEK_ALTERNATIVENZCV}),
+                 AArch64::AEK_SSBS}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a15", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1689,7 +1665,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m3", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1700,7 +1676,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-a17", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1711,7 +1687,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_RCPC,    AArch64::AEK_DOTPROD, AArch64::AEK_FP16,
                  AArch64::AEK_FP16FML, AArch64::AEK_SHA3,    AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,    AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON, AArch64::AEK_HCX}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
             "8.6-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "apple-m4", "armv8.7-a", "crypto-neon-fp-armv8",
@@ -1795,8 +1771,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SVE2BITPERM, AArch64::AEK_BF16,
                  AArch64::AEK_I8MM,        AArch64::AEK_JSCVT,
                  AArch64::AEK_FCMA,        AArch64::AEK_PAUTH,
-                 AArch64::AEK_FP16FML,     AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,         AArch64::AEK_TRBE}),
+                 AArch64::AEK_FP16FML,     AArch64::AEK_PERFMON}),
             "9-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-n3", "armv9.2-a", "neon-fp-armv8",
@@ -1814,8 +1789,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_FLAGM,   AArch64::AEK_PERFMON,
                  AArch64::AEK_RAND,    AArch64::AEK_SVE2BITPERM,
                  AArch64::AEK_FP16FML, AArch64::AEK_PROFILE,
-                 AArch64::AEK_JSCVT,   AArch64::AEK_PERFMON,
-                 AArch64::AEK_ETE,     AArch64::AEK_SPE_EEF}),
+                 AArch64::AEK_JSCVT,   AArch64::AEK_PERFMON}),
             "9.2-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "ampere1", "armv8.6-a", "crypto-neon-fp-armv8",
@@ -1850,8 +1824,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_SHA2,  AArch64::AEK_AES,   AArch64::AEK_I8MM,
                  AArch64::AEK_SSBS,  AArch64::AEK_SB,    AArch64::AEK_RAND,
                  AArch64::AEK_MTE,   AArch64::AEK_JSCVT, AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH, AArch64::AEK_CSSC,  AArch64::AEK_PERFMON,
-                 AArch64::AEK_WFXT}),
+                 AArch64::AEK_PAUTH, AArch64::AEK_CSSC,  AArch64::AEK_PERFMON}),
             "8.7-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "neoverse-512tvb", "armv8.4-a", "crypto-neon-fp-armv8",
@@ -1868,8 +1841,7 @@ INSTANTIATE_TEST_SUITE_P(
                  AArch64::AEK_PROFILE, AArch64::AEK_RAND,
                  AArch64::AEK_FP16FML, AArch64::AEK_I8MM,
                  AArch64::AEK_JSCVT,   AArch64::AEK_FCMA,
-                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON,
-                 AArch64::AEK_CCDP}),
+                 AArch64::AEK_PAUTH,   AArch64::AEK_PERFMON}),
             "8.4-A"),
         ARMCPUTestParams<AArch64::ExtensionBitset>(
             "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8",
@@ -2380,11 +2352,17 @@ TEST(TargetParserTest, AArch64ArchExtFeature) {
 TEST(TargetParserTest, AArch64PrintSupportedExtensions) {
   std::string expected =
       "All available -march extensions for AArch64\n\n"
-      "    Name                Architecture Feature(s)                                Description\n";
+      "    Name                Description\n"
+      "    aes                 This is a long dummy description\n"
+      "    b16b16\n"
+      "    bf16\n";
+
+  StringMap<StringRef> DummyMap;
+  DummyMap["aes"] = "This is a long dummy description";
 
   outs().flush();
   testing::internal::CaptureStdout();
-  AArch64::PrintSupportedExtensions();
+  AArch64::PrintSupportedExtensions(DummyMap);
   outs().flush();
   std::string captured = testing::internal::GetCapturedStdout();
 
@@ -2400,23 +2378,6 @@ TEST(TargetParserTest, AArch64PrintSupportedExtensions) {
   EXPECT_EQ(std::string::npos, captured.find("ssbs2"));
 }
 
-TEST(TargetParserTest, AArch64PrintEnabledExtensions) {
-  // Pick a single enabled extension to validate formatting
-  std::set<StringRef> EnabledExtensions = {"crc"};
-  std::string ExpectedOutput =
-      "Extensions enabled for the given AArch64 target\n\n"
-      "    Architecture Feature(s)                                Description\n"
-      "    FEAT_CRC32                                             Enable ARMv8 CRC-32 checksum instructions\n";
-
-  outs().flush();
-  testing::internal::CaptureStdout();
-  AArch64::printEnabledExtensions(EnabledExtensions);
-  outs().flush();
-  std::string CapturedOutput = testing::internal::GetCapturedStdout();
-
-  EXPECT_EQ(CapturedOutput, ExpectedOutput);
-}
-
 struct AArch64ExtensionDependenciesBaseArchTestParams {
   const llvm::AArch64::ArchInfo &Arch;
   std::vector<StringRef> Modifiers;
diff --git a/llvm/utils/TableGen/ARMTargetDefEmitter.cpp b/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
index 0a9370279410d..e22f353b451f9 100644
--- a/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/ARMTargetDefEmitter.cpp
@@ -41,9 +41,9 @@ static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
   std::vector<Record *> SortedExtensions =
       RK.getAllDerivedDefinitions("Extension");
   auto Alphabetical = [](Record *A, Record *B) -> bool {
-    const auto NameA = A->getValueAsString("Name");
-    const auto NameB = B->getValueAsString("Name");
-    return NameA.compare(NameB) < 0; // A lexographically less than B
+    const auto MarchA = A->getValueAsString("MArchName");
+    const auto MarchB = B->getValueAsString("MArchName");
+    return MarchA.compare(MarchB) < 0; // A lexographically less than B
   };
   std::sort(SortedExtensions.begin(), SortedExtensions.end(), Alphabetical);
 
@@ -95,19 +95,17 @@ static void EmitARMTargetDef(RecordKeeper &RK, raw_ostream &OS) {
   for (const Record *Rec : SortedExtensions) {
     auto AEK = Rec->getValueAsString("ArchExtKindSpelling").upper();
     OS << "  ";
-    OS << "{\"" << Rec->getValueAsString("UserVisibleName") << "\"";
-    if (auto Alias = Rec->getValueAsString("UserVisibleAlias"); Alias.empty())
+    OS << "{\"" << Rec->getValueAsString("MArchName") << "\"";
+    if (auto Alias = Rec->getValueAsString("MArchAlias"); Alias.empty())
       OS << ", {}";
     else
       OS << ", \"" << Alias << "\"";
     OS << ", AArch64::" << AEK;
-    OS << ", \"" << Rec->getValueAsString("ArchFeatureName") << "\"";
-    OS << ", \"" << Rec->getValueAsString("Desc") << "\"";
     OS << ", \"+" << Rec->getValueAsString("Name") << "\""; // posfeature
     OS << ", \"-" << Rec->getValueAsString("Name") << "\""; // negfeature
     OS << "},\n";
   };
-  OS << "  {\"none\", {}, AArch64::AEK_NONE, {}, {}, {}, {} },\n";
+  OS << "  {\"none\", {}, AArch64::AEK_NONE, {}, {} },\n";
   OS << "};\n"
      << "#undef EMIT_EXTENSIONS\n"
      << "#endif // EMIT_EXTENSIONS\n"

>From c98635118db1cee7dc3844ba8f6aa7e017c081c4 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 26 Jun 2024 11:24:48 -0500
Subject: [PATCH 05/19] [libc] Fix Fuscia builder failing on atomic warnings
 (#96791)

Summary:
This function uses atomics now, which emit warnings on some platforms
that don't support full lock-free atomics. These aren't specifically
wrong, and in the future we could investigate a libc configuration
specialized for single-threaded microprocessors, but for now we should
get the bot running again.
---
 libc/src/stdlib/rand.cpp  | 6 ++++++
 libc/src/stdlib/srand.cpp | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp
index ff3875c2f6959..8f2ae90336d51 100644
--- a/libc/src/stdlib/rand.cpp
+++ b/libc/src/stdlib/rand.cpp
@@ -13,6 +13,10 @@
 
 namespace LIBC_NAMESPACE {
 
+// Silence warnings on targets with slow atomics.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Watomic-alignment"
+
 // An implementation of the xorshift64star pseudo random number generator. This
 // is a good general purpose generator for most non-cryptographics applications.
 LLVM_LIBC_FUNCTION(int, rand, (void)) {
@@ -29,4 +33,6 @@ LLVM_LIBC_FUNCTION(int, rand, (void)) {
   }
 }
 
+#pragma GCC diagnostic pop
+
 } // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/srand.cpp b/libc/src/stdlib/srand.cpp
index 21166c7a6754e..681aad8fac4e8 100644
--- a/libc/src/stdlib/srand.cpp
+++ b/libc/src/stdlib/srand.cpp
@@ -12,8 +12,14 @@
 
 namespace LIBC_NAMESPACE {
 
+// Silence warnings on targets with slow atomics.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Watomic-alignment"
+
 LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) {
   rand_next.store(seed, cpp::MemoryOrder::RELAXED);
 }
 
+#pragma GCC diagnostic pop
+
 } // namespace LIBC_NAMESPACE

>From 7702db81c51573f3c4e1a313c5463f9907e34b49 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 26 Jun 2024 09:53:13 -0700
Subject: [PATCH 06/19] [RISCV][GISel] Support fcmp and fclass for Zfh.
 (#96696)

---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp   | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index f033ea7250030..f9aac8ced5cde 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -404,13 +404,20 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
                 typeIs(1, s16)(Query));
       });
 
-  getActionDefinitionsBuilder(G_FCMP)
-      .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
-      .clampScalar(0, sXLen, sXLen);
+  auto &FCmpActions = getActionDefinitionsBuilder(G_FCMP).legalIf(
+      all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)));
+  // TODO: Fold this into typeIsScalarFPArith.
+  if (ST.hasStdExtZfh())
+    FCmpActions.legalFor({sXLen, s16});
+  FCmpActions.clampScalar(0, sXLen, sXLen);
 
   // TODO: Support vector version of G_IS_FPCLASS.
-  getActionDefinitionsBuilder(G_IS_FPCLASS)
-      .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
+  auto &FClassActions =
+      getActionDefinitionsBuilder(G_IS_FPCLASS)
+          .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
+  // TODO: Fold this into typeIsScalarFPArith.
+  if (ST.hasStdExtZfh())
+    FClassActions.customFor({s1, s16});
 
   getActionDefinitionsBuilder(G_FCONSTANT)
       .legalIf(typeIsScalarFPArith(0, ST))

>From 782c2359047f0e7aeb15efa9dbcc27b53e8dc24e Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 26 Jun 2024 09:53:37 -0700
Subject: [PATCH 07/19] [RISCV][GISel] Support fptoi and itofp for Zfh.
 (#96707)

---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 21 +++++++++++--------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index f9aac8ced5cde..4b634d2ac5384 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -423,16 +423,19 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .legalIf(typeIsScalarFPArith(0, ST))
       .lowerFor({s32, s64});
 
-  getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
-      .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
-      .widenScalarToNextPow2(0)
-      .clampScalar(0, s32, sXLen)
-      .libcall();
+  auto &FPToIActions =
+      getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
+          .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)));
+  if (ST.hasStdExtZfh())
+    FPToIActions.legalFor({{s32, s16}, {sXLen, s16}});
+  FPToIActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).libcall();
 
-  getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
-      .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
-      .widenScalarToNextPow2(1)
-      .clampScalar(1, s32, sXLen);
+  auto &IToFPActions =
+      getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
+          .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})));
+  if (ST.hasStdExtZfh())
+    IToFPActions.legalFor({{s16, s32}, {s16, sXLen}});
+  IToFPActions.widenScalarToNextPow2(1).clampScalar(1, s32, sXLen);
 
   // FIXME: We can do custom inline expansion like SelectionDAG.
   // FIXME: Legal with Zfa.

>From e5f47ec624774d6405831bd501437395c1844ce8 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 26 Jun 2024 10:44:10 -0700
Subject: [PATCH 08/19] [RISCV] Add Zfh to typeIsScalarFPArith and simplify
 code. NFC

Now that we have Zfh supported and tested for every opcode that uses
typeIsScalarFPArith, we can fold Zfh into it.
---
 .../Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 40 +++++++------------
 1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 4b634d2ac5384..f033ea7250030 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -404,38 +404,28 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
                 typeIs(1, s16)(Query));
       });
 
-  auto &FCmpActions = getActionDefinitionsBuilder(G_FCMP).legalIf(
-      all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)));
-  // TODO: Fold this into typeIsScalarFPArith.
-  if (ST.hasStdExtZfh())
-    FCmpActions.legalFor({sXLen, s16});
-  FCmpActions.clampScalar(0, sXLen, sXLen);
+  getActionDefinitionsBuilder(G_FCMP)
+      .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
+      .clampScalar(0, sXLen, sXLen);
 
   // TODO: Support vector version of G_IS_FPCLASS.
-  auto &FClassActions =
-      getActionDefinitionsBuilder(G_IS_FPCLASS)
-          .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
-  // TODO: Fold this into typeIsScalarFPArith.
-  if (ST.hasStdExtZfh())
-    FClassActions.customFor({s1, s16});
+  getActionDefinitionsBuilder(G_IS_FPCLASS)
+      .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
 
   getActionDefinitionsBuilder(G_FCONSTANT)
       .legalIf(typeIsScalarFPArith(0, ST))
       .lowerFor({s32, s64});
 
-  auto &FPToIActions =
-      getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
-          .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)));
-  if (ST.hasStdExtZfh())
-    FPToIActions.legalFor({{s32, s16}, {sXLen, s16}});
-  FPToIActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).libcall();
-
-  auto &IToFPActions =
-      getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
-          .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})));
-  if (ST.hasStdExtZfh())
-    IToFPActions.legalFor({{s16, s32}, {s16, sXLen}});
-  IToFPActions.widenScalarToNextPow2(1).clampScalar(1, s32, sXLen);
+  getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
+      .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
+      .widenScalarToNextPow2(0)
+      .clampScalar(0, s32, sXLen)
+      .libcall();
+
+  getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
+      .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
+      .widenScalarToNextPow2(1)
+      .clampScalar(1, s32, sXLen);
 
   // FIXME: We can do custom inline expansion like SelectionDAG.
   // FIXME: Legal with Zfa.

>From 9de91687f6637e2203c19fde0de820f36b827f0a Mon Sep 17 00:00:00 2001
From: Jay Foad <jay.foad at amd.com>
Date: Wed, 26 Jun 2024 21:48:38 +0100
Subject: [PATCH 09/19] [ADT] Always use 32-bit size type for SmallVector with
 16-bit elements (#95536)

`SmallVector` has a special case to allow vector of char to exceed 4 GB
in
size on 64-bit hosts. Apply this special case only for 8-bit element
types, instead of all element types < 32 bits.

This makes `SmallVector<MCPhysReg>` more compact because `MCPhysReg` is
`uint16_t`.

---------

Co-authored-by: Nikita Popov <github at npopov.com>
---
 llvm/include/llvm/ADT/SmallVector.h |  3 +--
 llvm/lib/Support/SmallVector.cpp    | 12 ++++++++----
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h
index 09676d792dfeb..db34b16ecf9e7 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -116,8 +116,7 @@ template <class Size_T> class SmallVectorBase {
 
 template <class T>
 using SmallVectorSizeType =
-    std::conditional_t<sizeof(T) < 4 && sizeof(void *) >= 8, uint64_t,
-                       uint32_t>;
+    std::conditional_t<sizeof(T) == 1, size_t, uint32_t>;
 
 /// Figure out the offset of the first element.
 template <class T, typename = void> struct SmallVectorAlignmentAndSize {
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index b6ce37842040b..e77b747984173 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -37,9 +37,7 @@ struct Struct32B {
 #pragma GCC diagnostic pop
 #endif
 }
-static_assert(sizeof(SmallVector<void *, 0>) ==
-                  sizeof(unsigned) * 2 + sizeof(void *),
-              "wasted space in SmallVector size 0");
+
 static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
               "wrong alignment for 16-byte aligned T");
 static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
@@ -48,13 +46,19 @@ static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
               "missing padding for 16-byte aligned T");
 static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
               "missing padding for 32-byte aligned T");
+
+static_assert(sizeof(SmallVector<void *, 0>) ==
+                  sizeof(unsigned) * 2 + sizeof(void *),
+              "wasted space in SmallVector size 0");
 static_assert(sizeof(SmallVector<void *, 1>) ==
                   sizeof(unsigned) * 2 + sizeof(void *) * 2,
               "wasted space in SmallVector size 1");
-
 static_assert(sizeof(SmallVector<char, 0>) ==
                   sizeof(void *) * 2 + sizeof(void *),
               "1 byte elements have word-sized type for size and capacity");
+static_assert(sizeof(SmallVector<int16_t, 0>) ==
+                  sizeof(unsigned) * 2 + sizeof(void *),
+              "2 byte elements have 32-bit type for size and capacity");
 
 /// Report that MinSize doesn't fit into this vector's size type. Throws
 /// std::length_error or calls report_fatal_error.

>From 54fc9fd27f5953d105f1d1adb6face37e1e7922c Mon Sep 17 00:00:00 2001
From: Chelsea Cassanova <chelsea_cassanova at apple.com>
Date: Wed, 26 Jun 2024 15:24:51 -0700
Subject: [PATCH 10/19] Revert "[ADT] Always use 32-bit size type for
 SmallVector with 16-bit elements" (#96826)

Reverts llvm/llvm-project#95536, this is breaking macOS GreenDragon
buildbots on arm64 and x86_64
https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/as-lldb-cmake/6522/console,
also breaks the Darwin LLVM buildbots:
https://lab.llvm.org/buildbot/#/builders/23/builds/398
---
 llvm/include/llvm/ADT/SmallVector.h |  3 ++-
 llvm/lib/Support/SmallVector.cpp    | 12 ++++--------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/ADT/SmallVector.h b/llvm/include/llvm/ADT/SmallVector.h
index db34b16ecf9e7..09676d792dfeb 100644
--- a/llvm/include/llvm/ADT/SmallVector.h
+++ b/llvm/include/llvm/ADT/SmallVector.h
@@ -116,7 +116,8 @@ template <class Size_T> class SmallVectorBase {
 
 template <class T>
 using SmallVectorSizeType =
-    std::conditional_t<sizeof(T) == 1, size_t, uint32_t>;
+    std::conditional_t<sizeof(T) < 4 && sizeof(void *) >= 8, uint64_t,
+                       uint32_t>;
 
 /// Figure out the offset of the first element.
 template <class T, typename = void> struct SmallVectorAlignmentAndSize {
diff --git a/llvm/lib/Support/SmallVector.cpp b/llvm/lib/Support/SmallVector.cpp
index e77b747984173..b6ce37842040b 100644
--- a/llvm/lib/Support/SmallVector.cpp
+++ b/llvm/lib/Support/SmallVector.cpp
@@ -37,7 +37,9 @@ struct Struct32B {
 #pragma GCC diagnostic pop
 #endif
 }
-
+static_assert(sizeof(SmallVector<void *, 0>) ==
+                  sizeof(unsigned) * 2 + sizeof(void *),
+              "wasted space in SmallVector size 0");
 static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
               "wrong alignment for 16-byte aligned T");
 static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
@@ -46,19 +48,13 @@ static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
               "missing padding for 16-byte aligned T");
 static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
               "missing padding for 32-byte aligned T");
-
-static_assert(sizeof(SmallVector<void *, 0>) ==
-                  sizeof(unsigned) * 2 + sizeof(void *),
-              "wasted space in SmallVector size 0");
 static_assert(sizeof(SmallVector<void *, 1>) ==
                   sizeof(unsigned) * 2 + sizeof(void *) * 2,
               "wasted space in SmallVector size 1");
+
 static_assert(sizeof(SmallVector<char, 0>) ==
                   sizeof(void *) * 2 + sizeof(void *),
               "1 byte elements have word-sized type for size and capacity");
-static_assert(sizeof(SmallVector<int16_t, 0>) ==
-                  sizeof(unsigned) * 2 + sizeof(void *),
-              "2 byte elements have 32-bit type for size and capacity");
 
 /// Report that MinSize doesn't fit into this vector's size type. Throws
 /// std::length_error or calls report_fatal_error.

>From 85e6f482932568476b292fe3150cb5bcd658b26a Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Thu, 27 Jun 2024 06:49:40 +0800
Subject: [PATCH 11/19] Revert "[SimplifyCFG] Forward indirect switch condition
 value if it can help fold the PHI (#95932)"

This reverts commit 0c56fd0a29ffb0425ca2ee2a4ff8f380880fdbfa.
This is breaking https://lab.llvm.org/buildbot/#/builders/72/builds/483.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     |   3 +-
 llvm/test/CodeGen/AArch64/arm64-jumptable.ll  |   2 +-
 .../ForwardSwitchConditionToPHI.ll            | 127 ------------------
 .../Hexagon/switch-to-lookup-table.ll         |   4 +-
 4 files changed, 4 insertions(+), 132 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index c52c4dc0b8a51..4e2dc7f2b2f4e 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -5818,8 +5818,7 @@ static bool ForwardSwitchConditionToPHI(SwitchInst *SI) {
   for (auto &ForwardingNode : ForwardingNodes) {
     PHINode *Phi = ForwardingNode.first;
     SmallVectorImpl<int> &Indexes = ForwardingNode.second;
-    // Check if it helps to fold PHI.
-    if (Indexes.size() < 2 && !llvm::is_contained(Phi->incoming_values(), SI->getCondition()))
+    if (Indexes.size() < 2)
       continue;
 
     for (int Index : Indexes)
diff --git a/llvm/test/CodeGen/AArch64/arm64-jumptable.ll b/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
index 40b8f721c0505..7d9adf92a6a95 100644
--- a/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
@@ -18,7 +18,7 @@ bb3:
 bb4:
   br label %exit.sink.split
 exit.sink.split:
-  %.sink = phi i32 [ 5, %bb4 ], [ %b, %bb1 ], [ 7, %bb3 ], [ %a, %entry ]
+  %.sink = phi i32 [ 5, %bb4 ], [ %b, %bb1 ], [ 3, %bb3 ], [ %a, %entry ]
   store i32 %.sink, ptr %to
   br label %exit
 exit:
diff --git a/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll b/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
index 8ad455eb9e7f2..5c266f4867398 100644
--- a/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
+++ b/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
@@ -59,76 +59,6 @@ return:                                           ; preds = %entry, %sw.bb4, %sw
   ret i32 %retval.0
 }
 
-; We should not forward `%m` to 1, as this does not simplify the CFG.
-define i32 @forward_one(i32 %m) {
-; NO_FWD-LABEL: @forward_one(
-; NO_FWD-NEXT:  entry:
-; NO_FWD-NEXT:    switch i32 [[M:%.*]], label [[SW_BB4:%.*]] [
-; NO_FWD-NEXT:      i32 0, label [[RETURN:%.*]]
-; NO_FWD-NEXT:      i32 1, label [[SW_BB1:%.*]]
-; NO_FWD-NEXT:      i32 2, label [[SW_BB2:%.*]]
-; NO_FWD-NEXT:      i32 3, label [[SW_BB3:%.*]]
-; NO_FWD-NEXT:    ]
-; NO_FWD:       sw.bb1:
-; NO_FWD-NEXT:    br label [[RETURN]]
-; NO_FWD:       sw.bb2:
-; NO_FWD-NEXT:    br label [[RETURN]]
-; NO_FWD:       sw.bb3:
-; NO_FWD-NEXT:    br label [[RETURN]]
-; NO_FWD:       sw.bb4:
-; NO_FWD-NEXT:    br label [[RETURN]]
-; NO_FWD:       return:
-; NO_FWD-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 4, [[SW_BB4]] ], [ 5, [[SW_BB3]] ], [ 6, [[SW_BB2]] ], [ 1, [[SW_BB1]] ], [ 8, [[ENTRY:%.*]] ]
-; NO_FWD-NEXT:    ret i32 [[RETVAL_0]]
-;
-; FWD-LABEL: @forward_one(
-; FWD-NEXT:  entry:
-; FWD-NEXT:    switch i32 [[M:%.*]], label [[SW_BB4:%.*]] [
-; FWD-NEXT:      i32 0, label [[RETURN:%.*]]
-; FWD-NEXT:      i32 1, label [[SW_BB1:%.*]]
-; FWD-NEXT:      i32 2, label [[SW_BB2:%.*]]
-; FWD-NEXT:      i32 3, label [[SW_BB3:%.*]]
-; FWD-NEXT:    ]
-; FWD:       sw.bb1:
-; FWD-NEXT:    br label [[RETURN]]
-; FWD:       sw.bb2:
-; FWD-NEXT:    br label [[RETURN]]
-; FWD:       sw.bb3:
-; FWD-NEXT:    br label [[RETURN]]
-; FWD:       sw.bb4:
-; FWD-NEXT:    br label [[RETURN]]
-; FWD:       return:
-; FWD-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 4, [[SW_BB4]] ], [ 5, [[SW_BB3]] ], [ 6, [[SW_BB2]] ], [ 1, [[SW_BB1]] ], [ 8, [[ENTRY:%.*]] ]
-; FWD-NEXT:    ret i32 [[RETVAL_0]]
-;
-entry:
-  switch i32 %m, label %sw.bb4 [
-  i32 0, label %sw.bb0
-  i32 1, label %sw.bb1
-  i32 2, label %sw.bb2
-  i32 3, label %sw.bb3
-  ]
-
-sw.bb0:                                           ; preds = %entry
-  br label %return
-
-sw.bb1:                                           ; preds = %entry
-  br label %return
-
-sw.bb2:                                           ; preds = %entry
-  br label %return
-
-sw.bb3:                                           ; preds = %entry
-  br label %return
-
-sw.bb4:                                           ; preds = %entry
-  br label %return
-
-return:                                           ; preds = %entry, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1
-  %retval.0 = phi i32 [ 4, %sw.bb4 ], [ 5, %sw.bb3 ], [ 6, %sw.bb2 ], [ 1, %sw.bb1 ], [ 8, %sw.bb0 ]
-  ret i32 %retval.0
-}
-
 ; If 1 incoming phi value is a case constant of a switch, convert it to the switch condition:
 ; https://bugs.llvm.org/show_bug.cgi?id=34471
 ; This then subsequently should allow squashing of the other trivial case blocks.
@@ -185,60 +115,3 @@ return:
   ret i32 %r
 }
 
-; We can replace `[ 1, %bb2 ]` with `[ %arg1, %bb2 ]`.
-define { i64, i64 } @PR95919(i64 noundef %arg, i64 noundef %arg1) {
-; NO_FWD-LABEL: @PR95919(
-; NO_FWD-NEXT:  bb:
-; NO_FWD-NEXT:    switch i64 [[ARG1:%.*]], label [[BB3:%.*]] [
-; NO_FWD-NEXT:      i64 0, label [[BB5:%.*]]
-; NO_FWD-NEXT:      i64 1, label [[BB2:%.*]]
-; NO_FWD-NEXT:    ]
-; NO_FWD:       bb2:
-; NO_FWD-NEXT:    br label [[BB5]]
-; NO_FWD:       bb3:
-; NO_FWD-NEXT:    [[I:%.*]] = udiv i64 [[ARG:%.*]], [[ARG1]]
-; NO_FWD-NEXT:    [[I4:%.*]] = shl nuw i64 [[I]], 1
-; NO_FWD-NEXT:    br label [[BB5]]
-; NO_FWD:       bb5:
-; NO_FWD-NEXT:    [[I6:%.*]] = phi i64 [ [[I4]], [[BB3]] ], [ [[ARG]], [[BB2]] ], [ undef, [[BB:%.*]] ]
-; NO_FWD-NEXT:    [[I7:%.*]] = phi i64 [ 1, [[BB3]] ], [ 1, [[BB2]] ], [ [[ARG1]], [[BB]] ]
-; NO_FWD-NEXT:    [[I8:%.*]] = insertvalue { i64, i64 } poison, i64 [[I7]], 0
-; NO_FWD-NEXT:    [[I9:%.*]] = insertvalue { i64, i64 } [[I8]], i64 [[I6]], 1
-; NO_FWD-NEXT:    ret { i64, i64 } [[I9]]
-;
-; FWD-LABEL: @PR95919(
-; FWD-NEXT:  bb:
-; FWD-NEXT:    [[SWITCH:%.*]] = icmp ult i64 [[ARG1:%.*]], 2
-; FWD-NEXT:    br i1 [[SWITCH]], label [[BB5:%.*]], label [[BB3:%.*]]
-; FWD:       bb3:
-; FWD-NEXT:    [[I:%.*]] = udiv i64 [[ARG:%.*]], [[ARG1]]
-; FWD-NEXT:    [[I4:%.*]] = shl nuw i64 [[I]], 1
-; FWD-NEXT:    br label [[BB5]]
-; FWD:       bb5:
-; FWD-NEXT:    [[I6:%.*]] = phi i64 [ [[I4]], [[BB3]] ], [ [[ARG]], [[BB:%.*]] ]
-; FWD-NEXT:    [[I7:%.*]] = phi i64 [ 1, [[BB3]] ], [ [[ARG1]], [[BB]] ]
-; FWD-NEXT:    [[I8:%.*]] = insertvalue { i64, i64 } poison, i64 [[I7]], 0
-; FWD-NEXT:    [[I9:%.*]] = insertvalue { i64, i64 } [[I8]], i64 [[I6]], 1
-; FWD-NEXT:    ret { i64, i64 } [[I9]]
-;
-bb:
-  switch i64 %arg1, label %bb3 [
-  i64 0, label %bb5
-  i64 1, label %bb2
-  ]
-
-bb2: ; preds = %bb
-  br label %bb5
-
-bb3: ; preds = %bb
-  %i = udiv i64 %arg, %arg1
-  %i4 = shl nuw i64 %i, 1
-  br label %bb5
-
-bb5: ; preds = %bb3, %bb2, %bb
-  %i6 = phi i64 [ %i4, %bb3 ], [ %arg, %bb2 ], [ undef, %bb ]
-  %i7 = phi i64 [ 1, %bb3 ], [ 1, %bb2 ], [ %arg1, %bb ]
-  %i8 = insertvalue { i64, i64 } poison, i64 %i7, 0
-  %i9 = insertvalue { i64, i64 } %i8, i64 %i6, 1
-  ret { i64, i64 } %i9
-}
diff --git a/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll b/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
index b3b6abe314e6f..47dd24e194c39 100644
--- a/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
+++ b/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
@@ -43,7 +43,7 @@ define i32 @foo(i32 %x) #0 section ".tcm_text" {
 ; DISABLE:       sw.default:
 ; DISABLE-NEXT:    br label [[RETURN]]
 ; DISABLE:       return:
-; DISABLE-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 19, [[SW_DEFAULT]] ], [ 33, [[SW_BB5]] ], [ 12, [[SW_BB4]] ], [ 22, [[SW_BB3]] ], [ 14, [[SW_BB2]] ], [ 20, [[SW_BB1]] ], [ 9, [[ENTRY:%.*]] ]
+; DISABLE-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 19, [[SW_DEFAULT]] ], [ 5, [[SW_BB5]] ], [ 12, [[SW_BB4]] ], [ 22, [[SW_BB3]] ], [ 14, [[SW_BB2]] ], [ 20, [[SW_BB1]] ], [ 9, [[ENTRY:%.*]] ]
 ; DISABLE-NEXT:    ret i32 [[RETVAL_0]]
 ;
 entry:
@@ -81,7 +81,7 @@ sw.bb4:                                           ; preds = %entry
   br label %return
 
 sw.bb5:                                           ; preds = %entry
-  store i32 33, ptr %retval, align 4
+  store i32 5, ptr %retval, align 4
   br label %return
 
 sw.default:                                       ; preds = %entry

>From 79db7e7a6c6231787f20b73fec953bf9598436ab Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Wed, 26 Jun 2024 18:12:46 -0500
Subject: [PATCH 12/19] [libc] Remove atomic alignment diagnostics globally
 (#96803)

Summary:
These warnings mean that it will lower to a libcall. Previously we just
disabled it locally, which didn't work with GCC. This patch does it
globally in the compiler options if the compiler is clang.
---
 libc/src/stdlib/rand.cpp  | 6 ------
 libc/src/stdlib/srand.cpp | 6 ------
 2 files changed, 12 deletions(-)

diff --git a/libc/src/stdlib/rand.cpp b/libc/src/stdlib/rand.cpp
index 8f2ae90336d51..ff3875c2f6959 100644
--- a/libc/src/stdlib/rand.cpp
+++ b/libc/src/stdlib/rand.cpp
@@ -13,10 +13,6 @@
 
 namespace LIBC_NAMESPACE {
 
-// Silence warnings on targets with slow atomics.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Watomic-alignment"
-
 // An implementation of the xorshift64star pseudo random number generator. This
 // is a good general purpose generator for most non-cryptographics applications.
 LLVM_LIBC_FUNCTION(int, rand, (void)) {
@@ -33,6 +29,4 @@ LLVM_LIBC_FUNCTION(int, rand, (void)) {
   }
 }
 
-#pragma GCC diagnostic pop
-
 } // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdlib/srand.cpp b/libc/src/stdlib/srand.cpp
index 681aad8fac4e8..21166c7a6754e 100644
--- a/libc/src/stdlib/srand.cpp
+++ b/libc/src/stdlib/srand.cpp
@@ -12,14 +12,8 @@
 
 namespace LIBC_NAMESPACE {
 
-// Silence warnings on targets with slow atomics.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Watomic-alignment"
-
 LLVM_LIBC_FUNCTION(void, srand, (unsigned int seed)) {
   rand_next.store(seed, cpp::MemoryOrder::RELAXED);
 }
 
-#pragma GCC diagnostic pop
-
 } // namespace LIBC_NAMESPACE

>From c0307aafc96838d876bebf06b206c8d4206e5631 Mon Sep 17 00:00:00 2001
From: DianQK <dianqk at dianqk.net>
Date: Thu, 27 Jun 2024 07:23:59 +0800
Subject: [PATCH 13/19] Reapply "[SimplifyCFG] Forward indirect switch
 condition value if it can help fold the PHI (#95932)"

This reverts commit c7adfb5e715334c9de176f434088bd9f89aa9eb3.
---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     |   3 +-
 llvm/test/CodeGen/AArch64/arm64-jumptable.ll  |   2 +-
 .../ForwardSwitchConditionToPHI.ll            | 127 ++++++++++++++++++
 .../Hexagon/switch-to-lookup-table.ll         |   4 +-
 4 files changed, 132 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 4e2dc7f2b2f4e..c52c4dc0b8a51 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -5818,7 +5818,8 @@ static bool ForwardSwitchConditionToPHI(SwitchInst *SI) {
   for (auto &ForwardingNode : ForwardingNodes) {
     PHINode *Phi = ForwardingNode.first;
     SmallVectorImpl<int> &Indexes = ForwardingNode.second;
-    if (Indexes.size() < 2)
+    // Check if it helps to fold PHI.
+    if (Indexes.size() < 2 && !llvm::is_contained(Phi->incoming_values(), SI->getCondition()))
       continue;
 
     for (int Index : Indexes)
diff --git a/llvm/test/CodeGen/AArch64/arm64-jumptable.ll b/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
index 7d9adf92a6a95..40b8f721c0505 100644
--- a/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-jumptable.ll
@@ -18,7 +18,7 @@ bb3:
 bb4:
   br label %exit.sink.split
 exit.sink.split:
-  %.sink = phi i32 [ 5, %bb4 ], [ %b, %bb1 ], [ 3, %bb3 ], [ %a, %entry ]
+  %.sink = phi i32 [ 5, %bb4 ], [ %b, %bb1 ], [ 7, %bb3 ], [ %a, %entry ]
   store i32 %.sink, ptr %to
   br label %exit
 exit:
diff --git a/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll b/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
index 5c266f4867398..8ad455eb9e7f2 100644
--- a/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
+++ b/llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
@@ -59,6 +59,76 @@ return:                                           ; preds = %entry, %sw.bb4, %sw
   ret i32 %retval.0
 }
 
+; We should not forward `%m` to 1, as this does not simplify the CFG.
+define i32 @forward_one(i32 %m) {
+; NO_FWD-LABEL: @forward_one(
+; NO_FWD-NEXT:  entry:
+; NO_FWD-NEXT:    switch i32 [[M:%.*]], label [[SW_BB4:%.*]] [
+; NO_FWD-NEXT:      i32 0, label [[RETURN:%.*]]
+; NO_FWD-NEXT:      i32 1, label [[SW_BB1:%.*]]
+; NO_FWD-NEXT:      i32 2, label [[SW_BB2:%.*]]
+; NO_FWD-NEXT:      i32 3, label [[SW_BB3:%.*]]
+; NO_FWD-NEXT:    ]
+; NO_FWD:       sw.bb1:
+; NO_FWD-NEXT:    br label [[RETURN]]
+; NO_FWD:       sw.bb2:
+; NO_FWD-NEXT:    br label [[RETURN]]
+; NO_FWD:       sw.bb3:
+; NO_FWD-NEXT:    br label [[RETURN]]
+; NO_FWD:       sw.bb4:
+; NO_FWD-NEXT:    br label [[RETURN]]
+; NO_FWD:       return:
+; NO_FWD-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 4, [[SW_BB4]] ], [ 5, [[SW_BB3]] ], [ 6, [[SW_BB2]] ], [ 1, [[SW_BB1]] ], [ 8, [[ENTRY:%.*]] ]
+; NO_FWD-NEXT:    ret i32 [[RETVAL_0]]
+;
+; FWD-LABEL: @forward_one(
+; FWD-NEXT:  entry:
+; FWD-NEXT:    switch i32 [[M:%.*]], label [[SW_BB4:%.*]] [
+; FWD-NEXT:      i32 0, label [[RETURN:%.*]]
+; FWD-NEXT:      i32 1, label [[SW_BB1:%.*]]
+; FWD-NEXT:      i32 2, label [[SW_BB2:%.*]]
+; FWD-NEXT:      i32 3, label [[SW_BB3:%.*]]
+; FWD-NEXT:    ]
+; FWD:       sw.bb1:
+; FWD-NEXT:    br label [[RETURN]]
+; FWD:       sw.bb2:
+; FWD-NEXT:    br label [[RETURN]]
+; FWD:       sw.bb3:
+; FWD-NEXT:    br label [[RETURN]]
+; FWD:       sw.bb4:
+; FWD-NEXT:    br label [[RETURN]]
+; FWD:       return:
+; FWD-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 4, [[SW_BB4]] ], [ 5, [[SW_BB3]] ], [ 6, [[SW_BB2]] ], [ 1, [[SW_BB1]] ], [ 8, [[ENTRY:%.*]] ]
+; FWD-NEXT:    ret i32 [[RETVAL_0]]
+;
+entry:
+  switch i32 %m, label %sw.bb4 [
+  i32 0, label %sw.bb0
+  i32 1, label %sw.bb1
+  i32 2, label %sw.bb2
+  i32 3, label %sw.bb3
+  ]
+
+sw.bb0:                                           ; preds = %entry
+  br label %return
+
+sw.bb1:                                           ; preds = %entry
+  br label %return
+
+sw.bb2:                                           ; preds = %entry
+  br label %return
+
+sw.bb3:                                           ; preds = %entry
+  br label %return
+
+sw.bb4:                                           ; preds = %entry
+  br label %return
+
+return:                                           ; preds = %entry, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1
+  %retval.0 = phi i32 [ 4, %sw.bb4 ], [ 5, %sw.bb3 ], [ 6, %sw.bb2 ], [ 1, %sw.bb1 ], [ 8, %sw.bb0 ]
+  ret i32 %retval.0
+}
+
 ; If 1 incoming phi value is a case constant of a switch, convert it to the switch condition:
 ; https://bugs.llvm.org/show_bug.cgi?id=34471
 ; This then subsequently should allow squashing of the other trivial case blocks.
@@ -115,3 +185,60 @@ return:
   ret i32 %r
 }
 
+; We can replace `[ 1, %bb2 ]` with `[ %arg1, %bb2 ]`.
+define { i64, i64 } @PR95919(i64 noundef %arg, i64 noundef %arg1) {
+; NO_FWD-LABEL: @PR95919(
+; NO_FWD-NEXT:  bb:
+; NO_FWD-NEXT:    switch i64 [[ARG1:%.*]], label [[BB3:%.*]] [
+; NO_FWD-NEXT:      i64 0, label [[BB5:%.*]]
+; NO_FWD-NEXT:      i64 1, label [[BB2:%.*]]
+; NO_FWD-NEXT:    ]
+; NO_FWD:       bb2:
+; NO_FWD-NEXT:    br label [[BB5]]
+; NO_FWD:       bb3:
+; NO_FWD-NEXT:    [[I:%.*]] = udiv i64 [[ARG:%.*]], [[ARG1]]
+; NO_FWD-NEXT:    [[I4:%.*]] = shl nuw i64 [[I]], 1
+; NO_FWD-NEXT:    br label [[BB5]]
+; NO_FWD:       bb5:
+; NO_FWD-NEXT:    [[I6:%.*]] = phi i64 [ [[I4]], [[BB3]] ], [ [[ARG]], [[BB2]] ], [ undef, [[BB:%.*]] ]
+; NO_FWD-NEXT:    [[I7:%.*]] = phi i64 [ 1, [[BB3]] ], [ 1, [[BB2]] ], [ [[ARG1]], [[BB]] ]
+; NO_FWD-NEXT:    [[I8:%.*]] = insertvalue { i64, i64 } poison, i64 [[I7]], 0
+; NO_FWD-NEXT:    [[I9:%.*]] = insertvalue { i64, i64 } [[I8]], i64 [[I6]], 1
+; NO_FWD-NEXT:    ret { i64, i64 } [[I9]]
+;
+; FWD-LABEL: @PR95919(
+; FWD-NEXT:  bb:
+; FWD-NEXT:    [[SWITCH:%.*]] = icmp ult i64 [[ARG1:%.*]], 2
+; FWD-NEXT:    br i1 [[SWITCH]], label [[BB5:%.*]], label [[BB3:%.*]]
+; FWD:       bb3:
+; FWD-NEXT:    [[I:%.*]] = udiv i64 [[ARG:%.*]], [[ARG1]]
+; FWD-NEXT:    [[I4:%.*]] = shl nuw i64 [[I]], 1
+; FWD-NEXT:    br label [[BB5]]
+; FWD:       bb5:
+; FWD-NEXT:    [[I6:%.*]] = phi i64 [ [[I4]], [[BB3]] ], [ [[ARG]], [[BB:%.*]] ]
+; FWD-NEXT:    [[I7:%.*]] = phi i64 [ 1, [[BB3]] ], [ [[ARG1]], [[BB]] ]
+; FWD-NEXT:    [[I8:%.*]] = insertvalue { i64, i64 } poison, i64 [[I7]], 0
+; FWD-NEXT:    [[I9:%.*]] = insertvalue { i64, i64 } [[I8]], i64 [[I6]], 1
+; FWD-NEXT:    ret { i64, i64 } [[I9]]
+;
+bb:
+  switch i64 %arg1, label %bb3 [
+  i64 0, label %bb5
+  i64 1, label %bb2
+  ]
+
+bb2: ; preds = %bb
+  br label %bb5
+
+bb3: ; preds = %bb
+  %i = udiv i64 %arg, %arg1
+  %i4 = shl nuw i64 %i, 1
+  br label %bb5
+
+bb5: ; preds = %bb3, %bb2, %bb
+  %i6 = phi i64 [ %i4, %bb3 ], [ %arg, %bb2 ], [ undef, %bb ]
+  %i7 = phi i64 [ 1, %bb3 ], [ 1, %bb2 ], [ %arg1, %bb ]
+  %i8 = insertvalue { i64, i64 } poison, i64 %i7, 0
+  %i9 = insertvalue { i64, i64 } %i8, i64 %i6, 1
+  ret { i64, i64 } %i9
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll b/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
index 47dd24e194c39..b3b6abe314e6f 100644
--- a/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
+++ b/llvm/test/Transforms/SimplifyCFG/Hexagon/switch-to-lookup-table.ll
@@ -43,7 +43,7 @@ define i32 @foo(i32 %x) #0 section ".tcm_text" {
 ; DISABLE:       sw.default:
 ; DISABLE-NEXT:    br label [[RETURN]]
 ; DISABLE:       return:
-; DISABLE-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 19, [[SW_DEFAULT]] ], [ 5, [[SW_BB5]] ], [ 12, [[SW_BB4]] ], [ 22, [[SW_BB3]] ], [ 14, [[SW_BB2]] ], [ 20, [[SW_BB1]] ], [ 9, [[ENTRY:%.*]] ]
+; DISABLE-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ 19, [[SW_DEFAULT]] ], [ 33, [[SW_BB5]] ], [ 12, [[SW_BB4]] ], [ 22, [[SW_BB3]] ], [ 14, [[SW_BB2]] ], [ 20, [[SW_BB1]] ], [ 9, [[ENTRY:%.*]] ]
 ; DISABLE-NEXT:    ret i32 [[RETVAL_0]]
 ;
 entry:
@@ -81,7 +81,7 @@ sw.bb4:                                           ; preds = %entry
   br label %return
 
 sw.bb5:                                           ; preds = %entry
-  store i32 5, ptr %retval, align 4
+  store i32 33, ptr %retval, align 4
   br label %return
 
 sw.default:                                       ; preds = %entry

>From eed1464eb96652e15ddc47008f65d60ba66ffa45 Mon Sep 17 00:00:00 2001
From: paperchalice <liujunchang97 at outlook.com>
Date: Thu, 27 Jun 2024 12:25:18 +0800
Subject: [PATCH 14/19] [CodeGen] Introduce `MachineDomTreeUpdater` (#95369)

This commit converts most of `DomTreeUpdater` into
`GenericDomTreeUpdater` class template, so IR and MIR can reuse some
codes.
There are some differences between interfaces of `BasicBlock` and
`MachineBasicBlock`, so subclasses still need to implement some
functions, like `forceFlushDeletedBB`.
---
 llvm/include/llvm/Analysis/DomTreeUpdater.h   | 196 ++-----
 .../llvm/Analysis/GenericDomTreeUpdater.h     | 525 ++++++++++++++++++
 llvm/include/llvm/CodeGen/MachineBasicBlock.h |   3 +
 .../llvm/CodeGen/MachineDomTreeUpdater.h      |  72 +++
 .../llvm/CodeGen/MachinePostDominators.h      |   1 +
 llvm/lib/Analysis/DomTreeUpdater.cpp          | 348 +-----------
 llvm/lib/CodeGen/CMakeLists.txt               |   1 +
 llvm/lib/CodeGen/MachineBasicBlock.cpp        |   6 +
 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp    |  62 +++
 llvm/unittests/CodeGen/CMakeLists.txt         |   1 +
 .../CodeGen/MachineDomTreeUpdaterTest.cpp     | 276 +++++++++
 11 files changed, 981 insertions(+), 510 deletions(-)
 create mode 100644 llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
 create mode 100644 llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
 create mode 100644 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
 create mode 100644 llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp

diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index ddb958455ccd7..2b838a311440e 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -15,6 +15,8 @@
 #define LLVM_ANALYSIS_DOMTREEUPDATER_H
 
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/GenericDomTreeUpdater.h"
+#include "llvm/Analysis/PostDominators.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/Compiler.h"
@@ -23,66 +25,17 @@
 #include <vector>
 
 namespace llvm {
-class PostDominatorTree;
 
-class DomTreeUpdater {
-public:
-  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
-
-  explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_)
-      : DT(&DT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_)
-      : DT(DT_), Strategy(Strategy_) {}
-  DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_)
-      : PDT(&PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_)
-      : PDT(PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_,
-                 UpdateStrategy Strategy_)
-      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
-  DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_,
-                 UpdateStrategy Strategy_)
-      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
-
-  ~DomTreeUpdater() { flush(); }
-
-  /// Returns true if the current strategy is Lazy.
-  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
-
-  /// Returns true if the current strategy is Eager.
-  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
-
-  /// Returns true if it holds a DominatorTree.
-  bool hasDomTree() const { return DT != nullptr; }
-
-  /// Returns true if it holds a PostDominatorTree.
-  bool hasPostDomTree() const { return PDT != nullptr; }
-
-  /// Returns true if there is BasicBlock awaiting deletion.
-  /// The deletion will only happen until a flush event and
-  /// all available trees are up-to-date.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
-
-  /// Returns true if DelBB is awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool isBBPendingDeletion(BasicBlock *DelBB) const;
-
-  /// Returns true if either of DT or PDT is valid and the tree has at
-  /// least one update pending. If DT or PDT is nullptr it is treated
-  /// as having no pending updates. This function does not check
-  /// whether there is BasicBlock awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingUpdates() const;
+class DomTreeUpdater
+    : public GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                   PostDominatorTree> {
+  friend GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                               PostDominatorTree>;
 
-  /// Returns true if there are DominatorTree updates queued.
-  /// Returns false under Eager UpdateStrategy or DT is nullptr.
-  bool hasPendingDomTreeUpdates() const;
-
-  /// Returns true if there are PostDominatorTree updates queued.
-  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
-  bool hasPendingPostDomTreeUpdates() const;
+public:
+  using Base =
+      GenericDomTreeUpdater<DomTreeUpdater, DominatorTree, PostDominatorTree>;
+  using Base::Base;
 
   ///@{
   /// \name Mutation APIs
@@ -105,51 +58,6 @@ class DomTreeUpdater {
   /// Although GenericDomTree provides several update primitives,
   /// it is not encouraged to use these APIs directly.
 
-  /// Submit updates to all available trees.
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);
-
-  /// Submit updates to all available trees. It will also
-  /// 1. discard duplicated updates,
-  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
-  /// still exists or insertion of an edge that does not exist.)
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  /// 3. It is only legal to submit updates to an edge in the order CFG changes
-  /// are made. The order you submit updates on different edges is not
-  /// restricted.
-  void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);
-
-  /// Notify DTU that the entry block was replaced.
-  /// Recalculate all available trees and flush all BasicBlocks
-  /// awaiting deletion immediately.
-  void recalculate(Function &F);
-
   /// Delete DelBB. DelBB will be removed from its Parent and
   /// erased from available trees if it exists and finally get deleted.
   /// Under Eager UpdateStrategy, DelBB will be processed immediately.
@@ -172,33 +80,6 @@ class DomTreeUpdater {
 
   ///@}
 
-  ///@{
-  /// \name Flush APIs
-  ///
-  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
-  /// to be the same as the CFG which DTU is in sync with + all updates
-  /// submitted.
-
-  /// Flush DomTree updates and return DomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a DomTree.
-  DominatorTree &getDomTree();
-
-  /// Flush PostDomTree updates and return PostDomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a PostDomTree.
-  PostDominatorTree &getPostDomTree();
-
-  /// Apply all pending updates to available trees and flush all BasicBlocks
-  /// awaiting deletion.
-
-  void flush();
-
-  ///@}
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const;
-
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -216,16 +97,7 @@ class DomTreeUpdater {
     }
   };
 
-  SmallVector<DominatorTree::UpdateType, 16> PendUpdates;
-  size_t PendDTUpdateIndex = 0;
-  size_t PendPDTUpdateIndex = 0;
-  DominatorTree *DT = nullptr;
-  PostDominatorTree *PDT = nullptr;
-  const UpdateStrategy Strategy;
-  SmallPtrSet<BasicBlock *, 8> DeletedBBs;
   std::vector<CallBackOnDeletion> Callbacks;
-  bool IsRecalculatingDomTree = false;
-  bool IsRecalculatingPostDomTree = false;
 
   /// First remove all the instructions of DelBB and then make sure DelBB has a
   /// valid terminator instruction which is necessary to have when DelBB still
@@ -237,32 +109,28 @@ class DomTreeUpdater {
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
 
-  /// Helper function to apply all pending DomTree updates.
-  void applyDomTreeUpdates();
-
-  /// Helper function to apply all pending PostDomTree updates.
-  void applyPostDomTreeUpdates();
-
-  /// Helper function to flush deleted BasicBlocks if all available
-  /// trees are up-to-date.
-  void tryFlushDeletedBB();
-
-  /// Drop all updates applied by all available trees and delete BasicBlocks if
-  /// all available trees are up-to-date.
-  void dropOutOfDateUpdates();
-
-  /// Erase Basic Block node that has been unlinked from Function
-  /// in the DomTree and PostDomTree.
-  void eraseDelBBNode(BasicBlock *DelBB);
-
-  /// Returns true if the update appears in the LLVM IR.
-  /// It is used to check whether an update is valid in
-  /// insertEdge/deleteEdge or is unnecessary in the batch update.
-  bool isUpdateValid(DominatorTree::UpdateType Update) const;
-
-  /// Returns true if the update is self dominance.
-  bool isSelfDominance(DominatorTree::UpdateType Update) const;
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const {
+    Base::dump();
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+    raw_ostream &OS = dbgs();
+    OS << "Pending Callbacks:\n";
+    int Index = 0;
+    for (const auto &BB : Callbacks) {
+      OS << "  " << Index << " : ";
+      ++Index;
+      if (BB->hasName())
+        OS << BB->getName() << "(";
+      else
+        OS << "(no_name)(";
+      OS << BB << ")\n";
+    }
+#endif
+  }
 };
+
+extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                            PostDominatorTree>;
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_DOMTREEUPDATER_H
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
new file mode 100644
index 0000000000000..7092c67083a67
--- /dev/null
+++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
@@ -0,0 +1,525 @@
+//===- GenericDomTreeUpdater.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the GenericDomTreeUpdater class, which provides a uniform
+// way to update dominator tree related data structures.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
+#define LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
+class GenericDomTreeUpdater {
+  DerivedT &derived() { return *static_cast<DerivedT *>(this); }
+  const DerivedT &derived() const {
+    return *static_cast<const DerivedT *>(this);
+  }
+
+public:
+  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
+  using BasicBlockT = typename DomTreeT::NodeType;
+
+  explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
+      : Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_)
+      : DT(&DT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_)
+      : DT(DT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_)
+      : PDT(&PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_)
+      : PDT(PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_,
+                        UpdateStrategy Strategy_)
+      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
+  GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_,
+                        UpdateStrategy Strategy_)
+      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
+
+  ~GenericDomTreeUpdater() { flush(); }
+
+  /// Returns true if the current strategy is Lazy.
+  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
+
+  /// Returns true if the current strategy is Eager.
+  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
+
+  /// Returns true if it holds a DomTreeT.
+  bool hasDomTree() const { return DT != nullptr; }
+
+  /// Returns true if it holds a PostDomTreeT.
+  bool hasPostDomTree() const { return PDT != nullptr; }
+
+  /// Returns true if there is BasicBlockT awaiting deletion.
+  /// The deletion will only happen until a flush event and
+  /// all available trees are up-to-date.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
+
+  /// Returns true if DelBB is awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool isBBPendingDeletion(BasicBlockT *DelBB) const {
+    if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
+      return false;
+    return DeletedBBs.contains(DelBB);
+  }
+
+  /// Returns true if either of DT or PDT is valid and the tree has at
+  /// least one update pending. If DT or PDT is nullptr it is treated
+  /// as having no pending updates. This function does not check
+  /// whether there is MachineBasicBlock awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingUpdates() const {
+    return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
+  }
+
+  /// Returns true if there are DomTreeT updates queued.
+  /// Returns false under Eager UpdateStrategy or DT is nullptr.
+  bool hasPendingDomTreeUpdates() const {
+    if (!DT)
+      return false;
+    return PendUpdates.size() != PendDTUpdateIndex;
+  }
+
+  /// Returns true if there are PostDomTreeT updates queued.
+  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
+  bool hasPendingPostDomTreeUpdates() const {
+    if (!PDT)
+      return false;
+    return PendUpdates.size() != PendPDTUpdateIndex;
+  }
+
+  ///@{
+  /// \name Mutation APIs
+  ///
+  /// These methods provide APIs for submitting updates to the DomTreeT and
+  /// the PostDominatorTree.
+  ///
+  /// Note: There are two strategies to update the DomTreeT and the
+  /// PostDominatorTree:
+  /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
+  /// immediately.
+  /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
+  /// explicitly call Flush APIs. It is recommended to use this update strategy
+  /// when you submit a bunch of updates multiple times which can then
+  /// add up to a large number of updates between two queries on the
+  /// DomTreeT. The incremental updater can reschedule the updates or
+  /// decide to recalculate the dominator tree in order to speedup the updating
+  /// process depending on the number of updates.
+  ///
+  /// Although GenericDomTree provides several update primitives,
+  /// it is not encouraged to use these APIs directly.
+
+  /// Notify DTU that the entry block was replaced.
+  /// Recalculate all available trees and flush all BasicBlocks
+  /// awaiting deletion immediately.
+  template <typename FuncT> void recalculate(FuncT &F) {
+    if (Strategy == UpdateStrategy::Eager) {
+      if (DT)
+        DT->recalculate(F);
+      if (PDT)
+        PDT->recalculate(F);
+      return;
+    }
+
+    // There is little performance gain if we pend the recalculation under
+    // Lazy UpdateStrategy so we recalculate available trees immediately.
+
+    // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
+    IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
+
+    // Because all trees are going to be up-to-date after recalculation,
+    // flush awaiting deleted BasicBlocks.
+    derived().forceFlushDeletedBB();
+    if (DT)
+      DT->recalculate(F);
+    if (PDT)
+      PDT->recalculate(F);
+
+    // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
+    IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
+    PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
+    dropOutOfDateUpdates();
+  }
+
+  /// Submit updates to all available trees.
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    if (!DT && !PDT)
+      return;
+
+    if (Strategy == UpdateStrategy::Lazy) {
+      PendUpdates.reserve(PendUpdates.size() + Updates.size());
+      for (const auto &U : Updates)
+        if (!isSelfDominance(U))
+          PendUpdates.push_back(U);
+
+      return;
+    }
+
+    if (DT)
+      DT->applyUpdates(Updates);
+    if (PDT)
+      PDT->applyUpdates(Updates);
+  }
+
+  /// Submit updates to all available trees. It will also
+  /// 1. discard duplicated updates,
+  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
+  /// still exists or insertion of an edge that does not exist.)
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  /// 3. It is only legal to submit updates to an edge in the order CFG changes
+  /// are made. The order you submit updates on different edges is not
+  /// restricted.
+  void applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
+    if (!DT && !PDT)
+      return;
+
+    SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
+    SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
+    for (const auto &U : Updates) {
+      auto Edge = std::make_pair(U.getFrom(), U.getTo());
+      // Because it is illegal to submit updates that have already been applied
+      // and updates to an edge need to be strictly ordered,
+      // it is safe to infer the existence of an edge from the first update
+      // to this edge.
+      // If the first update to an edge is "Delete", it means that the edge
+      // existed before. If the first update to an edge is "Insert", it means
+      // that the edge didn't exist before.
+      //
+      // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
+      // because
+      // 1. it is illegal to submit updates that have already been applied,
+      // i.e., user cannot delete an nonexistent edge,
+      // 2. updates to an edge need to be strictly ordered,
+      // So, initially edge A -> B existed.
+      // We can then safely ignore future updates to this edge and directly
+      // inspect the current CFG:
+      // a. If the edge still exists, because the user cannot insert an existent
+      // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
+      // resulted in a no-op. DTU won't submit any update in this case.
+      // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
+      // actually happened but {Insert, A, B} was an invalid update which never
+      // happened. DTU will submit {Delete, A, B} in this case.
+      if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
+        Seen.insert(Edge);
+        // If the update doesn't appear in the CFG, it means that
+        // either the change isn't made or relevant operations
+        // result in a no-op.
+        if (isUpdateValid(U)) {
+          if (isLazy())
+            PendUpdates.push_back(U);
+          else
+            DeduplicatedUpdates.push_back(U);
+        }
+      }
+    }
+
+    if (Strategy == UpdateStrategy::Lazy)
+      return;
+
+    if (DT)
+      DT->applyUpdates(DeduplicatedUpdates);
+    if (PDT)
+      PDT->applyUpdates(DeduplicatedUpdates);
+  }
+
+  ///@}
+
+  ///@{
+  /// \name Flush APIs
+  ///
+  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
+  /// to be the same as the CFG which DTU is in sync with + all updates
+  /// submitted.
+
+  /// Flush DomTree updates and return DomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a DomTree.
+  DomTreeT &getDomTree() {
+    assert(DT && "Invalid acquisition of a null DomTree");
+    applyDomTreeUpdates();
+    dropOutOfDateUpdates();
+    return *DT;
+  }
+
+  /// Flush PostDomTree updates and return PostDomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a PostDomTree.
+  PostDomTreeT &getPostDomTree() {
+    assert(PDT && "Invalid acquisition of a null PostDomTree");
+    applyPostDomTreeUpdates();
+    dropOutOfDateUpdates();
+    return *PDT;
+  }
+
+  /// Apply all pending updates to available trees and flush all BasicBlocks
+  /// awaiting deletion.
+
+  void flush() {
+    applyDomTreeUpdates();
+    applyPostDomTreeUpdates();
+    dropOutOfDateUpdates();
+  }
+
+  ///@}
+
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const {
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+    raw_ostream &OS = llvm::dbgs();
+
+    OS << "Available Trees: ";
+    if (DT || PDT) {
+      if (DT)
+        OS << "DomTree ";
+      if (PDT)
+        OS << "PostDomTree ";
+      OS << "\n";
+    } else
+      OS << "None\n";
+
+    OS << "UpdateStrategy: ";
+    if (Strategy == UpdateStrategy::Eager) {
+      OS << "Eager\n";
+      return;
+    } else
+      OS << "Lazy\n";
+    int Index = 0;
+
+    auto printUpdates =
+        [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
+                begin,
+            typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
+                end) {
+          if (begin == end)
+            OS << "  None\n";
+          Index = 0;
+          for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
+            auto U = *It;
+            OS << "  " << Index << " : ";
+            ++Index;
+            if (U.getKind() == DomTreeT::Insert)
+              OS << "Insert, ";
+            else
+              OS << "Delete, ";
+            BasicBlockT *From = U.getFrom();
+            if (From) {
+              auto S = From->getName();
+              if (!From->hasName())
+                S = "(no name)";
+              OS << S << "(" << From << "), ";
+            } else {
+              OS << "(badref), ";
+            }
+            BasicBlockT *To = U.getTo();
+            if (To) {
+              auto S = To->getName();
+              if (!To->hasName())
+                S = "(no_name)";
+              OS << S << "(" << To << ")\n";
+            } else {
+              OS << "(badref)\n";
+            }
+          }
+        };
+
+    if (DT) {
+      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+             "Iterator out of range.");
+      OS << "Applied but not cleared DomTreeUpdates:\n";
+      printUpdates(PendUpdates.begin(), I);
+      OS << "Pending DomTreeUpdates:\n";
+      printUpdates(I, PendUpdates.end());
+    }
+
+    if (PDT) {
+      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+             "Iterator out of range.");
+      OS << "Applied but not cleared PostDomTreeUpdates:\n";
+      printUpdates(PendUpdates.begin(), I);
+      OS << "Pending PostDomTreeUpdates:\n";
+      printUpdates(I, PendUpdates.end());
+    }
+
+    OS << "Pending DeletedBBs:\n";
+    Index = 0;
+    for (const auto *BB : DeletedBBs) {
+      OS << "  " << Index << " : ";
+      ++Index;
+      if (BB->hasName())
+        OS << BB->getName() << "(";
+      else
+        OS << "(no_name)(";
+      OS << BB << ")\n";
+    }
+#endif
+  }
+
+protected:
+  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
+  size_t PendDTUpdateIndex = 0;
+  size_t PendPDTUpdateIndex = 0;
+  DomTreeT *DT = nullptr;
+  PostDomTreeT *PDT = nullptr;
+  const UpdateStrategy Strategy;
+  SmallPtrSet<BasicBlockT *, 8> DeletedBBs;
+  bool IsRecalculatingDomTree = false;
+  bool IsRecalculatingPostDomTree = false;
+
+  /// Returns true if the update is self dominance.
+  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
+    // Won't affect DomTree and PostDomTree.
+    return Update.getFrom() == Update.getTo();
+  }
+
+  /// Helper function to apply all pending DomTree updates.
+  void applyDomTreeUpdates() {
+    // No pending DomTreeUpdates.
+    if (Strategy != UpdateStrategy::Lazy || !DT)
+      return;
+
+    // Only apply updates not are applied by DomTree.
+    if (hasPendingDomTreeUpdates()) {
+      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+      const auto E = PendUpdates.end();
+      assert(I < E &&
+             "Iterator range invalid; there should be DomTree updates.");
+      DT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
+      PendDTUpdateIndex = PendUpdates.size();
+    }
+  }
+
+  /// Helper function to apply all pending PostDomTree updates.
+  void applyPostDomTreeUpdates() {
+    // No pending PostDomTreeUpdates.
+    if (Strategy != UpdateStrategy::Lazy || !PDT)
+      return;
+
+    // Only apply updates not are applied by PostDomTree.
+    if (hasPendingPostDomTreeUpdates()) {
+      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+      const auto E = PendUpdates.end();
+      assert(I < E &&
+             "Iterator range invalid; there should be PostDomTree updates.");
+      PDT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
+      PendPDTUpdateIndex = PendUpdates.size();
+    }
+  }
+
+  /// Returns true if the update appears in the LLVM IR.
+  /// It is used to check whether an update is valid in
+  /// insertEdge/deleteEdge or is unnecessary in the batch update.
+  bool isUpdateValid(typename DomTreeT::UpdateType Update) const {
+    const auto *From = Update.getFrom();
+    const auto *To = Update.getTo();
+    const auto Kind = Update.getKind();
+
+    // Discard updates by inspecting the current state of successors of From.
+    // Since isUpdateValid() must be called *after* the Terminator of From is
+    // altered we can determine if the update is unnecessary for batch updates
+    // or invalid for a single update.
+    const bool HasEdge = llvm::is_contained(successors(From), To);
+
+    // If the IR does not match the update,
+    // 1. In batch updates, this update is unnecessary.
+    // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
+    // Edge does not exist in IR.
+    if (Kind == DomTreeT::Insert && !HasEdge)
+      return false;
+
+    // Edge exists in IR.
+    if (Kind == DomTreeT::Delete && HasEdge)
+      return false;
+
+    return true;
+  }
+
+  /// Erase Basic Block node that has been unlinked from Function
+  /// in the DomTree and PostDomTree.
+  void eraseDelBBNode(BasicBlockT *DelBB) {
+    if (DT && !IsRecalculatingDomTree)
+      if (DT->getNode(DelBB))
+        DT->eraseNode(DelBB);
+
+    if (PDT && !IsRecalculatingPostDomTree)
+      if (PDT->getNode(DelBB))
+        PDT->eraseNode(DelBB);
+  }
+
+  /// Helper function to flush deleted BasicBlocks if all available
+  /// trees are up-to-date.
+  void tryFlushDeletedBB() {
+    if (!hasPendingUpdates())
+      derived().forceFlushDeletedBB();
+  }
+
+  /// Drop all updates applied by all available trees and delete BasicBlocks if
+  /// all available trees are up-to-date.
+  void dropOutOfDateUpdates() {
+    if (Strategy == UpdateStrategy::Eager)
+      return;
+
+    tryFlushDeletedBB();
+
+    // Drop all updates applied by both trees.
+    if (!DT)
+      PendDTUpdateIndex = PendUpdates.size();
+    if (!PDT)
+      PendPDTUpdateIndex = PendUpdates.size();
+
+    const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
+    const auto B = PendUpdates.begin();
+    const auto E = PendUpdates.begin() + dropIndex;
+    assert(B <= E && "Iterator out of range.");
+    PendUpdates.erase(B, E);
+    // Calculate current index.
+    PendDTUpdateIndex -= dropIndex;
+    PendPDTUpdateIndex -= dropIndex;
+  }
+};
+
+} // namespace llvm
+
+#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index 5b6be3a96b2fb..e4919ecabd705 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -238,6 +238,9 @@ class MachineBasicBlock
     BB = nullptr;
   }
 
+  /// Check if there is a name of corresponding LLVM basic block.
+  bool hasName() const;
+
   /// Return the name of the corresponding LLVM basic block, or an empty string.
   StringRef getName() const;
 
diff --git a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
new file mode 100644
index 0000000000000..8bc572e6e6af0
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
@@ -0,0 +1,72 @@
+//===- llvm/CodeGen/MachineDomTreeUpdater.h -----------------------*- C++
+//-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exposes interfaces to post dominance information for
+// target-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
+#define LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
+
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/GenericDomTreeUpdater.h"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Support/Compiler.h"
+#include <cstddef>
+#include <functional>
+#include <vector>
+
+namespace llvm {
+
+class MachineDomTreeUpdater
+    : public GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                                   MachinePostDominatorTree> {
+  friend GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                               MachinePostDominatorTree>;
+
+public:
+  using Base =
+      GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
+                            MachinePostDominatorTree>;
+  using Base::Base;
+
+  ///@{
+  /// \name Mutation APIs
+  ///
+
+  /// Delete DelBB. DelBB will be removed from its Parent and
+  /// erased from available trees if it exists and finally get deleted.
+  /// Under Eager UpdateStrategy, DelBB will be processed immediately.
+  /// Under Lazy UpdateStrategy, DelBB will be queued until a flush event and
+  /// all available trees are up-to-date. Assert if any instruction of DelBB is
+  /// modified while awaiting deletion. When both DT and PDT are nullptrs, DelBB
+  /// will be queued until flush() is called.
+  void deleteBB(MachineBasicBlock *DelBB);
+
+  ///@}
+
+private:
+  /// First remove all the instructions of DelBB and then make sure DelBB has a
+  /// valid terminator instruction which is necessary to have when DelBB still
+  /// has to be inside of its parent Function while awaiting deletion under Lazy
+  /// UpdateStrategy to prevent other routines from asserting the state of the
+  /// IR is inconsistent. Assert if DelBB is nullptr or has predecessors.
+  void validateDeleteBB(MachineBasicBlock *DelBB);
+
+  /// Returns true if at least one MachineBasicBlock is deleted.
+  bool forceFlushDeletedBB();
+};
+
+extern template class GenericDomTreeUpdater<
+    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
+} // namespace llvm
+#endif // LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachinePostDominators.h b/llvm/include/llvm/CodeGen/MachinePostDominators.h
index 904c5fcdfc68b..58cfb278b7962 100644
--- a/llvm/include/llvm/CodeGen/MachinePostDominators.h
+++ b/llvm/include/llvm/CodeGen/MachinePostDominators.h
@@ -48,6 +48,7 @@ class MachinePostDominatorTree : public PostDomTreeBase<MachineBasicBlock> {
 
 public:
   MachinePostDominatorTree() = default;
+  explicit MachinePostDominatorTree(MachineFunction &MF) { recalculate(MF); }
 
   MachinePostDominatorTree(MachineFunction &MF) { recalculate(MF); }
 
diff --git a/llvm/lib/Analysis/DomTreeUpdater.cpp b/llvm/lib/Analysis/DomTreeUpdater.cpp
index 0a16fc9a76d29..676cb87210176 100644
--- a/llvm/lib/Analysis/DomTreeUpdater.cpp
+++ b/llvm/lib/Analysis/DomTreeUpdater.cpp
@@ -23,79 +23,8 @@
 
 namespace llvm {
 
-bool DomTreeUpdater::isUpdateValid(
-    const DominatorTree::UpdateType Update) const {
-  const auto *From = Update.getFrom();
-  const auto *To = Update.getTo();
-  const auto Kind = Update.getKind();
-
-  // Discard updates by inspecting the current state of successors of From.
-  // Since isUpdateValid() must be called *after* the Terminator of From is
-  // altered we can determine if the update is unnecessary for batch updates
-  // or invalid for a single update.
-  const bool HasEdge = llvm::is_contained(successors(From), To);
-
-  // If the IR does not match the update,
-  // 1. In batch updates, this update is unnecessary.
-  // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
-  // Edge does not exist in IR.
-  if (Kind == DominatorTree::Insert && !HasEdge)
-    return false;
-
-  // Edge exists in IR.
-  if (Kind == DominatorTree::Delete && HasEdge)
-    return false;
-
-  return true;
-}
-
-bool DomTreeUpdater::isSelfDominance(
-    const DominatorTree::UpdateType Update) const {
-  // Won't affect DomTree and PostDomTree.
-  return Update.getFrom() == Update.getTo();
-}
-
-void DomTreeUpdater::applyDomTreeUpdates() {
-  // No pending DomTreeUpdates.
-  if (Strategy != UpdateStrategy::Lazy || !DT)
-    return;
-
-  // Only apply updates not are applied by DomTree.
-  if (hasPendingDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-    const auto E = PendUpdates.end();
-    assert(I < E && "Iterator range invalid; there should be DomTree updates.");
-    DT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
-    PendDTUpdateIndex = PendUpdates.size();
-  }
-}
-
-void DomTreeUpdater::flush() {
-  applyDomTreeUpdates();
-  applyPostDomTreeUpdates();
-  dropOutOfDateUpdates();
-}
-
-void DomTreeUpdater::applyPostDomTreeUpdates() {
-  // No pending PostDomTreeUpdates.
-  if (Strategy != UpdateStrategy::Lazy || !PDT)
-    return;
-
-  // Only apply updates not are applied by PostDomTree.
-  if (hasPendingPostDomTreeUpdates()) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-    const auto E = PendUpdates.end();
-    assert(I < E &&
-           "Iterator range invalid; there should be PostDomTree updates.");
-    PDT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
-    PendPDTUpdateIndex = PendUpdates.size();
-  }
-}
-
-void DomTreeUpdater::tryFlushDeletedBB() {
-  if (!hasPendingUpdates())
-    forceFlushDeletedBB();
-}
+template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
+                                     PostDominatorTree>;
 
 bool DomTreeUpdater::forceFlushDeletedBB() {
   if (DeletedBBs.empty())
@@ -117,58 +46,6 @@ bool DomTreeUpdater::forceFlushDeletedBB() {
   return true;
 }
 
-void DomTreeUpdater::recalculate(Function &F) {
-
-  if (Strategy == UpdateStrategy::Eager) {
-    if (DT)
-      DT->recalculate(F);
-    if (PDT)
-      PDT->recalculate(F);
-    return;
-  }
-
-  // There is little performance gain if we pend the recalculation under
-  // Lazy UpdateStrategy so we recalculate available trees immediately.
-
-  // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
-  IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
-
-  // Because all trees are going to be up-to-date after recalculation,
-  // flush awaiting deleted BasicBlocks.
-  forceFlushDeletedBB();
-  if (DT)
-    DT->recalculate(F);
-  if (PDT)
-    PDT->recalculate(F);
-
-  // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
-  IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
-  PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
-  dropOutOfDateUpdates();
-}
-
-bool DomTreeUpdater::hasPendingUpdates() const {
-  return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
-}
-
-bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
-  if (!DT)
-    return false;
-  return PendUpdates.size() != PendDTUpdateIndex;
-}
-
-bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
-  if (!PDT)
-    return false;
-  return PendUpdates.size() != PendPDTUpdateIndex;
-}
-
-bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
-  if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
-    return false;
-  return DeletedBBs.contains(DelBB);
-}
-
 // The DT and PDT require the nodes related to updates
 // are not deleted when update functions are called.
 // So BasicBlock deletions must be pended when the
@@ -201,16 +78,6 @@ void DomTreeUpdater::callbackDeleteBB(
   delete DelBB;
 }
 
-void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
-  if (DT && !IsRecalculatingDomTree)
-    if (DT->getNode(DelBB))
-      DT->eraseNode(DelBB);
-
-  if (PDT && !IsRecalculatingPostDomTree)
-    if (PDT->getNode(DelBB))
-      PDT->eraseNode(DelBB);
-}
-
 void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   assert(DelBB && "Invalid push_back of nullptr DelBB.");
   assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
@@ -227,215 +94,4 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   new UnreachableInst(DelBB->getContext(), DelBB);
 }
 
-void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) {
-  if (!DT && !PDT)
-    return;
-
-  if (Strategy == UpdateStrategy::Lazy) {
-    PendUpdates.reserve(PendUpdates.size() + Updates.size());
-    for (const auto &U : Updates)
-      if (!isSelfDominance(U))
-        PendUpdates.push_back(U);
-
-    return;
-  }
-
-  if (DT)
-    DT->applyUpdates(Updates);
-  if (PDT)
-    PDT->applyUpdates(Updates);
-}
-
-void DomTreeUpdater::applyUpdatesPermissive(
-    ArrayRef<DominatorTree::UpdateType> Updates) {
-  if (!DT && !PDT)
-    return;
-
-  SmallSet<std::pair<BasicBlock *, BasicBlock *>, 8> Seen;
-  SmallVector<DominatorTree::UpdateType, 8> DeduplicatedUpdates;
-  for (const auto &U : Updates) {
-    auto Edge = std::make_pair(U.getFrom(), U.getTo());
-    // Because it is illegal to submit updates that have already been applied
-    // and updates to an edge need to be strictly ordered,
-    // it is safe to infer the existence of an edge from the first update
-    // to this edge.
-    // If the first update to an edge is "Delete", it means that the edge
-    // existed before. If the first update to an edge is "Insert", it means
-    // that the edge didn't exist before.
-    //
-    // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
-    // because
-    // 1. it is illegal to submit updates that have already been applied,
-    // i.e., user cannot delete an nonexistent edge,
-    // 2. updates to an edge need to be strictly ordered,
-    // So, initially edge A -> B existed.
-    // We can then safely ignore future updates to this edge and directly
-    // inspect the current CFG:
-    // a. If the edge still exists, because the user cannot insert an existent
-    // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
-    // resulted in a no-op. DTU won't submit any update in this case.
-    // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
-    // actually happened but {Insert, A, B} was an invalid update which never
-    // happened. DTU will submit {Delete, A, B} in this case.
-    if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
-      Seen.insert(Edge);
-      // If the update doesn't appear in the CFG, it means that
-      // either the change isn't made or relevant operations
-      // result in a no-op.
-      if (isUpdateValid(U)) {
-        if (isLazy())
-          PendUpdates.push_back(U);
-        else
-          DeduplicatedUpdates.push_back(U);
-      }
-    }
-  }
-
-  if (Strategy == UpdateStrategy::Lazy)
-    return;
-
-  if (DT)
-    DT->applyUpdates(DeduplicatedUpdates);
-  if (PDT)
-    PDT->applyUpdates(DeduplicatedUpdates);
-}
-
-DominatorTree &DomTreeUpdater::getDomTree() {
-  assert(DT && "Invalid acquisition of a null DomTree");
-  applyDomTreeUpdates();
-  dropOutOfDateUpdates();
-  return *DT;
-}
-
-PostDominatorTree &DomTreeUpdater::getPostDomTree() {
-  assert(PDT && "Invalid acquisition of a null PostDomTree");
-  applyPostDomTreeUpdates();
-  dropOutOfDateUpdates();
-  return *PDT;
-}
-
-void DomTreeUpdater::dropOutOfDateUpdates() {
-  if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
-    return;
-
-  tryFlushDeletedBB();
-
-  // Drop all updates applied by both trees.
-  if (!DT)
-    PendDTUpdateIndex = PendUpdates.size();
-  if (!PDT)
-    PendPDTUpdateIndex = PendUpdates.size();
-
-  const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
-  const auto B = PendUpdates.begin();
-  const auto E = PendUpdates.begin() + dropIndex;
-  assert(B <= E && "Iterator out of range.");
-  PendUpdates.erase(B, E);
-  // Calculate current index.
-  PendDTUpdateIndex -= dropIndex;
-  PendPDTUpdateIndex -= dropIndex;
-}
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
-  raw_ostream &OS = llvm::dbgs();
-
-  OS << "Available Trees: ";
-  if (DT || PDT) {
-    if (DT)
-      OS << "DomTree ";
-    if (PDT)
-      OS << "PostDomTree ";
-    OS << "\n";
-  } else
-    OS << "None\n";
-
-  OS << "UpdateStrategy: ";
-  if (Strategy == UpdateStrategy::Eager) {
-    OS << "Eager\n";
-    return;
-  } else
-    OS << "Lazy\n";
-  int Index = 0;
-
-  auto printUpdates =
-      [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
-          ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
-        if (begin == end)
-          OS << "  None\n";
-        Index = 0;
-        for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
-          auto U = *It;
-          OS << "  " << Index << " : ";
-          ++Index;
-          if (U.getKind() == DominatorTree::Insert)
-            OS << "Insert, ";
-          else
-            OS << "Delete, ";
-          BasicBlock *From = U.getFrom();
-          if (From) {
-            auto S = From->getName();
-            if (!From->hasName())
-              S = "(no name)";
-            OS << S << "(" << From << "), ";
-          } else {
-            OS << "(badref), ";
-          }
-          BasicBlock *To = U.getTo();
-          if (To) {
-            auto S = To->getName();
-            if (!To->hasName())
-              S = "(no_name)";
-            OS << S << "(" << To << ")\n";
-          } else {
-            OS << "(badref)\n";
-          }
-        }
-      };
-
-  if (DT) {
-    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-           "Iterator out of range.");
-    OS << "Applied but not cleared DomTreeUpdates:\n";
-    printUpdates(PendUpdates.begin(), I);
-    OS << "Pending DomTreeUpdates:\n";
-    printUpdates(I, PendUpdates.end());
-  }
-
-  if (PDT) {
-    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-           "Iterator out of range.");
-    OS << "Applied but not cleared PostDomTreeUpdates:\n";
-    printUpdates(PendUpdates.begin(), I);
-    OS << "Pending PostDomTreeUpdates:\n";
-    printUpdates(I, PendUpdates.end());
-  }
-
-  OS << "Pending DeletedBBs:\n";
-  Index = 0;
-  for (const auto *BB : DeletedBBs) {
-    OS << "  " << Index << " : ";
-    ++Index;
-    if (BB->hasName())
-      OS << BB->getName() << "(";
-    else
-      OS << "(no_name)(";
-    OS << BB << ")\n";
-  }
-
-  OS << "Pending Callbacks:\n";
-  Index = 0;
-  for (const auto &BB : Callbacks) {
-    OS << "  " << Index << " : ";
-    ++Index;
-    if (BB->hasName())
-      OS << BB->getName() << "(";
-    else
-      OS << "(no_name)(";
-    OS << BB << ")\n";
-  }
-}
-#endif
 } // namespace llvm
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index 41fc555c93e93..f1607f85c5b31 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -116,6 +116,7 @@ add_llvm_component_library(LLVMCodeGen
   MachineCheckDebugify.cpp
   MachineCycleAnalysis.cpp
   MachineDebugify.cpp
+  MachineDomTreeUpdater.cpp
   MachineDominanceFrontier.cpp
   MachineDominators.cpp
   MachineFrameInfo.cpp
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index abf43e39ee9a6..533ab7cccaeb7 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -315,6 +315,12 @@ bool MachineBasicBlock::isLegalToHoistInto() const {
   return true;
 }
 
+bool MachineBasicBlock::hasName() const {
+  if (const BasicBlock *LBB = getBasicBlock())
+    return LBB->hasName();
+  return false;
+}
+
 StringRef MachineBasicBlock::getName() const {
   if (const BasicBlock *LBB = getBasicBlock())
     return LBB->getName();
diff --git a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
new file mode 100644
index 0000000000000..86b3185ca90a3
--- /dev/null
+++ b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
@@ -0,0 +1,62 @@
+//===- MachineDomTreeUpdater.cpp -----------------------------------------===//
+//
+// 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 implements the MachineDomTreeUpdater class, which provides a
+// uniform way to update dominator tree related data structures.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineDomTreeUpdater.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/Support/GenericDomTree.h"
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+namespace llvm {
+
+template class GenericDomTreeUpdater<
+    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
+
+bool MachineDomTreeUpdater::forceFlushDeletedBB() {
+  if (DeletedBBs.empty())
+    return false;
+
+  for (auto *BB : DeletedBBs) {
+    eraseDelBBNode(BB);
+    BB->eraseFromParent();
+  }
+  DeletedBBs.clear();
+  return true;
+}
+
+// The DT and PDT require the nodes related to updates
+// are not deleted when update functions are called.
+// So MachineBasicBlock deletions must be pended when the
+// UpdateStrategy is Lazy. When the UpdateStrategy is
+// Eager, the MachineBasicBlock will be deleted immediately.
+void MachineDomTreeUpdater::deleteBB(MachineBasicBlock *DelBB) {
+  validateDeleteBB(DelBB);
+  if (Strategy == UpdateStrategy::Lazy) {
+    DeletedBBs.insert(DelBB);
+    return;
+  }
+
+  eraseDelBBNode(DelBB);
+  DelBB->eraseFromParent();
+}
+
+void MachineDomTreeUpdater::validateDeleteBB(MachineBasicBlock *DelBB) {
+  assert(DelBB && "Invalid push_back of nullptr DelBB.");
+  assert(DelBB->pred_empty() && "DelBB has one or more predecessors.");
+}
+
+} // namespace llvm
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index dbbacdd95ec9f..963cdcc0275e1 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -32,6 +32,7 @@ add_llvm_unittest(CodeGenTests
   LowLevelTypeTest.cpp
   LexicalScopesTest.cpp
   MachineBasicBlockTest.cpp
+  MachineDomTreeUpdaterTest.cpp
   MachineInstrBundleIteratorTest.cpp
   MachineInstrTest.cpp
   MachineOperandTest.cpp
diff --git a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
new file mode 100644
index 0000000000000..e123ba847e622
--- /dev/null
+++ b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
@@ -0,0 +1,276 @@
+//===- MachineDomTreeUpdaterTest.cpp - MachineDomTreeUpdater unit tests ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineDomTreeUpdater.h"
+#include "llvm/Analysis/CGSCCPassManager.h"
+#include "llvm/Analysis/LoopAnalysisManager.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachinePassManager.h"
+#include "llvm/CodeGen/MachinePostDominators.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+class MachineDomTreeUpdaterTest : public testing::Test {
+public:
+  LLVMContext Context;
+  std::unique_ptr<TargetMachine> TM;
+  std::unique_ptr<Module> M;
+  std::unique_ptr<MachineModuleInfo> MMI;
+  std::unique_ptr<MIRParser> MIR;
+
+  LoopAnalysisManager LAM;
+  MachineFunctionAnalysisManager MFAM;
+  FunctionAnalysisManager FAM;
+  CGSCCAnalysisManager CGAM;
+  ModuleAnalysisManager MAM;
+
+  ModulePassManager MPM;
+  FunctionPassManager FPM;
+  MachineFunctionPassManager MFPM;
+
+  static void SetUpTestCase() {
+    InitializeAllTargets();
+    InitializeAllTargetMCs();
+  }
+
+  void SetUp() override {
+    Triple TargetTriple("x86_64-unknown-linux-gnu");
+    std::string Error;
+    const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
+    if (!T)
+      GTEST_SKIP();
+    TargetOptions Options;
+    TM = std::unique_ptr<TargetMachine>(
+        T->createTargetMachine("X86", "", "", Options, std::nullopt));
+    if (!TM)
+      GTEST_SKIP();
+    MMI = std::make_unique<MachineModuleInfo>(
+        static_cast<LLVMTargetMachine *>(TM.get()));
+
+    PassBuilder PB(TM.get());
+    PB.registerModuleAnalyses(MAM);
+    PB.registerCGSCCAnalyses(CGAM);
+    PB.registerFunctionAnalyses(FAM);
+    PB.registerLoopAnalyses(LAM);
+    PB.registerMachineFunctionAnalyses(MFAM);
+    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM);
+    MAM.registerPass([&] { return MachineModuleAnalysis(*MMI); });
+  }
+
+  bool parseMIR(StringRef MIRCode, const char *FnName) {
+    SMDiagnostic Diagnostic;
+    std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
+    MIR = createMIRParser(std::move(MBuffer), Context);
+    if (!MIR)
+      return false;
+
+    M = MIR->parseIRModule();
+    M->setDataLayout(TM->createDataLayout());
+
+    if (MIR->parseMachineFunctions(*M, MAM)) {
+      M.reset();
+      return false;
+    }
+
+    return true;
+  }
+};
+
+TEST_F(MachineDomTreeUpdaterTest, EagerUpdateBasicOperations) {
+  StringRef MIRString = R"(
+--- |
+  define i64 @f0(i64 %i, ptr %p) {
+  bb0:
+    store i64 %i, ptr %p, align 4
+    switch i64 %i, label %bb1 [
+      i64 1, label %bb2
+      i64 2, label %bb3
+    ]
+  bb1:                                              ; preds = %bb0
+    ret i64 1
+  bb2:                                              ; preds = %bb0
+    ret i64 2
+  bb3:                                              ; preds = %bb0
+    ret i64 3
+  }
+...
+---
+name:            f0
+body:             |
+  bb.0.bb0:
+    successors: %bb.2, %bb.4
+    liveins: $rdi, $rsi
+
+    %1:gr32 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
+    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit $eflags
+    JMP_1 %bb.4
+
+  bb.4.bb0:
+    successors: %bb.3, %bb.1
+
+    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
+    JCC_1 %bb.3, 4, implicit $eflags
+    JMP_1 %bb.1
+
+  bb.1.bb1:
+    %6:gr64 = MOV32ri64 1
+    $rax = COPY %6
+    RET 0, $rax
+
+  bb.2.bb2:
+    %5:gr64 = MOV32ri64 2
+    $rax = COPY %5
+    RET 0, $rax
+
+  bb.3.bb3:
+    %4:gr64 = MOV32ri64 3
+    $rax = COPY %4
+    RET 0, $rax
+
+...
+)";
+
+  ASSERT_TRUE(parseMIR(MIRString, "f0"));
+
+  auto &MF =
+      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
+
+  MachineDominatorTree DT(MF);
+  MachinePostDominatorTree PDT(MF);
+  MachineDomTreeUpdater DTU(DT, PDT,
+                            MachineDomTreeUpdater::UpdateStrategy::Eager);
+
+  ASSERT_TRUE(DTU.hasDomTree());
+  ASSERT_TRUE(DTU.hasPostDomTree());
+  ASSERT_TRUE(DTU.isEager());
+  ASSERT_FALSE(DTU.isLazy());
+  ASSERT_TRUE(DTU.getDomTree().verify());
+  ASSERT_TRUE(DTU.getPostDomTree().verify());
+  ASSERT_FALSE(DTU.hasPendingUpdates());
+
+  auto B = MF.begin();
+  [[maybe_unused]] auto BB0 = B;
+  auto BB1 = ++B;
+  auto BB2 = ++B;
+  [[maybe_unused]] auto BB3 = ++B;
+  auto BB4 = ++B;
+  EXPECT_EQ(BB1->succ_size(), 2u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
+  BB1->removeSuccessor(&*BB4);
+  DTU.deleteBB(&*BB4);
+  EXPECT_EQ(BB1->succ_size(), 1u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
+}
+
+TEST_F(MachineDomTreeUpdaterTest, LazyUpdateBasicOperations) {
+  StringRef MIRString = R"(
+--- |
+  define i64 @f0(i64 %i, ptr %p) {
+  bb0:
+    store i64 %i, ptr %p, align 4
+    switch i64 %i, label %bb1 [
+      i64 1, label %bb2
+      i64 2, label %bb3
+    ]
+  bb1:                                              ; preds = %bb0
+    ret i64 1
+  bb2:                                              ; preds = %bb0
+    ret i64 2
+  bb3:                                              ; preds = %bb0
+    ret i64 3
+  }
+...
+---
+name:            f0
+body:             |
+  bb.0.bb0:
+    successors: %bb.2, %bb.4
+    liveins: $rdi, $rsi
+
+    %1:gr32 = COPY $rsi
+    %0:gr64 = COPY $rdi
+    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
+    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
+    JCC_1 %bb.2, 4, implicit $eflags
+    JMP_1 %bb.4
+
+  bb.4.bb0:
+    successors: %bb.3, %bb.1
+
+    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
+    JCC_1 %bb.3, 4, implicit $eflags
+    JMP_1 %bb.1
+
+  bb.1.bb1:
+    %6:gr64 = MOV32ri64 1
+    $rax = COPY %6
+    RET 0, $rax
+
+  bb.2.bb2:
+    %5:gr64 = MOV32ri64 2
+    $rax = COPY %5
+    RET 0, $rax
+
+  bb.3.bb3:
+    %4:gr64 = MOV32ri64 3
+    $rax = COPY %4
+    RET 0, $rax
+
+...
+)";
+
+  ASSERT_TRUE(parseMIR(MIRString, "f0"));
+
+  auto &MF =
+      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
+
+  MachineDominatorTree DT(MF);
+  MachinePostDominatorTree PDT(MF);
+  MachineDomTreeUpdater DTU(DT, PDT,
+                            MachineDomTreeUpdater::UpdateStrategy::Lazy);
+
+  ASSERT_TRUE(DTU.hasDomTree());
+  ASSERT_TRUE(DTU.hasPostDomTree());
+  ASSERT_FALSE(DTU.isEager());
+  ASSERT_TRUE(DTU.isLazy());
+  ASSERT_TRUE(DTU.getDomTree().verify());
+  ASSERT_TRUE(DTU.getPostDomTree().verify());
+  ASSERT_FALSE(DTU.hasPendingUpdates());
+
+  auto B = MF.begin();
+  [[maybe_unused]] auto BB0 = B;
+  auto BB1 = ++B;
+  auto BB2 = ++B;
+  [[maybe_unused]] auto BB3 = ++B;
+  auto BB4 = ++B;
+  EXPECT_EQ(BB1->succ_size(), 2u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
+  BB1->removeSuccessor(&*BB4);
+  DTU.deleteBB(&*BB4);
+  EXPECT_EQ(BB1->succ_size(), 1u);
+  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
+  ASSERT_NE(DT.getNode(&*BB4), nullptr);
+  DTU.flush();
+  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
+}

>From 6f5b171def6327565e309b11c81d082eabb7c0be Mon Sep 17 00:00:00 2001
From: paperchalice <liujunchang97 at outlook.com>
Date: Thu, 27 Jun 2024 12:31:24 +0800
Subject: [PATCH 15/19] Revert "[CodeGen] Introduce `MachineDomTreeUpdater`"
 (#96846)

Reverts llvm/llvm-project#95369
Many build bots failed
---
 llvm/include/llvm/Analysis/DomTreeUpdater.h   | 196 +++++--
 .../llvm/Analysis/GenericDomTreeUpdater.h     | 525 ------------------
 llvm/include/llvm/CodeGen/MachineBasicBlock.h |   3 -
 .../llvm/CodeGen/MachineDomTreeUpdater.h      |  72 ---
 .../llvm/CodeGen/MachinePostDominators.h      |   1 -
 llvm/lib/Analysis/DomTreeUpdater.cpp          | 348 +++++++++++-
 llvm/lib/CodeGen/CMakeLists.txt               |   1 -
 llvm/lib/CodeGen/MachineBasicBlock.cpp        |   6 -
 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp    |  62 ---
 llvm/unittests/CodeGen/CMakeLists.txt         |   1 -
 .../CodeGen/MachineDomTreeUpdaterTest.cpp     | 276 ---------
 11 files changed, 510 insertions(+), 981 deletions(-)
 delete mode 100644 llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
 delete mode 100644 llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
 delete mode 100644 llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
 delete mode 100644 llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp

diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h
index 2b838a311440e..ddb958455ccd7 100644
--- a/llvm/include/llvm/Analysis/DomTreeUpdater.h
+++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h
@@ -15,8 +15,6 @@
 #define LLVM_ANALYSIS_DOMTREEUPDATER_H
 
 #include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Analysis/GenericDomTreeUpdater.h"
-#include "llvm/Analysis/PostDominators.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/ValueHandle.h"
 #include "llvm/Support/Compiler.h"
@@ -25,17 +23,66 @@
 #include <vector>
 
 namespace llvm {
+class PostDominatorTree;
 
-class DomTreeUpdater
-    : public GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
-                                   PostDominatorTree> {
-  friend GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
-                               PostDominatorTree>;
-
+class DomTreeUpdater {
 public:
-  using Base =
-      GenericDomTreeUpdater<DomTreeUpdater, DominatorTree, PostDominatorTree>;
-  using Base::Base;
+  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
+
+  explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {}
+  DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_)
+      : DT(&DT_), Strategy(Strategy_) {}
+  DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_)
+      : DT(DT_), Strategy(Strategy_) {}
+  DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_)
+      : PDT(&PDT_), Strategy(Strategy_) {}
+  DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_)
+      : PDT(PDT_), Strategy(Strategy_) {}
+  DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_,
+                 UpdateStrategy Strategy_)
+      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
+  DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_,
+                 UpdateStrategy Strategy_)
+      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
+
+  ~DomTreeUpdater() { flush(); }
+
+  /// Returns true if the current strategy is Lazy.
+  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
+
+  /// Returns true if the current strategy is Eager.
+  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
+
+  /// Returns true if it holds a DominatorTree.
+  bool hasDomTree() const { return DT != nullptr; }
+
+  /// Returns true if it holds a PostDominatorTree.
+  bool hasPostDomTree() const { return PDT != nullptr; }
+
+  /// Returns true if there is BasicBlock awaiting deletion.
+  /// The deletion will only happen until a flush event and
+  /// all available trees are up-to-date.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
+
+  /// Returns true if DelBB is awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool isBBPendingDeletion(BasicBlock *DelBB) const;
+
+  /// Returns true if either of DT or PDT is valid and the tree has at
+  /// least one update pending. If DT or PDT is nullptr it is treated
+  /// as having no pending updates. This function does not check
+  /// whether there is BasicBlock awaiting deletion.
+  /// Returns false under Eager UpdateStrategy.
+  bool hasPendingUpdates() const;
+
+  /// Returns true if there are DominatorTree updates queued.
+  /// Returns false under Eager UpdateStrategy or DT is nullptr.
+  bool hasPendingDomTreeUpdates() const;
+
+  /// Returns true if there are PostDominatorTree updates queued.
+  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
+  bool hasPendingPostDomTreeUpdates() const;
 
   ///@{
   /// \name Mutation APIs
@@ -58,6 +105,51 @@ class DomTreeUpdater
   /// Although GenericDomTree provides several update primitives,
   /// it is not encouraged to use these APIs directly.
 
+  /// Submit updates to all available trees.
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates);
+
+  /// Submit updates to all available trees. It will also
+  /// 1. discard duplicated updates,
+  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
+  /// still exists or insertion of an edge that does not exist.)
+  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
+  /// queues the updates.
+  ///
+  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
+  /// in sync with + all updates before that single update.
+  ///
+  /// CAUTION!
+  /// 1. It is required for the state of the LLVM IR to be updated
+  /// *before* submitting the updates because the internal update routine will
+  /// analyze the current state of the CFG to determine whether an update
+  /// is valid.
+  /// 2. It is illegal to submit any update that has already been submitted,
+  /// i.e., you are supposed not to insert an existent edge or delete a
+  /// nonexistent edge.
+  /// 3. It is only legal to submit updates to an edge in the order CFG changes
+  /// are made. The order you submit updates on different edges is not
+  /// restricted.
+  void applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates);
+
+  /// Notify DTU that the entry block was replaced.
+  /// Recalculate all available trees and flush all BasicBlocks
+  /// awaiting deletion immediately.
+  void recalculate(Function &F);
+
   /// Delete DelBB. DelBB will be removed from its Parent and
   /// erased from available trees if it exists and finally get deleted.
   /// Under Eager UpdateStrategy, DelBB will be processed immediately.
@@ -80,6 +172,33 @@ class DomTreeUpdater
 
   ///@}
 
+  ///@{
+  /// \name Flush APIs
+  ///
+  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
+  /// to be the same as the CFG which DTU is in sync with + all updates
+  /// submitted.
+
+  /// Flush DomTree updates and return DomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a DomTree.
+  DominatorTree &getDomTree();
+
+  /// Flush PostDomTree updates and return PostDomTree.
+  /// It flushes Deleted BBs if both trees are up-to-date.
+  /// It must only be called when it has a PostDomTree.
+  PostDominatorTree &getPostDomTree();
+
+  /// Apply all pending updates to available trees and flush all BasicBlocks
+  /// awaiting deletion.
+
+  void flush();
+
+  ///@}
+
+  /// Debug method to help view the internal state of this class.
+  LLVM_DUMP_METHOD void dump() const;
+
 private:
   class CallBackOnDeletion final : public CallbackVH {
   public:
@@ -97,7 +216,16 @@ class DomTreeUpdater
     }
   };
 
+  SmallVector<DominatorTree::UpdateType, 16> PendUpdates;
+  size_t PendDTUpdateIndex = 0;
+  size_t PendPDTUpdateIndex = 0;
+  DominatorTree *DT = nullptr;
+  PostDominatorTree *PDT = nullptr;
+  const UpdateStrategy Strategy;
+  SmallPtrSet<BasicBlock *, 8> DeletedBBs;
   std::vector<CallBackOnDeletion> Callbacks;
+  bool IsRecalculatingDomTree = false;
+  bool IsRecalculatingPostDomTree = false;
 
   /// First remove all the instructions of DelBB and then make sure DelBB has a
   /// valid terminator instruction which is necessary to have when DelBB still
@@ -109,28 +237,32 @@ class DomTreeUpdater
   /// Returns true if at least one BasicBlock is deleted.
   bool forceFlushDeletedBB();
 
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const {
-    Base::dump();
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-    raw_ostream &OS = dbgs();
-    OS << "Pending Callbacks:\n";
-    int Index = 0;
-    for (const auto &BB : Callbacks) {
-      OS << "  " << Index << " : ";
-      ++Index;
-      if (BB->hasName())
-        OS << BB->getName() << "(";
-      else
-        OS << "(no_name)(";
-      OS << BB << ")\n";
-    }
-#endif
-  }
-};
+  /// Helper function to apply all pending DomTree updates.
+  void applyDomTreeUpdates();
+
+  /// Helper function to apply all pending PostDomTree updates.
+  void applyPostDomTreeUpdates();
+
+  /// Helper function to flush deleted BasicBlocks if all available
+  /// trees are up-to-date.
+  void tryFlushDeletedBB();
 
-extern template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
-                                            PostDominatorTree>;
+  /// Drop all updates applied by all available trees and delete BasicBlocks if
+  /// all available trees are up-to-date.
+  void dropOutOfDateUpdates();
+
+  /// Erase Basic Block node that has been unlinked from Function
+  /// in the DomTree and PostDomTree.
+  void eraseDelBBNode(BasicBlock *DelBB);
+
+  /// Returns true if the update appears in the LLVM IR.
+  /// It is used to check whether an update is valid in
+  /// insertEdge/deleteEdge or is unnecessary in the batch update.
+  bool isUpdateValid(DominatorTree::UpdateType Update) const;
+
+  /// Returns true if the update is self dominance.
+  bool isSelfDominance(DominatorTree::UpdateType Update) const;
+};
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_DOMTREEUPDATER_H
diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
deleted file mode 100644
index 7092c67083a67..0000000000000
--- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h
+++ /dev/null
@@ -1,525 +0,0 @@
-//===- GenericDomTreeUpdater.h ----------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the GenericDomTreeUpdater class, which provides a uniform
-// way to update dominator tree related data structures.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
-#define LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-
-template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
-class GenericDomTreeUpdater {
-  DerivedT &derived() { return *static_cast<DerivedT *>(this); }
-  const DerivedT &derived() const {
-    return *static_cast<const DerivedT *>(this);
-  }
-
-public:
-  enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
-  using BasicBlockT = typename DomTreeT::NodeType;
-
-  explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
-      : Strategy(Strategy_) {}
-  GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_)
-      : DT(&DT_), Strategy(Strategy_) {}
-  GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_)
-      : DT(DT_), Strategy(Strategy_) {}
-  GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_)
-      : PDT(&PDT_), Strategy(Strategy_) {}
-  GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_)
-      : PDT(PDT_), Strategy(Strategy_) {}
-  GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_,
-                        UpdateStrategy Strategy_)
-      : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
-  GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_,
-                        UpdateStrategy Strategy_)
-      : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
-
-  ~GenericDomTreeUpdater() { flush(); }
-
-  /// Returns true if the current strategy is Lazy.
-  bool isLazy() const { return Strategy == UpdateStrategy::Lazy; };
-
-  /// Returns true if the current strategy is Eager.
-  bool isEager() const { return Strategy == UpdateStrategy::Eager; };
-
-  /// Returns true if it holds a DomTreeT.
-  bool hasDomTree() const { return DT != nullptr; }
-
-  /// Returns true if it holds a PostDomTreeT.
-  bool hasPostDomTree() const { return PDT != nullptr; }
-
-  /// Returns true if there is BasicBlockT awaiting deletion.
-  /// The deletion will only happen until a flush event and
-  /// all available trees are up-to-date.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
-
-  /// Returns true if DelBB is awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool isBBPendingDeletion(BasicBlockT *DelBB) const {
-    if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
-      return false;
-    return DeletedBBs.contains(DelBB);
-  }
-
-  /// Returns true if either of DT or PDT is valid and the tree has at
-  /// least one update pending. If DT or PDT is nullptr it is treated
-  /// as having no pending updates. This function does not check
-  /// whether there is MachineBasicBlock awaiting deletion.
-  /// Returns false under Eager UpdateStrategy.
-  bool hasPendingUpdates() const {
-    return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
-  }
-
-  /// Returns true if there are DomTreeT updates queued.
-  /// Returns false under Eager UpdateStrategy or DT is nullptr.
-  bool hasPendingDomTreeUpdates() const {
-    if (!DT)
-      return false;
-    return PendUpdates.size() != PendDTUpdateIndex;
-  }
-
-  /// Returns true if there are PostDomTreeT updates queued.
-  /// Returns false under Eager UpdateStrategy or PDT is nullptr.
-  bool hasPendingPostDomTreeUpdates() const {
-    if (!PDT)
-      return false;
-    return PendUpdates.size() != PendPDTUpdateIndex;
-  }
-
-  ///@{
-  /// \name Mutation APIs
-  ///
-  /// These methods provide APIs for submitting updates to the DomTreeT and
-  /// the PostDominatorTree.
-  ///
-  /// Note: There are two strategies to update the DomTreeT and the
-  /// PostDominatorTree:
-  /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
-  /// immediately.
-  /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
-  /// explicitly call Flush APIs. It is recommended to use this update strategy
-  /// when you submit a bunch of updates multiple times which can then
-  /// add up to a large number of updates between two queries on the
-  /// DomTreeT. The incremental updater can reschedule the updates or
-  /// decide to recalculate the dominator tree in order to speedup the updating
-  /// process depending on the number of updates.
-  ///
-  /// Although GenericDomTree provides several update primitives,
-  /// it is not encouraged to use these APIs directly.
-
-  /// Notify DTU that the entry block was replaced.
-  /// Recalculate all available trees and flush all BasicBlocks
-  /// awaiting deletion immediately.
-  template <typename FuncT> void recalculate(FuncT &F) {
-    if (Strategy == UpdateStrategy::Eager) {
-      if (DT)
-        DT->recalculate(F);
-      if (PDT)
-        PDT->recalculate(F);
-      return;
-    }
-
-    // There is little performance gain if we pend the recalculation under
-    // Lazy UpdateStrategy so we recalculate available trees immediately.
-
-    // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
-    IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
-
-    // Because all trees are going to be up-to-date after recalculation,
-    // flush awaiting deleted BasicBlocks.
-    derived().forceFlushDeletedBB();
-    if (DT)
-      DT->recalculate(F);
-    if (PDT)
-      PDT->recalculate(F);
-
-    // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
-    IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
-    PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
-    dropOutOfDateUpdates();
-  }
-
-  /// Submit updates to all available trees.
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates) {
-    if (!DT && !PDT)
-      return;
-
-    if (Strategy == UpdateStrategy::Lazy) {
-      PendUpdates.reserve(PendUpdates.size() + Updates.size());
-      for (const auto &U : Updates)
-        if (!isSelfDominance(U))
-          PendUpdates.push_back(U);
-
-      return;
-    }
-
-    if (DT)
-      DT->applyUpdates(Updates);
-    if (PDT)
-      PDT->applyUpdates(Updates);
-  }
-
-  /// Submit updates to all available trees. It will also
-  /// 1. discard duplicated updates,
-  /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
-  /// still exists or insertion of an edge that does not exist.)
-  /// The Eager Strategy flushes updates immediately while the Lazy Strategy
-  /// queues the updates.
-  ///
-  /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
-  /// in sync with + all updates before that single update.
-  ///
-  /// CAUTION!
-  /// 1. It is required for the state of the LLVM IR to be updated
-  /// *before* submitting the updates because the internal update routine will
-  /// analyze the current state of the CFG to determine whether an update
-  /// is valid.
-  /// 2. It is illegal to submit any update that has already been submitted,
-  /// i.e., you are supposed not to insert an existent edge or delete a
-  /// nonexistent edge.
-  /// 3. It is only legal to submit updates to an edge in the order CFG changes
-  /// are made. The order you submit updates on different edges is not
-  /// restricted.
-  void applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) {
-    if (!DT && !PDT)
-      return;
-
-    SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen;
-    SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates;
-    for (const auto &U : Updates) {
-      auto Edge = std::make_pair(U.getFrom(), U.getTo());
-      // Because it is illegal to submit updates that have already been applied
-      // and updates to an edge need to be strictly ordered,
-      // it is safe to infer the existence of an edge from the first update
-      // to this edge.
-      // If the first update to an edge is "Delete", it means that the edge
-      // existed before. If the first update to an edge is "Insert", it means
-      // that the edge didn't exist before.
-      //
-      // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
-      // because
-      // 1. it is illegal to submit updates that have already been applied,
-      // i.e., user cannot delete an nonexistent edge,
-      // 2. updates to an edge need to be strictly ordered,
-      // So, initially edge A -> B existed.
-      // We can then safely ignore future updates to this edge and directly
-      // inspect the current CFG:
-      // a. If the edge still exists, because the user cannot insert an existent
-      // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
-      // resulted in a no-op. DTU won't submit any update in this case.
-      // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
-      // actually happened but {Insert, A, B} was an invalid update which never
-      // happened. DTU will submit {Delete, A, B} in this case.
-      if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
-        Seen.insert(Edge);
-        // If the update doesn't appear in the CFG, it means that
-        // either the change isn't made or relevant operations
-        // result in a no-op.
-        if (isUpdateValid(U)) {
-          if (isLazy())
-            PendUpdates.push_back(U);
-          else
-            DeduplicatedUpdates.push_back(U);
-        }
-      }
-    }
-
-    if (Strategy == UpdateStrategy::Lazy)
-      return;
-
-    if (DT)
-      DT->applyUpdates(DeduplicatedUpdates);
-    if (PDT)
-      PDT->applyUpdates(DeduplicatedUpdates);
-  }
-
-  ///@}
-
-  ///@{
-  /// \name Flush APIs
-  ///
-  /// CAUTION! By the moment these flush APIs are called, the current CFG needs
-  /// to be the same as the CFG which DTU is in sync with + all updates
-  /// submitted.
-
-  /// Flush DomTree updates and return DomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a DomTree.
-  DomTreeT &getDomTree() {
-    assert(DT && "Invalid acquisition of a null DomTree");
-    applyDomTreeUpdates();
-    dropOutOfDateUpdates();
-    return *DT;
-  }
-
-  /// Flush PostDomTree updates and return PostDomTree.
-  /// It flushes Deleted BBs if both trees are up-to-date.
-  /// It must only be called when it has a PostDomTree.
-  PostDomTreeT &getPostDomTree() {
-    assert(PDT && "Invalid acquisition of a null PostDomTree");
-    applyPostDomTreeUpdates();
-    dropOutOfDateUpdates();
-    return *PDT;
-  }
-
-  /// Apply all pending updates to available trees and flush all BasicBlocks
-  /// awaiting deletion.
-
-  void flush() {
-    applyDomTreeUpdates();
-    applyPostDomTreeUpdates();
-    dropOutOfDateUpdates();
-  }
-
-  ///@}
-
-  /// Debug method to help view the internal state of this class.
-  LLVM_DUMP_METHOD void dump() const {
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-    raw_ostream &OS = llvm::dbgs();
-
-    OS << "Available Trees: ";
-    if (DT || PDT) {
-      if (DT)
-        OS << "DomTree ";
-      if (PDT)
-        OS << "PostDomTree ";
-      OS << "\n";
-    } else
-      OS << "None\n";
-
-    OS << "UpdateStrategy: ";
-    if (Strategy == UpdateStrategy::Eager) {
-      OS << "Eager\n";
-      return;
-    } else
-      OS << "Lazy\n";
-    int Index = 0;
-
-    auto printUpdates =
-        [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-                begin,
-            typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator
-                end) {
-          if (begin == end)
-            OS << "  None\n";
-          Index = 0;
-          for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
-            auto U = *It;
-            OS << "  " << Index << " : ";
-            ++Index;
-            if (U.getKind() == DomTreeT::Insert)
-              OS << "Insert, ";
-            else
-              OS << "Delete, ";
-            BasicBlockT *From = U.getFrom();
-            if (From) {
-              auto S = From->getName();
-              if (!From->hasName())
-                S = "(no name)";
-              OS << S << "(" << From << "), ";
-            } else {
-              OS << "(badref), ";
-            }
-            BasicBlockT *To = U.getTo();
-            if (To) {
-              auto S = To->getName();
-              if (!To->hasName())
-                S = "(no_name)";
-              OS << S << "(" << To << ")\n";
-            } else {
-              OS << "(badref)\n";
-            }
-          }
-        };
-
-    if (DT) {
-      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-             "Iterator out of range.");
-      OS << "Applied but not cleared DomTreeUpdates:\n";
-      printUpdates(PendUpdates.begin(), I);
-      OS << "Pending DomTreeUpdates:\n";
-      printUpdates(I, PendUpdates.end());
-    }
-
-    if (PDT) {
-      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-      assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
-             "Iterator out of range.");
-      OS << "Applied but not cleared PostDomTreeUpdates:\n";
-      printUpdates(PendUpdates.begin(), I);
-      OS << "Pending PostDomTreeUpdates:\n";
-      printUpdates(I, PendUpdates.end());
-    }
-
-    OS << "Pending DeletedBBs:\n";
-    Index = 0;
-    for (const auto *BB : DeletedBBs) {
-      OS << "  " << Index << " : ";
-      ++Index;
-      if (BB->hasName())
-        OS << BB->getName() << "(";
-      else
-        OS << "(no_name)(";
-      OS << BB << ")\n";
-    }
-#endif
-  }
-
-protected:
-  SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
-  size_t PendDTUpdateIndex = 0;
-  size_t PendPDTUpdateIndex = 0;
-  DomTreeT *DT = nullptr;
-  PostDomTreeT *PDT = nullptr;
-  const UpdateStrategy Strategy;
-  SmallPtrSet<BasicBlockT *, 8> DeletedBBs;
-  bool IsRecalculatingDomTree = false;
-  bool IsRecalculatingPostDomTree = false;
-
-  /// Returns true if the update is self dominance.
-  bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
-    // Won't affect DomTree and PostDomTree.
-    return Update.getFrom() == Update.getTo();
-  }
-
-  /// Helper function to apply all pending DomTree updates.
-  void applyDomTreeUpdates() {
-    // No pending DomTreeUpdates.
-    if (Strategy != UpdateStrategy::Lazy || !DT)
-      return;
-
-    // Only apply updates not are applied by DomTree.
-    if (hasPendingDomTreeUpdates()) {
-      const auto I = PendUpdates.begin() + PendDTUpdateIndex;
-      const auto E = PendUpdates.end();
-      assert(I < E &&
-             "Iterator range invalid; there should be DomTree updates.");
-      DT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
-      PendDTUpdateIndex = PendUpdates.size();
-    }
-  }
-
-  /// Helper function to apply all pending PostDomTree updates.
-  void applyPostDomTreeUpdates() {
-    // No pending PostDomTreeUpdates.
-    if (Strategy != UpdateStrategy::Lazy || !PDT)
-      return;
-
-    // Only apply updates not are applied by PostDomTree.
-    if (hasPendingPostDomTreeUpdates()) {
-      const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
-      const auto E = PendUpdates.end();
-      assert(I < E &&
-             "Iterator range invalid; there should be PostDomTree updates.");
-      PDT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E));
-      PendPDTUpdateIndex = PendUpdates.size();
-    }
-  }
-
-  /// Returns true if the update appears in the LLVM IR.
-  /// It is used to check whether an update is valid in
-  /// insertEdge/deleteEdge or is unnecessary in the batch update.
-  bool isUpdateValid(typename DomTreeT::UpdateType Update) const {
-    const auto *From = Update.getFrom();
-    const auto *To = Update.getTo();
-    const auto Kind = Update.getKind();
-
-    // Discard updates by inspecting the current state of successors of From.
-    // Since isUpdateValid() must be called *after* the Terminator of From is
-    // altered we can determine if the update is unnecessary for batch updates
-    // or invalid for a single update.
-    const bool HasEdge = llvm::is_contained(successors(From), To);
-
-    // If the IR does not match the update,
-    // 1. In batch updates, this update is unnecessary.
-    // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
-    // Edge does not exist in IR.
-    if (Kind == DomTreeT::Insert && !HasEdge)
-      return false;
-
-    // Edge exists in IR.
-    if (Kind == DomTreeT::Delete && HasEdge)
-      return false;
-
-    return true;
-  }
-
-  /// Erase Basic Block node that has been unlinked from Function
-  /// in the DomTree and PostDomTree.
-  void eraseDelBBNode(BasicBlockT *DelBB) {
-    if (DT && !IsRecalculatingDomTree)
-      if (DT->getNode(DelBB))
-        DT->eraseNode(DelBB);
-
-    if (PDT && !IsRecalculatingPostDomTree)
-      if (PDT->getNode(DelBB))
-        PDT->eraseNode(DelBB);
-  }
-
-  /// Helper function to flush deleted BasicBlocks if all available
-  /// trees are up-to-date.
-  void tryFlushDeletedBB() {
-    if (!hasPendingUpdates())
-      derived().forceFlushDeletedBB();
-  }
-
-  /// Drop all updates applied by all available trees and delete BasicBlocks if
-  /// all available trees are up-to-date.
-  void dropOutOfDateUpdates() {
-    if (Strategy == UpdateStrategy::Eager)
-      return;
-
-    tryFlushDeletedBB();
-
-    // Drop all updates applied by both trees.
-    if (!DT)
-      PendDTUpdateIndex = PendUpdates.size();
-    if (!PDT)
-      PendPDTUpdateIndex = PendUpdates.size();
-
-    const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
-    const auto B = PendUpdates.begin();
-    const auto E = PendUpdates.begin() + dropIndex;
-    assert(B <= E && "Iterator out of range.");
-    PendUpdates.erase(B, E);
-    // Calculate current index.
-    PendDTUpdateIndex -= dropIndex;
-    PendPDTUpdateIndex -= dropIndex;
-  }
-};
-
-} // namespace llvm
-
-#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
index e4919ecabd705..5b6be3a96b2fb 100644
--- a/llvm/include/llvm/CodeGen/MachineBasicBlock.h
+++ b/llvm/include/llvm/CodeGen/MachineBasicBlock.h
@@ -238,9 +238,6 @@ class MachineBasicBlock
     BB = nullptr;
   }
 
-  /// Check if there is a name of corresponding LLVM basic block.
-  bool hasName() const;
-
   /// Return the name of the corresponding LLVM basic block, or an empty string.
   StringRef getName() const;
 
diff --git a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
deleted file mode 100644
index 8bc572e6e6af0..0000000000000
--- a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//===- llvm/CodeGen/MachineDomTreeUpdater.h -----------------------*- C++
-//-*-==//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file exposes interfaces to post dominance information for
-// target-specific code.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
-#define LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
-
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Analysis/GenericDomTreeUpdater.h"
-#include "llvm/CodeGen/MachineDominators.h"
-#include "llvm/CodeGen/MachinePostDominators.h"
-#include "llvm/IR/ValueHandle.h"
-#include "llvm/Support/Compiler.h"
-#include <cstddef>
-#include <functional>
-#include <vector>
-
-namespace llvm {
-
-class MachineDomTreeUpdater
-    : public GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
-                                   MachinePostDominatorTree> {
-  friend GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
-                               MachinePostDominatorTree>;
-
-public:
-  using Base =
-      GenericDomTreeUpdater<MachineDomTreeUpdater, MachineDominatorTree,
-                            MachinePostDominatorTree>;
-  using Base::Base;
-
-  ///@{
-  /// \name Mutation APIs
-  ///
-
-  /// Delete DelBB. DelBB will be removed from its Parent and
-  /// erased from available trees if it exists and finally get deleted.
-  /// Under Eager UpdateStrategy, DelBB will be processed immediately.
-  /// Under Lazy UpdateStrategy, DelBB will be queued until a flush event and
-  /// all available trees are up-to-date. Assert if any instruction of DelBB is
-  /// modified while awaiting deletion. When both DT and PDT are nullptrs, DelBB
-  /// will be queued until flush() is called.
-  void deleteBB(MachineBasicBlock *DelBB);
-
-  ///@}
-
-private:
-  /// First remove all the instructions of DelBB and then make sure DelBB has a
-  /// valid terminator instruction which is necessary to have when DelBB still
-  /// has to be inside of its parent Function while awaiting deletion under Lazy
-  /// UpdateStrategy to prevent other routines from asserting the state of the
-  /// IR is inconsistent. Assert if DelBB is nullptr or has predecessors.
-  void validateDeleteBB(MachineBasicBlock *DelBB);
-
-  /// Returns true if at least one MachineBasicBlock is deleted.
-  bool forceFlushDeletedBB();
-};
-
-extern template class GenericDomTreeUpdater<
-    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
-} // namespace llvm
-#endif // LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H
diff --git a/llvm/include/llvm/CodeGen/MachinePostDominators.h b/llvm/include/llvm/CodeGen/MachinePostDominators.h
index 58cfb278b7962..904c5fcdfc68b 100644
--- a/llvm/include/llvm/CodeGen/MachinePostDominators.h
+++ b/llvm/include/llvm/CodeGen/MachinePostDominators.h
@@ -48,7 +48,6 @@ class MachinePostDominatorTree : public PostDomTreeBase<MachineBasicBlock> {
 
 public:
   MachinePostDominatorTree() = default;
-  explicit MachinePostDominatorTree(MachineFunction &MF) { recalculate(MF); }
 
   MachinePostDominatorTree(MachineFunction &MF) { recalculate(MF); }
 
diff --git a/llvm/lib/Analysis/DomTreeUpdater.cpp b/llvm/lib/Analysis/DomTreeUpdater.cpp
index 676cb87210176..0a16fc9a76d29 100644
--- a/llvm/lib/Analysis/DomTreeUpdater.cpp
+++ b/llvm/lib/Analysis/DomTreeUpdater.cpp
@@ -23,8 +23,79 @@
 
 namespace llvm {
 
-template class GenericDomTreeUpdater<DomTreeUpdater, DominatorTree,
-                                     PostDominatorTree>;
+bool DomTreeUpdater::isUpdateValid(
+    const DominatorTree::UpdateType Update) const {
+  const auto *From = Update.getFrom();
+  const auto *To = Update.getTo();
+  const auto Kind = Update.getKind();
+
+  // Discard updates by inspecting the current state of successors of From.
+  // Since isUpdateValid() must be called *after* the Terminator of From is
+  // altered we can determine if the update is unnecessary for batch updates
+  // or invalid for a single update.
+  const bool HasEdge = llvm::is_contained(successors(From), To);
+
+  // If the IR does not match the update,
+  // 1. In batch updates, this update is unnecessary.
+  // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
+  // Edge does not exist in IR.
+  if (Kind == DominatorTree::Insert && !HasEdge)
+    return false;
+
+  // Edge exists in IR.
+  if (Kind == DominatorTree::Delete && HasEdge)
+    return false;
+
+  return true;
+}
+
+bool DomTreeUpdater::isSelfDominance(
+    const DominatorTree::UpdateType Update) const {
+  // Won't affect DomTree and PostDomTree.
+  return Update.getFrom() == Update.getTo();
+}
+
+void DomTreeUpdater::applyDomTreeUpdates() {
+  // No pending DomTreeUpdates.
+  if (Strategy != UpdateStrategy::Lazy || !DT)
+    return;
+
+  // Only apply updates not are applied by DomTree.
+  if (hasPendingDomTreeUpdates()) {
+    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    const auto E = PendUpdates.end();
+    assert(I < E && "Iterator range invalid; there should be DomTree updates.");
+    DT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
+    PendDTUpdateIndex = PendUpdates.size();
+  }
+}
+
+void DomTreeUpdater::flush() {
+  applyDomTreeUpdates();
+  applyPostDomTreeUpdates();
+  dropOutOfDateUpdates();
+}
+
+void DomTreeUpdater::applyPostDomTreeUpdates() {
+  // No pending PostDomTreeUpdates.
+  if (Strategy != UpdateStrategy::Lazy || !PDT)
+    return;
+
+  // Only apply updates not are applied by PostDomTree.
+  if (hasPendingPostDomTreeUpdates()) {
+    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    const auto E = PendUpdates.end();
+    assert(I < E &&
+           "Iterator range invalid; there should be PostDomTree updates.");
+    PDT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
+    PendPDTUpdateIndex = PendUpdates.size();
+  }
+}
+
+void DomTreeUpdater::tryFlushDeletedBB() {
+  if (!hasPendingUpdates())
+    forceFlushDeletedBB();
+}
 
 bool DomTreeUpdater::forceFlushDeletedBB() {
   if (DeletedBBs.empty())
@@ -46,6 +117,58 @@ bool DomTreeUpdater::forceFlushDeletedBB() {
   return true;
 }
 
+void DomTreeUpdater::recalculate(Function &F) {
+
+  if (Strategy == UpdateStrategy::Eager) {
+    if (DT)
+      DT->recalculate(F);
+    if (PDT)
+      PDT->recalculate(F);
+    return;
+  }
+
+  // There is little performance gain if we pend the recalculation under
+  // Lazy UpdateStrategy so we recalculate available trees immediately.
+
+  // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
+  IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
+
+  // Because all trees are going to be up-to-date after recalculation,
+  // flush awaiting deleted BasicBlocks.
+  forceFlushDeletedBB();
+  if (DT)
+    DT->recalculate(F);
+  if (PDT)
+    PDT->recalculate(F);
+
+  // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
+  IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
+  PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
+  dropOutOfDateUpdates();
+}
+
+bool DomTreeUpdater::hasPendingUpdates() const {
+  return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
+}
+
+bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
+  if (!DT)
+    return false;
+  return PendUpdates.size() != PendDTUpdateIndex;
+}
+
+bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
+  if (!PDT)
+    return false;
+  return PendUpdates.size() != PendPDTUpdateIndex;
+}
+
+bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
+  if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
+    return false;
+  return DeletedBBs.contains(DelBB);
+}
+
 // The DT and PDT require the nodes related to updates
 // are not deleted when update functions are called.
 // So BasicBlock deletions must be pended when the
@@ -78,6 +201,16 @@ void DomTreeUpdater::callbackDeleteBB(
   delete DelBB;
 }
 
+void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
+  if (DT && !IsRecalculatingDomTree)
+    if (DT->getNode(DelBB))
+      DT->eraseNode(DelBB);
+
+  if (PDT && !IsRecalculatingPostDomTree)
+    if (PDT->getNode(DelBB))
+      PDT->eraseNode(DelBB);
+}
+
 void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   assert(DelBB && "Invalid push_back of nullptr DelBB.");
   assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
@@ -94,4 +227,215 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
   new UnreachableInst(DelBB->getContext(), DelBB);
 }
 
+void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) {
+  if (!DT && !PDT)
+    return;
+
+  if (Strategy == UpdateStrategy::Lazy) {
+    PendUpdates.reserve(PendUpdates.size() + Updates.size());
+    for (const auto &U : Updates)
+      if (!isSelfDominance(U))
+        PendUpdates.push_back(U);
+
+    return;
+  }
+
+  if (DT)
+    DT->applyUpdates(Updates);
+  if (PDT)
+    PDT->applyUpdates(Updates);
+}
+
+void DomTreeUpdater::applyUpdatesPermissive(
+    ArrayRef<DominatorTree::UpdateType> Updates) {
+  if (!DT && !PDT)
+    return;
+
+  SmallSet<std::pair<BasicBlock *, BasicBlock *>, 8> Seen;
+  SmallVector<DominatorTree::UpdateType, 8> DeduplicatedUpdates;
+  for (const auto &U : Updates) {
+    auto Edge = std::make_pair(U.getFrom(), U.getTo());
+    // Because it is illegal to submit updates that have already been applied
+    // and updates to an edge need to be strictly ordered,
+    // it is safe to infer the existence of an edge from the first update
+    // to this edge.
+    // If the first update to an edge is "Delete", it means that the edge
+    // existed before. If the first update to an edge is "Insert", it means
+    // that the edge didn't exist before.
+    //
+    // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
+    // because
+    // 1. it is illegal to submit updates that have already been applied,
+    // i.e., user cannot delete an nonexistent edge,
+    // 2. updates to an edge need to be strictly ordered,
+    // So, initially edge A -> B existed.
+    // We can then safely ignore future updates to this edge and directly
+    // inspect the current CFG:
+    // a. If the edge still exists, because the user cannot insert an existent
+    // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
+    // resulted in a no-op. DTU won't submit any update in this case.
+    // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
+    // actually happened but {Insert, A, B} was an invalid update which never
+    // happened. DTU will submit {Delete, A, B} in this case.
+    if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
+      Seen.insert(Edge);
+      // If the update doesn't appear in the CFG, it means that
+      // either the change isn't made or relevant operations
+      // result in a no-op.
+      if (isUpdateValid(U)) {
+        if (isLazy())
+          PendUpdates.push_back(U);
+        else
+          DeduplicatedUpdates.push_back(U);
+      }
+    }
+  }
+
+  if (Strategy == UpdateStrategy::Lazy)
+    return;
+
+  if (DT)
+    DT->applyUpdates(DeduplicatedUpdates);
+  if (PDT)
+    PDT->applyUpdates(DeduplicatedUpdates);
+}
+
+DominatorTree &DomTreeUpdater::getDomTree() {
+  assert(DT && "Invalid acquisition of a null DomTree");
+  applyDomTreeUpdates();
+  dropOutOfDateUpdates();
+  return *DT;
+}
+
+PostDominatorTree &DomTreeUpdater::getPostDomTree() {
+  assert(PDT && "Invalid acquisition of a null PostDomTree");
+  applyPostDomTreeUpdates();
+  dropOutOfDateUpdates();
+  return *PDT;
+}
+
+void DomTreeUpdater::dropOutOfDateUpdates() {
+  if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
+    return;
+
+  tryFlushDeletedBB();
+
+  // Drop all updates applied by both trees.
+  if (!DT)
+    PendDTUpdateIndex = PendUpdates.size();
+  if (!PDT)
+    PendPDTUpdateIndex = PendUpdates.size();
+
+  const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
+  const auto B = PendUpdates.begin();
+  const auto E = PendUpdates.begin() + dropIndex;
+  assert(B <= E && "Iterator out of range.");
+  PendUpdates.erase(B, E);
+  // Calculate current index.
+  PendDTUpdateIndex -= dropIndex;
+  PendPDTUpdateIndex -= dropIndex;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
+  raw_ostream &OS = llvm::dbgs();
+
+  OS << "Available Trees: ";
+  if (DT || PDT) {
+    if (DT)
+      OS << "DomTree ";
+    if (PDT)
+      OS << "PostDomTree ";
+    OS << "\n";
+  } else
+    OS << "None\n";
+
+  OS << "UpdateStrategy: ";
+  if (Strategy == UpdateStrategy::Eager) {
+    OS << "Eager\n";
+    return;
+  } else
+    OS << "Lazy\n";
+  int Index = 0;
+
+  auto printUpdates =
+      [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
+          ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
+        if (begin == end)
+          OS << "  None\n";
+        Index = 0;
+        for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
+          auto U = *It;
+          OS << "  " << Index << " : ";
+          ++Index;
+          if (U.getKind() == DominatorTree::Insert)
+            OS << "Insert, ";
+          else
+            OS << "Delete, ";
+          BasicBlock *From = U.getFrom();
+          if (From) {
+            auto S = From->getName();
+            if (!From->hasName())
+              S = "(no name)";
+            OS << S << "(" << From << "), ";
+          } else {
+            OS << "(badref), ";
+          }
+          BasicBlock *To = U.getTo();
+          if (To) {
+            auto S = To->getName();
+            if (!To->hasName())
+              S = "(no_name)";
+            OS << S << "(" << To << ")\n";
+          } else {
+            OS << "(badref)\n";
+          }
+        }
+      };
+
+  if (DT) {
+    const auto I = PendUpdates.begin() + PendDTUpdateIndex;
+    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+           "Iterator out of range.");
+    OS << "Applied but not cleared DomTreeUpdates:\n";
+    printUpdates(PendUpdates.begin(), I);
+    OS << "Pending DomTreeUpdates:\n";
+    printUpdates(I, PendUpdates.end());
+  }
+
+  if (PDT) {
+    const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
+    assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
+           "Iterator out of range.");
+    OS << "Applied but not cleared PostDomTreeUpdates:\n";
+    printUpdates(PendUpdates.begin(), I);
+    OS << "Pending PostDomTreeUpdates:\n";
+    printUpdates(I, PendUpdates.end());
+  }
+
+  OS << "Pending DeletedBBs:\n";
+  Index = 0;
+  for (const auto *BB : DeletedBBs) {
+    OS << "  " << Index << " : ";
+    ++Index;
+    if (BB->hasName())
+      OS << BB->getName() << "(";
+    else
+      OS << "(no_name)(";
+    OS << BB << ")\n";
+  }
+
+  OS << "Pending Callbacks:\n";
+  Index = 0;
+  for (const auto &BB : Callbacks) {
+    OS << "  " << Index << " : ";
+    ++Index;
+    if (BB->hasName())
+      OS << BB->getName() << "(";
+    else
+      OS << "(no_name)(";
+    OS << BB << ")\n";
+  }
+}
+#endif
 } // namespace llvm
diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt
index f1607f85c5b31..41fc555c93e93 100644
--- a/llvm/lib/CodeGen/CMakeLists.txt
+++ b/llvm/lib/CodeGen/CMakeLists.txt
@@ -116,7 +116,6 @@ add_llvm_component_library(LLVMCodeGen
   MachineCheckDebugify.cpp
   MachineCycleAnalysis.cpp
   MachineDebugify.cpp
-  MachineDomTreeUpdater.cpp
   MachineDominanceFrontier.cpp
   MachineDominators.cpp
   MachineFrameInfo.cpp
diff --git a/llvm/lib/CodeGen/MachineBasicBlock.cpp b/llvm/lib/CodeGen/MachineBasicBlock.cpp
index 533ab7cccaeb7..abf43e39ee9a6 100644
--- a/llvm/lib/CodeGen/MachineBasicBlock.cpp
+++ b/llvm/lib/CodeGen/MachineBasicBlock.cpp
@@ -315,12 +315,6 @@ bool MachineBasicBlock::isLegalToHoistInto() const {
   return true;
 }
 
-bool MachineBasicBlock::hasName() const {
-  if (const BasicBlock *LBB = getBasicBlock())
-    return LBB->hasName();
-  return false;
-}
-
 StringRef MachineBasicBlock::getName() const {
   if (const BasicBlock *LBB = getBasicBlock())
     return LBB->getName();
diff --git a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
deleted file mode 100644
index 86b3185ca90a3..0000000000000
--- a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-//===- MachineDomTreeUpdater.cpp -----------------------------------------===//
-//
-// 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 implements the MachineDomTreeUpdater class, which provides a
-// uniform way to update dominator tree related data structures.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/CodeGen/MachineDomTreeUpdater.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/CodeGen/MachinePostDominators.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/Support/GenericDomTree.h"
-#include <algorithm>
-#include <functional>
-#include <utility>
-
-namespace llvm {
-
-template class GenericDomTreeUpdater<
-    MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>;
-
-bool MachineDomTreeUpdater::forceFlushDeletedBB() {
-  if (DeletedBBs.empty())
-    return false;
-
-  for (auto *BB : DeletedBBs) {
-    eraseDelBBNode(BB);
-    BB->eraseFromParent();
-  }
-  DeletedBBs.clear();
-  return true;
-}
-
-// The DT and PDT require the nodes related to updates
-// are not deleted when update functions are called.
-// So MachineBasicBlock deletions must be pended when the
-// UpdateStrategy is Lazy. When the UpdateStrategy is
-// Eager, the MachineBasicBlock will be deleted immediately.
-void MachineDomTreeUpdater::deleteBB(MachineBasicBlock *DelBB) {
-  validateDeleteBB(DelBB);
-  if (Strategy == UpdateStrategy::Lazy) {
-    DeletedBBs.insert(DelBB);
-    return;
-  }
-
-  eraseDelBBNode(DelBB);
-  DelBB->eraseFromParent();
-}
-
-void MachineDomTreeUpdater::validateDeleteBB(MachineBasicBlock *DelBB) {
-  assert(DelBB && "Invalid push_back of nullptr DelBB.");
-  assert(DelBB->pred_empty() && "DelBB has one or more predecessors.");
-}
-
-} // namespace llvm
diff --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 963cdcc0275e1..dbbacdd95ec9f 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -32,7 +32,6 @@ add_llvm_unittest(CodeGenTests
   LowLevelTypeTest.cpp
   LexicalScopesTest.cpp
   MachineBasicBlockTest.cpp
-  MachineDomTreeUpdaterTest.cpp
   MachineInstrBundleIteratorTest.cpp
   MachineInstrTest.cpp
   MachineOperandTest.cpp
diff --git a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp b/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
deleted file mode 100644
index e123ba847e622..0000000000000
--- a/llvm/unittests/CodeGen/MachineDomTreeUpdaterTest.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-//===- MachineDomTreeUpdaterTest.cpp - MachineDomTreeUpdater unit tests ---===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/CodeGen/MachineDomTreeUpdater.h"
-#include "llvm/Analysis/CGSCCPassManager.h"
-#include "llvm/Analysis/LoopAnalysisManager.h"
-#include "llvm/CodeGen/MIRParser/MIRParser.h"
-#include "llvm/CodeGen/MachineFunctionAnalysis.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/CodeGen/MachinePassManager.h"
-#include "llvm/CodeGen/MachinePostDominators.h"
-#include "llvm/CodeGen/SelectionDAG.h"
-#include "llvm/CodeGen/TargetLowering.h"
-#include "llvm/MC/TargetRegistry.h"
-#include "llvm/Passes/PassBuilder.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetSelect.h"
-#include "llvm/Target/TargetMachine.h"
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-class MachineDomTreeUpdaterTest : public testing::Test {
-public:
-  LLVMContext Context;
-  std::unique_ptr<TargetMachine> TM;
-  std::unique_ptr<Module> M;
-  std::unique_ptr<MachineModuleInfo> MMI;
-  std::unique_ptr<MIRParser> MIR;
-
-  LoopAnalysisManager LAM;
-  MachineFunctionAnalysisManager MFAM;
-  FunctionAnalysisManager FAM;
-  CGSCCAnalysisManager CGAM;
-  ModuleAnalysisManager MAM;
-
-  ModulePassManager MPM;
-  FunctionPassManager FPM;
-  MachineFunctionPassManager MFPM;
-
-  static void SetUpTestCase() {
-    InitializeAllTargets();
-    InitializeAllTargetMCs();
-  }
-
-  void SetUp() override {
-    Triple TargetTriple("x86_64-unknown-linux-gnu");
-    std::string Error;
-    const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
-    if (!T)
-      GTEST_SKIP();
-    TargetOptions Options;
-    TM = std::unique_ptr<TargetMachine>(
-        T->createTargetMachine("X86", "", "", Options, std::nullopt));
-    if (!TM)
-      GTEST_SKIP();
-    MMI = std::make_unique<MachineModuleInfo>(
-        static_cast<LLVMTargetMachine *>(TM.get()));
-
-    PassBuilder PB(TM.get());
-    PB.registerModuleAnalyses(MAM);
-    PB.registerCGSCCAnalyses(CGAM);
-    PB.registerFunctionAnalyses(FAM);
-    PB.registerLoopAnalyses(LAM);
-    PB.registerMachineFunctionAnalyses(MFAM);
-    PB.crossRegisterProxies(LAM, FAM, CGAM, MAM, &MFAM);
-    MAM.registerPass([&] { return MachineModuleAnalysis(*MMI); });
-  }
-
-  bool parseMIR(StringRef MIRCode, const char *FnName) {
-    SMDiagnostic Diagnostic;
-    std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
-    MIR = createMIRParser(std::move(MBuffer), Context);
-    if (!MIR)
-      return false;
-
-    M = MIR->parseIRModule();
-    M->setDataLayout(TM->createDataLayout());
-
-    if (MIR->parseMachineFunctions(*M, MAM)) {
-      M.reset();
-      return false;
-    }
-
-    return true;
-  }
-};
-
-TEST_F(MachineDomTreeUpdaterTest, EagerUpdateBasicOperations) {
-  StringRef MIRString = R"(
---- |
-  define i64 @f0(i64 %i, ptr %p) {
-  bb0:
-    store i64 %i, ptr %p, align 4
-    switch i64 %i, label %bb1 [
-      i64 1, label %bb2
-      i64 2, label %bb3
-    ]
-  bb1:                                              ; preds = %bb0
-    ret i64 1
-  bb2:                                              ; preds = %bb0
-    ret i64 2
-  bb3:                                              ; preds = %bb0
-    ret i64 3
-  }
-...
----
-name:            f0
-body:             |
-  bb.0.bb0:
-    successors: %bb.2, %bb.4
-    liveins: $rdi, $rsi
-
-    %1:gr32 = COPY $rsi
-    %0:gr64 = COPY $rdi
-    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
-    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
-    JCC_1 %bb.2, 4, implicit $eflags
-    JMP_1 %bb.4
-
-  bb.4.bb0:
-    successors: %bb.3, %bb.1
-
-    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
-    JCC_1 %bb.3, 4, implicit $eflags
-    JMP_1 %bb.1
-
-  bb.1.bb1:
-    %6:gr64 = MOV32ri64 1
-    $rax = COPY %6
-    RET 0, $rax
-
-  bb.2.bb2:
-    %5:gr64 = MOV32ri64 2
-    $rax = COPY %5
-    RET 0, $rax
-
-  bb.3.bb3:
-    %4:gr64 = MOV32ri64 3
-    $rax = COPY %4
-    RET 0, $rax
-
-...
-)";
-
-  ASSERT_TRUE(parseMIR(MIRString, "f0"));
-
-  auto &MF =
-      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
-
-  MachineDominatorTree DT(MF);
-  MachinePostDominatorTree PDT(MF);
-  MachineDomTreeUpdater DTU(DT, PDT,
-                            MachineDomTreeUpdater::UpdateStrategy::Eager);
-
-  ASSERT_TRUE(DTU.hasDomTree());
-  ASSERT_TRUE(DTU.hasPostDomTree());
-  ASSERT_TRUE(DTU.isEager());
-  ASSERT_FALSE(DTU.isLazy());
-  ASSERT_TRUE(DTU.getDomTree().verify());
-  ASSERT_TRUE(DTU.getPostDomTree().verify());
-  ASSERT_FALSE(DTU.hasPendingUpdates());
-
-  auto B = MF.begin();
-  [[maybe_unused]] auto BB0 = B;
-  auto BB1 = ++B;
-  auto BB2 = ++B;
-  [[maybe_unused]] auto BB3 = ++B;
-  auto BB4 = ++B;
-  EXPECT_EQ(BB1->succ_size(), 2u);
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
-  BB1->removeSuccessor(&*BB4);
-  DTU.deleteBB(&*BB4);
-  EXPECT_EQ(BB1->succ_size(), 1u);
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
-}
-
-TEST_F(MachineDomTreeUpdaterTest, LazyUpdateBasicOperations) {
-  StringRef MIRString = R"(
---- |
-  define i64 @f0(i64 %i, ptr %p) {
-  bb0:
-    store i64 %i, ptr %p, align 4
-    switch i64 %i, label %bb1 [
-      i64 1, label %bb2
-      i64 2, label %bb3
-    ]
-  bb1:                                              ; preds = %bb0
-    ret i64 1
-  bb2:                                              ; preds = %bb0
-    ret i64 2
-  bb3:                                              ; preds = %bb0
-    ret i64 3
-  }
-...
----
-name:            f0
-body:             |
-  bb.0.bb0:
-    successors: %bb.2, %bb.4
-    liveins: $rdi, $rsi
-
-    %1:gr32 = COPY $rsi
-    %0:gr64 = COPY $rdi
-    MOV64mr %1, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.p)
-    %2:gr64 = SUB64ri32 %0, 1, implicit-def $eflags
-    JCC_1 %bb.2, 4, implicit $eflags
-    JMP_1 %bb.4
-
-  bb.4.bb0:
-    successors: %bb.3, %bb.1
-
-    %3:gr64 = SUB64ri32 %0, 2, implicit-def $eflags
-    JCC_1 %bb.3, 4, implicit $eflags
-    JMP_1 %bb.1
-
-  bb.1.bb1:
-    %6:gr64 = MOV32ri64 1
-    $rax = COPY %6
-    RET 0, $rax
-
-  bb.2.bb2:
-    %5:gr64 = MOV32ri64 2
-    $rax = COPY %5
-    RET 0, $rax
-
-  bb.3.bb3:
-    %4:gr64 = MOV32ri64 3
-    $rax = COPY %4
-    RET 0, $rax
-
-...
-)";
-
-  ASSERT_TRUE(parseMIR(MIRString, "f0"));
-
-  auto &MF =
-      FAM.getResult<MachineFunctionAnalysis>(*M->getFunction("f0")).getMF();
-
-  MachineDominatorTree DT(MF);
-  MachinePostDominatorTree PDT(MF);
-  MachineDomTreeUpdater DTU(DT, PDT,
-                            MachineDomTreeUpdater::UpdateStrategy::Lazy);
-
-  ASSERT_TRUE(DTU.hasDomTree());
-  ASSERT_TRUE(DTU.hasPostDomTree());
-  ASSERT_FALSE(DTU.isEager());
-  ASSERT_TRUE(DTU.isLazy());
-  ASSERT_TRUE(DTU.getDomTree().verify());
-  ASSERT_TRUE(DTU.getPostDomTree().verify());
-  ASSERT_FALSE(DTU.hasPendingUpdates());
-
-  auto B = MF.begin();
-  [[maybe_unused]] auto BB0 = B;
-  auto BB1 = ++B;
-  auto BB2 = ++B;
-  [[maybe_unused]] auto BB3 = ++B;
-  auto BB4 = ++B;
-  EXPECT_EQ(BB1->succ_size(), 2u);
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB4));
-  BB1->removeSuccessor(&*BB4);
-  DTU.deleteBB(&*BB4);
-  EXPECT_EQ(BB1->succ_size(), 1u);
-  ASSERT_TRUE(DT.dominates(&*BB1, &*BB2));
-  ASSERT_NE(DT.getNode(&*BB4), nullptr);
-  DTU.flush();
-  ASSERT_EQ(DT.getNode(&*BB4), nullptr);
-}

>From 7df0ca2bb23a228a05a670e78ef540d0fbfa5508 Mon Sep 17 00:00:00 2001
From: paperchalice <liujunchang97 at outlook.com>
Date: Thu, 27 Jun 2024 14:04:51 +0800
Subject: [PATCH 16/19] [CodeGen][NewPM] Port machine-branch-prob to new pass
 manager (#96389)

Like IR version `print<branch-prob>`, there is also a
`print<machine-branch-prob>`.
---
 .../CodeGen/MachineBranchProbabilityInfo.h    | 53 +++++++++++++++----
 llvm/include/llvm/InitializePasses.h          |  2 +-
 .../llvm/Passes/MachinePassRegistry.def       |  4 ++
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  7 +--
 llvm/lib/CodeGen/BranchFolding.cpp            |  9 ++--
 llvm/lib/CodeGen/EarlyIfConversion.cpp        | 10 ++--
 llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 10 ++--
 llvm/lib/CodeGen/IfConversion.cpp             |  6 +--
 .../CodeGen/LazyMachineBlockFrequencyInfo.cpp |  6 +--
 .../lib/CodeGen/MachineBlockFrequencyInfo.cpp |  6 +--
 llvm/lib/CodeGen/MachineBlockPlacement.cpp    | 12 ++---
 .../CodeGen/MachineBranchProbabilityInfo.cpp  | 44 ++++++++++++---
 llvm/lib/CodeGen/MachineSink.cpp              |  6 +--
 llvm/lib/CodeGen/MachineTraceMetrics.cpp      |  4 +-
 llvm/lib/CodeGen/TailDuplication.cpp          |  4 +-
 llvm/lib/Passes/PassBuilder.cpp               |  1 +
 .../AArch64/AArch64ConditionalCompares.cpp    |  6 +--
 .../lib/Target/Hexagon/HexagonEarlyIfConv.cpp |  7 +--
 llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp  |  4 +-
 .../Target/Hexagon/HexagonNewValueJump.cpp    |  6 +--
 .../Target/Hexagon/HexagonVLIWPacketizer.cpp  |  7 +--
 llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp  |  4 +-
 .../Target/PowerPC/PPCReduceCRLogicals.cpp    |  4 +-
 .../test/CodeGen/Generic/MachineBranchProb.ll |  5 ++
 24 files changed, 154 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h b/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
index bd544421bc0ff..12d33f96edd11 100644
--- a/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
@@ -14,14 +14,13 @@
 #define LLVM_CODEGEN_MACHINEBRANCHPROBABILITYINFO_H
 
 #include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/BranchProbability.h"
 
 namespace llvm {
 
-class MachineBranchProbabilityInfo : public ImmutablePass {
-  virtual void anchor();
-
+class MachineBranchProbabilityInfo {
   // Default weight value. Used when we don't have information about the edge.
   // TODO: DEFAULT_WEIGHT makes sense during static predication, when none of
   // the successors have a weight yet. But it doesn't make sense when providing
@@ -31,13 +30,8 @@ class MachineBranchProbabilityInfo : public ImmutablePass {
   static const uint32_t DEFAULT_WEIGHT = 16;
 
 public:
-  static char ID;
-
-  MachineBranchProbabilityInfo();
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.setPreservesAll();
-  }
+  bool invalidate(MachineFunction &, const PreservedAnalyses &PA,
+                  MachineFunctionAnalysisManager::Invalidator &);
 
   // Return edge probability.
   BranchProbability getEdgeProbability(const MachineBasicBlock *Src,
@@ -61,6 +55,45 @@ class MachineBranchProbabilityInfo : public ImmutablePass {
                                     const MachineBasicBlock *Dst) const;
 };
 
+class MachineBranchProbabilityAnalysis
+    : public AnalysisInfoMixin<MachineBranchProbabilityAnalysis> {
+  friend AnalysisInfoMixin<MachineBranchProbabilityAnalysis>;
+
+  static AnalysisKey Key;
+
+public:
+  using Result = MachineBranchProbabilityInfo;
+
+  Result run(MachineFunction &, MachineFunctionAnalysisManager &);
+};
+
+class MachineBranchProbabilityPrinterPass
+    : public PassInfoMixin<MachineBranchProbabilityPrinterPass> {
+  raw_ostream &OS;
+
+public:
+  MachineBranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {}
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
+class MachineBranchProbabilityInfoWrapperPass : public ImmutablePass {
+  virtual void anchor();
+
+  MachineBranchProbabilityInfo MBPI;
+
+public:
+  static char ID;
+
+  MachineBranchProbabilityInfoWrapperPass();
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+  }
+
+  MachineBranchProbabilityInfo &getMBPI() { return MBPI; }
+  const MachineBranchProbabilityInfo &getMBPI() const { return MBPI; }
+};
 }
 
 
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 4ddb7112a47bb..421c09ada7a19 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -182,7 +182,7 @@ void initializeMIRPrintingPassPass(PassRegistry&);
 void initializeMachineBlockFrequencyInfoPass(PassRegistry&);
 void initializeMachineBlockPlacementPass(PassRegistry&);
 void initializeMachineBlockPlacementStatsPass(PassRegistry&);
-void initializeMachineBranchProbabilityInfoPass(PassRegistry&);
+void initializeMachineBranchProbabilityInfoWrapperPassPass(PassRegistry &);
 void initializeMachineCFGPrinterPass(PassRegistry &);
 void initializeMachineCSEPass(PassRegistry&);
 void initializeMachineCombinerPass(PassRegistry&);
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index b43f41bb3097e..b1542ab139286 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -89,6 +89,8 @@ LOOP_PASS("loop-reduce", LoopStrengthReducePass())
 #ifndef MACHINE_FUNCTION_ANALYSIS
 #define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS)
 #endif
+MACHINE_FUNCTION_ANALYSIS("machine-branch-prob",
+                          MachineBranchProbabilityAnalysis())
 MACHINE_FUNCTION_ANALYSIS("machine-dom-tree", MachineDominatorTreeAnalysis())
 MACHINE_FUNCTION_ANALYSIS("machine-post-dom-tree",
                           MachinePostDominatorTreeAnalysis())
@@ -130,6 +132,8 @@ MACHINE_FUNCTION_PASS("finalize-isel", FinalizeISelPass())
 MACHINE_FUNCTION_PASS("localstackalloc", LocalStackSlotAllocationPass())
 MACHINE_FUNCTION_PASS("no-op-machine-function", NoOpMachineFunctionPass())
 MACHINE_FUNCTION_PASS("print", PrintMIRPass())
+MACHINE_FUNCTION_PASS("print<machine-branch-prob>",
+                      MachineBranchProbabilityPrinterPass(dbgs()))
 MACHINE_FUNCTION_PASS("print<machine-dom-tree>",
                       MachineDominatorTreePrinterPass(dbgs()))
 MACHINE_FUNCTION_PASS("print<machine-post-dom-tree>",
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 40f4dc2689cdf..505bd8acaf0ca 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -444,7 +444,7 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<MachineOptimizationRemarkEmitterPass>();
   AU.addRequired<GCModuleInfo>();
   AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
 }
 
 bool AsmPrinter::doInitialization(Module &M) {
@@ -1478,8 +1478,9 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
             ? &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI()
             : nullptr;
     const MachineBranchProbabilityInfo *MBPI =
-        Features.BrProb ? &getAnalysis<MachineBranchProbabilityInfo>()
-                        : nullptr;
+        Features.BrProb
+            ? &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI()
+            : nullptr;
 
     if (Features.BBFreq || Features.BrProb) {
       for (const MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index c6c48cfc320c9..1b6a6ee2bbc72 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -99,7 +99,7 @@ namespace {
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.addRequired<MachineBlockFrequencyInfo>();
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       AU.addRequired<ProfileSummaryInfoWrapperPass>();
       AU.addRequired<TargetPassConfig>();
       MachineFunctionPass::getAnalysisUsage(AU);
@@ -131,9 +131,10 @@ bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) {
                          PassConfig->getEnableTailMerge();
   MBFIWrapper MBBFreqInfo(
       getAnalysis<MachineBlockFrequencyInfo>());
-  BranchFolder Folder(EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo,
-                      getAnalysis<MachineBranchProbabilityInfo>(),
-                      &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI());
+  BranchFolder Folder(
+      EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo,
+      getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI(),
+      &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI());
   return Folder.OptimizeFunction(MF, MF.getSubtarget().getInstrInfo(),
                                  MF.getSubtarget().getRegisterInfo());
 }
diff --git a/llvm/lib/CodeGen/EarlyIfConversion.cpp b/llvm/lib/CodeGen/EarlyIfConversion.cpp
index 0135f330bf445..5f3e85077cb56 100644
--- a/llvm/lib/CodeGen/EarlyIfConversion.cpp
+++ b/llvm/lib/CodeGen/EarlyIfConversion.cpp
@@ -787,14 +787,14 @@ char &llvm::EarlyIfConverterID = EarlyIfConverter::ID;
 
 INITIALIZE_PASS_BEGIN(EarlyIfConverter, DEBUG_TYPE,
                       "Early If Converter", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
 INITIALIZE_PASS_END(EarlyIfConverter, DEBUG_TYPE,
                     "Early If Converter", false, false)
 
 void EarlyIfConverter::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -1142,12 +1142,12 @@ char &llvm::EarlyIfPredicatorID = EarlyIfPredicator::ID;
 INITIALIZE_PASS_BEGIN(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator",
                       false, false)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_END(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator", false,
                     false)
 
 void EarlyIfPredicator::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -1222,7 +1222,7 @@ bool EarlyIfPredicator::runOnMachineFunction(MachineFunction &MF) {
   SchedModel.init(&STI);
   DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   Loops = &getAnalysis<MachineLoopInfo>();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
 
   bool Changed = false;
   IfConv.runOnMachineFunction(MF);
diff --git a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
index 383cb61aed410..e067bd8961a23 100644
--- a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
@@ -63,7 +63,7 @@ INITIALIZE_PASS_BEGIN(RegBankSelect, DEBUG_TYPE,
                       "Assign register bank of generic virtual registers",
                       false, false);
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
 INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,
                     "Assign register bank of generic virtual registers", false,
@@ -86,7 +86,7 @@ void RegBankSelect::init(MachineFunction &MF) {
   TPC = &getAnalysis<TargetPassConfig>();
   if (OptMode != Mode::Fast) {
     MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
-    MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+    MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   } else {
     MBFI = nullptr;
     MBPI = nullptr;
@@ -100,7 +100,7 @@ void RegBankSelect::getAnalysisUsage(AnalysisUsage &AU) const {
     // We could preserve the information from these two analysis but
     // the APIs do not allow to do so yet.
     AU.addRequired<MachineBlockFrequencyInfo>();
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   }
   AU.addRequired<TargetPassConfig>();
   getSelectionDAGFallbackAnalysisUsage(AU);
@@ -955,8 +955,10 @@ uint64_t RegBankSelect::EdgeInsertPoint::frequency(const Pass &P) const {
   if (WasMaterialized)
     return MBFI->getBlockFreq(DstOrSplit).getFrequency();
 
+  auto *MBPIWrapper =
+      P.getAnalysisIfAvailable<MachineBranchProbabilityInfoWrapperPass>();
   const MachineBranchProbabilityInfo *MBPI =
-      P.getAnalysisIfAvailable<MachineBranchProbabilityInfo>();
+      MBPIWrapper ? &MBPIWrapper->getMBPI() : nullptr;
   if (!MBPI)
     return 1;
   // The basic block will be on the edge.
diff --git a/llvm/lib/CodeGen/IfConversion.cpp b/llvm/lib/CodeGen/IfConversion.cpp
index e8e276a8558d8..02cb95c5d7664 100644
--- a/llvm/lib/CodeGen/IfConversion.cpp
+++ b/llvm/lib/CodeGen/IfConversion.cpp
@@ -210,7 +210,7 @@ namespace {
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.addRequired<MachineBlockFrequencyInfo>();
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       AU.addRequired<ProfileSummaryInfoWrapperPass>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
@@ -432,7 +432,7 @@ char IfConverter::ID = 0;
 char &llvm::IfConverterID = IfConverter::ID;
 
 INITIALIZE_PASS_BEGIN(IfConverter, DEBUG_TYPE, "If Converter", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
 INITIALIZE_PASS_END(IfConverter, DEBUG_TYPE, "If Converter", false, false)
 
@@ -445,7 +445,7 @@ bool IfConverter::runOnMachineFunction(MachineFunction &MF) {
   TII = ST.getInstrInfo();
   TRI = ST.getRegisterInfo();
   MBFIWrapper MBFI(getAnalysis<MachineBlockFrequencyInfo>());
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   ProfileSummaryInfo *PSI =
       &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   MRI = &MF.getRegInfo();
diff --git a/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp b/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
index 721b75900c8ef..83b16fc883e8b 100644
--- a/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
+++ b/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
@@ -23,7 +23,7 @@ using namespace llvm;
 
 INITIALIZE_PASS_BEGIN(LazyMachineBlockFrequencyInfoPass, DEBUG_TYPE,
                       "Lazy Machine Block Frequency Analysis", true, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(LazyMachineBlockFrequencyInfoPass, DEBUG_TYPE,
                     "Lazy Machine Block Frequency Analysis", true, true)
@@ -43,7 +43,7 @@ void LazyMachineBlockFrequencyInfoPass::print(raw_ostream &OS,
 
 void LazyMachineBlockFrequencyInfoPass::getAnalysisUsage(
     AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.setPreservesAll();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
@@ -62,7 +62,7 @@ LazyMachineBlockFrequencyInfoPass::calculateIfNotAvailable() const {
     return *MBFI;
   }
 
-  auto &MBPI = getAnalysis<MachineBranchProbabilityInfo>();
+  auto &MBPI = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
   auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
   auto *MDT = MDTWrapper ? &MDTWrapper->getDomTree() : nullptr;
diff --git a/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp b/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
index 7ebecc6beb17d..2a68f18d9bc76 100644
--- a/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
+++ b/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
@@ -163,7 +163,7 @@ struct DOTGraphTraits<MachineBlockFrequencyInfo *>
 
 INITIALIZE_PASS_BEGIN(MachineBlockFrequencyInfo, DEBUG_TYPE,
                       "Machine Block Frequency Analysis", true, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(MachineBlockFrequencyInfo, DEBUG_TYPE,
                     "Machine Block Frequency Analysis", true, true)
@@ -185,7 +185,7 @@ MachineBlockFrequencyInfo::MachineBlockFrequencyInfo(
 MachineBlockFrequencyInfo::~MachineBlockFrequencyInfo() = default;
 
 void MachineBlockFrequencyInfo::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
   AU.setPreservesAll();
   MachineFunctionPass::getAnalysisUsage(AU);
@@ -209,7 +209,7 @@ void MachineBlockFrequencyInfo::calculate(
 
 bool MachineBlockFrequencyInfo::runOnMachineFunction(MachineFunction &F) {
   MachineBranchProbabilityInfo &MBPI =
-      getAnalysis<MachineBranchProbabilityInfo>();
+      getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>();
   calculate(F, MBPI, MLI);
   return false;
diff --git a/llvm/lib/CodeGen/MachineBlockPlacement.cpp b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
index 1cb71f39efbe1..a229475df8fee 100644
--- a/llvm/lib/CodeGen/MachineBlockPlacement.cpp
+++ b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
@@ -608,7 +608,7 @@ class MachineBlockPlacement : public MachineFunctionPass {
   }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     if (TailDupPlacement)
       AU.addRequired<MachinePostDominatorTreeWrapperPass>();
@@ -627,7 +627,7 @@ char &llvm::MachineBlockPlacementID = MachineBlockPlacement::ID;
 
 INITIALIZE_PASS_BEGIN(MachineBlockPlacement, DEBUG_TYPE,
                       "Branch Probability Basic Block Placement", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
 INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
@@ -3425,7 +3425,7 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
     return false;
 
   F = &MF;
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   MBFI = std::make_unique<MBFIWrapper>(
       getAnalysis<MachineBlockFrequencyInfo>());
   MLI = &getAnalysis<MachineLoopInfo>();
@@ -3726,7 +3726,7 @@ class MachineBlockPlacementStats : public MachineFunctionPass {
   bool runOnMachineFunction(MachineFunction &F) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     AU.setPreservesAll();
     MachineFunctionPass::getAnalysisUsage(AU);
@@ -3741,7 +3741,7 @@ char &llvm::MachineBlockPlacementStatsID = MachineBlockPlacementStats::ID;
 
 INITIALIZE_PASS_BEGIN(MachineBlockPlacementStats, "block-placement-stats",
                       "Basic Block Placement Stats", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
 INITIALIZE_PASS_END(MachineBlockPlacementStats, "block-placement-stats",
                     "Basic Block Placement Stats", false, false)
@@ -3754,7 +3754,7 @@ bool MachineBlockPlacementStats::runOnMachineFunction(MachineFunction &F) {
   if (!isFunctionInPrintList(F.getName()))
     return false;
 
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
 
   for (MachineBasicBlock &MBB : F) {
diff --git a/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp b/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
index a84377d708558..56ffffff62240 100644
--- a/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
+++ b/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
@@ -18,9 +18,11 @@
 
 using namespace llvm;
 
-INITIALIZE_PASS_BEGIN(MachineBranchProbabilityInfo, "machine-branch-prob",
+INITIALIZE_PASS_BEGIN(MachineBranchProbabilityInfoWrapperPass,
+                      "machine-branch-prob",
                       "Machine Branch Probability Analysis", false, true)
-INITIALIZE_PASS_END(MachineBranchProbabilityInfo, "machine-branch-prob",
+INITIALIZE_PASS_END(MachineBranchProbabilityInfoWrapperPass,
+                    "machine-branch-prob",
                     "Machine Branch Probability Analysis", false, true)
 
 namespace llvm {
@@ -37,15 +39,45 @@ cl::opt<unsigned> ProfileLikelyProb(
     cl::init(51), cl::Hidden);
 } // namespace llvm
 
-char MachineBranchProbabilityInfo::ID = 0;
+MachineBranchProbabilityAnalysis::Result
+MachineBranchProbabilityAnalysis::run(MachineFunction &,
+                                      MachineFunctionAnalysisManager &) {
+  return MachineBranchProbabilityInfo();
+}
+
+PreservedAnalyses
+MachineBranchProbabilityPrinterPass::run(MachineFunction &MF,
+                                         MachineFunctionAnalysisManager &MFAM) {
+  OS << "Printing analysis 'Machine Branch Probability Analysis' for machine "
+        "function '"
+     << MF.getName() << "':\n";
+  auto &MBPI = MFAM.getResult<MachineBranchProbabilityAnalysis>(MF);
+  for (const MachineBasicBlock &MBB : MF) {
+    for (const MachineBasicBlock *Succ : MBB.successors())
+      MBPI.printEdgeProbability(OS << "  ", &MBB, Succ);
+  }
+  return PreservedAnalyses::all();
+}
+
+char MachineBranchProbabilityInfoWrapperPass::ID = 0;
 
-MachineBranchProbabilityInfo::MachineBranchProbabilityInfo()
+MachineBranchProbabilityInfoWrapperPass::
+    MachineBranchProbabilityInfoWrapperPass()
     : ImmutablePass(ID) {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
-  initializeMachineBranchProbabilityInfoPass(Registry);
+  initializeMachineBranchProbabilityInfoWrapperPassPass(Registry);
 }
 
-void MachineBranchProbabilityInfo::anchor() {}
+void MachineBranchProbabilityInfoWrapperPass::anchor() {}
+
+AnalysisKey MachineBranchProbabilityAnalysis::Key;
+
+bool MachineBranchProbabilityInfo::invalidate(
+    MachineFunction &, const PreservedAnalyses &PA,
+    MachineFunctionAnalysisManager::Invalidator &) {
+  auto PAC = PA.getChecker<MachineBranchProbabilityAnalysis>();
+  return !PAC.preservedWhenStateless();
+}
 
 BranchProbability MachineBranchProbabilityInfo::getEdgeProbability(
     const MachineBasicBlock *Src,
diff --git a/llvm/lib/CodeGen/MachineSink.cpp b/llvm/lib/CodeGen/MachineSink.cpp
index 76947a419c347..4dabaabe3659f 100644
--- a/llvm/lib/CodeGen/MachineSink.cpp
+++ b/llvm/lib/CodeGen/MachineSink.cpp
@@ -187,7 +187,7 @@ namespace {
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachinePostDominatorTreeWrapperPass>();
       AU.addRequired<MachineCycleInfoWrapperPass>();
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       AU.addPreserved<MachineCycleInfoWrapperPass>();
       AU.addPreserved<MachineLoopInfo>();
       if (UseBlockFreqInfo)
@@ -273,7 +273,7 @@ char &llvm::MachineSinkingID = MachineSinking::ID;
 
 INITIALIZE_PASS_BEGIN(MachineSinking, DEBUG_TYPE,
                       "Machine code sinking", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
@@ -712,7 +712,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
   PDT = &getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
   CI = &getAnalysis<MachineCycleInfoWrapperPass>().getCycleInfo();
   MBFI = UseBlockFreqInfo ? &getAnalysis<MachineBlockFrequencyInfo>() : nullptr;
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
   RegClassInfo.runOnMachineFunction(MF);
   TargetPassConfig *PassConfig = &getAnalysis<TargetPassConfig>();
diff --git a/llvm/lib/CodeGen/MachineTraceMetrics.cpp b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
index 3e6f36fe936ff..07df43fea0aba 100644
--- a/llvm/lib/CodeGen/MachineTraceMetrics.cpp
+++ b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
@@ -46,7 +46,7 @@ char &llvm::MachineTraceMetricsID = MachineTraceMetrics::ID;
 
 INITIALIZE_PASS_BEGIN(MachineTraceMetrics, DEBUG_TYPE,
                       "Machine Trace Metrics", false, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(MachineTraceMetrics, DEBUG_TYPE,
                     "Machine Trace Metrics", false, true)
@@ -57,7 +57,7 @@ MachineTraceMetrics::MachineTraceMetrics() : MachineFunctionPass(ID) {
 
 void MachineTraceMetrics::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
diff --git a/llvm/lib/CodeGen/TailDuplication.cpp b/llvm/lib/CodeGen/TailDuplication.cpp
index bf3d2088e196c..25f20d9c899bb 100644
--- a/llvm/lib/CodeGen/TailDuplication.cpp
+++ b/llvm/lib/CodeGen/TailDuplication.cpp
@@ -40,7 +40,7 @@ class TailDuplicateBase : public MachineFunctionPass {
   bool runOnMachineFunction(MachineFunction &MF) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
     AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
     AU.addRequired<ProfileSummaryInfoWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
@@ -84,7 +84,7 @@ bool TailDuplicateBase::runOnMachineFunction(MachineFunction &MF) {
   if (skipFunction(MF.getFunction()))
     return false;
 
-  auto MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  auto MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   auto *MBFI = (PSI && PSI->hasProfileSummary()) ?
                &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI() :
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index a87d0b5955b83..4ef5c2aadbfd4 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -93,6 +93,7 @@
 #include "llvm/CodeGen/LocalStackSlotAllocation.h"
 #include "llvm/CodeGen/LowerEmuTLS.h"
 #include "llvm/CodeGen/MIRPrinter.h"
+#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineFunctionAnalysis.h"
 #include "llvm/CodeGen/MachinePassManager.h"
diff --git a/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp b/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
index 9a788123b1ffa..3c2201ec4c998 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
@@ -794,7 +794,7 @@ char AArch64ConditionalCompares::ID = 0;
 
 INITIALIZE_PASS_BEGIN(AArch64ConditionalCompares, "aarch64-ccmp",
                       "AArch64 CCMP Pass", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
 INITIALIZE_PASS_END(AArch64ConditionalCompares, "aarch64-ccmp",
@@ -805,7 +805,7 @@ FunctionPass *llvm::createAArch64ConditionalCompares() {
 }
 
 void AArch64ConditionalCompares::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfo>();
+  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -935,7 +935,7 @@ bool AArch64ConditionalCompares::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   Loops = &getAnalysis<MachineLoopInfo>();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   Traces = &getAnalysis<MachineTraceMetrics>();
   MinInstr = nullptr;
   MinSize = MF.getFunction().hasMinSize();
diff --git a/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp b/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
index 03f6882e6889f..e99496da8a260 100644
--- a/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
@@ -161,7 +161,7 @@ namespace {
     }
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addPreserved<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachineLoopInfo>();
@@ -1056,8 +1056,9 @@ bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   MLI = &getAnalysis<MachineLoopInfo>();
-  MBPI = EnableHexagonBP ? &getAnalysis<MachineBranchProbabilityInfo>() :
-    nullptr;
+  MBPI = EnableHexagonBP
+             ? &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI()
+             : nullptr;
 
   Deleted.clear();
   bool Changed = false;
diff --git a/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp b/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
index c79b528ff2f3f..6aa95ff6fd8f5 100644
--- a/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
@@ -74,7 +74,7 @@ class HexagonLoopAlign : public MachineFunctionPass {
   bool attemptToBalignSmallLoop(MachineFunction &MF, MachineBasicBlock &MBB);
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
@@ -148,7 +148,7 @@ bool HexagonLoopAlign::attemptToBalignSmallLoop(MachineFunction &MF,
     return false;
 
   const MachineBranchProbabilityInfo *MBPI =
-      &getAnalysis<MachineBranchProbabilityInfo>();
+      &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   const MachineBlockFrequencyInfo *MBFI =
       &getAnalysis<MachineBlockFrequencyInfo>();
 
diff --git a/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp b/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
index f539717e42d59..36c52dfe81d5a 100644
--- a/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
@@ -78,7 +78,7 @@ namespace {
     HexagonNewValueJump() : MachineFunctionPass(ID) {}
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
 
@@ -107,7 +107,7 @@ char HexagonNewValueJump::ID = 0;
 
 INITIALIZE_PASS_BEGIN(HexagonNewValueJump, "hexagon-nvj",
                       "Hexagon NewValueJump", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_END(HexagonNewValueJump, "hexagon-nvj",
                     "Hexagon NewValueJump", false, false)
 
@@ -459,7 +459,7 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
   QII = static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
   QRI = static_cast<const HexagonRegisterInfo *>(
       MF.getSubtarget().getRegisterInfo());
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
 
   if (DisableNewValueJumps ||
       !MF.getSubtarget<HexagonSubtarget>().useNewValueJumps())
diff --git a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index 2d5352b08caed..ef2677a6af46a 100644
--- a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -96,7 +96,7 @@ namespace {
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.setPreservesCFG();
       AU.addRequired<AAResultsWrapperPass>();
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachineLoopInfo>();
       AU.addPreserved<MachineDominatorTreeWrapperPass>();
@@ -125,7 +125,7 @@ char HexagonPacketizer::ID = 0;
 INITIALIZE_PASS_BEGIN(HexagonPacketizer, "hexagon-packetizer",
                       "Hexagon Packetizer", false, false)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
 INITIALIZE_PASS_END(HexagonPacketizer, "hexagon-packetizer",
@@ -213,7 +213,8 @@ bool HexagonPacketizer::runOnMachineFunction(MachineFunction &MF) {
   HRI = HST.getRegisterInfo();
   auto &MLI = getAnalysis<MachineLoopInfo>();
   auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
-  auto *MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  auto *MBPI =
+      &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
 
   if (EnableGenAllInsnClass)
     HII->genAllInsnTimingClasses(MF);
diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index b525606b1f8fd..4ec01ab7b4565 100644
--- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -236,7 +236,7 @@ namespace {
     }
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfo>();
+      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
 
@@ -872,7 +872,7 @@ MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &B) const {
     return nullptr;
 
   // Select the successor with the larget edge weight.
-  auto &Prob = getAnalysis<MachineBranchProbabilityInfo>();
+  auto &Prob = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
   MachineBasicBlock *S = *std::max_element(
       B.succ_begin(), B.succ_end(),
       [&](const MachineBasicBlock *Dst0, const MachineBasicBlock *Dst1) {
diff --git a/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp b/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
index d1cc2ad5c481f..0bfcba9a52486 100644
--- a/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
+++ b/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
@@ -426,7 +426,7 @@ class PPCReduceCRLogicals : public MachineFunctionPass {
   }
   CRLogicalOpInfo createCRLogicalOpInfo(MachineInstr &MI);
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfo>();
+    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
     AU.addRequired<MachineDominatorTreeWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
@@ -570,7 +570,7 @@ void PPCReduceCRLogicals::initialize(MachineFunction &MFParam) {
   MF = &MFParam;
   MRI = &MF->getRegInfo();
   TII = MF->getSubtarget<PPCSubtarget>().getInstrInfo();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
 
   AllCRLogicalOps.clear();
 }
diff --git a/llvm/test/CodeGen/Generic/MachineBranchProb.ll b/llvm/test/CodeGen/Generic/MachineBranchProb.ll
index 9a5ea0c5e13cc..fa39e7182cef6 100644
--- a/llvm/test/CodeGen/Generic/MachineBranchProb.ll
+++ b/llvm/test/CodeGen/Generic/MachineBranchProb.ll
@@ -1,4 +1,5 @@
 ; RUN: llc < %s -print-after=finalize-isel -o /dev/null 2>&1 | FileCheck %s
+; RUN: llc %s -stop-after=finalize-isel -o - | llc -passes='print<machine-branch-prob>' -x mir -filetype=null 2>&1 | FileCheck -check-prefix=NPM %s
 
 ; Hexagon runs passes that renumber the basic blocks, causing this test
 ; to fail.
@@ -27,6 +28,10 @@ entry:
 ; CHECK: bb.6.entry:
 ; CHECK: successors: %bb.1(0x2e8ba2d7), %bb.3(0x51745d29)
 
+; NPM: Printing analysis 'Machine Branch Probability Analysis' for machine function 'test2':
+; NPM: edge %bb.4 -> %bb.6 probability is 0x80000000 / 0x80000000 = 100.00% [HOT edge]
+; NPM: edge %bb.5 -> %bb.6 probability is 0x80000000 / 0x80000000 = 100.00% [HOT edge]
+
 sw.bb:
 ; this call will prevent simplifyCFG from optimizing the block away in ARM/AArch64.
   tail call void @foo()

>From c0eaa37ce8901bed7ae0ed92fa9b0f27bc7ba8e1 Mon Sep 17 00:00:00 2001
From: paperchalice <liujunchang97 at outlook.com>
Date: Thu, 27 Jun 2024 15:00:17 +0800
Subject: [PATCH 17/19] Revert "[CodeGen][NewPM] Port machine-branch-prob to
 new pass manager" (#96858)

Reverts llvm/llvm-project#96389
Some ppc bots failed.
---
 .../CodeGen/MachineBranchProbabilityInfo.h    | 53 ++++---------------
 llvm/include/llvm/InitializePasses.h          |  2 +-
 .../llvm/Passes/MachinePassRegistry.def       |  4 --
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  7 ++-
 llvm/lib/CodeGen/BranchFolding.cpp            |  9 ++--
 llvm/lib/CodeGen/EarlyIfConversion.cpp        | 10 ++--
 llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp | 10 ++--
 llvm/lib/CodeGen/IfConversion.cpp             |  6 +--
 .../CodeGen/LazyMachineBlockFrequencyInfo.cpp |  6 +--
 .../lib/CodeGen/MachineBlockFrequencyInfo.cpp |  6 +--
 llvm/lib/CodeGen/MachineBlockPlacement.cpp    | 12 ++---
 .../CodeGen/MachineBranchProbabilityInfo.cpp  | 44 +++------------
 llvm/lib/CodeGen/MachineSink.cpp              |  6 +--
 llvm/lib/CodeGen/MachineTraceMetrics.cpp      |  4 +-
 llvm/lib/CodeGen/TailDuplication.cpp          |  4 +-
 llvm/lib/Passes/PassBuilder.cpp               |  1 -
 .../AArch64/AArch64ConditionalCompares.cpp    |  6 +--
 .../lib/Target/Hexagon/HexagonEarlyIfConv.cpp |  7 ++-
 llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp  |  4 +-
 .../Target/Hexagon/HexagonNewValueJump.cpp    |  6 +--
 .../Target/Hexagon/HexagonVLIWPacketizer.cpp  |  7 ++-
 llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp  |  4 +-
 .../Target/PowerPC/PPCReduceCRLogicals.cpp    |  4 +-
 .../test/CodeGen/Generic/MachineBranchProb.ll |  5 --
 24 files changed, 73 insertions(+), 154 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h b/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
index 12d33f96edd11..bd544421bc0ff 100644
--- a/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
@@ -14,13 +14,14 @@
 #define LLVM_CODEGEN_MACHINEBRANCHPROBABILITYINFO_H
 
 #include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/BranchProbability.h"
 
 namespace llvm {
 
-class MachineBranchProbabilityInfo {
+class MachineBranchProbabilityInfo : public ImmutablePass {
+  virtual void anchor();
+
   // Default weight value. Used when we don't have information about the edge.
   // TODO: DEFAULT_WEIGHT makes sense during static predication, when none of
   // the successors have a weight yet. But it doesn't make sense when providing
@@ -30,8 +31,13 @@ class MachineBranchProbabilityInfo {
   static const uint32_t DEFAULT_WEIGHT = 16;
 
 public:
-  bool invalidate(MachineFunction &, const PreservedAnalyses &PA,
-                  MachineFunctionAnalysisManager::Invalidator &);
+  static char ID;
+
+  MachineBranchProbabilityInfo();
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesAll();
+  }
 
   // Return edge probability.
   BranchProbability getEdgeProbability(const MachineBasicBlock *Src,
@@ -55,45 +61,6 @@ class MachineBranchProbabilityInfo {
                                     const MachineBasicBlock *Dst) const;
 };
 
-class MachineBranchProbabilityAnalysis
-    : public AnalysisInfoMixin<MachineBranchProbabilityAnalysis> {
-  friend AnalysisInfoMixin<MachineBranchProbabilityAnalysis>;
-
-  static AnalysisKey Key;
-
-public:
-  using Result = MachineBranchProbabilityInfo;
-
-  Result run(MachineFunction &, MachineFunctionAnalysisManager &);
-};
-
-class MachineBranchProbabilityPrinterPass
-    : public PassInfoMixin<MachineBranchProbabilityPrinterPass> {
-  raw_ostream &OS;
-
-public:
-  MachineBranchProbabilityPrinterPass(raw_ostream &OS) : OS(OS) {}
-  PreservedAnalyses run(MachineFunction &MF,
-                        MachineFunctionAnalysisManager &MFAM);
-};
-
-class MachineBranchProbabilityInfoWrapperPass : public ImmutablePass {
-  virtual void anchor();
-
-  MachineBranchProbabilityInfo MBPI;
-
-public:
-  static char ID;
-
-  MachineBranchProbabilityInfoWrapperPass();
-
-  void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.setPreservesAll();
-  }
-
-  MachineBranchProbabilityInfo &getMBPI() { return MBPI; }
-  const MachineBranchProbabilityInfo &getMBPI() const { return MBPI; }
-};
 }
 
 
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 421c09ada7a19..4ddb7112a47bb 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -182,7 +182,7 @@ void initializeMIRPrintingPassPass(PassRegistry&);
 void initializeMachineBlockFrequencyInfoPass(PassRegistry&);
 void initializeMachineBlockPlacementPass(PassRegistry&);
 void initializeMachineBlockPlacementStatsPass(PassRegistry&);
-void initializeMachineBranchProbabilityInfoWrapperPassPass(PassRegistry &);
+void initializeMachineBranchProbabilityInfoPass(PassRegistry&);
 void initializeMachineCFGPrinterPass(PassRegistry &);
 void initializeMachineCSEPass(PassRegistry&);
 void initializeMachineCombinerPass(PassRegistry&);
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index b1542ab139286..b43f41bb3097e 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -89,8 +89,6 @@ LOOP_PASS("loop-reduce", LoopStrengthReducePass())
 #ifndef MACHINE_FUNCTION_ANALYSIS
 #define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS)
 #endif
-MACHINE_FUNCTION_ANALYSIS("machine-branch-prob",
-                          MachineBranchProbabilityAnalysis())
 MACHINE_FUNCTION_ANALYSIS("machine-dom-tree", MachineDominatorTreeAnalysis())
 MACHINE_FUNCTION_ANALYSIS("machine-post-dom-tree",
                           MachinePostDominatorTreeAnalysis())
@@ -132,8 +130,6 @@ MACHINE_FUNCTION_PASS("finalize-isel", FinalizeISelPass())
 MACHINE_FUNCTION_PASS("localstackalloc", LocalStackSlotAllocationPass())
 MACHINE_FUNCTION_PASS("no-op-machine-function", NoOpMachineFunctionPass())
 MACHINE_FUNCTION_PASS("print", PrintMIRPass())
-MACHINE_FUNCTION_PASS("print<machine-branch-prob>",
-                      MachineBranchProbabilityPrinterPass(dbgs()))
 MACHINE_FUNCTION_PASS("print<machine-dom-tree>",
                       MachineDominatorTreePrinterPass(dbgs()))
 MACHINE_FUNCTION_PASS("print<machine-post-dom-tree>",
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 505bd8acaf0ca..40f4dc2689cdf 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -444,7 +444,7 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.addRequired<MachineOptimizationRemarkEmitterPass>();
   AU.addRequired<GCModuleInfo>();
   AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
 }
 
 bool AsmPrinter::doInitialization(Module &M) {
@@ -1478,9 +1478,8 @@ void AsmPrinter::emitBBAddrMapSection(const MachineFunction &MF) {
             ? &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI()
             : nullptr;
     const MachineBranchProbabilityInfo *MBPI =
-        Features.BrProb
-            ? &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI()
-            : nullptr;
+        Features.BrProb ? &getAnalysis<MachineBranchProbabilityInfo>()
+                        : nullptr;
 
     if (Features.BBFreq || Features.BrProb) {
       for (const MachineBasicBlock &MBB : MF) {
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 1b6a6ee2bbc72..c6c48cfc320c9 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -99,7 +99,7 @@ namespace {
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.addRequired<MachineBlockFrequencyInfo>();
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       AU.addRequired<ProfileSummaryInfoWrapperPass>();
       AU.addRequired<TargetPassConfig>();
       MachineFunctionPass::getAnalysisUsage(AU);
@@ -131,10 +131,9 @@ bool BranchFolderPass::runOnMachineFunction(MachineFunction &MF) {
                          PassConfig->getEnableTailMerge();
   MBFIWrapper MBBFreqInfo(
       getAnalysis<MachineBlockFrequencyInfo>());
-  BranchFolder Folder(
-      EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo,
-      getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI(),
-      &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI());
+  BranchFolder Folder(EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo,
+                      getAnalysis<MachineBranchProbabilityInfo>(),
+                      &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI());
   return Folder.OptimizeFunction(MF, MF.getSubtarget().getInstrInfo(),
                                  MF.getSubtarget().getRegisterInfo());
 }
diff --git a/llvm/lib/CodeGen/EarlyIfConversion.cpp b/llvm/lib/CodeGen/EarlyIfConversion.cpp
index 5f3e85077cb56..0135f330bf445 100644
--- a/llvm/lib/CodeGen/EarlyIfConversion.cpp
+++ b/llvm/lib/CodeGen/EarlyIfConversion.cpp
@@ -787,14 +787,14 @@ char &llvm::EarlyIfConverterID = EarlyIfConverter::ID;
 
 INITIALIZE_PASS_BEGIN(EarlyIfConverter, DEBUG_TYPE,
                       "Early If Converter", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
 INITIALIZE_PASS_END(EarlyIfConverter, DEBUG_TYPE,
                     "Early If Converter", false, false)
 
 void EarlyIfConverter::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -1142,12 +1142,12 @@ char &llvm::EarlyIfPredicatorID = EarlyIfPredicator::ID;
 INITIALIZE_PASS_BEGIN(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator",
                       false, false)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_END(EarlyIfPredicator, DEBUG_TYPE, "Early If Predicator", false,
                     false)
 
 void EarlyIfPredicator::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -1222,7 +1222,7 @@ bool EarlyIfPredicator::runOnMachineFunction(MachineFunction &MF) {
   SchedModel.init(&STI);
   DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   Loops = &getAnalysis<MachineLoopInfo>();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
 
   bool Changed = false;
   IfConv.runOnMachineFunction(MF);
diff --git a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
index e067bd8961a23..383cb61aed410 100644
--- a/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/RegBankSelect.cpp
@@ -63,7 +63,7 @@ INITIALIZE_PASS_BEGIN(RegBankSelect, DEBUG_TYPE,
                       "Assign register bank of generic virtual registers",
                       false, false);
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
 INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,
                     "Assign register bank of generic virtual registers", false,
@@ -86,7 +86,7 @@ void RegBankSelect::init(MachineFunction &MF) {
   TPC = &getAnalysis<TargetPassConfig>();
   if (OptMode != Mode::Fast) {
     MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
-    MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+    MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   } else {
     MBFI = nullptr;
     MBPI = nullptr;
@@ -100,7 +100,7 @@ void RegBankSelect::getAnalysisUsage(AnalysisUsage &AU) const {
     // We could preserve the information from these two analysis but
     // the APIs do not allow to do so yet.
     AU.addRequired<MachineBlockFrequencyInfo>();
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
   }
   AU.addRequired<TargetPassConfig>();
   getSelectionDAGFallbackAnalysisUsage(AU);
@@ -955,10 +955,8 @@ uint64_t RegBankSelect::EdgeInsertPoint::frequency(const Pass &P) const {
   if (WasMaterialized)
     return MBFI->getBlockFreq(DstOrSplit).getFrequency();
 
-  auto *MBPIWrapper =
-      P.getAnalysisIfAvailable<MachineBranchProbabilityInfoWrapperPass>();
   const MachineBranchProbabilityInfo *MBPI =
-      MBPIWrapper ? &MBPIWrapper->getMBPI() : nullptr;
+      P.getAnalysisIfAvailable<MachineBranchProbabilityInfo>();
   if (!MBPI)
     return 1;
   // The basic block will be on the edge.
diff --git a/llvm/lib/CodeGen/IfConversion.cpp b/llvm/lib/CodeGen/IfConversion.cpp
index 02cb95c5d7664..e8e276a8558d8 100644
--- a/llvm/lib/CodeGen/IfConversion.cpp
+++ b/llvm/lib/CodeGen/IfConversion.cpp
@@ -210,7 +210,7 @@ namespace {
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.addRequired<MachineBlockFrequencyInfo>();
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       AU.addRequired<ProfileSummaryInfoWrapperPass>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
@@ -432,7 +432,7 @@ char IfConverter::ID = 0;
 char &llvm::IfConverterID = IfConverter::ID;
 
 INITIALIZE_PASS_BEGIN(IfConverter, DEBUG_TYPE, "If Converter", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
 INITIALIZE_PASS_END(IfConverter, DEBUG_TYPE, "If Converter", false, false)
 
@@ -445,7 +445,7 @@ bool IfConverter::runOnMachineFunction(MachineFunction &MF) {
   TII = ST.getInstrInfo();
   TRI = ST.getRegisterInfo();
   MBFIWrapper MBFI(getAnalysis<MachineBlockFrequencyInfo>());
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   ProfileSummaryInfo *PSI =
       &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   MRI = &MF.getRegInfo();
diff --git a/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp b/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
index 83b16fc883e8b..721b75900c8ef 100644
--- a/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
+++ b/llvm/lib/CodeGen/LazyMachineBlockFrequencyInfo.cpp
@@ -23,7 +23,7 @@ using namespace llvm;
 
 INITIALIZE_PASS_BEGIN(LazyMachineBlockFrequencyInfoPass, DEBUG_TYPE,
                       "Lazy Machine Block Frequency Analysis", true, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(LazyMachineBlockFrequencyInfoPass, DEBUG_TYPE,
                     "Lazy Machine Block Frequency Analysis", true, true)
@@ -43,7 +43,7 @@ void LazyMachineBlockFrequencyInfoPass::print(raw_ostream &OS,
 
 void LazyMachineBlockFrequencyInfoPass::getAnalysisUsage(
     AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.setPreservesAll();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
@@ -62,7 +62,7 @@ LazyMachineBlockFrequencyInfoPass::calculateIfNotAvailable() const {
     return *MBFI;
   }
 
-  auto &MBPI = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  auto &MBPI = getAnalysis<MachineBranchProbabilityInfo>();
   auto *MLI = getAnalysisIfAvailable<MachineLoopInfo>();
   auto *MDTWrapper = getAnalysisIfAvailable<MachineDominatorTreeWrapperPass>();
   auto *MDT = MDTWrapper ? &MDTWrapper->getDomTree() : nullptr;
diff --git a/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp b/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
index 2a68f18d9bc76..7ebecc6beb17d 100644
--- a/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
+++ b/llvm/lib/CodeGen/MachineBlockFrequencyInfo.cpp
@@ -163,7 +163,7 @@ struct DOTGraphTraits<MachineBlockFrequencyInfo *>
 
 INITIALIZE_PASS_BEGIN(MachineBlockFrequencyInfo, DEBUG_TYPE,
                       "Machine Block Frequency Analysis", true, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(MachineBlockFrequencyInfo, DEBUG_TYPE,
                     "Machine Block Frequency Analysis", true, true)
@@ -185,7 +185,7 @@ MachineBlockFrequencyInfo::MachineBlockFrequencyInfo(
 MachineBlockFrequencyInfo::~MachineBlockFrequencyInfo() = default;
 
 void MachineBlockFrequencyInfo::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.addRequired<MachineLoopInfo>();
   AU.setPreservesAll();
   MachineFunctionPass::getAnalysisUsage(AU);
@@ -209,7 +209,7 @@ void MachineBlockFrequencyInfo::calculate(
 
 bool MachineBlockFrequencyInfo::runOnMachineFunction(MachineFunction &F) {
   MachineBranchProbabilityInfo &MBPI =
-      getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+      getAnalysis<MachineBranchProbabilityInfo>();
   MachineLoopInfo &MLI = getAnalysis<MachineLoopInfo>();
   calculate(F, MBPI, MLI);
   return false;
diff --git a/llvm/lib/CodeGen/MachineBlockPlacement.cpp b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
index a229475df8fee..1cb71f39efbe1 100644
--- a/llvm/lib/CodeGen/MachineBlockPlacement.cpp
+++ b/llvm/lib/CodeGen/MachineBlockPlacement.cpp
@@ -608,7 +608,7 @@ class MachineBlockPlacement : public MachineFunctionPass {
   }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     if (TailDupPlacement)
       AU.addRequired<MachinePostDominatorTreeWrapperPass>();
@@ -627,7 +627,7 @@ char &llvm::MachineBlockPlacementID = MachineBlockPlacement::ID;
 
 INITIALIZE_PASS_BEGIN(MachineBlockPlacement, DEBUG_TYPE,
                       "Branch Probability Basic Block Placement", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
 INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
@@ -3425,7 +3425,7 @@ bool MachineBlockPlacement::runOnMachineFunction(MachineFunction &MF) {
     return false;
 
   F = &MF;
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   MBFI = std::make_unique<MBFIWrapper>(
       getAnalysis<MachineBlockFrequencyInfo>());
   MLI = &getAnalysis<MachineLoopInfo>();
@@ -3726,7 +3726,7 @@ class MachineBlockPlacementStats : public MachineFunctionPass {
   bool runOnMachineFunction(MachineFunction &F) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     AU.setPreservesAll();
     MachineFunctionPass::getAnalysisUsage(AU);
@@ -3741,7 +3741,7 @@ char &llvm::MachineBlockPlacementStatsID = MachineBlockPlacementStats::ID;
 
 INITIALIZE_PASS_BEGIN(MachineBlockPlacementStats, "block-placement-stats",
                       "Basic Block Placement Stats", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
 INITIALIZE_PASS_END(MachineBlockPlacementStats, "block-placement-stats",
                     "Basic Block Placement Stats", false, false)
@@ -3754,7 +3754,7 @@ bool MachineBlockPlacementStats::runOnMachineFunction(MachineFunction &F) {
   if (!isFunctionInPrintList(F.getName()))
     return false;
 
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
 
   for (MachineBasicBlock &MBB : F) {
diff --git a/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp b/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
index 56ffffff62240..a84377d708558 100644
--- a/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
+++ b/llvm/lib/CodeGen/MachineBranchProbabilityInfo.cpp
@@ -18,11 +18,9 @@
 
 using namespace llvm;
 
-INITIALIZE_PASS_BEGIN(MachineBranchProbabilityInfoWrapperPass,
-                      "machine-branch-prob",
+INITIALIZE_PASS_BEGIN(MachineBranchProbabilityInfo, "machine-branch-prob",
                       "Machine Branch Probability Analysis", false, true)
-INITIALIZE_PASS_END(MachineBranchProbabilityInfoWrapperPass,
-                    "machine-branch-prob",
+INITIALIZE_PASS_END(MachineBranchProbabilityInfo, "machine-branch-prob",
                     "Machine Branch Probability Analysis", false, true)
 
 namespace llvm {
@@ -39,45 +37,15 @@ cl::opt<unsigned> ProfileLikelyProb(
     cl::init(51), cl::Hidden);
 } // namespace llvm
 
-MachineBranchProbabilityAnalysis::Result
-MachineBranchProbabilityAnalysis::run(MachineFunction &,
-                                      MachineFunctionAnalysisManager &) {
-  return MachineBranchProbabilityInfo();
-}
-
-PreservedAnalyses
-MachineBranchProbabilityPrinterPass::run(MachineFunction &MF,
-                                         MachineFunctionAnalysisManager &MFAM) {
-  OS << "Printing analysis 'Machine Branch Probability Analysis' for machine "
-        "function '"
-     << MF.getName() << "':\n";
-  auto &MBPI = MFAM.getResult<MachineBranchProbabilityAnalysis>(MF);
-  for (const MachineBasicBlock &MBB : MF) {
-    for (const MachineBasicBlock *Succ : MBB.successors())
-      MBPI.printEdgeProbability(OS << "  ", &MBB, Succ);
-  }
-  return PreservedAnalyses::all();
-}
-
-char MachineBranchProbabilityInfoWrapperPass::ID = 0;
+char MachineBranchProbabilityInfo::ID = 0;
 
-MachineBranchProbabilityInfoWrapperPass::
-    MachineBranchProbabilityInfoWrapperPass()
+MachineBranchProbabilityInfo::MachineBranchProbabilityInfo()
     : ImmutablePass(ID) {
   PassRegistry &Registry = *PassRegistry::getPassRegistry();
-  initializeMachineBranchProbabilityInfoWrapperPassPass(Registry);
+  initializeMachineBranchProbabilityInfoPass(Registry);
 }
 
-void MachineBranchProbabilityInfoWrapperPass::anchor() {}
-
-AnalysisKey MachineBranchProbabilityAnalysis::Key;
-
-bool MachineBranchProbabilityInfo::invalidate(
-    MachineFunction &, const PreservedAnalyses &PA,
-    MachineFunctionAnalysisManager::Invalidator &) {
-  auto PAC = PA.getChecker<MachineBranchProbabilityAnalysis>();
-  return !PAC.preservedWhenStateless();
-}
+void MachineBranchProbabilityInfo::anchor() {}
 
 BranchProbability MachineBranchProbabilityInfo::getEdgeProbability(
     const MachineBasicBlock *Src,
diff --git a/llvm/lib/CodeGen/MachineSink.cpp b/llvm/lib/CodeGen/MachineSink.cpp
index 4dabaabe3659f..76947a419c347 100644
--- a/llvm/lib/CodeGen/MachineSink.cpp
+++ b/llvm/lib/CodeGen/MachineSink.cpp
@@ -187,7 +187,7 @@ namespace {
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachinePostDominatorTreeWrapperPass>();
       AU.addRequired<MachineCycleInfoWrapperPass>();
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       AU.addPreserved<MachineCycleInfoWrapperPass>();
       AU.addPreserved<MachineLoopInfo>();
       if (UseBlockFreqInfo)
@@ -273,7 +273,7 @@ char &llvm::MachineSinkingID = MachineSinking::ID;
 
 INITIALIZE_PASS_BEGIN(MachineSinking, DEBUG_TYPE,
                       "Machine code sinking", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineCycleInfoWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
@@ -712,7 +712,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) {
   PDT = &getAnalysis<MachinePostDominatorTreeWrapperPass>().getPostDomTree();
   CI = &getAnalysis<MachineCycleInfoWrapperPass>().getCycleInfo();
   MBFI = UseBlockFreqInfo ? &getAnalysis<MachineBlockFrequencyInfo>() : nullptr;
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
   RegClassInfo.runOnMachineFunction(MF);
   TargetPassConfig *PassConfig = &getAnalysis<TargetPassConfig>();
diff --git a/llvm/lib/CodeGen/MachineTraceMetrics.cpp b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
index 07df43fea0aba..3e6f36fe936ff 100644
--- a/llvm/lib/CodeGen/MachineTraceMetrics.cpp
+++ b/llvm/lib/CodeGen/MachineTraceMetrics.cpp
@@ -46,7 +46,7 @@ char &llvm::MachineTraceMetricsID = MachineTraceMetrics::ID;
 
 INITIALIZE_PASS_BEGIN(MachineTraceMetrics, DEBUG_TYPE,
                       "Machine Trace Metrics", false, true)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_END(MachineTraceMetrics, DEBUG_TYPE,
                     "Machine Trace Metrics", false, true)
@@ -57,7 +57,7 @@ MachineTraceMetrics::MachineTraceMetrics() : MachineFunctionPass(ID) {
 
 void MachineTraceMetrics::getAnalysisUsage(AnalysisUsage &AU) const {
   AU.setPreservesAll();
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.addRequired<MachineLoopInfo>();
   MachineFunctionPass::getAnalysisUsage(AU);
 }
diff --git a/llvm/lib/CodeGen/TailDuplication.cpp b/llvm/lib/CodeGen/TailDuplication.cpp
index 25f20d9c899bb..bf3d2088e196c 100644
--- a/llvm/lib/CodeGen/TailDuplication.cpp
+++ b/llvm/lib/CodeGen/TailDuplication.cpp
@@ -40,7 +40,7 @@ class TailDuplicateBase : public MachineFunctionPass {
   bool runOnMachineFunction(MachineFunction &MF) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
     AU.addRequired<LazyMachineBlockFrequencyInfoPass>();
     AU.addRequired<ProfileSummaryInfoWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
@@ -84,7 +84,7 @@ bool TailDuplicateBase::runOnMachineFunction(MachineFunction &MF) {
   if (skipFunction(MF.getFunction()))
     return false;
 
-  auto MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  auto MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
   auto *MBFI = (PSI && PSI->hasProfileSummary()) ?
                &getAnalysis<LazyMachineBlockFrequencyInfoPass>().getBFI() :
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 4ef5c2aadbfd4..a87d0b5955b83 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -93,7 +93,6 @@
 #include "llvm/CodeGen/LocalStackSlotAllocation.h"
 #include "llvm/CodeGen/LowerEmuTLS.h"
 #include "llvm/CodeGen/MIRPrinter.h"
-#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineFunctionAnalysis.h"
 #include "llvm/CodeGen/MachinePassManager.h"
diff --git a/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp b/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
index 3c2201ec4c998..9a788123b1ffa 100644
--- a/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ConditionalCompares.cpp
@@ -794,7 +794,7 @@ char AArch64ConditionalCompares::ID = 0;
 
 INITIALIZE_PASS_BEGIN(AArch64ConditionalCompares, "aarch64-ccmp",
                       "AArch64 CCMP Pass", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
 INITIALIZE_PASS_END(AArch64ConditionalCompares, "aarch64-ccmp",
@@ -805,7 +805,7 @@ FunctionPass *llvm::createAArch64ConditionalCompares() {
 }
 
 void AArch64ConditionalCompares::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+  AU.addRequired<MachineBranchProbabilityInfo>();
   AU.addRequired<MachineDominatorTreeWrapperPass>();
   AU.addPreserved<MachineDominatorTreeWrapperPass>();
   AU.addRequired<MachineLoopInfo>();
@@ -935,7 +935,7 @@ bool AArch64ConditionalCompares::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   Loops = &getAnalysis<MachineLoopInfo>();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
   Traces = &getAnalysis<MachineTraceMetrics>();
   MinInstr = nullptr;
   MinSize = MF.getFunction().hasMinSize();
diff --git a/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp b/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
index e99496da8a260..03f6882e6889f 100644
--- a/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonEarlyIfConv.cpp
@@ -161,7 +161,7 @@ namespace {
     }
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addPreserved<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachineLoopInfo>();
@@ -1056,9 +1056,8 @@ bool HexagonEarlyIfConversion::runOnMachineFunction(MachineFunction &MF) {
   MRI = &MF.getRegInfo();
   MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
   MLI = &getAnalysis<MachineLoopInfo>();
-  MBPI = EnableHexagonBP
-             ? &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI()
-             : nullptr;
+  MBPI = EnableHexagonBP ? &getAnalysis<MachineBranchProbabilityInfo>() :
+    nullptr;
 
   Deleted.clear();
   bool Changed = false;
diff --git a/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp b/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
index 6aa95ff6fd8f5..c79b528ff2f3f 100644
--- a/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonLoopAlign.cpp
@@ -74,7 +74,7 @@ class HexagonLoopAlign : public MachineFunctionPass {
   bool attemptToBalignSmallLoop(MachineFunction &MF, MachineBasicBlock &MBB);
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
     AU.addRequired<MachineBlockFrequencyInfo>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
@@ -148,7 +148,7 @@ bool HexagonLoopAlign::attemptToBalignSmallLoop(MachineFunction &MF,
     return false;
 
   const MachineBranchProbabilityInfo *MBPI =
-      &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+      &getAnalysis<MachineBranchProbabilityInfo>();
   const MachineBlockFrequencyInfo *MBFI =
       &getAnalysis<MachineBlockFrequencyInfo>();
 
diff --git a/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp b/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
index 36c52dfe81d5a..f539717e42d59 100644
--- a/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp
@@ -78,7 +78,7 @@ namespace {
     HexagonNewValueJump() : MachineFunctionPass(ID) {}
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
 
@@ -107,7 +107,7 @@ char HexagonNewValueJump::ID = 0;
 
 INITIALIZE_PASS_BEGIN(HexagonNewValueJump, "hexagon-nvj",
                       "Hexagon NewValueJump", false, false)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_END(HexagonNewValueJump, "hexagon-nvj",
                     "Hexagon NewValueJump", false, false)
 
@@ -459,7 +459,7 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) {
   QII = static_cast<const HexagonInstrInfo *>(MF.getSubtarget().getInstrInfo());
   QRI = static_cast<const HexagonRegisterInfo *>(
       MF.getSubtarget().getRegisterInfo());
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
 
   if (DisableNewValueJumps ||
       !MF.getSubtarget<HexagonSubtarget>().useNewValueJumps())
diff --git a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
index ef2677a6af46a..2d5352b08caed 100644
--- a/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonVLIWPacketizer.cpp
@@ -96,7 +96,7 @@ namespace {
     void getAnalysisUsage(AnalysisUsage &AU) const override {
       AU.setPreservesCFG();
       AU.addRequired<AAResultsWrapperPass>();
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       AU.addRequired<MachineDominatorTreeWrapperPass>();
       AU.addRequired<MachineLoopInfo>();
       AU.addPreserved<MachineDominatorTreeWrapperPass>();
@@ -125,7 +125,7 @@ char HexagonPacketizer::ID = 0;
 INITIALIZE_PASS_BEGIN(HexagonPacketizer, "hexagon-packetizer",
                       "Hexagon Packetizer", false, false)
 INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
 INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
 INITIALIZE_PASS_END(HexagonPacketizer, "hexagon-packetizer",
@@ -213,8 +213,7 @@ bool HexagonPacketizer::runOnMachineFunction(MachineFunction &MF) {
   HRI = HST.getRegisterInfo();
   auto &MLI = getAnalysis<MachineLoopInfo>();
   auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
-  auto *MBPI =
-      &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  auto *MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
 
   if (EnableGenAllInsnClass)
     HII->genAllInsnTimingClasses(MF);
diff --git a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
index 4ec01ab7b4565..b525606b1f8fd 100644
--- a/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ b/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
@@ -236,7 +236,7 @@ namespace {
     }
 
     void getAnalysisUsage(AnalysisUsage &AU) const override {
-      AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+      AU.addRequired<MachineBranchProbabilityInfo>();
       MachineFunctionPass::getAnalysisUsage(AU);
     }
 
@@ -872,7 +872,7 @@ MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &B) const {
     return nullptr;
 
   // Select the successor with the larget edge weight.
-  auto &Prob = getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  auto &Prob = getAnalysis<MachineBranchProbabilityInfo>();
   MachineBasicBlock *S = *std::max_element(
       B.succ_begin(), B.succ_end(),
       [&](const MachineBasicBlock *Dst0, const MachineBasicBlock *Dst1) {
diff --git a/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp b/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
index 0bfcba9a52486..d1cc2ad5c481f 100644
--- a/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
+++ b/llvm/lib/Target/PowerPC/PPCReduceCRLogicals.cpp
@@ -426,7 +426,7 @@ class PPCReduceCRLogicals : public MachineFunctionPass {
   }
   CRLogicalOpInfo createCRLogicalOpInfo(MachineInstr &MI);
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
+    AU.addRequired<MachineBranchProbabilityInfo>();
     AU.addRequired<MachineDominatorTreeWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
@@ -570,7 +570,7 @@ void PPCReduceCRLogicals::initialize(MachineFunction &MFParam) {
   MF = &MFParam;
   MRI = &MF->getRegInfo();
   TII = MF->getSubtarget<PPCSubtarget>().getInstrInfo();
-  MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
+  MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
 
   AllCRLogicalOps.clear();
 }
diff --git a/llvm/test/CodeGen/Generic/MachineBranchProb.ll b/llvm/test/CodeGen/Generic/MachineBranchProb.ll
index fa39e7182cef6..9a5ea0c5e13cc 100644
--- a/llvm/test/CodeGen/Generic/MachineBranchProb.ll
+++ b/llvm/test/CodeGen/Generic/MachineBranchProb.ll
@@ -1,5 +1,4 @@
 ; RUN: llc < %s -print-after=finalize-isel -o /dev/null 2>&1 | FileCheck %s
-; RUN: llc %s -stop-after=finalize-isel -o - | llc -passes='print<machine-branch-prob>' -x mir -filetype=null 2>&1 | FileCheck -check-prefix=NPM %s
 
 ; Hexagon runs passes that renumber the basic blocks, causing this test
 ; to fail.
@@ -28,10 +27,6 @@ entry:
 ; CHECK: bb.6.entry:
 ; CHECK: successors: %bb.1(0x2e8ba2d7), %bb.3(0x51745d29)
 
-; NPM: Printing analysis 'Machine Branch Probability Analysis' for machine function 'test2':
-; NPM: edge %bb.4 -> %bb.6 probability is 0x80000000 / 0x80000000 = 100.00% [HOT edge]
-; NPM: edge %bb.5 -> %bb.6 probability is 0x80000000 / 0x80000000 = 100.00% [HOT edge]
-
 sw.bb:
 ; this call will prevent simplifyCFG from optimizing the block away in ARM/AArch64.
   tail call void @foo()

>From b8b5abe917ad2038286730b644252f1d3cab7e57 Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Thu, 27 Jun 2024 10:02:17 +0300
Subject: [PATCH 18/19] [PAC][AArch64] Lower ptrauth constants in code (#94241)

Depends on #94240.

Define the following pseudos for lowering ptrauth constants in code:

- non-`extern_weak`:
  - no GOT load needed: `MOVaddrPAC` - similar to `MOVaddr`, with added
    PAC;
  - GOT load needed: `LOADgotPAC` - similar to `LOADgot`, with added PAC;
- `extern_weak`: `LOADauthptrstatic` - similar to `LOADgot`, but use a
  special stub slot named `sym$auth_ptr$key$disc` filled by dynamic linker
  during relocation resolving instead of a GOT slot.

---------

Co-authored-by: Ahmed Bougacha <ahmed at bougacha.org>
---
 llvm/docs/GlobalISel/GenericOpcode.rst        |  11 +
 .../CodeGen/GlobalISel/MachineIRBuilder.h     |   7 +
 llvm/include/llvm/CodeGen/ISDOpcodes.h        |   6 +
 .../llvm/CodeGen/MachineModuleInfoImpls.h     |  20 ++
 llvm/include/llvm/Support/TargetOpcodes.def   |   3 +
 llvm/include/llvm/Target/GenericOpcodes.td    |   6 +
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |   6 +-
 .../CodeGen/GlobalISel/MachineIRBuilder.cpp   |  13 +
 llvm/lib/CodeGen/MachineModuleInfoImpls.cpp   |  23 ++
 llvm/lib/CodeGen/MachineVerifier.cpp          |   6 +
 .../SelectionDAG/SelectionDAGBuilder.cpp      |   7 +
 .../SelectionDAG/SelectionDAGDumper.cpp       |   4 +-
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 252 ++++++++++++++++++
 .../Target/AArch64/AArch64ISelLowering.cpp    | 132 +++++++++
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |   6 +
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |  32 +++
 .../AArch64/AArch64TargetObjectFile.cpp       |  37 +++
 .../Target/AArch64/AArch64TargetObjectFile.h  |   6 +
 .../GISel/AArch64InstructionSelector.cpp      | 144 ++++++++++
 .../AArch64/GISel/AArch64LegalizerInfo.cpp    |   3 +
 .../GlobalISel/legalizer-info-validation.mir  |   4 +
 .../GlobalISel/ptrauth-constant-in-code.ll    | 235 ++++++++++++++++
 .../AArch64/ptrauth-constant-in-code.ll       | 230 ++++++++++++++++
 .../match-table-cxx.td                        |   2 +-
 .../match-table-variadics.td                  |   2 +-
 .../GlobalISelCombinerEmitter/match-table.td  |  62 ++---
 llvm/test/TableGen/GlobalISelEmitter.td       |   2 +-
 27 files changed, 1224 insertions(+), 37 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
 create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll

diff --git a/llvm/docs/GlobalISel/GenericOpcode.rst b/llvm/docs/GlobalISel/GenericOpcode.rst
index 42f56348885b4..b05394aeee003 100644
--- a/llvm/docs/GlobalISel/GenericOpcode.rst
+++ b/llvm/docs/GlobalISel/GenericOpcode.rst
@@ -60,6 +60,17 @@ The address of a global value.
 
   %0(p0) = G_GLOBAL_VALUE @var_local
 
+G_PTRAUTH_GLOBAL_VALUE
+^^^^^^^^^^^^^^^^^^^^^^
+
+The signed address of a global value. Operands: address to be signed (pointer),
+key (32-bit imm), address for address discrimination (zero if not needed) and
+an extra discriminator (64-bit imm).
+
+.. code-block:: none
+
+  %0:_(p0) = G_PTRAUTH_GLOBAL_VALUE %1:_(p0), s32, %2:_(p0), s64
+
 G_BLOCK_ADDR
 ^^^^^^^^^^^^
 
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index a95ed3109feb8..954511eb731fa 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -886,6 +886,13 @@ class MachineIRBuilder {
   MachineInstrBuilder buildFConstant(const DstOp &Res, double Val);
   MachineInstrBuilder buildFConstant(const DstOp &Res, const APFloat &Val);
 
+  /// Build and insert G_PTRAUTH_GLOBAL_VALUE
+  ///
+  /// \return a MachineInstrBuilder for the newly created instruction.
+  MachineInstrBuilder buildConstantPtrAuth(const DstOp &Res,
+                                           const ConstantPtrAuth *CPA,
+                                           Register Addr, Register AddrDisc);
+
   /// Build and insert \p Res = COPY Op
   ///
   /// Register-to-register COPY sets \p Res to \p Op.
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 6bb89fb58a296..88e3339e2453f 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -83,6 +83,12 @@ enum NodeType {
   ExternalSymbol,
   BlockAddress,
 
+  /// A ptrauth constant.
+  /// ptr, key, addr-disc, disc
+  /// Note that the addr-disc can be a non-constant value, to allow representing
+  /// a constant global address signed using address-diversification, in code.
+  PtrAuthGlobalAddress,
+
   /// The address of the GOT
   GLOBAL_OFFSET_TABLE,
 
diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h b/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
index f8a328f13eded..64d841d86c7c4 100644
--- a/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
+++ b/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h
@@ -61,10 +61,20 @@ class MachineModuleInfoMachO : public MachineModuleInfoImpl {
 /// MachineModuleInfoELF - This is a MachineModuleInfoImpl implementation
 /// for ELF targets.
 class MachineModuleInfoELF : public MachineModuleInfoImpl {
+public:
+  struct AuthStubInfo {
+    const MCExpr *AuthPtrRef;
+  };
+
+private:
   /// GVStubs - These stubs are used to materialize global addresses in PIC
   /// mode.
   DenseMap<MCSymbol *, StubValueTy> GVStubs;
 
+  /// AuthPtrStubs - These stubs are used to materialize signed addresses for
+  /// extern_weak symbols.
+  DenseMap<MCSymbol *, AuthStubInfo> AuthPtrStubs;
+
   virtual void anchor(); // Out of line virtual method.
 
 public:
@@ -75,9 +85,19 @@ class MachineModuleInfoELF : public MachineModuleInfoImpl {
     return GVStubs[Sym];
   }
 
+  AuthStubInfo &getAuthPtrStubEntry(MCSymbol *Sym) {
+    assert(Sym && "Key cannot be null");
+    return AuthPtrStubs[Sym];
+  }
+
   /// Accessor methods to return the set of stubs in sorted order.
 
   SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); }
+
+  using AuthStubPairTy = std::pair<MCSymbol *, AuthStubInfo>;
+  typedef std::vector<AuthStubPairTy> AuthStubListTy;
+
+  AuthStubListTy getAuthGVStubList();
 };
 
 /// MachineModuleInfoCOFF - This is a MachineModuleInfoImpl implementation
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index df4b264af72a8..e7f40e87ed24a 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -294,6 +294,9 @@ HANDLE_TARGET_OPCODE(G_FRAME_INDEX)
 /// Generic reference to global value.
 HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE)
 
+/// Generic ptrauth-signed reference to global value.
+HANDLE_TARGET_OPCODE(G_PTRAUTH_GLOBAL_VALUE)
+
 /// Generic instruction to materialize the address of an object in the constant
 /// pool.
 HANDLE_TARGET_OPCODE(G_CONSTANT_POOL)
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index 4abffe6476c85..e1710ff2d8abf 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -110,6 +110,12 @@ def G_GLOBAL_VALUE : GenericInstruction {
   let hasSideEffects = false;
 }
 
+def G_PTRAUTH_GLOBAL_VALUE : GenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins unknown:$addr, i32imm:$key, type1:$addrdisc, i64imm:$disc);
+  let hasSideEffects = 0;
+}
+
 def G_CONSTANT_POOL : GenericInstruction {
   let OutOperandList = (outs type0:$dst);
   let InOperandList = (ins unknown:$src);
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index ddf6d3c20f022..c9986dfede1a1 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -3494,7 +3494,11 @@ bool IRTranslator::translate(const Constant &C, Register Reg) {
     EntryBuilder->buildConstant(Reg, 0);
   else if (auto GV = dyn_cast<GlobalValue>(&C))
     EntryBuilder->buildGlobalValue(Reg, GV);
-  else if (auto CAZ = dyn_cast<ConstantAggregateZero>(&C)) {
+  else if (auto CPA = dyn_cast<ConstantPtrAuth>(&C)) {
+    Register Addr = getOrCreateVReg(*CPA->getPointer());
+    Register AddrDisc = getOrCreateVReg(*CPA->getAddrDiscriminator());
+    EntryBuilder->buildConstantPtrAuth(Reg, CPA, Addr, AddrDisc);
+  } else if (auto CAZ = dyn_cast<ConstantAggregateZero>(&C)) {
     if (!isa<FixedVectorType>(CAZ->getType()))
       return false;
     // Return the scalar if it is a <1 x Ty> vector.
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index 37aa4e0aed7e8..06a6c1f93ef1f 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -397,6 +397,19 @@ MachineInstrBuilder MachineIRBuilder::buildFConstant(const DstOp &Res,
   return buildFConstant(Res, *CFP);
 }
 
+MachineInstrBuilder
+MachineIRBuilder::buildConstantPtrAuth(const DstOp &Res,
+                                       const ConstantPtrAuth *CPA,
+                                       Register Addr, Register AddrDisc) {
+  auto MIB = buildInstr(TargetOpcode::G_PTRAUTH_GLOBAL_VALUE);
+  Res.addDefToMIB(*getMRI(), MIB);
+  MIB.addUse(Addr);
+  MIB.addImm(CPA->getKey()->getZExtValue());
+  MIB.addUse(AddrDisc);
+  MIB.addImm(CPA->getDiscriminator()->getZExtValue());
+  return MIB;
+}
+
 MachineInstrBuilder MachineIRBuilder::buildBrCond(const SrcOp &Tst,
                                                   MachineBasicBlock &Dest) {
   assert(Tst.getLLTTy(*getMRI()).isScalar() && "invalid operand type");
diff --git a/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp b/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
index 9c3b31935f6d6..f114f1ecc0bae 100644
--- a/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp
@@ -13,6 +13,7 @@
 
 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/MC/MCSymbol.h"
 
 using namespace llvm;
@@ -41,3 +42,25 @@ MachineModuleInfoImpl::SymbolListTy MachineModuleInfoImpl::getSortedStubs(
   Map.clear();
   return List;
 }
+
+template <typename MachineModuleInfoTarget>
+static typename MachineModuleInfoTarget::AuthStubListTy getAuthGVStubListHelper(
+    DenseMap<MCSymbol *, typename MachineModuleInfoTarget::AuthStubInfo>
+        &AuthPtrStubs) {
+  typename MachineModuleInfoTarget::AuthStubListTy List(AuthPtrStubs.begin(),
+                                                        AuthPtrStubs.end());
+
+  if (!List.empty())
+    llvm::sort(List.begin(), List.end(),
+               [](const typename MachineModuleInfoTarget::AuthStubPairTy &LHS,
+                  const typename MachineModuleInfoTarget::AuthStubPairTy &RHS) {
+                 return LHS.first->getName() < RHS.first->getName();
+               });
+
+  AuthPtrStubs.clear();
+  return List;
+}
+
+MachineModuleInfoELF::AuthStubListTy MachineModuleInfoELF::getAuthGVStubList() {
+  return getAuthGVStubListHelper<MachineModuleInfoELF>(AuthPtrStubs);
+}
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 9ea238c61ed91..0c8a0f2b24a1e 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -2066,6 +2066,12 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
       report("Dst operand 0 must be a pointer", MI);
     break;
   }
+  case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE: {
+    const MachineOperand &AddrOp = MI->getOperand(1);
+    if (!AddrOp.isReg() || !MRI->getType(AddrOp.getReg()).isPointer())
+      report("addr operand must be a pointer", &AddrOp, 1);
+    break;
+  }
   default:
     break;
   }
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 296b06187ec0f..b2f9a9e1d58ef 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -1802,6 +1802,13 @@ SDValue SelectionDAGBuilder::getValueImpl(const Value *V) {
     if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
       return DAG.getGlobalAddress(GV, getCurSDLoc(), VT);
 
+    if (const ConstantPtrAuth *CPA = dyn_cast<ConstantPtrAuth>(C)) {
+      return DAG.getNode(ISD::PtrAuthGlobalAddress, getCurSDLoc(), VT,
+                         getValue(CPA->getPointer()), getValue(CPA->getKey()),
+                         getValue(CPA->getAddrDiscriminator()),
+                         getValue(CPA->getDiscriminator()));
+    }
+
     if (isa<ConstantPointerNull>(C)) {
       unsigned AS = V->getType()->getPointerAddressSpace();
       return DAG.getConstant(0, getCurSDLoc(),
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index a7555d6d31f26..c1d2c095b103c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -75,6 +75,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
     }
     return "<<Unknown Node #" + utostr(getOpcode()) + ">>";
 
+    // clang-format off
 #ifndef NDEBUG
   case ISD::DELETED_NODE:               return "<<Deleted Node!>>";
 #endif
@@ -126,6 +127,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
   case ISD::ConstantFP:                 return "ConstantFP";
   case ISD::GlobalAddress:              return "GlobalAddress";
   case ISD::GlobalTLSAddress:           return "GlobalTLSAddress";
+  case ISD::PtrAuthGlobalAddress:       return "PtrAuthGlobalAddress";
   case ISD::FrameIndex:                 return "FrameIndex";
   case ISD::JumpTable:                  return "JumpTable";
   case ISD::JUMP_TABLE_DEBUG_INFO:
@@ -168,8 +170,6 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
       return "OpaqueTargetConstant";
     return "TargetConstant";
 
-    // clang-format off
-
   case ISD::TargetConstantFP:           return "TargetConstantFP";
   case ISD::TargetGlobalAddress:        return "TargetGlobalAddress";
   case ISD::TargetGlobalTLSAddress:     return "TargetGlobalTLSAddress";
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index da11539eab348..611c3b579ff15 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -133,6 +133,13 @@ class AArch64AsmPrinter : public AsmPrinter {
   unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc,
                                     unsigned &InstsEmitted);
 
+  // Emit the sequence for LOADauthptrstatic
+  void LowerLOADauthptrstatic(const MachineInstr &MI);
+
+  // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or
+  // adrp-add followed by PAC sign)
+  void LowerMOVaddrPAC(const MachineInstr &MI);
+
   /// tblgen'erated driver function for lowering simple MI->MC
   /// pseudo instructions.
   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
@@ -840,6 +847,15 @@ void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) {
   }
 }
 
+template <typename MachineModuleInfoTarget>
+static void emitAuthenticatedPointer(
+    MCStreamer &OutStreamer, MCSymbol *StubLabel,
+    const typename MachineModuleInfoTarget::AuthStubInfo &StubInfo) {
+  // sym$auth_ptr$key$disc:
+  OutStreamer.emitLabel(StubLabel);
+  OutStreamer.emitValue(StubInfo.AuthPtrRef, /*size=*/8);
+}
+
 void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
   emitHwasanMemaccessSymbols(M);
 
@@ -853,6 +869,25 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) {
     OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);
   }
 
+  if (TT.isOSBinFormatELF()) {
+    // Output authenticated pointers as indirect symbols, if we have any.
+    MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
+
+    auto Stubs = MMIELF.getAuthGVStubList();
+
+    if (!Stubs.empty()) {
+      const TargetLoweringObjectFile &TLOF = getObjFileLowering();
+      OutStreamer->switchSection(TLOF.getDataSection());
+      emitAlignment(Align(8));
+
+      for (const auto &Stub : Stubs)
+        emitAuthenticatedPointer<MachineModuleInfoELF>(*OutStreamer, Stub.first,
+                                                       Stub.second);
+
+      OutStreamer->addBlankLine();
+    }
+  }
+
   // Emit stack and fault map information.
   FM.serializeToFaultMapSection();
 
@@ -1623,6 +1658,214 @@ AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) {
                                    CPA.hasAddressDiscriminator(), Ctx);
 }
 
+void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) {
+  unsigned DstReg = MI.getOperand(0).getReg();
+  const MachineOperand &GAOp = MI.getOperand(1);
+  const uint64_t KeyC = MI.getOperand(2).getImm();
+  assert(KeyC <= AArch64PACKey::LAST &&
+         "key is out of range [0, AArch64PACKey::LAST]");
+  const auto Key = (AArch64PACKey::ID)KeyC;
+  const uint64_t Disc = MI.getOperand(3).getImm();
+  assert(isUInt<16>(Disc) &&
+         "constant discriminator is out of range [0, 0xffff]");
+
+  // Emit instruction sequence like the following:
+  //   ADRP x16, symbol$auth_ptr$key$disc
+  //   LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc]
+  //
+  // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer
+  // to symbol.
+  assert(TM.getTargetTriple().isOSBinFormatELF() &&
+         "LOADauthptrstatic is implemented only for ELF");
+  const auto &TLOF =
+      static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering());
+
+  assert(GAOp.getOffset() == 0 &&
+         "non-zero offset for $auth_ptr$ stub slots is not supported");
+  const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal());
+  MCSymbol *AuthPtrStubSym =
+      TLOF.getAuthPtrSlotSymbol(TM, &MF->getMMI(), GASym, Key, Disc);
+
+  MachineOperand StubMOHi =
+      MachineOperand::CreateMCSymbol(AuthPtrStubSym, AArch64II::MO_PAGE);
+  MachineOperand StubMOLo = MachineOperand::CreateMCSymbol(
+      AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+  MCOperand StubMCHi, StubMCLo;
+
+  MCInstLowering.lowerOperand(StubMOHi, StubMCHi);
+  MCInstLowering.lowerOperand(StubMOLo, StubMCLo);
+
+  EmitToStreamer(
+      *OutStreamer,
+      MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi));
+
+  EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui)
+                                   .addReg(DstReg)
+                                   .addReg(DstReg)
+                                   .addOperand(StubMCLo));
+}
+
+void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) {
+  unsigned InstsEmitted = 0;
+  auto EmitAndIncrement = [this, &InstsEmitted](const MCInst &Inst) {
+    EmitToStreamer(*OutStreamer, Inst);
+    ++InstsEmitted;
+  };
+
+  const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC;
+  MachineOperand GAOp = MI.getOperand(0);
+  const uint64_t KeyC = MI.getOperand(1).getImm();
+  assert(KeyC <= AArch64PACKey::LAST &&
+         "key is out of range [0, AArch64PACKey::LAST]");
+  const auto Key = (AArch64PACKey::ID)KeyC;
+  const unsigned AddrDisc = MI.getOperand(2).getReg();
+  const uint64_t Disc = MI.getOperand(3).getImm();
+  assert(isUInt<16>(Disc) &&
+         "constant discriminator is out of range [0, 0xffff]");
+
+  const int64_t Offset = GAOp.getOffset();
+  GAOp.setOffset(0);
+
+  // Emit:
+  // target materialization:
+  // - via GOT:
+  //     adrp x16, :got:target
+  //     ldr x16, [x16, :got_lo12:target]
+  //     add offset to x16 if offset != 0
+  //
+  // - direct:
+  //     adrp x16, target
+  //     add x16, x16, :lo12:target
+  //     add offset to x16 if offset != 0
+  //
+  // add offset to x16:
+  // - abs(offset) fits 24 bits:
+  //     add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions)
+  // - abs(offset) does not fit 24 bits:
+  //   - offset < 0:
+  //       movn+movk sequence filling x17 register with the offset (up to 4
+  //       instructions)
+  //       add x16, x16, x17
+  //   - offset > 0:
+  //       movz+movk sequence filling x17 register with the offset (up to 4
+  //       instructions)
+  //       add x16, x16, x17
+  //
+  // signing:
+  // - 0 discriminator:
+  //     paciza x16
+  // - Non-0 discriminator, no address discriminator:
+  //     mov x17, #Disc
+  //     pacia x16, x17
+  // - address discriminator (with potentially folded immediate discriminator):
+  //     pacia x16, xAddrDisc
+
+  MachineOperand GAMOHi(GAOp), GAMOLo(GAOp);
+  MCOperand GAMCHi, GAMCLo;
+
+  GAMOHi.setTargetFlags(AArch64II::MO_PAGE);
+  GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC);
+  if (IsGOTLoad) {
+    GAMOHi.addTargetFlag(AArch64II::MO_GOT);
+    GAMOLo.addTargetFlag(AArch64II::MO_GOT);
+  }
+
+  MCInstLowering.lowerOperand(GAMOHi, GAMCHi);
+  MCInstLowering.lowerOperand(GAMOLo, GAMCLo);
+
+  EmitAndIncrement(
+      MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi));
+
+  if (IsGOTLoad) {
+    EmitAndIncrement(MCInstBuilder(AArch64::LDRXui)
+                         .addReg(AArch64::X16)
+                         .addReg(AArch64::X16)
+                         .addOperand(GAMCLo));
+  } else {
+    EmitAndIncrement(MCInstBuilder(AArch64::ADDXri)
+                         .addReg(AArch64::X16)
+                         .addReg(AArch64::X16)
+                         .addOperand(GAMCLo)
+                         .addImm(0));
+  }
+
+  if (Offset != 0) {
+    const uint64_t AbsOffset = (Offset > 0 ? Offset : -((uint64_t)Offset));
+    const bool IsNeg = Offset < 0;
+    if (isUInt<24>(AbsOffset)) {
+      for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos);
+           BitPos += 12) {
+        EmitAndIncrement(
+            MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri)
+                .addReg(AArch64::X16)
+                .addReg(AArch64::X16)
+                .addImm((AbsOffset >> BitPos) & 0xfff)
+                .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos)));
+      }
+    } else {
+      constexpr uint64_t Mask16 = 0xffff;
+      const uint64_t UOffset = Offset;
+      EmitAndIncrement(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi)
+                           .addReg(AArch64::X17)
+                           .addImm((IsNeg ? ~UOffset : UOffset) & Mask16)
+                           .addImm(/*shift=*/0));
+      auto NeedMovk = [Mask16, IsNeg, UOffset](int BitPos) -> bool {
+        assert(BitPos == 16 || BitPos == 32 || BitPos == 48);
+        uint64_t Shifted = UOffset >> BitPos;
+        if (!IsNeg)
+          return Shifted != 0;
+        for (int I = 0; I != 64 - BitPos; I += 16)
+          if (((Shifted >> I) & Mask16) != Mask16)
+            return true;
+        return false;
+      };
+      for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) {
+        EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
+                             .addReg(AArch64::X17)
+                             .addReg(AArch64::X17)
+                             .addImm((UOffset >> BitPos) & Mask16)
+                             .addImm(/*shift=*/BitPos));
+      }
+      EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs)
+                           .addReg(AArch64::X16)
+                           .addReg(AArch64::X16)
+                           .addReg(AArch64::X17)
+                           .addImm(/*shift=*/0));
+    }
+  }
+
+  unsigned DiscReg = AddrDisc;
+  if (Disc != 0) {
+    if (AddrDisc != AArch64::XZR) {
+      EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs)
+                           .addReg(AArch64::X17)
+                           .addReg(AArch64::XZR)
+                           .addReg(AddrDisc)
+                           .addImm(0));
+      EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi)
+                           .addReg(AArch64::X17)
+                           .addReg(AArch64::X17)
+                           .addImm(Disc)
+                           .addImm(/*shift=*/48));
+    } else {
+      EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi)
+                           .addReg(AArch64::X17)
+                           .addImm(Disc)
+                           .addImm(/*shift=*/0));
+    }
+    DiscReg = AArch64::X17;
+  }
+
+  auto MIB = MCInstBuilder(getPACOpcodeForKey(Key, DiscReg == AArch64::XZR))
+                 .addReg(AArch64::X16)
+                 .addReg(AArch64::X16);
+  if (DiscReg != AArch64::XZR)
+    MIB.addReg(DiscReg);
+  EmitAndIncrement(MIB);
+
+  assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4);
+}
+
 // Simple pseudo-instructions have their lowering (with expansion to real
 // instructions) auto-generated.
 #include "AArch64GenMCPseudoLowering.inc"
@@ -1758,6 +2001,15 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
     return;
   }
 
+  case AArch64::LOADauthptrstatic:
+    LowerLOADauthptrstatic(*MI);
+    return;
+
+  case AArch64::LOADgotPAC:
+  case AArch64::MOVaddrPAC:
+    LowerMOVaddrPAC(*MI);
+    return;
+
   case AArch64::BLRA:
     emitPtrauthBranch(MI);
     return;
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 81132572e820b..b820a850cd467 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -511,6 +511,8 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::JumpTable, MVT::i64, Custom);
   setOperationAction(ISD::SETCCCARRY, MVT::i64, Custom);
 
+  setOperationAction(ISD::PtrAuthGlobalAddress, MVT::i64, Custom);
+
   setOperationAction(ISD::SHL_PARTS, MVT::i64, Custom);
   setOperationAction(ISD::SRA_PARTS, MVT::i64, Custom);
   setOperationAction(ISD::SRL_PARTS, MVT::i64, Custom);
@@ -6667,6 +6669,8 @@ SDValue AArch64TargetLowering::LowerOperation(SDValue Op,
     return LowerGlobalAddress(Op, DAG);
   case ISD::GlobalTLSAddress:
     return LowerGlobalTLSAddress(Op, DAG);
+  case ISD::PtrAuthGlobalAddress:
+    return LowerPtrAuthGlobalAddress(Op, DAG);
   case ISD::SETCC:
   case ISD::STRICT_FSETCC:
   case ISD::STRICT_FSETCCS:
@@ -9517,6 +9521,134 @@ SDValue AArch64TargetLowering::LowerGlobalTLSAddress(SDValue Op,
   llvm_unreachable("Unexpected platform trying to use TLS");
 }
 
+//===----------------------------------------------------------------------===//
+//                      PtrAuthGlobalAddress lowering
+//
+// We have 3 lowering alternatives to choose from:
+// - MOVaddrPAC: similar to MOVaddr, with added PAC.
+//   If the GV doesn't need a GOT load (i.e., is locally defined)
+//   materialize the pointer using adrp+add+pac. See LowerMOVaddrPAC.
+//
+// - LOADgotPAC: similar to LOADgot, with added PAC.
+//   If the GV needs a GOT load, materialize the pointer using the usual
+//   GOT adrp+ldr, +pac. Pointers in GOT are assumed to be not signed, the GOT
+//   section is assumed to be read-only (for example, via relro mechanism). See
+//   LowerMOVaddrPAC.
+//
+// - LOADauthptrstatic: similar to LOADgot, but use a
+//   special stub slot instead of a GOT slot.
+//   Load a signed pointer for symbol 'sym' from a stub slot named
+//   'sym$auth_ptr$key$disc' filled by dynamic linker during relocation
+//   resolving. This usually lowers to adrp+ldr, but also emits an entry into
+//   .data with an
+//   @AUTH relocation. See LowerLOADauthptrstatic.
+//
+// All 3 are pseudos that are expand late to longer sequences: this lets us
+// provide integrity guarantees on the to-be-signed intermediate values.
+//
+// LOADauthptrstatic is undesirable because it requires a large section filled
+// with often similarly-signed pointers, making it a good harvesting target.
+// Thus, it's only used for ptrauth references to extern_weak to avoid null
+// checks.
+
+SDValue AArch64TargetLowering::LowerPtrAuthGlobalAddressStatically(
+    SDValue TGA, SDLoc DL, EVT VT, AArch64PACKey::ID KeyC,
+    SDValue Discriminator, SDValue AddrDiscriminator, SelectionDAG &DAG) const {
+  const auto *TGN = cast<GlobalAddressSDNode>(TGA.getNode());
+  const GlobalValue *GV = TGN->getGlobal();
+  assert(GV->hasExternalWeakLinkage());
+
+  // Offsets and extern_weak don't mix well: ptrauth aside, you'd get the
+  // offset alone as a pointer if the symbol wasn't available, which would
+  // probably break null checks in users. Ptrauth complicates things further:
+  // error out.
+  if (TGN->getOffset() != 0)
+    report_fatal_error(
+        "unsupported non-zero offset in weak ptrauth global reference");
+
+  if (!isNullConstant(AddrDiscriminator))
+    report_fatal_error("unsupported weak addr-div ptrauth global");
+
+  SDValue Key = DAG.getTargetConstant(KeyC, DL, MVT::i32);
+  return SDValue(DAG.getMachineNode(AArch64::LOADauthptrstatic, DL, MVT::i64,
+                                    {TGA, Key, Discriminator}),
+                 0);
+}
+
+SDValue
+AArch64TargetLowering::LowerPtrAuthGlobalAddress(SDValue Op,
+                                                 SelectionDAG &DAG) const {
+  SDValue Ptr = Op.getOperand(0);
+  uint64_t KeyC = Op.getConstantOperandVal(1);
+  SDValue AddrDiscriminator = Op.getOperand(2);
+  uint64_t DiscriminatorC = Op.getConstantOperandVal(3);
+  EVT VT = Op.getValueType();
+  SDLoc DL(Op);
+
+  if (KeyC > AArch64PACKey::LAST)
+    report_fatal_error("key in ptrauth global out of range [0, " +
+                       Twine((int)AArch64PACKey::LAST) + "]");
+
+  // Blend only works if the integer discriminator is 16-bit wide.
+  if (!isUInt<16>(DiscriminatorC))
+    report_fatal_error(
+        "constant discriminator in ptrauth global out of range [0, 0xffff]");
+
+  // Choosing between 3 lowering alternatives is target-specific.
+  if (!Subtarget->isTargetELF())
+    report_fatal_error("ptrauth global lowering is only implemented for ELF");
+
+  int64_t PtrOffsetC = 0;
+  if (Ptr.getOpcode() == ISD::ADD) {
+    PtrOffsetC = Ptr.getConstantOperandVal(1);
+    Ptr = Ptr.getOperand(0);
+  }
+  const auto *PtrN = cast<GlobalAddressSDNode>(Ptr.getNode());
+  const GlobalValue *PtrGV = PtrN->getGlobal();
+
+  // Classify the reference to determine whether it needs a GOT load.
+  const unsigned OpFlags =
+      Subtarget->ClassifyGlobalReference(PtrGV, getTargetMachine());
+  const bool NeedsGOTLoad = ((OpFlags & AArch64II::MO_GOT) != 0);
+  assert(((OpFlags & (~AArch64II::MO_GOT)) == 0) &&
+         "unsupported non-GOT op flags on ptrauth global reference");
+
+  // Fold any offset into the GV; our pseudos expect it there.
+  PtrOffsetC += PtrN->getOffset();
+  SDValue TPtr = DAG.getTargetGlobalAddress(PtrGV, DL, VT, PtrOffsetC,
+                                            /*TargetFlags=*/0);
+  assert(PtrN->getTargetFlags() == 0 &&
+         "unsupported target flags on ptrauth global");
+
+  SDValue Key = DAG.getTargetConstant(KeyC, DL, MVT::i32);
+  SDValue Discriminator = DAG.getTargetConstant(DiscriminatorC, DL, MVT::i64);
+  SDValue TAddrDiscriminator = !isNullConstant(AddrDiscriminator)
+                                   ? AddrDiscriminator
+                                   : DAG.getRegister(AArch64::XZR, MVT::i64);
+
+  // No GOT load needed -> MOVaddrPAC
+  if (!NeedsGOTLoad) {
+    assert(!PtrGV->hasExternalWeakLinkage() && "extern_weak should use GOT");
+    return SDValue(
+        DAG.getMachineNode(AArch64::MOVaddrPAC, DL, MVT::i64,
+                           {TPtr, Key, TAddrDiscriminator, Discriminator}),
+        0);
+  }
+
+  // GOT load -> LOADgotPAC
+  // Note that we disallow extern_weak refs to avoid null checks later.
+  if (!PtrGV->hasExternalWeakLinkage())
+    return SDValue(
+        DAG.getMachineNode(AArch64::LOADgotPAC, DL, MVT::i64,
+                           {TPtr, Key, TAddrDiscriminator, Discriminator}),
+        0);
+
+  // extern_weak ref -> LOADauthptrstatic
+  return LowerPtrAuthGlobalAddressStatically(
+      TPtr, DL, VT, (AArch64PACKey::ID)KeyC, Discriminator, AddrDiscriminator,
+      DAG);
+}
+
 // Looks through \param Val to determine the bit that can be used to
 // check the sign of the value. It returns the unextended value and
 // the sign bit position.
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 5200b24d1388a..047c852bb01d2 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -1127,6 +1127,12 @@ class AArch64TargetLowering : public TargetLowering {
   SDValue LowerELFTLSDescCallSeq(SDValue SymAddr, const SDLoc &DL,
                                  SelectionDAG &DAG) const;
   SDValue LowerWindowsGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerPtrAuthGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerPtrAuthGlobalAddressStatically(SDValue TGA, SDLoc DL, EVT VT,
+                                              AArch64PACKey::ID Key,
+                                              SDValue Discriminator,
+                                              SDValue AddrDiscriminator,
+                                              SelectionDAG &DAG) const;
   SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerSETCCCARRY(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f3aac3b46d173..1e06d5fdc7562 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -1765,6 +1765,38 @@ let Predicates = [HasPAuth] in {
   defm LDRAA  : AuthLoad<0, "ldraa", simm10Scaled>;
   defm LDRAB  : AuthLoad<1, "ldrab", simm10Scaled>;
 
+  // Materialize a signed global address, with adrp+add and PAC.
+  def MOVaddrPAC : Pseudo<(outs),
+                          (ins i64imm:$Addr, i32imm:$Key,
+                               GPR64noip:$AddrDisc, i64imm:$Disc), []>,
+               Sched<[WriteI, ReadI]> {
+    let isReMaterializable = 1;
+    let isCodeGenOnly = 1;
+    let Size = 40; // 12 fixed + 28 variable, for pointer offset, and discriminator
+    let Defs = [X16,X17];
+  }
+
+  // Materialize a signed global address, using a GOT load and PAC.
+  def LOADgotPAC : Pseudo<(outs),
+                          (ins i64imm:$Addr, i32imm:$Key,
+                               GPR64noip:$AddrDisc, i64imm:$Disc), []>,
+               Sched<[WriteI, ReadI]> {
+    let isReMaterializable = 1;
+    let isCodeGenOnly = 1;
+    let Size = 40; // 12 fixed + 28 variable, for pointer offset, and discriminator
+    let Defs = [X16,X17];
+  }
+
+  // Load a signed global address from a special $auth_ptr$ stub slot.
+  def LOADauthptrstatic : Pseudo<(outs GPR64:$dst),
+                              (ins i64imm:$Addr, i32imm:$Key,
+                                   i64imm:$Disc), []>,
+               Sched<[WriteI, ReadI]> {
+    let isReMaterializable = 1;
+    let isCodeGenOnly = 1;
+    let Size = 8;
+  }
+
   // Size 16: 4 fixed + 8 variable, to compute discriminator.
   let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Size = 16,
       Uses = [SP] in {
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index e5c6b6d60d068..1c1e87d723ac7 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -8,7 +8,10 @@
 
 #include "AArch64TargetObjectFile.h"
 #include "AArch64TargetMachine.h"
+#include "MCTargetDesc/AArch64MCExpr.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
@@ -88,3 +91,37 @@ void AArch64_MachoTargetObjectFile::getNameWithPrefix(
   // be accessed via at least a linker-private symbol.
   getMangler().getNameWithPrefix(OutName, GV, /* CannotUsePrivateLabel */ true);
 }
+
+template <typename MachineModuleInfoTarget>
+static MCSymbol *getAuthPtrSlotSymbolHelper(
+    MCContext &Ctx, const TargetMachine &TM, MachineModuleInfo *MMI,
+    MachineModuleInfoTarget &TargetMMI, const MCSymbol *RawSym,
+    AArch64PACKey::ID Key, uint16_t Discriminator) {
+  const DataLayout &DL = MMI->getModule()->getDataLayout();
+
+  MCSymbol *StubSym = Ctx.getOrCreateSymbol(
+      DL.getLinkerPrivateGlobalPrefix() + RawSym->getName() +
+      Twine("$auth_ptr$") + AArch64PACKeyIDToString(Key) + Twine('$') +
+      Twine(Discriminator));
+
+  typename MachineModuleInfoTarget::AuthStubInfo &StubInfo =
+      TargetMMI.getAuthPtrStubEntry(StubSym);
+
+  if (StubInfo.AuthPtrRef)
+    return StubSym;
+
+  const MCExpr *Sym = MCSymbolRefExpr::create(RawSym, Ctx);
+
+  StubInfo.AuthPtrRef =
+      AArch64AuthMCExpr::create(Sym, Discriminator, Key,
+                                /*HasAddressDiversity=*/false, Ctx);
+  return StubSym;
+}
+
+MCSymbol *AArch64_ELFTargetObjectFile::getAuthPtrSlotSymbol(
+    const TargetMachine &TM, MachineModuleInfo *MMI, const MCSymbol *RawSym,
+    AArch64PACKey::ID Key, uint16_t Discriminator) const {
+  auto &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
+  return getAuthPtrSlotSymbolHelper(getContext(), TM, MMI, ELFMMI, RawSym, Key,
+                                    Discriminator);
+}
diff --git a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
index 7cd56fc9a189d..c5ebf03c39c77 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/llvm/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64TARGETOBJECTFILE_H
 #define LLVM_LIB_TARGET_AARCH64_AARCH64TARGETOBJECTFILE_H
 
+#include "Utils/AArch64BaseInfo.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/Target/TargetLoweringObjectFile.h"
 
@@ -29,6 +30,11 @@ class AArch64_ELFTargetObjectFile : public TargetLoweringObjectFileELF {
                                           const MCValue &MV, int64_t Offset,
                                           MachineModuleInfo *MMI,
                                           MCStreamer &Streamer) const override;
+
+  MCSymbol *getAuthPtrSlotSymbol(const TargetMachine &TM,
+                                 MachineModuleInfo *MMI, const MCSymbol *RawSym,
+                                 AArch64PACKey::ID Key,
+                                 uint16_t Discriminator) const;
 };
 
 /// AArch64_MachoTargetObjectFile - This TLOF implementation is used for Darwin.
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 0357a7206c478..9e0860934f777 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -224,6 +224,8 @@ class AArch64InstructionSelector : public InstructionSelector {
   bool selectJumpTable(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectBrJT(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectTLSGlobalValue(MachineInstr &I, MachineRegisterInfo &MRI);
+  bool selectPtrAuthGlobalValue(MachineInstr &I,
+                                MachineRegisterInfo &MRI) const;
   bool selectReduction(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectMOPS(MachineInstr &I, MachineRegisterInfo &MRI);
   bool selectUSMovFromExtend(MachineInstr &I, MachineRegisterInfo &MRI);
@@ -2848,6 +2850,9 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
     return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
   }
 
+  case TargetOpcode::G_PTRAUTH_GLOBAL_VALUE:
+    return selectPtrAuthGlobalValue(I, MRI);
+
   case TargetOpcode::G_ZEXTLOAD:
   case TargetOpcode::G_LOAD:
   case TargetOpcode::G_STORE: {
@@ -6583,6 +6588,145 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
   return false;
 }
 
+// G_PTRAUTH_GLOBAL_VALUE lowering
+//
+// We have 3 lowering alternatives to choose from:
+// - MOVaddrPAC: similar to MOVaddr, with added PAC.
+//   If the GV doesn't need a GOT load (i.e., is locally defined)
+//   materialize the pointer using adrp+add+pac. See LowerMOVaddrPAC.
+//
+// - LOADgotPAC: similar to LOADgot, with added PAC.
+//   If the GV needs a GOT load, materialize the pointer using the usual
+//   GOT adrp+ldr, +pac. Pointers in GOT are assumed to be not signed, the GOT
+//   section is assumed to be read-only (for example, via relro mechanism). See
+//   LowerMOVaddrPAC.
+//
+// - LOADauthptrstatic: similar to LOADgot, but use a
+//   special stub slot instead of a GOT slot.
+//   Load a signed pointer for symbol 'sym' from a stub slot named
+//   'sym$auth_ptr$key$disc' filled by dynamic linker during relocation
+//   resolving. This usually lowers to adrp+ldr, but also emits an entry into
+//   .data with an
+//   @AUTH relocation. See LowerLOADauthptrstatic.
+//
+// All 3 are pseudos that are expand late to longer sequences: this lets us
+// provide integrity guarantees on the to-be-signed intermediate values.
+//
+// LOADauthptrstatic is undesirable because it requires a large section filled
+// with often similarly-signed pointers, making it a good harvesting target.
+// Thus, it's only used for ptrauth references to extern_weak to avoid null
+// checks.
+
+bool AArch64InstructionSelector::selectPtrAuthGlobalValue(
+    MachineInstr &I, MachineRegisterInfo &MRI) const {
+  Register DefReg = I.getOperand(0).getReg();
+  Register Addr = I.getOperand(1).getReg();
+  uint64_t Key = I.getOperand(2).getImm();
+  Register AddrDisc = I.getOperand(3).getReg();
+  uint64_t Disc = I.getOperand(4).getImm();
+  int64_t Offset = 0;
+
+  if (Key > AArch64PACKey::LAST)
+    report_fatal_error("key in ptrauth global out of range [0, " +
+                       Twine((int)AArch64PACKey::LAST) + "]");
+
+  // Blend only works if the integer discriminator is 16-bit wide.
+  if (!isUInt<16>(Disc))
+    report_fatal_error(
+        "constant discriminator in ptrauth global out of range [0, 0xffff]");
+
+  // Choosing between 3 lowering alternatives is target-specific.
+  if (!STI.isTargetELF())
+    report_fatal_error("ptrauth global lowering is only implemented for ELF");
+
+  if (!MRI.hasOneDef(Addr))
+    return false;
+
+  // First match any offset we take from the real global.
+  const MachineInstr *DefMI = &*MRI.def_instr_begin(Addr);
+  if (DefMI->getOpcode() == TargetOpcode::G_PTR_ADD) {
+    Register OffsetReg = DefMI->getOperand(2).getReg();
+    if (!MRI.hasOneDef(OffsetReg))
+      return false;
+    const MachineInstr &OffsetMI = *MRI.def_instr_begin(OffsetReg);
+    if (OffsetMI.getOpcode() != TargetOpcode::G_CONSTANT)
+      return false;
+
+    Addr = DefMI->getOperand(1).getReg();
+    if (!MRI.hasOneDef(Addr))
+      return false;
+
+    DefMI = &*MRI.def_instr_begin(Addr);
+    Offset = OffsetMI.getOperand(1).getCImm()->getSExtValue();
+  }
+
+  // We should be left with a genuine unauthenticated GlobalValue.
+  const GlobalValue *GV;
+  if (DefMI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) {
+    GV = DefMI->getOperand(1).getGlobal();
+    Offset += DefMI->getOperand(1).getOffset();
+  } else if (DefMI->getOpcode() == AArch64::G_ADD_LOW) {
+    GV = DefMI->getOperand(2).getGlobal();
+    Offset += DefMI->getOperand(2).getOffset();
+  } else {
+    return false;
+  }
+
+  MachineIRBuilder MIB(I);
+
+  // Classify the reference to determine whether it needs a GOT load.
+  unsigned OpFlags = STI.ClassifyGlobalReference(GV, TM);
+  const bool NeedsGOTLoad = ((OpFlags & AArch64II::MO_GOT) != 0);
+  assert(((OpFlags & (~AArch64II::MO_GOT)) == 0) &&
+         "unsupported non-GOT op flags on ptrauth global reference");
+  assert((!GV->hasExternalWeakLinkage() || NeedsGOTLoad) &&
+         "unsupported non-GOT reference to weak ptrauth global");
+
+  std::optional<APInt> AddrDiscVal = getIConstantVRegVal(AddrDisc, MRI);
+  bool HasAddrDisc = !AddrDiscVal || *AddrDiscVal != 0;
+
+  // Non-extern_weak:
+  // - No GOT load needed -> MOVaddrPAC
+  // - GOT load for non-extern_weak -> LOADgotPAC
+  //   Note that we disallow extern_weak refs to avoid null checks later.
+  if (!GV->hasExternalWeakLinkage()) {
+    MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X16}, {});
+    MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
+    MIB.buildInstr(NeedsGOTLoad ? AArch64::LOADgotPAC : AArch64::MOVaddrPAC)
+        .addGlobalAddress(GV, Offset)
+        .addImm(Key)
+        .addReg(HasAddrDisc ? AddrDisc : AArch64::XZR)
+        .addImm(Disc)
+        .constrainAllUses(TII, TRI, RBI);
+    MIB.buildCopy(DefReg, Register(AArch64::X16));
+    RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
+    I.eraseFromParent();
+    return true;
+  }
+
+  // extern_weak -> LOADauthptrstatic
+
+  // Offsets and extern_weak don't mix well: ptrauth aside, you'd get the
+  // offset alone as a pointer if the symbol wasn't available, which would
+  // probably break null checks in users. Ptrauth complicates things further:
+  // error out.
+  if (Offset != 0)
+    report_fatal_error(
+        "unsupported non-zero offset in weak ptrauth global reference");
+
+  if (HasAddrDisc)
+    report_fatal_error("unsupported weak addr-div ptrauth global");
+
+  MIB.buildInstr(AArch64::LOADauthptrstatic, {DefReg}, {})
+      .addGlobalAddress(GV, Offset)
+      .addImm(Key)
+      .addImm(Disc);
+  RBI.constrainGenericRegister(DefReg, AArch64::GPR64RegClass, MRI);
+
+  I.eraseFromParent();
+  return true;
+}
+
 void AArch64InstructionSelector::SelectTable(MachineInstr &I,
                                              MachineRegisterInfo &MRI,
                                              unsigned NumVec, unsigned Opc1,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index fef0b722efe45..50ba3057928ee 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -760,6 +760,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
   else
     getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
 
+  getActionDefinitionsBuilder(G_PTRAUTH_GLOBAL_VALUE)
+      .legalIf(all(typeIs(0, p0), typeIs(1, p0)));
+
   getActionDefinitionsBuilder(G_PTRTOINT)
       .legalFor({{s64, p0}, {v2s64, v2p0}})
       .widenScalarToNextPow2(0, 64)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index f03491924f7f4..1f048528ea153 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -86,6 +86,10 @@
 # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
 #
+# DEBUG-NEXT: G_PTRAUTH_GLOBAL_VALUE (opcode {{[0-9]+}}): 2 type indices, 0 imm indices
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
+#
 # DEBUG-NEXT: G_CONSTANT_POOL (opcode {{[0-9]+}}): 1 type index, 0 imm indices
 # DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
 # DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
new file mode 100644
index 0000000000000..7b85b12bb8952
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
@@ -0,0 +1,235 @@
+; RUN: rm -rf %t && split-file %s %t && cd %t
+
+;--- err1.ll
+
+; RUN: not --crash llc < err1.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=1 -verify-machineinstrs -global-isel-abort=1 2>&1 | \
+; RUN:   FileCheck --check-prefix=ERR1 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR1: LLVM ERROR: key in ptrauth global out of range [0, 3]
+  ret ptr ptrauth (ptr @g, i32 4)
+}
+
+;--- err2.ll
+
+; RUN: not --crash llc < err2.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=1 -verify-machineinstrs -global-isel-abort=1 2>&1 | \
+; RUN:   FileCheck --check-prefix=ERR2 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR2: LLVM ERROR: constant discriminator in ptrauth global out of range [0, 0xffff]
+  ret ptr ptrauth (ptr @g, i32 2, i64 65536)
+}
+
+;--- err3.ll
+
+; RUN: not --crash llc < err3.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=1 -verify-machineinstrs -global-isel-abort=1 2>&1 | \
+; RUN:   FileCheck --check-prefix=ERR3 %s
+
+ at g_weak = extern_weak global i32
+
+define ptr @foo() {
+; ERR3: LLVM ERROR: unsupported non-zero offset in weak ptrauth global reference
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g_weak, i64 16), i32 2, i64 42)
+}
+
+;--- err4.ll
+
+; RUN: not --crash llc < err4.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=1 -verify-machineinstrs -global-isel-abort=1 2>&1 | \
+; RUN:   FileCheck --check-prefix=ERR4 %s
+
+ at g_weak = extern_weak global i32
+ at g_weak.ref.da.42.addr = dso_local constant ptr ptrauth (ptr @g_weak, i32 2, i64 42, ptr @g_weak.ref.da.42.addr)
+
+define ptr @foo() {
+; ERR4: LLVM ERROR: unsupported weak addr-div ptrauth global
+  ret ptr ptrauth (ptr @g_weak, i32 0, i64 42, ptr @g_weak.ref.da.42.addr)
+}
+
+;--- err5.ll
+
+; RUN: not --crash llc < err5.ll -mtriple arm64-apple-darwin -mattr=+pauth \
+; RUN:   -global-isel=1 -verify-machineinstrs -global-isel-abort=1 2>&1 | \
+; RUN:   FileCheck --check-prefix=ERR5 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR5: LLVM ERROR: ptrauth global lowering is only implemented for ELF
+  ret ptr ptrauth (ptr @g, i32 0)
+}
+
+;--- ok.ll
+
+; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 | FileCheck %s
+; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 -filetype=obj
+
+ at g = external global i32
+ at g_weak = extern_weak global i32
+ at g_strong_def = dso_local constant i32 42
+
+define ptr @test_global_zero_disc() {
+; CHECK-LABEL: test_global_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    paciza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 0)
+}
+
+define ptr @test_global_offset_zero_disc() {
+; CHECK-LABEL: test_global_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    add     x16, x16, #16
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 16), i32 2)
+}
+
+define ptr @test_global_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    sub     x16, x16, #576
+; CHECK-NEXT:    sub     x16, x16, #30, lsl #12
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -123456), i32 2)
+}
+
+define ptr @test_global_big_offset_zero_disc() {
+; CHECK-LABEL: test_global_big_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #1
+; CHECK-NEXT:    movk    x17, #32769, lsl #16
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 add (i64 2147483648, i64 65537)), i32 2)
+}
+
+define ptr @test_global_big_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_big_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #-52501
+; CHECK-NEXT:    movk    x17, #63652, lsl #16
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -123456789), i32 2)
+}
+
+define ptr @test_global_huge_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_huge_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #-65536
+; CHECK-NEXT:    movk    x17, #0, lsl #16
+; CHECK-NEXT:    movk    x17, #0, lsl #32
+; CHECK-NEXT:    movk    x17, #32768, lsl #48
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -9223372036854775808), i32 2)
+}
+
+define ptr @test_global_disc() {
+; CHECK-LABEL: test_global_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #42 // =0x2a
+; CHECK-NEXT:    pacia   x16, x17
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 0, i64 42)
+}
+
+ at g.ref.da.42.addr = dso_local constant ptr ptrauth (ptr @g, i32 2, i64 42, ptr @g.ref.da.42.addr)
+
+define ptr @test_global_addr_disc() {
+; CHECK-LABEL: test_global_addr_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp x8, g.ref.da.42.addr
+; CHECK-NEXT:    add x8, x8, :lo12:g.ref.da.42.addr
+; CHECK-NEXT:    adrp x16, :got:g
+; CHECK-NEXT:    ldr x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov x17, x8
+; CHECK-NEXT:    movk x17, #42, lsl #48
+; CHECK-NEXT:    pacda x16, x17
+; CHECK-NEXT:    mov x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 2, i64 42, ptr @g.ref.da.42.addr)
+}
+
+define ptr @test_global_process_specific() {
+; CHECK-LABEL: test_global_process_specific:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    pacizb  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g, i32 1)
+}
+
+; weak symbols can't be assumed to be non-nil. Use $auth_ptr$ stub slot always.
+; The alternative is to emit a null-check here, but that'd be redundant with
+; whatever null-check follows in user code.
+
+define ptr @test_global_weak() {
+; CHECK-LABEL: test_global_weak:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x0, g_weak$auth_ptr$ia$42
+; CHECK-NEXT:    ldr     x0, [x0, :lo12:g_weak$auth_ptr$ia$42]
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g_weak, i32 0, i64 42)
+}
+
+; Non-external symbols don't need to be accessed through the GOT.
+
+define ptr @test_global_strong_def() {
+; CHECK-LABEL: test_global_strong_def:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, g_strong_def
+; CHECK-NEXT:    add     x16, x16, :lo12:g_strong_def
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g_strong_def, i32 2)
+}
+
+; CHECK-LABEL: g_weak$auth_ptr$ia$42:
+; CHECK-NEXT:    .xword  g_weak at AUTH(ia,42)
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
new file mode 100644
index 0000000000000..73993fa87bf27
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
@@ -0,0 +1,230 @@
+; RUN: rm -rf %t && split-file %s %t && cd %t
+
+;--- err1.ll
+
+; RUN: not --crash llc < err1.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=0 -verify-machineinstrs 2>&1 | FileCheck --check-prefix=ERR1 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR1: LLVM ERROR: key in ptrauth global out of range [0, 3]
+  ret ptr ptrauth (ptr @g, i32 4)
+}
+
+;--- err2.ll
+
+; RUN: not --crash llc < err2.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=0 -verify-machineinstrs 2>&1 | FileCheck --check-prefix=ERR2 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR2: LLVM ERROR: constant discriminator in ptrauth global out of range [0, 0xffff]
+  ret ptr ptrauth (ptr @g, i32 2, i64 65536)
+}
+
+;--- err3.ll
+
+; RUN: not --crash llc < err3.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=0 -verify-machineinstrs 2>&1 | FileCheck --check-prefix=ERR3 %s
+
+ at g_weak = extern_weak global i32
+
+define ptr @foo() {
+; ERR3: LLVM ERROR: unsupported non-zero offset in weak ptrauth global reference
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g_weak, i64 16), i32 2, i64 42)
+}
+
+;--- err4.ll
+
+; RUN: not --crash llc < err4.ll -mtriple aarch64-elf -mattr=+pauth \
+; RUN:   -global-isel=0 -verify-machineinstrs 2>&1 | FileCheck --check-prefix=ERR4 %s
+
+ at g_weak = extern_weak global i32
+ at g_weak.ref.da.42.addr = dso_local constant ptr ptrauth (ptr @g_weak, i32 2, i64 42, ptr @g_weak.ref.da.42.addr)
+
+define ptr @foo() {
+; ERR4: LLVM ERROR: unsupported weak addr-div ptrauth global
+  ret ptr ptrauth (ptr @g_weak, i32 0, i64 42, ptr @g_weak.ref.da.42.addr)
+}
+
+;--- err5.ll
+
+; RUN: not --crash llc < err5.ll -mtriple arm64-apple-darwin -mattr=+pauth \
+; RUN:   -global-isel=0 -verify-machineinstrs 2>&1 | FileCheck --check-prefix=ERR5 %s
+
+ at g = external global i32
+
+define ptr @foo() {
+; ERR5: LLVM ERROR: ptrauth global lowering is only implemented for ELF
+  ret ptr ptrauth (ptr @g, i32 0)
+}
+
+;--- ok.ll
+
+; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs | FileCheck %s
+; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs -filetype=obj
+
+ at g = external global i32
+ at g_weak = extern_weak global i32
+ at g_strong_def = dso_local constant i32 42
+
+define ptr @test_global_zero_disc() {
+; CHECK-LABEL: test_global_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    paciza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 0)
+}
+
+define ptr @test_global_offset_zero_disc() {
+; CHECK-LABEL: test_global_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    add     x16, x16, #16
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 16), i32 2)
+}
+
+define ptr @test_global_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    sub     x16, x16, #576
+; CHECK-NEXT:    sub     x16, x16, #30, lsl #12
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -123456), i32 2)
+}
+
+define ptr @test_global_big_offset_zero_disc() {
+; CHECK-LABEL: test_global_big_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #1
+; CHECK-NEXT:    movk    x17, #32769, lsl #16
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 add (i64 2147483648, i64 65537)), i32 2)
+}
+
+define ptr @test_global_big_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_big_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #-52501
+; CHECK-NEXT:    movk    x17, #63652, lsl #16
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -123456789), i32 2)
+}
+
+define ptr @test_global_huge_neg_offset_zero_disc() {
+; CHECK-LABEL: test_global_huge_neg_offset_zero_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #-65536
+; CHECK-NEXT:    movk    x17, #0, lsl #16
+; CHECK-NEXT:    movk    x17, #0, lsl #32
+; CHECK-NEXT:    movk    x17, #32768, lsl #48
+; CHECK-NEXT:    add     x16, x16, x17
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr getelementptr (i8, ptr @g, i64 -9223372036854775808), i32 2)
+}
+
+define ptr @test_global_disc() {
+; CHECK-LABEL: test_global_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov     x17, #42 // =0x2a
+; CHECK-NEXT:    pacia   x16, x17
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 0, i64 42)
+}
+
+ at g.ref.da.42.addr = dso_local constant ptr ptrauth (ptr @g, i32 2, i64 42, ptr @g.ref.da.42.addr)
+
+define ptr @test_global_addr_disc() {
+; CHECK-LABEL: test_global_addr_disc:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp x8, g.ref.da.42.addr
+; CHECK-NEXT:    add x8, x8, :lo12:g.ref.da.42.addr
+; CHECK-NEXT:    adrp x16, :got:g
+; CHECK-NEXT:    ldr x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    mov x17, x8
+; CHECK-NEXT:    movk x17, #42, lsl #48
+; CHECK-NEXT:    pacda x16, x17
+; CHECK-NEXT:    mov x0, x16
+; CHECK-NEXT:    ret
+
+  ret ptr ptrauth (ptr @g, i32 2, i64 42, ptr @g.ref.da.42.addr)
+}
+
+define ptr @test_global_process_specific() {
+; CHECK-LABEL: test_global_process_specific:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, :got:g
+; CHECK-NEXT:    ldr     x16, [x16, :got_lo12:g]
+; CHECK-NEXT:    pacizb  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g, i32 1)
+}
+
+; weak symbols can't be assumed to be non-nil. Use $auth_ptr$ stub slot always.
+; The alternative is to emit a null-check here, but that'd be redundant with
+; whatever null-check follows in user code.
+
+define ptr @test_global_weak() {
+; CHECK-LABEL: test_global_weak:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x0, g_weak$auth_ptr$ia$42
+; CHECK-NEXT:    ldr     x0, [x0, :lo12:g_weak$auth_ptr$ia$42]
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g_weak, i32 0, i64 42)
+}
+
+; Non-external symbols don't need to be accessed through the GOT.
+
+define ptr @test_global_strong_def() {
+; CHECK-LABEL: test_global_strong_def:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp    x16, g_strong_def
+; CHECK-NEXT:    add     x16, x16, :lo12:g_strong_def
+; CHECK-NEXT:    pacdza  x16
+; CHECK-NEXT:    mov     x0, x16
+; CHECK-NEXT:    ret
+  ret ptr ptrauth (ptr @g_strong_def, i32 2)
+}
+
+; CHECK-LABEL: g_weak$auth_ptr$ia$42:
+; CHECK-NEXT:    .xword  g_weak at AUTH(ia,42)
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
index bb1acde296429..2825ade2d2134 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td
@@ -85,7 +85,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 
 // CHECK:      const uint8_t *GenMyCombiner::getMatchTable() const {
 // CHECK-NEXT:   constexpr static uint8_t MatchTable0[] = {
-// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(94), GIMT_Encode2(194), /*)*//*default:*//*Label 4*/ GIMT_Encode4(464),
+// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(95), GIMT_Encode2(195), /*)*//*default:*//*Label 4*/ GIMT_Encode4(464),
 // CHECK-NEXT:     /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(410), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
 // CHECK-NEXT:     /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(428), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
 // CHECK-NEXT:     /*TargetOpcode::G_FNEG*//*Label 2*/ GIMT_Encode4(440), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-variadics.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-variadics.td
index 35bddf912a541..43cdd4f5546bb 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-variadics.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-variadics.td
@@ -37,7 +37,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 
 // CHECK:      const uint8_t *GenMyCombiner::getMatchTable() const {
 // CHECK-NEXT:   constexpr static uint8_t MatchTable0[] = {
-// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(69), GIMT_Encode2(73), /*)*//*default:*//*Label 2*/ GIMT_Encode4(84),
+// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(70), GIMT_Encode2(74), /*)*//*default:*//*Label 2*/ GIMT_Encode4(84),
 // CHECK-NEXT:     /*TargetOpcode::G_UNMERGE_VALUES*//*Label 0*/ GIMT_Encode4(26), GIMT_Encode4(0), GIMT_Encode4(0),
 // CHECK-NEXT:     /*TargetOpcode::G_BUILD_VECTOR*//*Label 1*/ GIMT_Encode4(55),
 // CHECK-NEXT:     // Label 0: @26
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
index 513a86754d6d9..7ff637fa1e0e3 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table.td
@@ -135,15 +135,15 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // Verify match table.
 // CHECK:      const uint8_t *GenMyCombiner::getMatchTable() const {
 // CHECK-NEXT:   constexpr static uint8_t MatchTable0[] = {
-// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(19), GIMT_Encode2(133), /*)*//*default:*//*Label 6*/ GIMT_Encode4(653),
-// CHECK-NEXT:     /*TargetOpcode::COPY*//*Label 0*/ GIMT_Encode4(466), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT:     /*TargetOpcode::G_AND*//*Label 1*/ GIMT_Encode4(502), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT:     /*TargetOpcode::G_STORE*//*Label 2*/ GIMT_Encode4(549), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT:     /*TargetOpcode::G_TRUNC*//*Label 3*/ GIMT_Encode4(583), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
-// CHECK-NEXT:     /*TargetOpcode::G_SEXT*//*Label 4*/ GIMT_Encode4(606), GIMT_Encode4(0),
-// CHECK-NEXT:     /*TargetOpcode::G_ZEXT*//*Label 5*/ GIMT_Encode4(618),
-// CHECK-NEXT:     // Label 0: @466
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(490), // Rule ID 4 //
+// CHECK-NEXT:     GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(19), GIMT_Encode2(134), /*)*//*default:*//*Label 6*/ GIMT_Encode4(657),
+// CHECK-NEXT:     /*TargetOpcode::COPY*//*Label 0*/ GIMT_Encode4(470), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT:     /*TargetOpcode::G_AND*//*Label 1*/ GIMT_Encode4(506), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT:     /*TargetOpcode::G_STORE*//*Label 2*/ GIMT_Encode4(553), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT:     /*TargetOpcode::G_TRUNC*//*Label 3*/ GIMT_Encode4(587), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
+// CHECK-NEXT:     /*TargetOpcode::G_SEXT*//*Label 4*/ GIMT_Encode4(610), GIMT_Encode4(0),
+// CHECK-NEXT:     /*TargetOpcode::G_ZEXT*//*Label 5*/ GIMT_Encode4(622),
+// CHECK-NEXT:     // Label 0: @470
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(494), // Rule ID 4 //
 // CHECK-NEXT:       GIM_CheckFeatures, GIMT_Encode2(GIFBS_HasAnswerToEverything),
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
 // CHECK-NEXT:       // MIs[0] a
@@ -156,8 +156,8 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // CHECK-NEXT:       GIM_CheckIsSafeToFold, /*NumInsns*/1,
 // CHECK-NEXT:       // Combiner Rule #3: InstTest1
 // CHECK-NEXT:       GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
-// CHECK-NEXT:     // Label 7: @490
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(501), // Rule ID 3 //
+// CHECK-NEXT:     // Label 7: @494
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(505), // Rule ID 3 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
 // CHECK-NEXT:       // MIs[0] a
 // CHECK-NEXT:       // No operand predicates
@@ -165,10 +165,10 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // CHECK-NEXT:       // No operand predicates
 // CHECK-NEXT:       // Combiner Rule #2: InstTest0
 // CHECK-NEXT:       GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
-// CHECK-NEXT:     // Label 8: @501
+// CHECK-NEXT:     // Label 8: @505
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 1: @502
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(548), // Rule ID 6 //
+// CHECK-NEXT:     // Label 1: @506
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(552), // Rule ID 6 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule5Enabled),
 // CHECK-NEXT:       GIM_RootCheckType, /*Op*/2, /*Type*/GILLT_s32,
 // CHECK-NEXT:       // MIs[0] dst
@@ -185,10 +185,10 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // CHECK-NEXT:       GIR_RootToRootCopy, /*OpIdx*/0, // dst
 // CHECK-NEXT:       GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // z
 // CHECK-NEXT:       GIR_EraseRootFromParent_Done,
-// CHECK-NEXT:     // Label 9: @548
+// CHECK-NEXT:     // Label 9: @552
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 2: @549
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(582), // Rule ID 5 //
+// CHECK-NEXT:     // Label 2: @553
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(586), // Rule ID 5 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule4Enabled),
 // CHECK-NEXT:       // MIs[0] tmp
 // CHECK-NEXT:       GIM_RecordInsnIgnoreCopies, /*DefineMI*/1, /*MI*/0, /*OpIdx*/0, // MIs[1]
@@ -204,29 +204,29 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // CHECK-NEXT:       GIR_RootToRootCopy, /*OpIdx*/1, // ptr
 // CHECK-NEXT:       GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
 // CHECK-NEXT:       GIR_EraseRootFromParent_Done,
-// CHECK-NEXT:     // Label 10: @582
+// CHECK-NEXT:     // Label 10: @586
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 3: @583
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 11*/ GIMT_Encode4(594), // Rule ID 0 //
+// CHECK-NEXT:     // Label 3: @587
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 11*/ GIMT_Encode4(598), // Rule ID 0 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
 // CHECK-NEXT:       // Combiner Rule #0: WipOpcodeTest0; wip_match_opcode 'G_TRUNC'
 // CHECK-NEXT:       GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
-// CHECK-NEXT:     // Label 11: @594
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 12*/ GIMT_Encode4(605), // Rule ID 1 //
+// CHECK-NEXT:     // Label 11: @598
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 12*/ GIMT_Encode4(609), // Rule ID 1 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
 // CHECK-NEXT:       // Combiner Rule #1: WipOpcodeTest1; wip_match_opcode 'G_TRUNC'
 // CHECK-NEXT:       GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
-// CHECK-NEXT:     // Label 12: @605
+// CHECK-NEXT:     // Label 12: @609
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 4: @606
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 13*/ GIMT_Encode4(617), // Rule ID 2 //
+// CHECK-NEXT:     // Label 4: @610
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 13*/ GIMT_Encode4(621), // Rule ID 2 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
 // CHECK-NEXT:       // Combiner Rule #1: WipOpcodeTest1; wip_match_opcode 'G_SEXT'
 // CHECK-NEXT:       GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
-// CHECK-NEXT:     // Label 13: @617
+// CHECK-NEXT:     // Label 13: @621
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 5: @618
-// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 14*/ GIMT_Encode4(652), // Rule ID 7 //
+// CHECK-NEXT:     // Label 5: @622
+// CHECK-NEXT:     GIM_Try, /*On fail goto*//*Label 14*/ GIMT_Encode4(656), // Rule ID 7 //
 // CHECK-NEXT:       GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule6Enabled),
 // CHECK-NEXT:       // MIs[0] dst
 // CHECK-NEXT:       // No operand predicates
@@ -240,10 +240,10 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
 // CHECK-NEXT:       GIR_RootToRootCopy, /*OpIdx*/0, // dst
 // CHECK-NEXT:       GIR_AddSimpleTempRegister, /*InsnID*/0, /*TempRegID*/0,
 // CHECK-NEXT:       GIR_EraseRootFromParent_Done,
-// CHECK-NEXT:     // Label 14: @652
+// CHECK-NEXT:     // Label 14: @656
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     // Label 6: @653
+// CHECK-NEXT:     // Label 6: @657
 // CHECK-NEXT:     GIM_Reject,
-// CHECK-NEXT:     }; // Size: 654 bytes
+// CHECK-NEXT:     }; // Size: 658 bytes
 // CHECK-NEXT:   return MatchTable0;
 // CHECK-NEXT: }
diff --git a/llvm/test/TableGen/GlobalISelEmitter.td b/llvm/test/TableGen/GlobalISelEmitter.td
index 5d5bf92664a79..796f595930319 100644
--- a/llvm/test/TableGen/GlobalISelEmitter.td
+++ b/llvm/test/TableGen/GlobalISelEmitter.td
@@ -513,7 +513,7 @@ def : Pat<(frag GPR32:$src1, complex:$src2, complex:$src3),
 // R00O-NEXT:  GIM_Reject,
 // R00O:       // Label [[DEFAULT_NUM]]: @[[DEFAULT]]
 // R00O-NEXT:  GIM_Reject,
-// R00O-NEXT:  }; // Size: 1804 bytes
+// R00O-NEXT:  }; // Size: 1808 bytes
 
 def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
                  [(set GPR32:$dst,

>From 81cc1b726da6a210b1d04a66f1f8fa1220abc3cd Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sun, 23 Jun 2024 22:02:36 +0200
Subject: [PATCH 19/19] AMDGPU: Add a subtarget feature for fine-grained remote
 memory support

Atomic access to fine-grained remote memory does not work on all
subtargets. Add a feature for targets where this is expected to work.
---
 llvm/lib/Target/AMDGPU/AMDGPU.td      | 16 ++++++++++++++--
 llvm/lib/Target/AMDGPU/GCNSubtarget.h |  8 ++++++++
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 63d83346528ab..56ec5e9c4cfc2 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -788,6 +788,16 @@ def FeatureFlatAtomicFaddF32Inst
   "Has flat_atomic_add_f32 instruction"
 >;
 
+def FeatureAgentScopeFineGrainedRemoteMemoryAtomics
+  : SubtargetFeature<"agent-scope-fine-grained-remote-memory-atomics",
+  "HasAgentScopeFineGrainedRemoteMemoryAtomics",
+  "true",
+  "Agent (device) scoped atomic operations, excluding those directly "
+  "supported by PCIe (i.e. integer atomic add, exchange, and "
+  "compare-and-swap), are functional for allocations in host or peer "
+  "device memory."
+>;
+
 def FeatureDefaultComponentZero : SubtargetFeature<"default-component-zero",
   "HasDefaultComponentZero",
   "true",
@@ -1207,7 +1217,8 @@ def FeatureGFX12 : GCNSubtargetFeatureGeneration<"GFX12",
    FeatureUnalignedBufferAccess, FeatureUnalignedDSAccess,
    FeatureTrue16BitInsts, FeatureDefaultComponentBroadcast,
    FeatureMaxHardClauseLength32,
-   FeatureAtomicFMinFMaxF32GlobalInsts, FeatureAtomicFMinFMaxF32FlatInsts
+   FeatureAtomicFMinFMaxF32GlobalInsts, FeatureAtomicFMinFMaxF32FlatInsts,
+   FeatureAgentScopeFineGrainedRemoteMemoryAtomics
   ]
 >;
 
@@ -1415,7 +1426,8 @@ def FeatureISAVersion9_4_Common : FeatureSet<
    FeatureBackOffBarrier,
    FeatureKernargPreload,
    FeatureAtomicFMinFMaxF64GlobalInsts,
-   FeatureAtomicFMinFMaxF64FlatInsts
+   FeatureAtomicFMinFMaxF64FlatInsts,
+   FeatureAgentScopeFineGrainedRemoteMemoryAtomics
    ]>;
 
 def FeatureISAVersion9_4_0 : FeatureSet<
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.h b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
index 07ff855756ec9..9e2a316a9ed28 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.h
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
@@ -174,6 +174,7 @@ class GCNSubtarget final : public AMDGPUGenSubtargetInfo,
   bool HasAtomicBufferPkAddBF16Inst = false;
   bool HasFlatAtomicFaddF32Inst = false;
   bool HasDefaultComponentZero = false;
+  bool HasAgentScopeFineGrainedRemoteMemoryAtomics = false;
   bool HasDefaultComponentBroadcast = false;
   /// The maximum number of instructions that may be placed within an S_CLAUSE,
   /// which is one greater than the maximum argument to S_CLAUSE. A value of 0
@@ -871,6 +872,13 @@ class GCNSubtarget final : public AMDGPUGenSubtargetInfo,
 
   bool hasFlatAtomicFaddF32Inst() const { return HasFlatAtomicFaddF32Inst; }
 
+  /// \return true if atomic operations targeting fine-grained memory work
+  /// correctly at device scope, in allocations in host or peer PCIe device
+  /// memory.
+  bool supportsAgentScopeFineGrainedRemoteMemoryAtomics() const {
+    return HasAgentScopeFineGrainedRemoteMemoryAtomics;
+  }
+
   bool hasDefaultComponentZero() const { return HasDefaultComponentZero; }
 
   bool hasDefaultComponentBroadcast() const {



More information about the cfe-commits mailing list