[llvm] a88c722 - [AArch64] PAC/BTI code generation for LLVM generated functions

Momchil Velikov via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 04:01:04 PDT 2020


Author: Momchil Velikov
Date: 2020-09-25T11:47:14+01:00
New Revision: a88c722e687e6780dcd6a58718350dc76fcc4cc9

URL: https://github.com/llvm/llvm-project/commit/a88c722e687e6780dcd6a58718350dc76fcc4cc9
DIFF: https://github.com/llvm/llvm-project/commit/a88c722e687e6780dcd6a58718350dc76fcc4cc9.diff

LOG: [AArch64] PAC/BTI code generation for LLVM generated functions

PAC/BTI-related codegen in the AArch64 backend is controlled by a set
of LLVM IR function attributes, added to the function by Clang, based
on command-line options and GCC-style function attributes. However,
functions, generated in the LLVM middle end (for example,
asan.module.ctor or __llvm_gcov_write_out) do not get any attributes
and the backend incorrectly does not do any PAC/BTI code generation.

This patch record the default state of PAC/BTI codegen in a set of
LLVM IR module-level attributes, based on command-line options:

* "sign-return-address", with non-zero value means generate code to
  sign return addresses (PAC-RET), zero value means disable PAC-RET.

* "sign-return-address-all", with non-zero value means enable PAC-RET
  for all functions, zero value means enable PAC-RET only for
  functions, which spill LR.

* "sign-return-address-with-bkey", with non-zero value means use B-key
  for signing, zero value mean use A-key.

This set of attributes are always added for AArch64 targets (as
opposed, for example, to interpreting a missing attribute as having a
value 0) in order to be able to check for conflicts when combining
module attributed during LTO.

Module-level attributes are overridden by function level attributes.
All the decision making about whether to not to generate PAC and/or
BTI code is factored out into AArch64FunctionInfo, there shouldn't be
any places left, other than AArch64FunctionInfo, which directly
examine PAC/BTI attributes, except AArch64AsmPrinter.cpp, which
is/will-be handled by a separate patch.

Differential Revision: https://reviews.llvm.org/D85649

Added: 
    llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll
    llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll
    llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll

Modified: 
    clang/lib/CodeGen/CGDeclCXX.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    clang/lib/CodeGen/TargetInfo.cpp
    clang/test/CodeGen/aarch64-branch-protection-attr.c
    clang/test/CodeGen/aarch64-sign-return-address.c
    llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
    llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
    llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
    llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
    llvm/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
    llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
    llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
    llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll
    llvm/test/CodeGen/AArch64/branch-target-enforcement.mir
    llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll
    llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir
    llvm/test/CodeGen/AArch64/machine-outliner-bti.mir
    llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll
    llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll
    llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll

Removed: 
    clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp


################################################################################
diff  --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index bfefd7956157..3f6d0e23c685 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -421,22 +421,6 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrCleanUpFunction(
       !isInSanitizerBlacklist(SanitizerKind::ShadowCallStack, Fn, Loc))
     Fn->addFnAttr(llvm::Attribute::ShadowCallStack);
 
-  auto RASignKind = getLangOpts().getSignReturnAddressScope();
-  if (RASignKind != LangOptions::SignReturnAddressScopeKind::None) {
-    Fn->addFnAttr("sign-return-address",
-                  RASignKind == LangOptions::SignReturnAddressScopeKind::All
-                      ? "all"
-                      : "non-leaf");
-    auto RASignKey = getLangOpts().getSignReturnAddressKey();
-    Fn->addFnAttr("sign-return-address-key",
-                  RASignKey == LangOptions::SignReturnAddressKeyKind::AKey
-                      ? "a_key"
-                      : "b_key");
-  }
-
-  if (getLangOpts().BranchTargetEnforcement)
-    Fn->addFnAttr("branch-target-enforcement");
-
   return Fn;
 }
 

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 6a77f6b040a1..c3457865c0b0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -590,6 +590,23 @@ void CodeGenModule::Release() {
                               1);
   }
 
+  if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
+      Arch == llvm::Triple::aarch64_be) {
+    getModule().addModuleFlag(llvm::Module::Error,
+                              "branch-target-enforcement",
+                              LangOpts.BranchTargetEnforcement);
+
+    getModule().addModuleFlag(llvm::Module::Error, "sign-return-address",
+                              LangOpts.hasSignReturnAddress());
+
+    getModule().addModuleFlag(llvm::Module::Error, "sign-return-address-all",
+                              LangOpts.isSignReturnAddressScopeAll());
+
+    getModule().addModuleFlag(llvm::Module::Error,
+                              "sign-return-address-with-bkey",
+                              !LangOpts.isSignReturnAddressWithAKey());
+  }
+
   if (LangOpts.CUDAIsDevice && getTriple().isNVPTX()) {
     // Indicate whether __nvvm_reflect should be configured to flush denormal
     // floating point values to 0.  (This corresponds to its "__CUDA_FTZ"

diff  --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index 5ebf432a4cd3..2f3f4c281079 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -5521,40 +5521,33 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
     if (!FD)
       return;
 
-    LangOptions::SignReturnAddressScopeKind Scope =
-        CGM.getLangOpts().getSignReturnAddressScope();
-    LangOptions::SignReturnAddressKeyKind Key =
-        CGM.getLangOpts().getSignReturnAddressKey();
-    bool BranchTargetEnforcement = CGM.getLangOpts().BranchTargetEnforcement;
-    if (const auto *TA = FD->getAttr<TargetAttr>()) {
-      ParsedTargetAttr Attr = TA->parse();
-      if (!Attr.BranchProtection.empty()) {
-        TargetInfo::BranchProtectionInfo BPI;
-        StringRef Error;
-        (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
-                                                       BPI, Error);
-        assert(Error.empty());
-        Scope = BPI.SignReturnAddr;
-        Key = BPI.SignKey;
-        BranchTargetEnforcement = BPI.BranchTargetEnforcement;
-      }
-    }
+    const auto *TA = FD->getAttr<TargetAttr>();
+    if (TA == nullptr)
+      return;
+
+    ParsedTargetAttr Attr = TA->parse();
+    if (Attr.BranchProtection.empty())
+      return;
+
+    TargetInfo::BranchProtectionInfo BPI;
+    StringRef Error;
+    (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection,
+                                                   BPI, Error);
+    assert(Error.empty());
 
     auto *Fn = cast<llvm::Function>(GV);
-    if (Scope != LangOptions::SignReturnAddressScopeKind::None) {
-      Fn->addFnAttr("sign-return-address",
-                    Scope == LangOptions::SignReturnAddressScopeKind::All
-                        ? "all"
-                        : "non-leaf");
+    static const char *SignReturnAddrStr[] = {"none", "non-leaf", "all"};
+    Fn->addFnAttr("sign-return-address", SignReturnAddrStr[static_cast<int>(BPI.SignReturnAddr)]);
 
+    if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
       Fn->addFnAttr("sign-return-address-key",
-                    Key == LangOptions::SignReturnAddressKeyKind::AKey
+                    BPI.SignKey == LangOptions::SignReturnAddressKeyKind::AKey
                         ? "a_key"
                         : "b_key");
     }
 
-    if (BranchTargetEnforcement)
-      Fn->addFnAttr("branch-target-enforcement");
+    Fn->addFnAttr("branch-target-enforcement",
+                  BPI.BranchTargetEnforcement ? "true" : "false");
   }
 };
 

diff  --git a/clang/test/CodeGen/aarch64-branch-protection-attr.c b/clang/test/CodeGen/aarch64-branch-protection-attr.c
index ee761d6e8977..d694b619802d 100644
--- a/clang/test/CodeGen/aarch64-branch-protection-attr.c
+++ b/clang/test/CodeGen/aarch64-branch-protection-attr.c
@@ -1,81 +1,63 @@
 // REQUIRES: aarch64-registered-target
 // RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm  -target-cpu generic -target-feature +v8.5a %s -o - \
-// RUN:                               | FileCheck %s --check-prefix=CHECK --check-prefix=NO-OVERRIDE
-// RUN: %clang_cc1 -triple aarch64-unknown-unknown-eabi -emit-llvm  -target-cpu generic -target-feature +v8.5a %s -o - \
-// RUN:   -msign-return-address=non-leaf -msign-return-address-key=a_key -mbranch-target-enforce \
-// RUN:                               | FileCheck %s --check-prefix=CHECK --check-prefix=OVERRIDE
-
-void missing() {}
-// NO-OVERRIDE: define void @missing() #[[#NONE:]]
-// OVERRIDE: define void @missing() #[[#STD:]]
+// RUN:                               | FileCheck %s --check-prefix=CHECK
 
 __attribute__ ((target("branch-protection=none")))
 void none() {}
-// NO-OVERRIDE: define void @none() #[[#NONE]]
-// OVERRIDE: define void @none() #[[#NONE:]]
+// CHECK: define void @none() #[[#NONE:]]
 
   __attribute__ ((target("branch-protection=standard")))
 void std() {}
-// NO-OVERRIDE: define void @std() #[[#STD:]]
-// OVERRIDE: define void @std() #[[#STD]]
+// CHECK: define void @std() #[[#STD:]]
 
 __attribute__ ((target("branch-protection=bti")))
 void btionly() {}
-// NO-OVERRIDE: define void @btionly() #[[#BTI:]]
-// OVERRIDE: define void @btionly() #[[#BTI:]]
+// CHECK: define void @btionly() #[[#BTI:]]
 
 __attribute__ ((target("branch-protection=pac-ret")))
 void paconly() {}
-// NO-OVERRIDE: define void @paconly() #[[#PAC:]]
-// OVERRIDE: define void @paconly() #[[#PAC:]]
+// CHECK: define void @paconly() #[[#PAC:]]
 
 __attribute__ ((target("branch-protection=pac-ret+bti")))
 void pacbti0() {}
-// NO-OVERRIDE: define void @pacbti0() #[[#PACBTI:]]
-// OVERRIDE: define void @pacbti0() #[[#PACBTI:]]
+// CHECK: define void @pacbti0() #[[#PACBTI:]]
 
 __attribute__ ((target("branch-protection=bti+pac-ret")))
 void pacbti1() {}
-// NO-OVERRIDE: define void @pacbti1() #[[#PACBTI]]
-// OVERRIDE: define void @pacbti1() #[[#PACBTI]]
+// CHECK: define void @pacbti1() #[[#PACBTI]]
 
 __attribute__ ((target("branch-protection=pac-ret+leaf")))
 void leaf() {}
-// NO-OVERRIDE: define void @leaf() #[[#PACLEAF:]]
-// OVERRIDE: define void @leaf() #[[#PACLEAF:]]
+// CHECK: define void @leaf() #[[#PACLEAF:]]
 
 __attribute__ ((target("branch-protection=pac-ret+b-key")))
 void bkey() {}
-// NO-OVERRIDE: define void @bkey() #[[#PACBKEY:]]
-// OVERRIDE: define void @bkey() #[[#PACBKEY:]]
+// CHECK: define void @bkey() #[[#PACBKEY:]]
 
 __attribute__ ((target("branch-protection=pac-ret+b-key+leaf")))
 void bkeyleaf0() {}
-// NO-OVERRIDE: define void @bkeyleaf0()  #[[#PACBKEYLEAF:]]
-// OVERRIDE: define void @bkeyleaf0()  #[[#PACBKEYLEAF:]]
+// CHECK: define void @bkeyleaf0()  #[[#PACBKEYLEAF:]]
 
 __attribute__ ((target("branch-protection=pac-ret+leaf+b-key")))
 void bkeyleaf1() {}
-// NO-OVERRIDE: define void @bkeyleaf1()  #[[#PACBKEYLEAF]]
-// OVERRIDE: define void @bkeyleaf1()  #[[#PACBKEYLEAF]]
+// CHECK: define void @bkeyleaf1()  #[[#PACBKEYLEAF]]
 
 __attribute__ ((target("branch-protection=pac-ret+leaf+bti")))
 void btileaf() {}
-// NO-OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]]
-// OVERRIDE: define void @btileaf() #[[#BTIPACLEAF:]]
+// CHECK: define void @btileaf() #[[#BTIPACLEAF:]]
 
-// CHECK-DAG: attributes #[[#NONE]]
+// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none"
 
-// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
+// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
 
-// CHECK-DAG: attributes #[[#BTI]] = { {{.*}}"branch-target-enforcement"
+// CHECK-DAG: attributes #[[#BTI]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="none"
 
-// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
+// CHECK-DAG: attributes #[[#PAC]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
 
-// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"
+// CHECK-DAG: attributes #[[#PACLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
 
-// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#PACBKEY]] = { {{.*}}"branch-target-enforcement"="false" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
 
-// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "sign-return-address"="all" "sign-return-address-key"="b_key"
+// CHECK-DAG: attributes #[[#PACBKEYLEAF]] = { {{.*}} "branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="b_key"
 
-// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"
+// CHECK-DAG: attributes #[[#BTIPACLEAF]] = { {{.*}}"branch-target-enforcement"="true" {{.*}} "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 d062685e40c9..7dd7231e824a 100644
--- a/clang/test/CodeGen/aarch64-sign-return-address.c
+++ b/clang/test/CodeGen/aarch64-sign-return-address.c
@@ -1,27 +1,46 @@
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=none  %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.2-a -S -emit-llvm -o - -msign-return-address=all  %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=all %s   | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=non-leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=PARTIAL --check-prefix=A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -msign-return-address=all %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.4-a -S -emit-llvm -o - -msign-return-address=all %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s   | FileCheck %s --check-prefix=CHECK --check-prefix=PARTIAL --check-prefix=B-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf %s   | FileCheck %s --check-prefix=CHECK --check-prefix=ALL --check-prefix=B-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -march=armv8.3-a -S -emit-llvm -o - -mbranch-protection=bti %s | FileCheck %s --check-prefix=CHECK --check-prefix=BTE
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=none     %s | FileCheck %s --check-prefix=CHECK --check-prefix=NONE
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=all      %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=non-leaf %s | FileCheck %s --check-prefix=CHECK --check-prefix=PART
+
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=none %s          | FileCheck %s --check-prefix=CHECK --check-prefix=NONE
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf  %s | FileCheck %s --check-prefix=CHECK --check-prefix=ALL
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | FileCheck %s --check-prefix=CHECK --check-prefix=B-KEY
+// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=bti %s           | FileCheck %s --check-prefix=CHECK --check-prefix=BTE
 
 // REQUIRES: aarch64-registered-target
 
-// CHECK: @foo() #[[ATTR:[0-9]*]]
-//
-// NONE-NOT: "sign-return-address"={{.*}}
+// Check there are no branch protection function attributes
+
+// CHECK-LABEL: @foo() #[[#ATTR:]]
+
+// CHECK-NOT:  attributes #[[#ATTR]] = { {{.*}} "sign-return-address"
+// CHECK-NOT:  attributes #[[#ATTR]] = { {{.*}} "sign-return-address-key"
+// CHECK-NOT:  attributes #[[#ATTR]] = { {{.*}} "branch-target-enforcement"
 
-// PARTIAL: "sign-return-address"="non-leaf"
+// Check module attributes
 
-// ALL: "sign-return-address"="all"
+// NONE:  !{i32 1, !"branch-target-enforcement", i32 0}
+// ALL:   !{i32 1, !"branch-target-enforcement", i32 0}
+// PART:  !{i32 1, !"branch-target-enforcement", i32 0}
+// BTE:   !{i32 1, !"branch-target-enforcement", i32 1}
+// B-KEY: !{i32 1, !"branch-target-enforcement", i32 0}
 
-// BTE: "branch-target-enforcement"
+// NONE:  !{i32 1, !"sign-return-address", i32 0}
+// ALL:   !{i32 1, !"sign-return-address", i32 1}
+// PART:  !{i32 1, !"sign-return-address", i32 1}
+// BTE:   !{i32 1, !"sign-return-address", i32 0}
+// B-KEY: !{i32 1, !"sign-return-address", i32 1}
 
-// A-KEY: "sign-return-address-key"="a_key"
+// NONE:  !{i32 1, !"sign-return-address-all", i32 0}
+// ALL:   !{i32 1, !"sign-return-address-all", i32 1}
+// PART:  !{i32 1, !"sign-return-address-all", i32 0}
+// BTE:   !{i32 1, !"sign-return-address-all", i32 0}
+// B-KEY: !{i32 1, !"sign-return-address-all", i32 0}
 
-// B-KEY: "sign-return-address-key"="b_key"
+// NONE:  !{i32 1, !"sign-return-address-with-bkey", i32 0}
+// ALL:   !{i32 1, !"sign-return-address-with-bkey", i32 0}
+// PART:  !{i32 1, !"sign-return-address-with-bkey", i32 0}
+// BTE:   !{i32 1, !"sign-return-address-with-bkey", i32 0}
+// B-KEY: !{i32 1, !"sign-return-address-with-bkey", i32 1}
 
 void foo() {}

diff  --git a/clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp b/clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp
deleted file mode 100644
index 3971c22287f9..000000000000
--- a/clang/test/CodeGenCXX/aarch64-sign-return-address-static-ctor.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=none  %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=non-leaf %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL  --check-prefix=CHECK-A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -msign-return-address=all %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL  --check-prefix=CHECK-A-KEY
-
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=none %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NONE
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=standard %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL  --check-prefix=CHECK-A-KEY  --check-prefix=CHECK-BTE
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL  --check-prefix=CHECK-A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+leaf %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL  --check-prefix=CHECK-A-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-PARTIAL  --check-prefix=CHECK-B-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL  --check-prefix=CHECK-B-KEY
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=bti %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BTE
-// RUN: %clang -target aarch64-arm-none-eabi -S -emit-llvm -o - -mbranch-protection=pac-ret+b-key+leaf+bti %s | \
-// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ALL  --check-prefix=CHECK-B-KEY --check-prefix=BTE
-
-struct Foo {
-  Foo() {}
-  ~Foo() {}
-};
-
-Foo f;
-
-// CHECK: @llvm.global_ctors {{.*}}i32 65535, void ()* @[[CTOR_FN:.*]], i8* null
-
-// CHECK: @[[CTOR_FN]]() #[[ATTR:[0-9]*]]
-
-// CHECK-NONE-NOT: "sign-return-address"={{.*}}
-// CHECK-PARTIAL: "sign-return-address"="non-leaf"
-// CHECK-ALL: "sign-return-address"="all"
-// CHECK-A-KEY: "sign-return-address-key"="a_key"
-// CHECK-B-KEY: "sign-return-address-key"="b_key"
-// CHECK-BTE: "branch-target-enforcement"

diff  --git a/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
index 1956014b738d..d3b5166585c3 100644
--- a/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
+++ b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
@@ -16,6 +16,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "AArch64MachineFunctionInfo.h"
 #include "AArch64Subtarget.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -57,13 +58,13 @@ FunctionPass *llvm::createAArch64BranchTargetsPass() {
 }
 
 bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) {
-  const Function &F = MF.getFunction();
-  if (!F.hasFnAttribute("branch-target-enforcement"))
+  if (!MF.getInfo<AArch64FunctionInfo>()->branchTargetEnforcement())
     return false;
 
   LLVM_DEBUG(
       dbgs() << "********** AArch64 Branch Targets  **********\n"
              << "********** Function: " << MF.getName() << '\n');
+  const Function &F = MF.getFunction();
 
   // LLVM does not consider basic blocks which are the targets of jump tables
   // to be address-taken (the address can't escape anywhere else), but they are

diff  --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 625415e93d9c..7f4498da317c 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -375,31 +375,6 @@ MachineBasicBlock::iterator AArch64FrameLowering::eliminateCallFramePseudoInstr(
   return MBB.erase(I);
 }
 
-static bool ShouldSignReturnAddress(MachineFunction &MF) {
-  // The function should be signed in the following situations:
-  // - sign-return-address=all
-  // - sign-return-address=non-leaf and the functions spills the LR
-
-  const Function &F = MF.getFunction();
-  if (!F.hasFnAttribute("sign-return-address"))
-    return false;
-
-  StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString();
-  if (Scope.equals("none"))
-    return false;
-
-  if (Scope.equals("all"))
-    return true;
-
-  assert(Scope.equals("non-leaf") && "Expected all, none or non-leaf");
-
-  for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo())
-    if (Info.getReg() == AArch64::LR)
-      return true;
-
-  return false;
-}
-
 // Convenience function to create a DWARF expression for
 //   Expr + NumBytes + NumVGScaledBytes * AArch64::VG
 static void appendVGScaledOffsetExpr(SmallVectorImpl<char> &Expr,
@@ -1007,17 +982,6 @@ static void adaptForLdStOpt(MachineBasicBlock &MBB,
   //
 }
 
-static bool ShouldSignWithAKey(MachineFunction &MF) {
-  const Function &F = MF.getFunction();
-  if (!F.hasFnAttribute("sign-return-address-key"))
-    return true;
-
-  const StringRef Key =
-      F.getFnAttribute("sign-return-address-key").getValueAsString();
-  assert(Key.equals_lower("a_key") || Key.equals_lower("b_key"));
-  return Key.equals_lower("a_key");
-}
-
 static bool needsWinCFI(const MachineFunction &MF) {
   const Function &F = MF.getFunction();
   return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
@@ -1070,15 +1034,16 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
   // to determine the end of the prologue.
   DebugLoc DL;
 
-  if (ShouldSignReturnAddress(MF)) {
-    if (ShouldSignWithAKey(MF))
-      BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP))
-          .setMIFlag(MachineInstr::FrameSetup);
-    else {
+  const auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
+  if (MFnI.shouldSignReturnAddress()) {
+    if (MFnI.shouldSignWithBKey()) {
       BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
           .setMIFlag(MachineInstr::FrameSetup);
       BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP))
           .setMIFlag(MachineInstr::FrameSetup);
+    } else {
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP))
+          .setMIFlag(MachineInstr::FrameSetup);
     }
 
     unsigned CFIIndex =
@@ -1510,7 +1475,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
 
 static void InsertReturnAddressAuth(MachineFunction &MF,
                                     MachineBasicBlock &MBB) {
-  if (!ShouldSignReturnAddress(MF))
+  const auto &MFI = *MF.getInfo<AArch64FunctionInfo>();
+  if (!MFI.shouldSignReturnAddress())
     return;
   const AArch64Subtarget &Subtarget = MF.getSubtarget<AArch64Subtarget>();
   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
@@ -1527,13 +1493,13 @@ static void InsertReturnAddressAuth(MachineFunction &MF,
   if (Subtarget.hasV8_3aOps() && MBBI != MBB.end() &&
       MBBI->getOpcode() == AArch64::RET_ReallyLR) {
     BuildMI(MBB, MBBI, DL,
-            TII->get(ShouldSignWithAKey(MF) ? AArch64::RETAA : AArch64::RETAB))
+            TII->get(MFI.shouldSignWithBKey() ? AArch64::RETAB : AArch64::RETAA))
         .copyImplicitOps(*MBBI);
     MBB.erase(MBBI);
   } else {
     BuildMI(
         MBB, MBBI, DL,
-        TII->get(ShouldSignWithAKey(MF) ? AArch64::AUTIASP : AArch64::AUTIBSP))
+        TII->get(MFI.shouldSignWithBKey() ? AArch64::AUTIBSP : AArch64::AUTIASP))
         .setMIFlag(MachineInstr::FrameDestroy);
   }
 }

diff  --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index fda514b2006c..16820fea0a7d 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "AArch64MachineFunctionInfo.h"
 #include "AArch64TargetMachine.h"
 #include "MCTargetDesc/AArch64AddressingModes.h"
 #include "llvm/ADT/APSInt.h"

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index cb9500c16f38..53ae3370c217 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -5842,84 +5842,20 @@ AArch64InstrInfo::findRegisterToSaveLRTo(const outliner::Candidate &C) const {
 static bool
 outliningCandidatesSigningScopeConsensus(const outliner::Candidate &a,
                                          const outliner::Candidate &b) {
-  const Function &Fa = a.getMF()->getFunction();
-  const Function &Fb = b.getMF()->getFunction();
+  const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
+  const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
 
-  // If none of the functions have the "sign-return-address" attribute their
-  // signing behaviour is equal
-  if (!Fa.hasFnAttribute("sign-return-address") &&
-      !Fb.hasFnAttribute("sign-return-address")) {
-    return true;
-  }
-
-  // If both functions have the "sign-return-address" attribute their signing
-  // behaviour is equal, if the values of the attributes are equal
-  if (Fa.hasFnAttribute("sign-return-address") &&
-      Fb.hasFnAttribute("sign-return-address")) {
-    StringRef ScopeA =
-        Fa.getFnAttribute("sign-return-address").getValueAsString();
-    StringRef ScopeB =
-        Fb.getFnAttribute("sign-return-address").getValueAsString();
-    return ScopeA.equals(ScopeB);
-  }
-
-  // If function B doesn't have the "sign-return-address" attribute but A does,
-  // the functions' signing behaviour is equal if A's value for
-  // "sign-return-address" is "none" and vice versa.
-  if (Fa.hasFnAttribute("sign-return-address")) {
-    StringRef ScopeA =
-        Fa.getFnAttribute("sign-return-address").getValueAsString();
-    return ScopeA.equals("none");
-  }
-
-  if (Fb.hasFnAttribute("sign-return-address")) {
-    StringRef ScopeB =
-        Fb.getFnAttribute("sign-return-address").getValueAsString();
-    return ScopeB.equals("none");
-  }
-
-  llvm_unreachable("Unkown combination of sign-return-address attributes");
+  return MFIa->shouldSignReturnAddress(false) == MFIb->shouldSignReturnAddress(false) &&
+         MFIa->shouldSignReturnAddress(true) == MFIb->shouldSignReturnAddress(true);
 }
 
 static bool
 outliningCandidatesSigningKeyConsensus(const outliner::Candidate &a,
                                        const outliner::Candidate &b) {
-  const Function &Fa = a.getMF()->getFunction();
-  const Function &Fb = b.getMF()->getFunction();
-
-  // If none of the functions have the "sign-return-address-key" attribute
-  // their keys are equal
-  if (!Fa.hasFnAttribute("sign-return-address-key") &&
-      !Fb.hasFnAttribute("sign-return-address-key")) {
-    return true;
-  }
-
-  // If both functions have the "sign-return-address-key" attribute their
-  // keys are equal if the values of "sign-return-address-key" are equal
-  if (Fa.hasFnAttribute("sign-return-address-key") &&
-      Fb.hasFnAttribute("sign-return-address-key")) {
-    StringRef KeyA =
-        Fa.getFnAttribute("sign-return-address-key").getValueAsString();
-    StringRef KeyB =
-        Fb.getFnAttribute("sign-return-address-key").getValueAsString();
-    return KeyA.equals(KeyB);
-  }
-
-  // If B doesn't have the "sign-return-address-key" attribute, both keys are
-  // equal, if function a has the default key (a_key)
-  if (Fa.hasFnAttribute("sign-return-address-key")) {
-    StringRef KeyA =
-        Fa.getFnAttribute("sign-return-address-key").getValueAsString();
-    return KeyA.equals_lower("a_key");
-  }
-
-  if (Fb.hasFnAttribute("sign-return-address-key")) {
-    StringRef KeyB =
-        Fb.getFnAttribute("sign-return-address-key").getValueAsString();
-    return KeyB.equals_lower("a_key");
-  }
+  const auto &MFIa = a.getMF()->getInfo<AArch64FunctionInfo>();
+  const auto &MFIb = b.getMF()->getInfo<AArch64FunctionInfo>();
 
-  llvm_unreachable("Unkown combination of sign-return-address-key attributes");
+  return MFIa->shouldSignWithBKey() == MFIb->shouldSignWithBKey();
 }
 
 static bool outliningCandidatesV8_3OpsConsensus(const outliner::Candidate &a,
@@ -5975,9 +5911,10 @@ outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
   // v8.3a RET can be replaced by RETAA/RETAB and no AUT instruction is
   // necessary. However, at this point we don't know if the outlined function
   // will have a RET instruction so we assume the worst.
-  const Function &FCF = FirstCand.getMF()->getFunction();
   const TargetRegisterInfo &TRI = getRegisterInfo();
-  if (FCF.hasFnAttribute("sign-return-address")) {
+  if (FirstCand.getMF()
+          ->getInfo<AArch64FunctionInfo>()
+          ->shouldSignReturnAddress(true)) {
     // One PAC and one AUT instructions
     NumBytesToCreateFrame += 8;
 
@@ -6106,7 +6043,7 @@ outliner::OutlinedFunction AArch64InstrInfo::getOutliningCandidateInfo(
   NumBytesToCreateFrame += 4;
 
   bool HasBTI = any_of(RepeatedSequenceLocs, [](outliner::Candidate &C) {
-    return C.getMF()->getFunction().hasFnAttribute("branch-target-enforcement");
+    return C.getMF()->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement();
   });
 
   // We check to see if CFI Instructions are present, and if they are
@@ -6811,27 +6748,11 @@ void AArch64InstrInfo::buildOutlinedFrame(
   // If a bunch of candidates reach this point they must agree on their return
   // address signing. It is therefore enough to just consider the signing
   // behaviour of one of them
-  const Function &CF = OF.Candidates.front().getMF()->getFunction();
-  bool ShouldSignReturnAddr = false;
-  if (CF.hasFnAttribute("sign-return-address")) {
-    StringRef Scope =
-        CF.getFnAttribute("sign-return-address").getValueAsString();
-    if (Scope.equals("all"))
-      ShouldSignReturnAddr = true;
-    else if (Scope.equals("non-leaf") && !IsLeafFunction)
-      ShouldSignReturnAddr = true;
-  }
+  const auto &MFI = *OF.Candidates.front().getMF()->getInfo<AArch64FunctionInfo>();
+  bool ShouldSignReturnAddr = MFI.shouldSignReturnAddress(!IsLeafFunction);
 
   // a_key is the default
-  bool ShouldSignReturnAddrWithAKey = true;
-  if (CF.hasFnAttribute("sign-return-address-key")) {
-    const StringRef Key =
-        CF.getFnAttribute("sign-return-address-key").getValueAsString();
-    // Key can either be a_key or b_key
-    assert((Key.equals_lower("a_key") || Key.equals_lower("b_key")) &&
-           "Return address signing key must be either a_key or b_key");
-    ShouldSignReturnAddrWithAKey = Key.equals_lower("a_key");
-  }
+  bool ShouldSignReturnAddrWithAKey = !MFI.shouldSignWithBKey();
 
   // If this is a tail call outlined function, then there's already a return.
   if (OF.FrameConstructionID == MachineOutlinerTailCall ||

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index ee12563cb093..3235e1971578 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -593,8 +593,8 @@ let RecomputePerFunction = 1 in {
   // Avoid generating STRQro if it is slow, unless we're optimizing for code size.
   def UseSTRQro : Predicate<"!Subtarget->isSTRQroSlow() || shouldOptForSize(MF)">;
 
-  def UseBTI : Predicate<[{ MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>;
-  def NotUseBTI : Predicate<[{ !MF->getFunction().hasFnAttribute("branch-target-enforcement") }]>;
+  def UseBTI : Predicate<[{ MF->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement() }]>;
+  def NotUseBTI : Predicate<[{ !MF->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement() }]>;
 
   def SLSBLRMitigation : Predicate<[{ MF->getSubtarget<AArch64Subtarget>().hardenSlsBlr() }]>;
   def NoSLSBLRMitigation : Predicate<[{ !MF->getSubtarget<AArch64Subtarget>().hardenSlsBlr() }]>;

diff  --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index a37e38072554..41343ba9700c 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -14,6 +14,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "AArch64MachineFunctionInfo.h"
+#include "AArch64InstrInfo.h"
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Module.h>
 
 using namespace llvm;
 
@@ -30,3 +33,82 @@ void AArch64FunctionInfo::initializeBaseYamlFields(
   if (YamlMFI.HasRedZone.hasValue())
     HasRedZone = YamlMFI.HasRedZone;
 }
+
+static std::pair<bool, bool> GetSignReturnAddress(const Function &F) {
+  // The function should be signed in the following situations:
+  // - sign-return-address=all
+  // - sign-return-address=non-leaf and the functions spills the LR
+  if (!F.hasFnAttribute("sign-return-address")) {
+    const Module &M = *F.getParent();
+    if (const auto *Sign = mdconst::extract_or_null<ConstantInt>(
+            M.getModuleFlag("sign-return-address"))) {
+      if (Sign->getZExtValue()) {
+        if (const auto *All = mdconst::extract_or_null<ConstantInt>(
+                M.getModuleFlag("sign-return-address-all")))
+          return {true, All->getZExtValue()};
+        return {true, false};
+      }
+    }
+    return {false, false};
+  }
+
+  StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString();
+  if (Scope.equals("none"))
+    return {false, false};
+
+  if (Scope.equals("all"))
+    return {true, true};
+
+  assert(Scope.equals("non-leaf"));
+  return {true, false};
+}
+
+static bool ShouldSignWithBKey(const Function &F) {
+  if (!F.hasFnAttribute("sign-return-address-key")) {
+    if (const auto *BKey = mdconst::extract_or_null<ConstantInt>(
+            F.getParent()->getModuleFlag("sign-return-address-with-bkey")))
+      return BKey->getZExtValue();
+    return false;
+  }
+
+  const StringRef Key =
+      F.getFnAttribute("sign-return-address-key").getValueAsString();
+  assert(Key.equals_lower("a_key") || Key.equals_lower("b_key"));
+  return Key.equals_lower("b_key");
+}
+
+AArch64FunctionInfo::AArch64FunctionInfo(MachineFunction &MF) : MF(MF) {
+  // If we already know that the function doesn't have a redzone, set
+  // HasRedZone here.
+  if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone))
+    HasRedZone = false;
+
+  const Function &F = MF.getFunction();
+  std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F);
+  SignWithBKey = ShouldSignWithBKey(F);
+
+  if (!F.hasFnAttribute("branch-target-enforcement")) {
+    if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
+            F.getParent()->getModuleFlag("branch-target-enforcement")))
+      BranchTargetEnforcement = BTE->getZExtValue();
+    return;
+  }
+
+  const StringRef BTIEnable = F.getFnAttribute("branch-target-enforcement").getValueAsString();
+  assert(BTIEnable.equals_lower("true") || BTIEnable.equals_lower("false"));
+  BranchTargetEnforcement = BTIEnable.equals_lower("true");
+}
+
+bool AArch64FunctionInfo::shouldSignReturnAddress(bool SpillsLR) const {
+  if (!SignReturnAddress)
+    return false;
+  if (SignReturnAddressAll)
+    return true;
+  return SpillsLR;
+}
+
+bool AArch64FunctionInfo::shouldSignReturnAddress() const {
+  return shouldSignReturnAddress(llvm::any_of(
+      MF.getFrameInfo().getCalleeSavedInfo(),
+      [](const auto &Info) { return Info.getReg() == AArch64::LR; }));
+}

diff  --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 7e995b8938c2..cc07b9ae465a 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -35,6 +35,9 @@ class MachineInstr;
 /// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and
 /// contains private AArch64-specific information for each MachineFunction.
 class AArch64FunctionInfo final : public MachineFunctionInfo {
+  /// Backreference to the machine function.
+  MachineFunction &MF;
+
   /// Number of bytes of arguments this function has on the stack. If the callee
   /// is expected to restore the argument stack this should be a multiple of 16,
   /// all usable during a tail call.
@@ -138,17 +141,24 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
   // CalleeSavedStackSize) to the address of the frame record.
   int CalleeSaveBaseToFrameRecordOffset = 0;
 
-public:
-  AArch64FunctionInfo() = default;
+  /// SignReturnAddress is true if PAC-RET is enabled for the function with
+  /// defaults being sign non-leaf functions only, with the B key.
+  bool SignReturnAddress = false;
 
-  explicit AArch64FunctionInfo(MachineFunction &MF) {
-    (void)MF;
+  /// SignReturnAddressAll modifies the default PAC-RET mode to signing leaf
+  /// functions as well.
+  bool SignReturnAddressAll = false;
+
+  /// SignWithBKey modifies the default PAC-RET mode to signing with the B key.
+  bool SignWithBKey = false;
+
+  /// BranchTargetEnforcement enables placing BTI instructions at potential
+  /// indirect branch destinations.
+  bool BranchTargetEnforcement = false;
+
+public:
+  explicit AArch64FunctionInfo(MachineFunction &MF);
 
-    // If we already know that the function doesn't have a redzone, set
-    // HasRedZone here.
-    if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone))
-      HasRedZone = false;
-  }
   void initializeBaseYamlFields(const yaml::AArch64FunctionInfo &YamlMFI);
 
   unsigned getBytesInStackArgArea() const { return BytesInStackArgArea; }
@@ -347,6 +357,13 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
     CalleeSaveBaseToFrameRecordOffset = Offset;
   }
 
+  bool shouldSignReturnAddress() const;
+  bool shouldSignReturnAddress(bool SpillsLR) const;
+
+  bool shouldSignWithBKey() const { return SignWithBKey; }
+
+  bool branchTargetEnforcement() const { return BranchTargetEnforcement; }
+
 private:
   // Hold the lists of LOHs.
   MILOHContainer LOHContainerSet;

diff  --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
index 5bfed7e472b0..4ab940c1f26a 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
@@ -789,7 +789,7 @@ static unsigned getCallOpcode(const MachineFunction &CallerF, bool IsIndirect,
 
   // When BTI is enabled, we need to use TCRETURNriBTI to make sure that we use
   // x16 or x17.
-  if (CallerF.getFunction().hasFnAttribute("branch-target-enforcement"))
+  if (CallerF.getInfo<AArch64FunctionInfo>()->branchTargetEnforcement())
     return AArch64::TCRETURNriBTI;
 
   return AArch64::TCRETURNri;
@@ -809,7 +809,7 @@ bool AArch64CallLowering::lowerTailCall(
 
   // TODO: Right now, regbankselect doesn't know how to handle the rtcGPR64
   // register class. Until we can do that, we should fall back here.
-  if (F.hasFnAttribute("branch-target-enforcement")) {
+  if (MF.getInfo<AArch64FunctionInfo>()->branchTargetEnforcement()) {
     LLVM_DEBUG(
         dbgs() << "Cannot lower indirect tail calls with BTI enabled yet.\n");
     return false;

diff  --git a/llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll b/llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll
index 3fb9e320f890..702d9dfc8fae 100644
--- a/llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll
+++ b/llvm/test/CodeGen/AArch64/branch-target-enforcement-indirect-calls.ll
@@ -20,7 +20,7 @@ entry:
   ret void
 }
 
-define void @bti_enabled(void ()* %p) "branch-target-enforcement" {
+define void @bti_enabled(void ()* %p) "branch-target-enforcement"="true" {
 entry:
   tail call void %p()
 ; CHECK: br {{x16|x17}}

diff  --git a/llvm/test/CodeGen/AArch64/branch-target-enforcement.mir b/llvm/test/CodeGen/AArch64/branch-target-enforcement.mir
index 4879a268407d..f34fb2b84bcc 100644
--- a/llvm/test/CodeGen/AArch64/branch-target-enforcement.mir
+++ b/llvm/test/CodeGen/AArch64/branch-target-enforcement.mir
@@ -3,29 +3,29 @@
   target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
   target triple = "aarch64-arm-none-eabi"
 
-  define hidden i32 @simple_external() "branch-target-enforcement" {
+  define hidden i32 @simple_external() "branch-target-enforcement"="true" {
   entry:
     ret i32 0
   }
 
-  define internal i32 @simple_internal() "branch-target-enforcement" {
+  define internal i32 @simple_internal() "branch-target-enforcement"="true" {
   entry:
     ret i32 0
   }
 
-  define hidden i32 @ptr_auth() "branch-target-enforcement" {
+  define hidden i32 @ptr_auth() "branch-target-enforcement"="true" {
   entry:
     tail call void asm sideeffect "", "~{lr}"()
     ret i32 0
   }
 
-  define hidden i32 @ptr_auth_b() "branch-target-enforcement" {
+  define hidden i32 @ptr_auth_b() "branch-target-enforcement"="true" {
   entry:
     tail call void asm sideeffect "", "~{lr}"()
     ret i32 0
   }
 
-  define hidden i32 @jump_table(i32 %a) "branch-target-enforcement" {
+  define hidden i32 @jump_table(i32 %a) "branch-target-enforcement"="true" {
   entry:
     switch i32 %a, label %sw.epilog [
       i32 1, label %sw.bb
@@ -61,7 +61,7 @@
 
   @label_address.addr = internal unnamed_addr global i8* blockaddress(@label_address, %return), align 8
 
-  define hidden i32 @label_address() "branch-target-enforcement" {
+  define hidden i32 @label_address() "branch-target-enforcement"="true" {
   entry:
     %0 = load i8*, i8** @label_address.addr, align 8
     indirectbr i8* %0, [label %return, label %lab2]
@@ -79,7 +79,7 @@
     ret i32 %merge2
   }
 
-  define hidden i32 @label_address_entry() "branch-target-enforcement" {
+  define hidden i32 @label_address_entry() "branch-target-enforcement"="true" {
   entry:
     %0 = load i8*, i8** @label_address.addr, align 8
     indirectbr i8* %0, [label %return, label %lab2]
@@ -97,7 +97,7 @@
     ret i32 %merge2
   }
 
-  define hidden i32 @debug_ptr_auth() "branch-target-enforcement" {
+  define hidden i32 @debug_ptr_auth() "branch-target-enforcement"="true" {
   entry:
     tail call void asm sideeffect "", "~{lr}"()
     ret i32 0

diff  --git a/llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll b/llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll
index 93cbc3b85bb4..20749f3efd47 100644
--- a/llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll
+++ b/llvm/test/CodeGen/AArch64/bti-branch-relaxation.ll
@@ -61,4 +61,4 @@ declare dso_local void @e(...) local_unnamed_addr #0
 
 declare dso_local i64 @llvm.aarch64.space(i32, i64) local_unnamed_addr #0
 
-attributes #0 = { nounwind "branch-target-enforcement" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+v8.5a" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #0 = { nounwind "branch-target-enforcement"="true" "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon,+v8.5a" "unsafe-fp-math"="false" "use-soft-float"="false" }

diff  --git a/llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir b/llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir
index 2111704c0898..958c28879710 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-2fixup-blr-terminator.mir
@@ -8,7 +8,7 @@
   define void @f2() #0 { ret void }
   define void @f3() #0 { ret void }
   define void @f4() #0 { ret void }
-  attributes #0 = { minsize noredzone "branch-target-enforcement" }
+  attributes #0 = { minsize noredzone "branch-target-enforcement"="true" }
 ...
 ---
 name: f1

diff  --git a/llvm/test/CodeGen/AArch64/machine-outliner-bti.mir b/llvm/test/CodeGen/AArch64/machine-outliner-bti.mir
index d15657ee4998..885c326fd91e 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-bti.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-bti.mir
@@ -15,7 +15,7 @@
 --- |
   @g = hidden local_unnamed_addr global i32 0, align 4
 
-  define hidden void @bar(void ()* nocapture %f) "branch-target-enforcement" {
+  define hidden void @bar(void ()* nocapture %f) "branch-target-enforcement"="true" {
   entry:
     ret void
   }

diff  --git a/llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll b/llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll
index bc1521c6c80d..c30d31fa91b2 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-outline-bti.ll
@@ -5,7 +5,7 @@
 
 @g = hidden global i32 0, align 4
 
-define hidden void @foo() minsize "branch-target-enforcement" {
+define hidden void @foo() minsize "branch-target-enforcement"="true" {
 entry:
 ; CHECK: hint #34
 ; CHECK: b       OUTLINED_FUNCTION_0
@@ -13,7 +13,7 @@ entry:
   ret void
 }
 
-define hidden void @bar() minsize "branch-target-enforcement" {
+define hidden void @bar() minsize "branch-target-enforcement"="true" {
 entry:
 ; CHECK: hint #34
 ; CHECK: b       OUTLINED_FUNCTION_0

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll
index 798cd72c5be6..fdd1d63b267b 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-0.ll
@@ -4,7 +4,7 @@
 ; RUN:   llvm-readelf --notes - | FileCheck %s --check-prefix=OBJ
 @x = common dso_local global i32 0, align 4
 
-attributes #0 = { "branch-target-enforcement" }
+attributes #0 = { "branch-target-enforcement"="true" }
 
 ; Both attributes present in a file with no functions.
 ; ASM:	    .word	3221225472

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll
index 747836cab832..9757dec1f844 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-1.ll
@@ -8,7 +8,7 @@ entry:
   ret i32 0
 }
 
-attributes #0 = { "branch-target-enforcement" }
+attributes #0 = { "branch-target-enforcement"="true" }
 
 ; BTI attribute present
 ; ASM:	    .word	3221225472

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll
index ad222e8b4e48..5082fa01f1d4 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-3.ll
@@ -8,7 +8,7 @@ entry:
   ret i32 0
 }
 
-attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" }
+attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" }
 
 ; Both attribute present
 ; ASM:	    .word	3221225472

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll
index 83da5305e249..5d81669db7ff 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-4.ll
@@ -13,9 +13,9 @@ entry:
   ret i32 0
 }
 
-attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" }
+attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" }
 
-attributes #1 = { "branch-target-enforcement" }
+attributes #1 = { "branch-target-enforcement"="true" }
 
 ; Only the common atttribute (BTI)
 ; ASM:	    .word	3221225472

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll
index 083f8b38f676..942eb5970c59 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-5.ll
@@ -13,7 +13,7 @@ entry:
   ret i32 0
 }
 
-attributes #0 = { "branch-target-enforcement" "sign-return-address"="non-leaf" }
+attributes #0 = { "branch-target-enforcement"="true" "sign-return-address"="non-leaf" }
 
 attributes #1 = { "sign-return-address"="all" }
 

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll
index 6768252feff1..67f0b2b71c4c 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-7.ll
@@ -15,7 +15,7 @@ entry:
 
 attributes #0 = { "sign-return-address"="non-leaf" }
 
-attributes #1 = { "branch-target-enforcement" }
+attributes #1 = { "branch-target-enforcement"="true" }
 
 ; No common attribute, no note section
 ; ASM: warning: not setting BTI in feature flags

diff  --git a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll
index 44545b413ad4..8549491186f5 100644
--- a/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll
+++ b/llvm/test/CodeGen/AArch64/note-gnu-property-pac-bti-8.ll
@@ -11,7 +11,7 @@ entry:
 
 declare dso_local i32 @g()
 
-attributes #0 = { "branch-target-enforcement" }
+attributes #0 = { "branch-target-enforcement"="true" }
 
 ; Declarations don't prevent setting BTI
 ; ASM:	    .word	3221225472

diff  --git a/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll b/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll
new file mode 100644
index 000000000000..98dcd16fadd4
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-1.ll
@@ -0,0 +1,33 @@
+;; RUN: llc %s -o -| FileCheck %s
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux"
+
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 1, void ()* @asan.module_ctor, i8* null }]
+
+define dso_local i32 @f() #0 {
+entry:
+  ret i32 0
+}
+;; CHECK-LABEL: f:
+;; CHECK: hint #34
+
+declare void @__asan_init()
+declare void @__asan_version_mismatch_check_v8()
+
+define internal void @asan.module_ctor() {
+  call void @__asan_init()
+  call void @__asan_version_mismatch_check_v8()
+  ret void
+}
+;; CHECK-LABEL: asan.module_ctor:
+;; CHECK: hint #34
+
+attributes #0 = { noinline nounwind optnone sanitize_address uwtable "branch-target-enforcement"="true" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 4, !"branch-target-enforcement", i32 1}
+!2 = !{i32 4, !"sign-return-address", i32 0}
+!3 = !{i32 4, !"sign-return-address-all", i32 0}
+!4 = !{i32 4, !"sign-return-address-with-bkey", i32 0}
\ No newline at end of file

diff  --git a/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll b/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll
new file mode 100644
index 000000000000..b302a3d55add
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/pacbti-llvm-generated-funcs-2.ll
@@ -0,0 +1,71 @@
+;; RUN: llc --mattr=+v8.3a %s -o - | FileCheck %s
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux"
+
+ at __llvm_gcov_ctr = internal global [1 x i64] zeroinitializer
+ at 0 = private unnamed_addr constant [7 x i8] c"m.gcda\00", align 1
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__llvm_gcov_init, i8* null }]
+
+define dso_local i32 @f() local_unnamed_addr #0 {
+entry:
+  ret i32 0
+}
+;; CHECK-LABEL: f:
+;; CHECK: pacibsp
+
+declare void @llvm_gcda_start_file(i8*, i32, i32) local_unnamed_addr
+
+declare void @llvm_gcda_emit_function(i32, i32, i32) local_unnamed_addr
+
+declare void @llvm_gcda_emit_arcs(i32, i64*) local_unnamed_addr
+
+declare void @llvm_gcda_summary_info() local_unnamed_addr
+
+declare void @llvm_gcda_end_file() local_unnamed_addr
+
+define internal void @__llvm_gcov_writeout() unnamed_addr #1 {
+entry:
+  tail call void @llvm_gcda_start_file(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i64 0, i64 0), i32 875575338, i32 0)
+  tail call void @llvm_gcda_emit_function(i32 0, i32 0, i32 0)
+  tail call void @llvm_gcda_emit_arcs(i32 1, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0))
+  tail call void @llvm_gcda_summary_info()
+  tail call void @llvm_gcda_end_file()
+  ret void
+}
+;; CHECK-LABEL: __llvm_gcov_writeout:
+;; CHECK:       .cfi_b_key_frame
+;; CHECK-NEXT:  pacibsp
+;; CHECK-NEXT: .cfi_negate_ra_state
+
+define internal void @__llvm_gcov_reset() unnamed_addr #2 {
+entry:
+  store i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__llvm_gcov_ctr, i64 0, i64 0), align 8
+  ret void
+}
+;; CHECK-LABEL: __llvm_gcov_reset:
+;; CHECK:       pacibsp
+
+declare void @llvm_gcov_init(void ()*, void ()*) local_unnamed_addr
+
+define internal void @__llvm_gcov_init() unnamed_addr #1 {
+entry:
+  tail call void @llvm_gcov_init(void ()* nonnull @__llvm_gcov_writeout, void ()* nonnull @__llvm_gcov_reset)
+  ret void
+}
+;; CHECK-LABEL: __llvm_gcov_init:
+;; CHECK:      .cfi_b_key_frame
+;; CHECK-NEXT:  pacibsp
+;; CHECK-NEXT: .cfi_negate_ra_state
+
+attributes #0 = { norecurse nounwind readnone "sign-return-address"="all" "sign-return-address-key"="b_key" }
+attributes #1 = { noinline }
+attributes #2 = { nofree noinline norecurse nounwind writeonly }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{i32 1, !"wchar_size", i32 4}
+!2 = !{i32 1, !"branch-target-enforcement", i32 0}
+!3 = !{i32 1, !"sign-return-address", i32 1}
+!4 = !{i32 1, !"sign-return-address-all", i32 1}
+!5 = !{i32 1, !"sign-return-address-with-bkey", i32 1}

diff  --git a/llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll b/llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll
new file mode 100644
index 000000000000..8fe20d5ebbb1
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/pacbti-module-attrs.ll
@@ -0,0 +1,77 @@
+;; RUN: llc -mtriple=aarch64-eabi -mattr=+v8.5a %s -o - | FileCheck %s
+
+declare i32 @g(i32) #5
+
+define i32 @f0(i32 %x) #0 {
+entry:
+  %call = tail call i32 @g(i32 %x) #5
+  %add = add nsw i32 %call, 1
+  ret i32 %add
+}
+;; CHECK-LABEL: f0:
+;; CHECK-NOT:   bti
+;; CHECK-NOT:   pacia
+;; CHECK-NOT:   reta
+
+define i32 @f1(i32 %x) #1 {
+entry:
+  %call = tail call i32 @g(i32 %x) #5
+  %add = add nsw i32 %call, 1
+  ret i32 %add
+}
+;; CHECK-LABEL: f1:
+;; CHECK:       bti c
+;; CHECK-NOT:   reta
+
+define i32 @f2(i32 %x) #2 {
+entry:
+  %call = tail call i32 @g(i32 %x) #5
+  %add = add nsw i32 %call, 1
+  ret i32 %add
+}
+;; CHECK-LABEL: f2:
+;; CHECK:       paciasp
+;; CHECK:       retaa
+
+define i32 @f3(i32 %x) #3 {
+entry:
+  %call = tail call i32 @g(i32 %x) #5
+  %add = add nsw i32 %call, 1
+  ret i32 %add
+}
+;; CHECK-LABEL: f3:
+;; CHECK:       pacibsp
+;; CHECK:       retab
+
+define i32 @f4(i32 %x) #4 {
+entry:
+  ret i32 1
+}
+;; CHECK-LABEL: f4:
+;; CHECK:       paciasp
+;; CHECK:       retaa
+
+define i32 @f5(i32 %x) #5 {
+entry:
+  %call = tail call i32 @g(i32 %x) #5
+  %add = add nsw i32 %call, 1
+  ret i32 %add
+}
+;; CHECK-LABEL: f5:
+;; CHECK:       paciasp
+;; CHECK:       retaa
+
+attributes #0 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="none" }
+attributes #1 = { nounwind "branch-target-enforcement"="true"  "sign-return-address"="none" }
+attributes #2 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" }
+attributes #3 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="non-leaf" "sign-return-address-key"="b_key" }
+attributes #4 = { nounwind "branch-target-enforcement"="false" "sign-return-address"="all" "sign-return-address-key"="a_key" }
+attributes #5 = { nounwind }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"branch-target-enforcement", i32 1}
+!2 = !{i32 1, !"sign-return-address", i32 1}
+!3 = !{i32 1, !"sign-return-address-all", i32 0}
+!4 = !{i32 1, !"sign-return-address-with-bkey", i32 0}

diff  --git a/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll b/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll
index 4d55eb8bb7d2..01c3d2b0666a 100644
--- a/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll
+++ b/llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll
@@ -1,6 +1,6 @@
 ; RUN: llc -mtriple=aarch64 %s -o - | FileCheck %s
 
-define void @f0() "patchable-function-entry"="0" "branch-target-enforcement" {
+define void @f0() "patchable-function-entry"="0" "branch-target-enforcement"="true" {
 ; CHECK-LABEL: f0:
 ; CHECK-NEXT: .Lfunc_begin0:
 ; CHECK:      // %bb.0:
@@ -12,7 +12,7 @@ define void @f0() "patchable-function-entry"="0" "branch-target-enforcement" {
 
 ;; -fpatchable-function-entry=1 -mbranch-protection=bti
 ;; For M=0, place the label .Lpatch0 after the initial BTI.
-define void @f1() "patchable-function-entry"="1" "branch-target-enforcement" {
+define void @f1() "patchable-function-entry"="1" "branch-target-enforcement"="true" {
 ; CHECK-LABEL: f1:
 ; CHECK-NEXT: .Lfunc_begin1:
 ; CHECK-NEXT: .cfi_startproc
@@ -28,7 +28,7 @@ define void @f1() "patchable-function-entry"="1" "branch-target-enforcement" {
 }
 
 ;; -fpatchable-function-entry=2,1 -mbranch-protection=bti
-define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="1" "branch-target-enforcement" {
+define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="1" "branch-target-enforcement"="true" {
 ; CHECK-LABEL: .type f2_1, at function
 ; CHECK-NEXT: .Ltmp0:
 ; CHECK-NEXT:  nop
@@ -50,7 +50,7 @@ define void @f2_1() "patchable-function-entry"="1" "patchable-function-prefix"="
 ;; -fpatchable-function-entry=1 -mbranch-protection=bti
 ;; For M=0, don't create .Lpatch0 if the initial instruction is not BTI,
 ;; even if other basic blocks may have BTI.
-define internal void @f1i(i64 %v) "patchable-function-entry"="1" "branch-target-enforcement" {
+define internal void @f1i(i64 %v) "patchable-function-entry"="1" "branch-target-enforcement"="true" {
 ; CHECK-LABEL: f1i:
 ; CHECK-NEXT: .Lfunc_begin3:
 ; CHECK:      // %bb.0:


        


More information about the llvm-commits mailing list