https://github.com/DanielKristofKiss updated 
https://github.com/llvm/llvm-project/pull/203989

>From 4a2365d62d51640e88b0a9a82434b9d9e6bb5cf8 Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 15 Jun 2026 22:04:24 +0200
Subject: [PATCH 1/6] [AArch64] Branch-protection=standard means "b-key".

On AArch64 Windows the B key is the only supported key right for userspace,
"standard" option generates "b-key".

Fixes: #203852
---
 clang/lib/Basic/Targets/AArch64.cpp                    | 3 ++-
 clang/lib/Basic/Targets/ARM.cpp                        | 2 +-
 clang/lib/Driver/ToolChains/Clang.cpp                  | 2 +-
 clang/test/CodeGen/AArch64/branch-protection-attr.c    | 4 ++++
 clang/test/CodeGen/AArch64/sign-return-address.c       | 8 ++++++++
 clang/test/Driver/aarch64-security-options.c           | 4 ++++
 clang/test/Preprocessor/aarch64-target-features.c      | 4 ++++
 llvm/include/llvm/TargetParser/ARMTargetParserCommon.h | 4 +++-
 llvm/lib/TargetParser/ARMTargetParserCommon.cpp        | 5 ++++-
 9 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Basic/Targets/AArch64.cpp 
b/clang/lib/Basic/Targets/AArch64.cpp
index 9afe6cb10729d..e7ca9c2414612 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -254,7 +254,8 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef 
Spec, StringRef,
                                                  const LangOptions &LO,
                                                  StringRef &Err) const {
   llvm::ARM::ParsedBranchProtection PBP;
-  if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err, HasPAuthLR))
+  if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err, getTriple(),
+                                        HasPAuthLR))
     return false;
 
   // GCS is currently untested with ptrauth-returns, but enabling this could be
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index f21e9ebbc903a..c0a71dcc618f2 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -375,7 +375,7 @@ bool ARMTargetInfo::validateBranchProtection(StringRef 
Spec, StringRef Arch,
                                              const LangOptions &LO,
                                              StringRef &Err) const {
   llvm::ARM::ParsedBranchProtection PBP;
-  if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err))
+  if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err, getTriple()))
     return false;
 
   if (!isBranchProtectionSupportedArch(Arch))
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 312e8f8c69f0a..4c4f62936ad5c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1442,7 +1442,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, 
const ArgList &Args,
       if (llvm::any_of(CmdArgs, isPAuthLR))
         EnablePAuthLR = true;
     }
-    if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg,
+    if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg, Triple,
                                           EnablePAuthLR))
       D.Diag(diag::err_drv_unsupported_option_argument)
           << A->getSpelling() << DiagMsg;
diff --git a/clang/test/CodeGen/AArch64/branch-protection-attr.c 
b/clang/test/CodeGen/AArch64/branch-protection-attr.c
index c66bce1bee6d3..d1bb8816d6e03 100644
--- a/clang/test/CodeGen/AArch64/branch-protection-attr.c
+++ b/clang/test/CodeGen/AArch64/branch-protection-attr.c
@@ -13,6 +13,8 @@
 // RUN:                               | FileCheck %s --check-prefix=CHECK
 // RUN: %clang_cc1 -triple aarch64 -emit-llvm  -target-cpu generic 
-target-feature +v8.5a -mguarded-control-stack -mbranch-target-enforce 
-mbranch-protection-pauth-lr -msign-return-address=all 
-msign-return-address-key=a_key %s -o - \
 // RUN:                               | FileCheck %s --check-prefix=CHECK
+// RUN: %clang_cc1 -triple aarch64-windows-msvc -emit-llvm -target-cpu generic 
-target-feature +v8.5a %s -o - \
+// RUN:                               | FileCheck %s --check-prefix=WIN
 
 __attribute__ ((target("branch-protection=none")))
 void none() {}
@@ -21,6 +23,7 @@ void none() {}
   __attribute__ ((target("branch-protection=standard")))
 void std() {}
 // CHECK: define{{.*}} void @std() #[[#STD:]]
+// WIN: define{{.*}} void @std() #[[#WINSTD:]]
 
 __attribute__ ((target("branch-protection=bti")))
 void btionly() {}
@@ -82,6 +85,7 @@ void gcs() {}
 // CHECK-DAG: attributes #[[#NONE]] = { {{.*}}
 
 // CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" 
"guarded-control-stack" {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="a_key"
+// WIN-DAG: attributes #[[#WINSTD]] = { {{.*}} "branch-target-enforcement" 
"guarded-control-stack" {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="b_key"
 
 // CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"
 
diff --git a/clang/test/CodeGen/AArch64/sign-return-address.c 
b/clang/test/CodeGen/AArch64/sign-return-address.c
index 2b505de339054..d39b246e95feb 100644
--- a/clang/test/CodeGen/AArch64/sign-return-address.c
+++ b/clang/test/CodeGen/AArch64/sign-return-address.c
@@ -6,6 +6,7 @@
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=pac-ret+leaf  %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=ALL
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=B-KEY
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=bti %s           | FileCheck %s --check-prefix=CHECK 
--check-prefix=BTE
+// RUN: %clang -target aarch64-windows-msvc -S -emit-llvm -o - 
-mbranch-protection=standard %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=WIN-STD
 
 // REQUIRES: aarch64-registered-target
 
@@ -21,6 +22,7 @@
 // PART:  attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="a_key"
 // B-KEY: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="b_key"
 // BTE:   attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
+// WIN-STD: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement" 
{{.*}} "guarded-control-stack" {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="b_key"
 
 
 // Check module attributes
@@ -30,23 +32,29 @@
 // PART-NOT:  !"branch-target-enforcement"
 // BTE:       !{i32 8, !"branch-target-enforcement", i32 2}
 // B-KEY-NOT: !"branch-target-enforcement"
+// WIN-STD:   !{i32 8, !"branch-target-enforcement", i32 2}
+
+// WIN-STD: !{i32 8, !"guarded-control-stack", i32 2}
 
 // NONE-NOT:  !"sign-return-address"
 // ALL:   !{i32 8, !"sign-return-address", i32 2}
 // PART:  !{i32 8, !"sign-return-address", i32 2}
 // BTE-NOT:   !"sign-return-address"
 // B-KEY: !{i32 8, !"sign-return-address", i32 2}
+// WIN-STD: !{i32 8, !"sign-return-address", i32 2}
 
 // NONE-NOT:  !"sign-return-address-all"
 // ALL:   !{i32 8, !"sign-return-address-all", i32 2}
 // PART-NOT:  !"sign-return-address-all"
 // BTE-NOT:   !"sign-return-address-all"
 // B-KEY-NOT: !"sign-return-address-all"
+// WIN-STD-NOT: !"sign-return-address-all"
 
 // NONE-NOT:  !"sign-return-address-with-bkey"
 // ALL-NOT:   !"sign-return-address-with-bkey"
 // PART-NOT:  !"sign-return-address-with-bkey"
 // BTE-NOT:   !"sign-return-address-with-bkey"
 // B-KEY: !{i32 8, !"sign-return-address-with-bkey", i32 2}
+// WIN-STD: !{i32 8, !"sign-return-address-with-bkey", i32 2}
 
 void foo() {}
diff --git a/clang/test/Driver/aarch64-security-options.c 
b/clang/test/Driver/aarch64-security-options.c
index 146add2d1cf70..967a6122a333d 100644
--- a/clang/test/Driver/aarch64-security-options.c
+++ b/clang/test/Driver/aarch64-security-options.c
@@ -13,6 +13,9 @@
 // RUN: %clang --target=aarch64 -c %s -### -mbranch-protection=standard        
                        2>&1 | \
 // RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-A 
--check-prefix=BTE-ON --check-prefix=GCS-ON --check-prefix=WARN
 
+// RUN: %clang --target=aarch64-windows-msvc -c %s -### 
-mbranch-protection=standard                  2>&1 | \
+// RUN: FileCheck %s --check-prefix=RA-NON-LEAF --check-prefix=KEY-B 
--check-prefix=BTE-ON --check-prefix=GCS-ON --check-prefix=WARN
+
 // If the -msign-return-address and -mbranch-protection are both used, the
 // right-most one controls return address signing.
 // RUN: %clang --target=aarch64 -c %s -### -msign-return-address=non-leaf 
-mbranch-protection=none     2>&1 | \
@@ -37,6 +40,7 @@
 // RA-ALL: "-msign-return-address=all"
 
 // KEY-A: "-msign-return-address-key=a_key"
+// KEY-B: "-msign-return-address-key=b_key"
 // KEY-NOT: "-msign-return-address-key"
 
 // BTE-OFF-NOT: "-mbranch-target-enforce"
diff --git a/clang/test/Preprocessor/aarch64-target-features.c 
b/clang/test/Preprocessor/aarch64-target-features.c
index 60ddaad639d48..b4fe9382320c0 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -541,6 +541,7 @@
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8-a 
-mbranch-protection=pac-ret+b-key -x c -E -dM %s -o - | FileCheck 
-check-prefix=CHECK-PAUTH-BKEY %s
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8-a 
-mbranch-protection=pac-ret+leaf -x c -E -dM %s -o - | FileCheck 
-check-prefix=CHECK-PAUTH-ALL %s
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8-a 
-mbranch-protection=pac-ret+leaf+b-key -x c -E -dM %s -o - | FileCheck 
-check-prefix=CHECK-PAUTH-BKEY-ALL %s
+// RUN: %clang -target aarch64-windows-msvc -march=armv8-a 
-mbranch-protection=standard -x c -E -dM %s -o - | FileCheck 
-check-prefix=CHECK-BRANCH-PROTECTION-STANDARD-WINDOWS %s
 //
 // Note: PAUTH-OFF - pac-ret is disabled
 //       CPU-NOPAUTH - FEAT_PAUTH support is disabled (but pac-ret can still 
use HINT-encoded instructions)
@@ -553,6 +554,9 @@
 // CHECK-PAUTH-BKEY-ALL:  #define __ARM_FEATURE_PAC_DEFAULT 6
 // CHECK-CPU-PAUTH:       #define __ARM_FEATURE_PAUTH 1
 // CHECK-CPU-NOPAUTH-NOT: __ARM_FEATURE_PAUTH
+// CHECK-BRANCH-PROTECTION-STANDARD-WINDOWS-DAG: #define 
__ARM_FEATURE_BTI_DEFAULT 1
+// CHECK-BRANCH-PROTECTION-STANDARD-WINDOWS-DAG: #define 
__ARM_FEATURE_GCS_DEFAULT 1
+// CHECK-BRANCH-PROTECTION-STANDARD-WINDOWS-DAG: #define 
__ARM_FEATURE_PAC_DEFAULT 2
 
 // ================== Check Branch Target Identification (BTI).
 // RUN: %clang -target arm64-none-linux-gnu -march=armv8-a -x c -E -dM %s -o - 
| FileCheck -check-prefix=CHECK-BTI-OFF %s
diff --git a/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h 
b/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
index 7c8030dd5576a..1df9740fde8b5 100644
--- a/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
+++ b/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
@@ -15,6 +15,7 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
+#include "llvm/TargetParser/Triple.h"
 
 namespace llvm {
 namespace ARM {
@@ -47,7 +48,8 @@ struct ParsedBranchProtection {
 };
 
 LLVM_ABI bool parseBranchProtection(StringRef Spec, ParsedBranchProtection 
&PBP,
-                                    StringRef &Err, bool EnablePAuthLR = 
false);
+                                    StringRef &Err, const llvm::Triple &Triple,
+                                    bool EnablePAuthLR = false);
 
 } // namespace ARM
 } // namespace llvm
diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp 
b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
index 15ba1ebd0c037..9d61dcc923671 100644
--- a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
@@ -141,7 +141,8 @@ ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
 // returned in `PBP`. Returns false in error, with `Err` containing
 // an erroneous part of the spec.
 bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
-                                StringRef &Err, bool EnablePAuthLR) {
+                                StringRef &Err, const llvm::Triple &Triple,
+                                bool EnablePAuthLR) {
   PBP = {"none", "a_key", false, false, false};
   if (Spec == "none")
     return true; // defaults are ok
@@ -151,6 +152,8 @@ bool ARM::parseBranchProtection(StringRef Spec, 
ParsedBranchProtection &PBP,
     PBP.BranchTargetEnforcement = true;
     PBP.GuardedControlStack = true;
     PBP.BranchProtectionPAuthLR = EnablePAuthLR;
+    if (Triple.isAArch64() && Triple.isOSWindows())
+      PBP.Key = "b_key";
     return true;
   }
 

>From 6d72446dc30dd604052d010749c1c2f999089ea2 Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 6 Jul 2026 21:59:42 +0200
Subject: [PATCH 2/6] Extend the b-key for pac-ret flag too.

---
 clang/test/CodeGen/AArch64/branch-protection-attr.c | 2 ++
 clang/test/CodeGen/AArch64/sign-return-address.c    | 7 +++++++
 llvm/lib/TargetParser/ARMTargetParserCommon.cpp     | 3 +++
 3 files changed, 12 insertions(+)

diff --git a/clang/test/CodeGen/AArch64/branch-protection-attr.c 
b/clang/test/CodeGen/AArch64/branch-protection-attr.c
index d1bb8816d6e03..d3fa2743ef626 100644
--- a/clang/test/CodeGen/AArch64/branch-protection-attr.c
+++ b/clang/test/CodeGen/AArch64/branch-protection-attr.c
@@ -32,6 +32,7 @@ void btionly() {}
 __attribute__ ((target("branch-protection=pac-ret")))
 void paconly() {}
 // CHECK: define{{.*}} void @paconly() #[[#PAC:]]
+// WIN: define{{.*}} void @paconly() #[[#WINPAC:]]
 
 __attribute__ ((target("branch-protection=pac-ret+bti")))
 void pacbti0() {}
@@ -90,6 +91,7 @@ void gcs() {}
 // CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"
 
 // CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="a_key"
+// WIN-DAG: attributes #[[#WINPAC]] = { {{.*}} 
"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
 
 // CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" 
"sign-return-address-key"="a_key"
 
diff --git a/clang/test/CodeGen/AArch64/sign-return-address.c 
b/clang/test/CodeGen/AArch64/sign-return-address.c
index d39b246e95feb..c617b45c21317 100644
--- a/clang/test/CodeGen/AArch64/sign-return-address.c
+++ b/clang/test/CodeGen/AArch64/sign-return-address.c
@@ -6,6 +6,7 @@
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=pac-ret+leaf  %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=ALL
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=B-KEY
 // RUN: %clang -target aarch64-none-elf -S -emit-llvm -o - 
-mbranch-protection=bti %s           | FileCheck %s --check-prefix=CHECK 
--check-prefix=BTE
+// RUN: %clang -target aarch64-windows-msvc -S -emit-llvm -o - 
-mbranch-protection=pac-ret %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=WIN-PAC
 // RUN: %clang -target aarch64-windows-msvc -S -emit-llvm -o - 
-mbranch-protection=standard %s | FileCheck %s --check-prefix=CHECK 
--check-prefix=WIN-STD
 
 // REQUIRES: aarch64-registered-target
@@ -22,6 +23,7 @@
 // PART:  attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="a_key"
 // B-KEY: attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"="b_key"
 // BTE:   attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
+// WIN-PAC: attributes #[[#ATTR]] = { {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="b_key"
 // WIN-STD: attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement" 
{{.*}} "guarded-control-stack" {{.*}} "sign-return-address"="non-leaf" 
"sign-return-address-key"="b_key"
 
 
@@ -32,8 +34,10 @@
 // PART-NOT:  !"branch-target-enforcement"
 // BTE:       !{i32 8, !"branch-target-enforcement", i32 2}
 // B-KEY-NOT: !"branch-target-enforcement"
+// WIN-PAC-NOT: !"branch-target-enforcement"
 // WIN-STD:   !{i32 8, !"branch-target-enforcement", i32 2}
 
+// WIN-PAC-NOT: !"guarded-control-stack"
 // WIN-STD: !{i32 8, !"guarded-control-stack", i32 2}
 
 // NONE-NOT:  !"sign-return-address"
@@ -41,6 +45,7 @@
 // PART:  !{i32 8, !"sign-return-address", i32 2}
 // BTE-NOT:   !"sign-return-address"
 // B-KEY: !{i32 8, !"sign-return-address", i32 2}
+// WIN-PAC: !{i32 8, !"sign-return-address", i32 2}
 // WIN-STD: !{i32 8, !"sign-return-address", i32 2}
 
 // NONE-NOT:  !"sign-return-address-all"
@@ -48,6 +53,7 @@
 // PART-NOT:  !"sign-return-address-all"
 // BTE-NOT:   !"sign-return-address-all"
 // B-KEY-NOT: !"sign-return-address-all"
+// WIN-PAC-NOT: !"sign-return-address-all"
 // WIN-STD-NOT: !"sign-return-address-all"
 
 // NONE-NOT:  !"sign-return-address-with-bkey"
@@ -55,6 +61,7 @@
 // PART-NOT:  !"sign-return-address-with-bkey"
 // BTE-NOT:   !"sign-return-address-with-bkey"
 // B-KEY: !{i32 8, !"sign-return-address-with-bkey", i32 2}
+// WIN-PAC: !{i32 8, !"sign-return-address-with-bkey", i32 2}
 // WIN-STD: !{i32 8, !"sign-return-address-with-bkey", i32 2}
 
 void foo() {}
diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp 
b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
index 9d61dcc923671..6d824c78cab97 100644
--- a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
@@ -167,6 +167,9 @@ bool ARM::parseBranchProtection(StringRef Spec, 
ParsedBranchProtection &PBP,
     }
     if (Opt == "pac-ret") {
       PBP.Scope = "non-leaf";
+      if (Triple.isAArch64() && Triple.isOSWindows())
+        PBP.Key = "b_key";
+
       for (; I + 1 != E; ++I) {
         StringRef PACOpt = Opts[I + 1].trim();
         if (PACOpt == "leaf")

>From 1ad8d53c12ba2e9d61f2c97f276d09a1cac01cb6 Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 6 Jul 2026 22:20:53 +0200
Subject: [PATCH 3/6] add usersguide

---
 clang/docs/UsersManual.rst | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 3f4b1585e5935..eeccd4e94e2c9 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2582,6 +2582,34 @@ are listed below.
    This option restricts the generated code to use general registers
    only. This only applies to the AArch64 architecture.
 
+.. option:: -mbranch-protection=features
+
+   Select the branch protection features to use for ARM and AArch64 targets.
+   ``features`` can be ``none``, ``standard``, or a ``+``-separated list of
+   ``bti``, ``gcs``, and ``pac-ret`` with optional ``pac-ret`` modifiers.
+
+   ``none`` is the default and turns off all types of branch protection.
+
+   ``standard`` turns on all branch protection features that are valid for the
+   target platform. If a feature has additional tuning options, ``standard``
+   sets them to their standard level.
+
+   ``pac-ret`` turns on return address signing to its standard level: signing
+   functions that save the return address to memory (non-leaf functions
+   practically always do this) using the A-key. On AArch64 Windows targets,
+   ``pac-ret`` uses the B-key by default.
+
+   ``+leaf`` extends the ``pac-ret`` signing to include leaf functions.
+
+   ``+b-key`` can be used to sign functions with the B-key instead of the A-key
+   on AArch64. ``b-key`` is accepted but ignored for ARM targets.
+
+   ``+pc`` enables the PAuth-LR form of return address signing.
+
+   ``bti`` turns on the Branch Target Identification mechanism.
+
+   ``gcs`` turns on Guarded Control Stack compatible code generation.
+
 .. option:: -mcompact-branches=[values]
 
    Control the usage of compact branches for MIPSR6.

>From 5e2dd2122109b0b7171c13801ead6e410c9b6a6b Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 6 Jul 2026 22:24:32 +0200
Subject: [PATCH 4/6] add ReleaseNote addition

---
 clang/docs/ReleaseNotes.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3ec47eb8b18c3..3131b9b0862f2 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -951,6 +951,9 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
   - Arm AGI CPU (armagicpu).
   - Hisilicon hip12 core (hip12).
 
+- On AArch64 Windows targets, `-mbranch-protection=standard` and 
`-mbranch-protection=pac-ret`
+  now uses the B-key by default.
+
 #### Android Support
 
 #### Windows Support

>From f72dac4ac06d18a1f43d2be96f0d062b96b3eb1b Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 6 Jul 2026 23:10:14 +0200
Subject: [PATCH 5/6] add llvm relnote

---
 llvm/docs/ReleaseNotes.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 3ca9f5166ad95..bb3558b53e9ab 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -203,6 +203,8 @@ Makes programs 10x faster by doing Special New Thing.
   instead of the ABI names FP and LR. Note that LLVM IR produced by Clang
   always uses the ABI names, but other frontends may not.
   ([#167783](https://github.com/llvm/llvm-project/pull/167783))
+* On AArch64 Windows targets, return address signing now uses the B-key by
+  default because Windows unwind information only supports B-key signing.
 
 ### Changes to the AMDGPU Backend
 

>From 9e2e3cca7f694aea94ecc6bfda77a7e43c1f1495 Mon Sep 17 00:00:00 2001
From: Daniel Kiss <[email protected]>
Date: Mon, 15 Jun 2026 22:23:40 +0200
Subject: [PATCH 6/6] add LLVM diagnostic for a-key missuse

---
 .../AArch64/AArch64MachineFunctionInfo.cpp    |  7 ++
 .../lib/Target/AArch64/AArch64PointerAuth.cpp |  4 ++
 .../CodeGen/AArch64/sign-return-address.ll    | 71 +++----------------
 .../AArch64/windows-pac-invalid-a-key.ll      | 11 +++
 llvm/test/CodeGen/AArch64/wineh-bti.ll        |  2 +-
 5 files changed, 34 insertions(+), 61 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll

diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp 
b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 90dbd7304ec85..29aea3694497f 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -18,6 +18,7 @@
 #include "AArch64Subtarget.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
@@ -93,6 +94,12 @@ static bool ShouldSignWithBKey(const Function &F, const 
AArch64Subtarget &STI) {
   const StringRef Key =
       F.getFnAttribute("sign-return-address-key").getValueAsString();
   assert(Key == "a_key" || Key == "b_key");
+  if (STI.getTargetTriple().isOSWindows() && Key == "a_key" &&
+      GetSignReturnAddress(F) != SignReturnAddress::None) {
+    F.getContext().diagnose(DiagnosticInfoUnsupported{
+        F, "A-key return address signing is unsupported on AArch64 Windows"});
+    return true;
+  }
   return Key == "b_key";
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp 
b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 5372ffe869e1f..6be02ba0dc38b 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -175,6 +175,8 @@ void AArch64PointerAuthImpl::signLR(MachineFunction &MF,
   }
 
   if (!EmitCFI && NeedsWinCFI) {
+    assert(UseBKey &&
+           "Windows SEH PAC unwind info only supports B-key signing");
     BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
         .setMIFlag(MachineInstr::FrameSetup);
   }
@@ -336,6 +338,8 @@ void AArch64PointerAuthImpl::authenticateLR(
   }
 
   if (NeedsWinCFI) {
+    assert(UseBKey &&
+           "Windows SEH PAC unwind info only supports B-key signing");
     BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PACSignLR))
         .setMIFlag(MachineInstr::FrameDestroy);
   }
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll 
b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index 7267ce0e3afbf..755ba860c7ccc 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -5,14 +5,21 @@
 ; v9.5-A is not expected to change codegen without -mbranch-protection=+pc, so 
reuse DWARFCFI-V83A.
 ; RUN: llc -mtriple=aarch64 -mattr=v9.5a < %s | FileCheck 
--check-prefixes=CHECK,DWARFCFI,DWARFCFI-V83A %s
 
-; RUN: llc -mtriple=aarch64-windows              < %s | FileCheck 
--check-prefixes=CHECK,WINCFI,WINCFI-COMPAT %s
-; RUN: llc -mtriple=aarch64-windows -mattr=v8.3a < %s | FileCheck 
--check-prefixes=CHECK,WINCFI,WINCFI-V83A %s
+; RUN: sed -e '/^define i32 @leaf_sign_all_a_key(/,/^}/d' -e '/^define i32 
@leaf_sign_all_a_key_bti(/,/^}/d' %s > %t.win-valid.ll
+; RUN: llc -mtriple=aarch64-windows              < %t.win-valid.ll | FileCheck 
--check-prefixes=CHECK,WINCFI,WINCFI-COMPAT %s
+; RUN: llc -mtriple=aarch64-windows -mattr=v8.3a < %t.win-valid.ll | FileCheck 
--check-prefixes=CHECK,WINCFI,WINCFI-V83A %s
+
+; RUN: sed -n -e '/^define i32 @leaf_sign_all_a_key(/,/^}/p' %s | not llc 
-mtriple=aarch64-windows -filetype=null 2>&1 | FileCheck 
--check-prefix=ERR-AKEY %s
 
 ; Make sure no errors are detected when emitting SEH opcodes.
 ; Errors are only checked for when generating a binary, so emit a dummy object
 ; file and make sure llc produces zero exit code.
-; RUN: llc -mtriple=aarch64-windows              -o %t.dummy.o --filetype=obj 
< %s
-; RUN: llc -mtriple=aarch64-windows -mattr=v8.3a -o %t.dummy.o --filetype=obj 
< %s
+; RUN: llc -mtriple=aarch64-windows              -o %t.dummy.o --filetype=obj 
< %t.win-valid.ll
+; RUN: llc -mtriple=aarch64-windows -mattr=v8.3a -o %t.dummy.o --filetype=obj 
< %t.win-valid.ll
+
+; ERR-AKEY: error:
+; ERR-AKEY-SAME: in function leaf_sign_all_a_key
+; ERR-AKEY-SAME: A-key return address signing is unsupported on AArch64 Windows
 
 define i32 @leaf(i32 %x) {
 ; CHECK-LABEL: leaf:
@@ -649,34 +656,6 @@ define i32 @leaf_sign_all_a_key(i32 %x) 
"sign-return-address"="all" "sign-return
 ; DWARFCFI-V83A-NEXT:    paciasp
 ; DWARFCFI-V83A-NEXT:    .cfi_negate_ra_state
 ; DWARFCFI-V83A-NEXT:    retaa
-;
-; WINCFI-COMPAT-LABEL: leaf_sign_all_a_key:
-; WINCFI-COMPAT:       .seh_proc leaf_sign_all_a_key
-; WINCFI-COMPAT-NEXT:  // %bb.0:
-; WINCFI-COMPAT-NEXT:    hint #25
-; WINCFI-COMPAT-NEXT:    .seh_pac_sign_lr
-; WINCFI-COMPAT-NEXT:    .seh_endprologue
-; WINCFI-COMPAT-NEXT:    .seh_startepilogue
-; WINCFI-COMPAT-NEXT:    hint #29
-; WINCFI-COMPAT-NEXT:    .seh_pac_sign_lr
-; WINCFI-COMPAT-NEXT:    .seh_endepilogue
-; WINCFI-COMPAT-NEXT:    ret
-; WINCFI-COMPAT-NEXT:    .seh_endfunclet
-; WINCFI-COMPAT-NEXT:    .seh_endproc
-;
-; WINCFI-V83A-LABEL: leaf_sign_all_a_key:
-; WINCFI-V83A:       .seh_proc leaf_sign_all_a_key
-; WINCFI-V83A-NEXT:  // %bb.0:
-; WINCFI-V83A-NEXT:    paciasp
-; WINCFI-V83A-NEXT:    .seh_pac_sign_lr
-; WINCFI-V83A-NEXT:    .seh_endprologue
-; WINCFI-V83A-NEXT:    .seh_startepilogue
-; WINCFI-V83A-NEXT:    autiasp
-; WINCFI-V83A-NEXT:    .seh_pac_sign_lr
-; WINCFI-V83A-NEXT:    .seh_endepilogue
-; WINCFI-V83A-NEXT:    ret
-; WINCFI-V83A-NEXT:    .seh_endfunclet
-; WINCFI-V83A-NEXT:    .seh_endproc
   ret i32 %x
 }
 
@@ -764,34 +743,6 @@ define i32 @leaf_sign_all_a_key_bti(i32 %x) 
"sign-return-address"="all" "sign-re
 ; DWARFCFI-V83A-NEXT:    paciasp
 ; DWARFCFI-V83A-NEXT:    .cfi_negate_ra_state
 ; DWARFCFI-V83A-NEXT:    retaa
-;
-; WINCFI-COMPAT-LABEL: leaf_sign_all_a_key_bti:
-; WINCFI-COMPAT:       .seh_proc leaf_sign_all_a_key_bti
-; WINCFI-COMPAT-NEXT:  // %bb.0:
-; WINCFI-COMPAT-NEXT:    hint #25
-; WINCFI-COMPAT-NEXT:    .seh_pac_sign_lr
-; WINCFI-COMPAT-NEXT:    .seh_endprologue
-; WINCFI-COMPAT-NEXT:    .seh_startepilogue
-; WINCFI-COMPAT-NEXT:    hint #29
-; WINCFI-COMPAT-NEXT:    .seh_pac_sign_lr
-; WINCFI-COMPAT-NEXT:    .seh_endepilogue
-; WINCFI-COMPAT-NEXT:    ret
-; WINCFI-COMPAT-NEXT:    .seh_endfunclet
-; WINCFI-COMPAT-NEXT:    .seh_endproc
-;
-; WINCFI-V83A-LABEL: leaf_sign_all_a_key_bti:
-; WINCFI-V83A:       .seh_proc leaf_sign_all_a_key_bti
-; WINCFI-V83A-NEXT:  // %bb.0:
-; WINCFI-V83A-NEXT:    paciasp
-; WINCFI-V83A-NEXT:    .seh_pac_sign_lr
-; WINCFI-V83A-NEXT:    .seh_endprologue
-; WINCFI-V83A-NEXT:    .seh_startepilogue
-; WINCFI-V83A-NEXT:    autiasp
-; WINCFI-V83A-NEXT:    .seh_pac_sign_lr
-; WINCFI-V83A-NEXT:    .seh_endepilogue
-; WINCFI-V83A-NEXT:    ret
-; WINCFI-V83A-NEXT:    .seh_endfunclet
-; WINCFI-V83A-NEXT:    .seh_endproc
   ret i32 %x
 }
 
diff --git a/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll 
b/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll
new file mode 100644
index 0000000000000..7203e10e4b200
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/windows-pac-invalid-a-key.ll
@@ -0,0 +1,11 @@
+; RUN: not llc -mtriple=aarch64-windows-msvc -filetype=null %s 2>&1 | 
FileCheck %s
+
+; CHECK: error:
+; CHECK-SAME: A-key return address signing is unsupported on AArch64 Windows
+
+define void @a_key() "sign-return-address"="non-leaf" 
"sign-return-address-key"="a_key" {
+  call void @callee()
+  ret void
+}
+
+declare void @callee()
diff --git a/llvm/test/CodeGen/AArch64/wineh-bti.ll 
b/llvm/test/CodeGen/AArch64/wineh-bti.ll
index 86555a7f64366..ce565bd16e880 100644
--- a/llvm/test/CodeGen/AArch64/wineh-bti.ll
+++ b/llvm/test/CodeGen/AArch64/wineh-bti.ll
@@ -1,6 +1,6 @@
 ; RUN: llc < %s -mtriple=aarch64-windows -aarch64-min-jump-table-entries=4 | 
FileCheck %s
 
-define dso_local i32 @func(i32 %in) "sign-return-address"="non-leaf" 
"sign-return-address-key"="a_key" "branch-target-enforcement" {
+define dso_local i32 @func(i32 %in) "sign-return-address"="non-leaf" 
"sign-return-address-key"="b_key" "branch-target-enforcement" {
 entry:
   call void asm sideeffect "", "~{x19}"()
   switch i32 %in, label %def [

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

Reply via email to