summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Matheson <tomas.matheson@arm.com>2023-12-21 18:16:30 +0000
committerTomas Matheson <tomas.matheson@arm.com>2023-12-21 18:32:55 +0000
commit7bd17212ef23a72ea224a037126d33d3e02553fe (patch)
tree2b18ccd6b94efb2fbd28687ab56b1454e91fbaf3
parentc50de57feb2b824d789fe3bc4e0d24c5bfc266ea (diff)
Re-land "[AArch64] Codegen support for FEAT_PAuthLR" (#75947)
This reverts commit 9f0f5587426a4ff24b240018cf8bf3acc3c566ae. Fix expensive checks failure by properly marking register def for ADR.
-rw-r--r--clang/include/clang/Basic/LangOptions.def1
-rw-r--r--clang/include/clang/Basic/TargetInfo.h1
-rw-r--r--clang/include/clang/Driver/Options.td2
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp1
-rw-r--r--clang/lib/Basic/Targets/ARM.cpp1
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp3
-rw-r--r--clang/lib/CodeGen/Targets/AArch64.cpp2
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp7
-rw-r--r--clang/test/CodeGen/aarch64-branch-protection-attr.c28
-rw-r--r--clang/test/Driver/aarch64-pauth-lr.c23
-rw-r--r--clang/test/Driver/aarch64-v95a.c7
-rw-r--r--llvm/include/llvm/TargetParser/AArch64TargetParser.h2
-rw-r--r--llvm/include/llvm/TargetParser/ARMTargetParserCommon.h1
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.cpp11
-rw-r--r--llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp28
-rw-r--r--llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h18
-rw-r--r--llvm/lib/Target/AArch64/AArch64PointerAuth.cpp86
-rw-r--r--llvm/lib/TargetParser/ARMTargetParserCommon.cpp6
-rw-r--r--llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll542
-rw-r--r--llvm/test/CodeGen/AArch64/sign-return-address.ll3
-rw-r--r--llvm/unittests/TargetParser/TargetParserTest.cpp4
21 files changed, 752 insertions, 25 deletions
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 152d9f65f86d..21abc346cf17 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -456,6 +456,7 @@ ENUM_LANGOPT(SignReturnAddressScope, SignReturnAddressScopeKind, 2, SignReturnAd
ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddressKeyKind::AKey,
"Key used for return address signing")
LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled")
+LANGOPT(BranchProtectionPAuthLR, 1, 0, "Use PC as a diversifier using PAuthLR NOP instructions.")
LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index aa0f5023104a..ac3c324c6c29 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1372,6 +1372,7 @@ public:
LangOptions::SignReturnAddressKeyKind SignKey =
LangOptions::SignReturnAddressKeyKind::AKey;
bool BranchTargetEnforcement = false;
+ bool BranchProtectionPAuthLR = false;
};
/// Determine if the Architecture in this TargetInfo supports branch
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 9678165bfd98..2b93ddf03349 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -7000,6 +7000,8 @@ def msign_return_address_key_EQ : Joined<["-"], "msign-return-address-key=">,
Values<"a_key,b_key">;
def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">,
MarshallingInfoFlag<LangOpts<"BranchTargetEnforcement">>;
+def mbranch_protection_pauth_lr : Flag<["-"], "mbranch-protection-pauth-lr">,
+ MarshallingInfoFlag<LangOpts<"BranchProtectionPAuthLR">>;
def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">,
MarshallingInfoNegativeFlag<LangOpts<"DllExportInlines">>;
def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">,
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index def16c032c86..3ee39133fcee 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -225,6 +225,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
BPI.SignKey = LangOptions::SignReturnAddressKeyKind::BKey;
BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
+ BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
return true;
}
diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp
index ce7e4d4639ce..6e1842fc64e5 100644
--- a/clang/lib/Basic/Targets/ARM.cpp
+++ b/clang/lib/Basic/Targets/ARM.cpp
@@ -419,6 +419,7 @@ bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch,
BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey;
BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
+ BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
return true;
}
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b2e173d0d694..d78f2594a237 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1106,6 +1106,9 @@ void CodeGenModule::Release() {
if (LangOpts.BranchTargetEnforcement)
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
1);
+ if (LangOpts.BranchProtectionPAuthLR)
+ getModule().addModuleFlag(llvm::Module::Min, "branch-protection-pauth-lr",
+ 1);
if (LangOpts.hasSignReturnAddress())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
if (LangOpts.isSignReturnAddressScopeAll())
diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp
index be5145daa00b..7102d190fe00 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -136,6 +136,8 @@ public:
Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
+ Fn->addFnAttr("branch-protection-pauth-lr",
+ BPI.BranchProtectionPAuthLR ? "true" : "false");
}
bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index de9fd5eaa1e0..4783affd3220 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -1497,7 +1497,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< Triple.getArchName();
StringRef Scope, Key;
- bool IndirectBranches;
+ bool IndirectBranches, BranchProtectionPAuthLR;
if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
@@ -1506,6 +1506,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< A->getSpelling() << Scope;
Key = "a_key";
IndirectBranches = false;
+ BranchProtectionPAuthLR = false;
} else {
StringRef DiagMsg;
llvm::ARM::ParsedBranchProtection PBP;
@@ -1517,6 +1518,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< "b-key" << A->getAsString(Args);
Scope = PBP.Scope;
Key = PBP.Key;
+ BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
IndirectBranches = PBP.BranchTargetEnforcement;
}
@@ -1525,6 +1527,9 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
if (!Scope.equals("none"))
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
+ if (BranchProtectionPAuthLR)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
}
diff --git a/clang/test/CodeGen/aarch64-branch-protection-attr.c b/clang/test/CodeGen/aarch64-branch-protection-attr.c
index 3c2714e2feda..8ab3e17ade42 100644
--- a/clang/test/CodeGen/aarch64-branch-protection-attr.c
+++ b/clang/test/CodeGen/aarch64-branch-protection-attr.c
@@ -46,6 +46,24 @@ __attribute__ ((target("branch-protection=pac-ret+leaf+bti")))
void btileaf() {}
// CHECK: define{{.*}} void @btileaf() #[[#BTIPACLEAF:]]
+
+__attribute__ ((target("branch-protection=pac-ret+pc")))
+void pauthlr() {}
+// CHECK: define{{.*}} void @pauthlr() #[[#PAUTHLR:]]
+
+__attribute__ ((target("branch-protection=pac-ret+pc+b-key")))
+void pauthlr_bkey() {}
+// CHECK: define{{.*}} void @pauthlr_bkey() #[[#PAUTHLR_BKEY:]]
+
+__attribute__ ((target("branch-protection=pac-ret+pc+leaf")))
+void pauthlr_leaf() {}
+// CHECK: define{{.*}} void @pauthlr_leaf() #[[#PAUTHLR_LEAF:]]
+
+__attribute__ ((target("branch-protection=pac-ret+pc+bti")))
+void pauthlr_bti() {}
+// CHECK: define{{.*}} void @pauthlr_bti() #[[#PAUTHLR_BTI:]]
+
+
// CHECK-DAG: attributes #[[#NONE]] = { {{.*}} "branch-target-enforcement"="false" {{.*}} "sign-return-address"="none"
// CHECK-DAG: attributes #[[#STD]] = { {{.*}} "branch-target-enforcement"="true" {{.*}} "sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
@@ -61,3 +79,13 @@ void btileaf() {}
// 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"="true" {{.*}} "sign-return-address"="all" "sign-return-address-key"="a_key"
+
+
+// CHECK-DAG: attributes #[[#PAUTHLR]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
+
+// CHECK-DAG: attributes #[[#PAUTHLR_BKEY]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="b_key"
+
+// CHECK-DAG: attributes #[[#PAUTHLR_LEAF]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="false" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"
+
+// CHECK-DAG: attributes #[[#PAUTHLR_BTI]] = { {{.*}}"branch-protection-pauth-lr"="true" {{.*}}"branch-target-enforcement"="true" {{.*}}"sign-return-address"="non-leaf" "sign-return-address-key"="a_key"
+
diff --git a/clang/test/Driver/aarch64-pauth-lr.c b/clang/test/Driver/aarch64-pauth-lr.c
new file mode 100644
index 000000000000..2e1b530fc989
--- /dev/null
+++ b/clang/test/Driver/aarch64-pauth-lr.c
@@ -0,0 +1,23 @@
+// Check the -cc1 flags for the various forms of -mbranch-protection=pac-ret+pc.
+
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+b-key 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-B-KEY
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+leaf 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-LEAF
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+bti 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-BTI
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+leaf+b-key+bti 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-LEAF-B-KEY-BTI
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc -march=armv9.5-a 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+b-key -march=armv9.5-a 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-B-KEY
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+leaf -march=armv9.5-a 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-LEAF
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+bti -march=armv9.5-a 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-BTI
+// RUN: %clang -target aarch64-arm-none-eabi -c %s -### -mbranch-protection=pac-ret+pc+leaf+b-key+bti -march=armv9.5-a 2>&1 | FileCheck %s --check-prefixes=PAUTH-LR-LEAF-B-KEY-BTI
+
+// PAUTH-LR: "-msign-return-address=non-leaf" "-msign-return-address-key=a_key" "-mbranch-protection-pauth-lr"
+// PAUTH-LR-B-KEY: "-msign-return-address=non-leaf" "-msign-return-address-key=b_key" "-mbranch-protection-pauth-lr"
+// PAUTH-LR-LEAF: "-msign-return-address=all" "-msign-return-address-key=a_key" "-mbranch-protection-pauth-lr"
+// PAUTH-LR-BTI: "-msign-return-address=non-leaf" "-msign-return-address-key=a_key" "-mbranch-protection-pauth-lr"
+// PAUTH-LR-LEAF-B-KEY-BTI: "-msign-return-address=all" "-msign-return-address-key=b_key" "-mbranch-protection-pauth-lr" "-mbranch-target-enforce"
+
+// NOT-PAUTH-LR: "-mbranch-target-enforce"
+// NOT-PAUTH-LR-B-KEY: "-mbranch-target-enforce"
+// NOT-PAUTH-LR-LEAF: "-mbranch-target-enforce"
+// NOT-PAUTH-LR-BTI: "-mbranch-target-enforce"
diff --git a/clang/test/Driver/aarch64-v95a.c b/clang/test/Driver/aarch64-v95a.c
index 366cade86a9f..6fac62e8b389 100644
--- a/clang/test/Driver/aarch64-v95a.c
+++ b/clang/test/Driver/aarch64-v95a.c
@@ -1,3 +1,5 @@
+// ===== Base v9.5a architecture =====
+
// RUN: %clang -target aarch64 -march=armv9.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A %s
// RUN: %clang -target aarch64 -march=armv9.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A %s
// RUN: %clang -target aarch64 -mlittle-endian -march=armv9.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A %s
@@ -5,6 +7,7 @@
// RUN: %clang -target aarch64_be -mlittle-endian -march=armv9.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A %s
// RUN: %clang -target aarch64_be -mlittle-endian -march=armv9.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A %s
// GENERICV95A: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a"
+
// RUN: %clang -target aarch64_be -march=armv9.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A-BE %s
// RUN: %clang -target aarch64_be -march=armv9.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A-BE %s
// RUN: %clang -target aarch64 -mbig-endian -march=armv9.5a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A-BE %s
@@ -18,3 +21,7 @@
// RUN: %clang -target aarch64 -march=armv9.5a+cpa -### -c %s 2>&1 | FileCheck -check-prefix=V95A-CPA %s
// RUN: %clang -target aarch64 -march=armv9.5-a+cpa -### -c %s 2>&1 | FileCheck -check-prefix=V95A-CPA %s
// V95A-CPA: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a" "-target-feature" "+cpa"
+
+// RUN: %clang -target aarch64 -march=armv9.5a+pauth-lr -### -c %s 2>&1 | FileCheck -check-prefix=V95A-PAUTHLR %s
+// RUN: %clang -target aarch64 -march=armv9.5-a+pauth-lr -### -c %s 2>&1 | FileCheck -check-prefix=V95A-PAUTHLR %s
+// V95A-PAUTHLR: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a" "-target-feature" "+pauth-lr"
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index f0b35790133f..6c7410a8b8f7 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -174,6 +174,7 @@ enum ArchExtKind : unsigned {
AEK_SMEF8F32 = 70, // FEAT_SME_F8F32
AEK_SMEFA64 = 71, // FEAT_SME_FA64
AEK_CPA = 72, // FEAT_CPA
+ AEK_PAUTHLR = 73, // FEAT_PAuth_LR
AEK_NUM_EXTENSIONS
};
using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
@@ -297,6 +298,7 @@ inline constexpr ExtensionInfo Extensions[] = {
{"sme-f8f32", AArch64::AEK_SMEF8F32, "+sme-f8f32", "-sme-f8f32", FEAT_INIT, "+sme2,+fp8", 0},
{"sme-fa64", AArch64::AEK_SMEFA64, "+sme-fa64", "-sme-fa64", FEAT_INIT, "", 0},
{"cpa", AArch64::AEK_CPA, "+cpa", "-cpa", FEAT_INIT, "", 0},
+ {"pauth-lr", AArch64::AEK_PAUTHLR, "+pauth-lr", "-pauth-lr", FEAT_INIT, "", 0},
// Special cases
{"none", AArch64::AEK_NONE, {}, {}, FEAT_INIT, "", ExtensionInfo::MaxFMVPriority},
};
diff --git a/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h b/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
index e3d9ffc1d4db..1e4187c6fb11 100644
--- a/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
+++ b/llvm/include/llvm/TargetParser/ARMTargetParserCommon.h
@@ -41,6 +41,7 @@ struct ParsedBranchProtection {
StringRef Scope;
StringRef Key;
bool BranchTargetEnforcement;
+ bool BranchProtectionPAuthLR;
};
bool parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 175f6ef49c3b..6d85e1fb5fbf 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -8802,12 +8802,23 @@ AArch64InstrInfo::getOutliningTypeImpl(MachineBasicBlock::iterator &MIT,
// Don't outline anything used for return address signing. The outlined
// function will get signed later if needed
switch (MI.getOpcode()) {
+ case AArch64::PACM:
case AArch64::PACIASP:
case AArch64::PACIBSP:
+ case AArch64::PACIASPPC:
+ case AArch64::PACIBSPPC:
case AArch64::AUTIASP:
case AArch64::AUTIBSP:
+ case AArch64::AUTIASPPCi:
+ case AArch64::AUTIASPPCr:
+ case AArch64::AUTIBSPPCi:
+ case AArch64::AUTIBSPPCr:
case AArch64::RETAA:
case AArch64::RETAB:
+ case AArch64::RETAASPPCi:
+ case AArch64::RETAASPPCr:
+ case AArch64::RETABSPPCi:
+ case AArch64::RETABSPPCr:
case AArch64::EMITBKEY:
case AArch64::PAUTH_PROLOGUE:
case AArch64::PAUTH_EPILOGUE:
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
index 9da59ef2a806..1a8c71888a85 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp
@@ -93,16 +93,24 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F,
// TODO: skip functions that have no instrumented allocas for optimization
IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag);
- if (!F.hasFnAttribute("branch-target-enforcement")) {
- if (const auto *BTE = mdconst::extract_or_null<ConstantInt>(
- F.getParent()->getModuleFlag("branch-target-enforcement")))
- BranchTargetEnforcement = BTE->getZExtValue();
- } else {
- const StringRef BTIEnable =
- F.getFnAttribute("branch-target-enforcement").getValueAsString();
- assert(BTIEnable == "true" || BTIEnable == "false");
- BranchTargetEnforcement = BTIEnable == "true";
- }
+ // BTI/PAuthLR may be set either on the function or the module. Set Bool from
+ // either the function attribute or module attribute, depending on what is
+ // set.
+ // Note: the module attributed is numeric (0 or 1) but the function attribute
+ // is stringy ("true" or "false").
+ auto TryFnThenModule = [&](StringRef AttrName, bool &Bool) {
+ if (F.hasFnAttribute(AttrName)) {
+ const StringRef V = F.getFnAttribute(AttrName).getValueAsString();
+ assert(V.equals_insensitive("true") || V.equals_insensitive("false"));
+ Bool = V.equals_insensitive("true");
+ } else if (const auto *ModVal = mdconst::extract_or_null<ConstantInt>(
+ F.getParent()->getModuleFlag(AttrName))) {
+ Bool = ModVal->getZExtValue();
+ }
+ };
+
+ TryFnThenModule("branch-target-enforcement", BranchTargetEnforcement);
+ TryFnThenModule("branch-protection-pauth-lr", BranchProtectionPAuthLR);
// The default stack probe size is 4096 if the function has no
// stack-probe-size attribute. This is a safe default because it is the
diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
index 219f83cfd32e..cd4a18bfbc23 100644
--- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h
@@ -22,6 +22,7 @@
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/Function.h"
#include "llvm/MC/MCLinkerOptimizationHint.h"
+#include "llvm/MC/MCSymbol.h"
#include <cassert>
#include <optional>
@@ -164,10 +165,21 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
/// SignWithBKey modifies the default PAC-RET mode to signing with the B key.
bool SignWithBKey = false;
+ /// SigningInstrOffset captures the offset of the PAC-RET signing instruction
+ /// within the prologue, so it can be re-used for authentication in the
+ /// epilogue when using PC as a second salt (FEAT_PAuth_LR)
+ MCSymbol *SignInstrLabel = nullptr;
+
/// BranchTargetEnforcement enables placing BTI instructions at potential
/// indirect branch destinations.
bool BranchTargetEnforcement = false;
+ /// Indicates that SP signing should be diversified with PC as-per PAuthLR.
+ /// This is set by -mbranch-protection and will emit NOP instructions unless
+ /// the subtarget feature +pauthlr is also used (in which case non-NOP
+ /// instructions are emitted).
+ bool BranchProtectionPAuthLR = false;
+
/// Whether this function has an extended frame record [Ctx, FP, LR]. If so,
/// bit 60 of the in-memory FP will be 1 to enable other tools to detect the
/// extended record.
@@ -436,10 +448,16 @@ public:
bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const;
bool shouldSignWithBKey() const { return SignWithBKey; }
+
+ MCSymbol *getSigningInstrLabel() const { return SignInstrLabel; }
+ void setSigningInstrLabel(MCSymbol *Label) { SignInstrLabel = Label; }
+
bool isMTETagged() const { return IsMTETagged; }
bool branchTargetEnforcement() const { return BranchTargetEnforcement; }
+ bool branchProtectionPAuthLR() const { return BranchProtectionPAuthLR; }
+
void setHasSwiftAsyncContext(bool HasContext) {
HasSwiftAsyncContext = HasContext;
}
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 7576d2a899d1..7509afaeb5fe 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -60,11 +60,35 @@ FunctionPass *llvm::createAArch64PointerAuthPass() {
char AArch64PointerAuth::ID = 0;
+// Where PAuthLR support is not known at compile time, it is supported using
+// PACM. PACM is in the hint space so has no effect when PAuthLR is not
+// supported by the hardware, but will alter the behaviour of PACI*SP, AUTI*SP
+// and RETAA/RETAB if the hardware supports PAuthLR.
+static void BuildPACM(const AArch64Subtarget &Subtarget, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI, DebugLoc DL,
+ MachineInstr::MIFlag Flags, MCSymbol *PACSym = nullptr) {
+ const TargetInstrInfo *TII = Subtarget.getInstrInfo();
+ auto &MFnI = *MBB.getParent()->getInfo<AArch64FunctionInfo>();
+
+ // ADR X16,<address_of_PACIASP>
+ if (PACSym) {
+ assert(Flags == MachineInstr::FrameDestroy);
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::ADR))
+ .addReg(AArch64::X16, RegState::Define)
+ .addSym(PACSym);
+ }
+
+ // Only emit PACM if -mbranch-protection has +pc and the target does not
+ // have feature +pauth-lr.
+ if (MFnI.branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
+ BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACM)).setMIFlag(Flags);
+}
+
void AArch64PointerAuth::signLR(MachineFunction &MF,
MachineBasicBlock::iterator MBBI) const {
- const AArch64FunctionInfo *MFnI = MF.getInfo<AArch64FunctionInfo>();
- bool UseBKey = MFnI->shouldSignWithBKey();
- bool EmitCFI = MFnI->needsDwarfUnwindInfo(MF);
+ auto &MFnI = *MF.getInfo<AArch64FunctionInfo>();
+ bool UseBKey = MFnI.shouldSignWithBKey();
+ bool EmitCFI = MFnI.needsDwarfUnwindInfo(MF);
bool NeedsWinCFI = MF.hasWinCFI();
MachineBasicBlock &MBB = *MBBI->getParent();
@@ -77,11 +101,29 @@ void AArch64PointerAuth::signLR(MachineFunction &MF,
.setMIFlag(MachineInstr::FrameSetup);
}
+ // PAuthLR authentication instructions need to know the value of PC at the
+ // point of signing (PACI*).
+ if (MFnI.branchProtectionPAuthLR()) {
+ MCSymbol *PACSym = MF.getMMI().getContext().createTempSymbol();
+ MFnI.setSigningInstrLabel(PACSym);
+ }
+
// No SEH opcode for this one; it doesn't materialize into an
// instruction on Windows.
- BuildMI(MBB, MBBI, DL,
- TII->get(UseBKey ? AArch64::PACIBSP : AArch64::PACIASP))
- .setMIFlag(MachineInstr::FrameSetup);
+ if (MFnI.branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
+ BuildMI(MBB, MBBI, DL,
+ TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSPPC
+ : AArch64::PACIASPPC))
+ .setMIFlag(MachineInstr::FrameSetup)
+ ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
+ } else {
+ BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameSetup);
+ BuildMI(MBB, MBBI, DL,
+ TII->get(MFnI.shouldSignWithBKey() ? AArch64::PACIBSP
+ : AArch64::PACIASP))
+ .setMIFlag(MachineInstr::FrameSetup)
+ ->setPreInstrSymbol(MF, MFnI.getSigningInstrLabel());
+ }
if (EmitCFI) {
unsigned CFIIndex =
@@ -118,15 +160,37 @@ void AArch64PointerAuth::authenticateLR(
// DW_CFA_AARCH64_negate_ra_state can't be emitted.
bool TerminatorIsCombinable =
TI != MBB.end() && TI->getOpcode() == AArch64::RET;
+ MCSymbol *PACSym = MFnI->getSigningInstrLabel();
+
if (Subtarget->hasPAuth() && TerminatorIsCombinable && !NeedsWinCFI &&
!MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) {
- unsigned CombinedRetOpcode = UseBKey ? AArch64::RETAB : AArch64::RETAA;
- BuildMI(MBB, TI, DL, TII->get(CombinedRetOpcode)).copyImplicitOps(*TI);
+ if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
+ assert(PACSym && "No PAC instruction to refer to");
+ BuildMI(MBB, TI, DL,
+ TII->get(UseBKey ? AArch64::RETABSPPCi : AArch64::RETAASPPCi))
+ .addSym(PACSym)
+ .copyImplicitOps(*MBBI)
+ .setMIFlag(MachineInstr::FrameDestroy);
+ } else {
+ BuildPACM(*Subtarget, MBB, TI, DL, MachineInstr::FrameDestroy, PACSym);
+ BuildMI(MBB, TI, DL, TII->get(UseBKey ? AArch64::RETAB : AArch64::RETAA))
+ .copyImplicitOps(*MBBI)
+ .setMIFlag(MachineInstr::FrameDestroy);
+ }
MBB.erase(TI);
} else {
- unsigned AutOpcode = UseBKey ? AArch64::AUTIBSP : AArch64::AUTIASP;
- BuildMI(MBB, MBBI, DL, TII->get(AutOpcode))
- .setMIFlag(MachineInstr::FrameDestroy);
+ if (MFnI->branchProtectionPAuthLR() && Subtarget->hasPAuthLR()) {
+ assert(PACSym && "No PAC instruction to refer to");
+ BuildMI(MBB, MBBI, DL,
+ TII->get(UseBKey ? AArch64::AUTIBSPPCi : AArch64::AUTIASPPCi))
+ .addSym(PACSym)
+ .setMIFlag(MachineInstr::FrameDestroy);
+ } else {
+ BuildPACM(*Subtarget, MBB, MBBI, DL, MachineInstr::FrameDestroy, PACSym);
+ BuildMI(MBB, MBBI, DL,
+ TII->get(UseBKey ? AArch64::AUTIBSP : AArch64::AUTIASP))
+ .setMIFlag(MachineInstr::FrameDestroy);
+ }
if (EmitAsyncCFI) {
unsigned CFIIndex =
diff --git a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
index 10b80cad4347..6d3a59d532fd 100644
--- a/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
+++ b/llvm/lib/TargetParser/ARMTargetParserCommon.cpp
@@ -134,13 +134,13 @@ ARM::EndianKind ARM::parseArchEndian(StringRef Arch) {
}
// Parse a branch protection specification, which has the form
-// standard | none | [bti,pac-ret[+b-key,+leaf]*]
+// standard | none | [bti,pac-ret[+b-key,+leaf,+pc]*]
// Returns true on success, with individual elements of the specification
// 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) {
- PBP = {"none", "a_key", false};
+ PBP = {"none", "a_key", false, false};
if (Spec == "none")
return true; // defaults are ok
@@ -166,6 +166,8 @@ bool ARM::parseBranchProtection(StringRef Spec, ParsedBranchProtection &PBP,
PBP.Scope = "all";
else if (PACOpt == "b-key")
PBP.Key = "b_key";
+ else if (PACOpt == "pc")
+ PBP.BranchProtectionPAuthLR = true;
else
break;
}
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll b/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll
new file mode 100644
index 000000000000..a78fa853d99d
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll
@@ -0,0 +1,542 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+
+; PauthLR is controlled via a combination of -mbranch-protection and +pauth-lr.
+; -mbranch-protection=+pc enables branch protection. If the feature +pauth-lr
+; is available (v9.5a onwards) then non-NOP instructions are used; otherwise
+; NOP instructions are used.
+
+; There are 6 cases to cover:
+
+; feature \ -mbranch-protection= | none | pac-ret | pac-ret+pc
+; ------------------------------------------------------------------------
+; without +pauth-lr | no codegen | old pac | NOP pauth-lr
+; with +pauth-lr | no codegen | old pac | non-NOP pauth-lr
+
+; sign-return-address.ll tests combinations of -mbranch-protection=none/pac-ret
+; and whether +pauth-lr is present or not.
+
+; sign-return-address-pauth-lr.ll is identical, with the addition of this module
+; attribute, which enables -mbranch-protection=pac-ret+pc, and therefore tests
+; the remaining parameter combinations in the table:
+!llvm.module.flags = !{!1}
+!1 = !{i32 1, !"branch-protection-pauth-lr", i32 1}
+
+; RUN: llc -mtriple=aarch64 < %s | FileCheck --check-prefixes=CHECK,COMPAT %s
+; RUN: llc -mtriple=aarch64 -mattr=v8.3a < %s | FileCheck --check-prefixes=CHECK,V83A %s
+; RUN: llc -mtriple=aarch64 -mattr=v9a -mattr=pauth-lr < %s | FileCheck --check-prefixes=PAUTHLR %s
+
+define i32 @leaf(i32 %x) {
+; CHECK-LABEL: leaf:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ret
+;
+; PAUTHLR-LABEL: leaf:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: ret
+ ret i32 %x
+}
+
+define i32 @leaf_sign_none(i32 %x) "sign-return-address"="none" {
+; CHECK-LABEL: leaf_sign_none:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ret
+;
+; PAUTHLR-LABEL: leaf_sign_none:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: ret
+ ret i32 %x
+}
+
+define i32 @leaf_sign_non_leaf(i32 %x) "sign-return-address"="non-leaf" {
+; CHECK-LABEL: leaf_sign_non_leaf:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ret
+;
+; PAUTHLR-LABEL: leaf_sign_non_leaf:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: ret
+ ret i32 %x
+}
+
+define i32 @leaf_sign_all(i32 %x) "sign-return-address"="all" {
+; COMPAT-LABEL: leaf_sign_all:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp0:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: adr x16, .Ltmp0
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_sign_all:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp0:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: adr x16, .Ltmp0
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: leaf_sign_all:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp0:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retaasppc .Ltmp0
+ ret i32 %x
+}
+
+define i64 @leaf_clobbers_lr(i64 %x) "sign-return-address"="non-leaf" {
+; COMPAT-LABEL: leaf_clobbers_lr:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp1:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: //APP
+; COMPAT-NEXT: mov x30, x0
+; COMPAT-NEXT: //NO_APP
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: adr x16, .Ltmp1
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_clobbers_lr:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp1:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: //APP
+; V83A-NEXT: mov x30, x0
+; V83A-NEXT: //NO_APP
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: adr x16, .Ltmp1
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: leaf_clobbers_lr:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp1:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; PAUTHLR-NEXT: .cfi_offset w30, -16
+; PAUTHLR-NEXT: //APP
+; PAUTHLR-NEXT: mov x30, x0
+; PAUTHLR-NEXT: //NO_APP
+; PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; PAUTHLR-NEXT: retaasppc .Ltmp1
+ call void asm sideeffect "mov x30, $0", "r,~{lr}"(i64 %x) #1
+ ret i64 %x
+}
+
+declare i32 @foo(i32)
+
+define i32 @non_leaf_sign_all(i32 %x) "sign-return-address"="all" {
+; COMPAT-LABEL: non_leaf_sign_all:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp2:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: bl foo
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: adr x16, .Ltmp2
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: non_leaf_sign_all:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp2:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: bl foo
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: adr x16, .Ltmp2
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: non_leaf_sign_all:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp2:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; PAUTHLR-NEXT: .cfi_offset w30, -16
+; PAUTHLR-NEXT: bl foo
+; PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; PAUTHLR-NEXT: retaasppc .Ltmp2
+ %call = call i32 @foo(i32 %x)
+ ret i32 %call
+}
+
+define i32 @non_leaf_sign_non_leaf(i32 %x) "sign-return-address"="non-leaf" {
+; COMPAT-LABEL: non_leaf_sign_non_leaf:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp3:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: bl foo
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: adr x16, .Ltmp3
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: non_leaf_sign_non_leaf:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp3:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: bl foo
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: adr x16, .Ltmp3
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: non_leaf_sign_non_leaf:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp3:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; PAUTHLR-NEXT: .cfi_offset w30, -16
+; PAUTHLR-NEXT: bl foo
+; PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; PAUTHLR-NEXT: retaasppc .Ltmp3
+ %call = call i32 @foo(i32 %x)
+ ret i32 %call
+}
+
+; Should not use the RETAA instruction.
+define i32 @non_leaf_scs(i32 %x) "sign-return-address"="non-leaf" shadowcallstack "target-features"="+v8.3a,+reserve-x18" {
+; CHECK-LABEL: non_leaf_scs:
+; CHECK: // %bb.0:
+; CHECK-NEXT: str x30, [x18], #8
+; CHECK-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 //
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: .Ltmp4:
+; CHECK-NEXT: paciasp
+; CHECK-NEXT: .cfi_negate_ra_state
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset w30, -16
+; CHECK-NEXT: bl foo
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: adr x16, .Ltmp4
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: autiasp
+; CHECK-NEXT: ldr x30, [x18, #-8]!
+; CHECK-NEXT: ret
+;
+; PAUTHLR-LABEL: non_leaf_scs:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: str x30, [x18], #8
+; PAUTHLR-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 //
+; PAUTHLR-NEXT: .Ltmp4:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; PAUTHLR-NEXT: .cfi_offset w30, -16
+; PAUTHLR-NEXT: bl foo
+; PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; PAUTHLR-NEXT: autiasppc .Ltmp4
+; PAUTHLR-NEXT: ldr x30, [x18, #-8]!
+; PAUTHLR-NEXT: ret
+ %call = call i32 @foo(i32 %x)
+ ret i32 %call
+}
+
+define i32 @leaf_sign_all_v83(i32 %x) "sign-return-address"="all" "target-features"="+v8.3a" {
+; CHECK-LABEL: leaf_sign_all_v83:
+; CHECK: // %bb.0:
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: .Ltmp5:
+; CHECK-NEXT: paciasp
+; CHECK-NEXT: .cfi_negate_ra_state
+; CHECK-NEXT: adr x16, .Ltmp5
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: retaa
+;
+; PAUTHLR-LABEL: leaf_sign_all_v83:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp5:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retaasppc .Ltmp5
+ ret i32 %x
+}
+
+declare fastcc i64 @bar(i64)
+
+define fastcc void @spill_lr_and_tail_call(i64 %x) "sign-return-address"="all" {
+; COMPAT-LABEL: spill_lr_and_tail_call:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp6:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; COMPAT-NEXT: .cfi_def_cfa_offset 16
+; COMPAT-NEXT: .cfi_offset w30, -16
+; COMPAT-NEXT: //APP
+; COMPAT-NEXT: mov x30, x0
+; COMPAT-NEXT: //NO_APP
+; COMPAT-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; COMPAT-NEXT: adr x16, .Ltmp6
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: b bar
+;
+; V83A-LABEL: spill_lr_and_tail_call:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp6:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; V83A-NEXT: .cfi_def_cfa_offset 16
+; V83A-NEXT: .cfi_offset w30, -16
+; V83A-NEXT: //APP
+; V83A-NEXT: mov x30, x0
+; V83A-NEXT: //NO_APP
+; V83A-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; V83A-NEXT: adr x16, .Ltmp6
+; V83A-NEXT: hint #39
+; V83A-NEXT: autiasp
+; V83A-NEXT: b bar
+;
+; PAUTHLR-LABEL: spill_lr_and_tail_call:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp6:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; PAUTHLR-NEXT: .cfi_offset w30, -16
+; PAUTHLR-NEXT: //APP
+; PAUTHLR-NEXT: mov x30, x0
+; PAUTHLR-NEXT: //NO_APP
+; PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; PAUTHLR-NEXT: autiasppc .Ltmp6
+; PAUTHLR-NEXT: b bar
+ call void asm sideeffect "mov x30, $0", "r,~{lr}"(i64 %x) #1
+ tail call fastcc i64 @bar(i64 %x)
+ ret void
+}
+
+define i32 @leaf_sign_all_a_key(i32 %x) "sign-return-address"="all" "sign-return-address-key"="a_key" {
+; COMPAT-LABEL: leaf_sign_all_a_key:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp7:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: adr x16, .Ltmp7
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_sign_all_a_key:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp7:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: adr x16, .Ltmp7
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: leaf_sign_all_a_key:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .Ltmp7:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retaasppc .Ltmp7
+ ret i32 %x
+}
+
+define i32 @leaf_sign_all_b_key(i32 %x) "sign-return-address"="all" "sign-return-address-key"="b_key" {
+; COMPAT-LABEL: leaf_sign_all_b_key:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: .cfi_b_key_frame
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp8:
+; COMPAT-NEXT: hint #27
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: adr x16, .Ltmp8
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #31
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_sign_all_b_key:
+; V83A: // %bb.0:
+; V83A-NEXT: .cfi_b_key_frame
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp8:
+; V83A-NEXT: pacibsp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: adr x16, .Ltmp8
+; V83A-NEXT: hint #39
+; V83A-NEXT: retab
+;
+; PAUTHLR-LABEL: leaf_sign_all_b_key:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .cfi_b_key_frame
+; PAUTHLR-NEXT: .Ltmp8:
+; PAUTHLR-NEXT: pacibsppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retabsppc .Ltmp8
+ ret i32 %x
+}
+
+define i32 @leaf_sign_all_v83_b_key(i32 %x) "sign-return-address"="all" "target-features"="+v8.3a" "sign-return-address-key"="b_key" {
+; CHECK-LABEL: leaf_sign_all_v83_b_key:
+; CHECK: // %bb.0:
+; CHECK-NEXT: .cfi_b_key_frame
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: .Ltmp9:
+; CHECK-NEXT: pacibsp
+; CHECK-NEXT: .cfi_negate_ra_state
+; CHECK-NEXT: adr x16, .Ltmp9
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: retab
+;
+; PAUTHLR-LABEL: leaf_sign_all_v83_b_key:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: .cfi_b_key_frame
+; PAUTHLR-NEXT: .Ltmp9:
+; PAUTHLR-NEXT: pacibsppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retabsppc .Ltmp9
+ ret i32 %x
+}
+
+; Note that BTI instruction is not needed before PACIASP.
+define i32 @leaf_sign_all_a_key_bti(i32 %x) "sign-return-address"="all" "sign-return-address-key"="a_key" "branch-target-enforcement"="true"{
+; COMPAT-LABEL: leaf_sign_all_a_key_bti:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #34
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp10:
+; COMPAT-NEXT: hint #25
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: adr x16, .Ltmp10
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #29
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_sign_all_a_key_bti:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #34
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp10:
+; V83A-NEXT: paciasp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: adr x16, .Ltmp10
+; V83A-NEXT: hint #39
+; V83A-NEXT: retaa
+;
+; PAUTHLR-LABEL: leaf_sign_all_a_key_bti:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: bti c
+; PAUTHLR-NEXT: .Ltmp10:
+; PAUTHLR-NEXT: paciasppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retaasppc .Ltmp10
+ ret i32 %x
+}
+
+; Note that BTI instruction is not needed before PACIBSP.
+define i32 @leaf_sign_all_b_key_bti(i32 %x) "sign-return-address"="all" "sign-return-address-key"="b_key" "branch-target-enforcement"="true"{
+; COMPAT-LABEL: leaf_sign_all_b_key_bti:
+; COMPAT: // %bb.0:
+; COMPAT-NEXT: hint #34
+; COMPAT-NEXT: .cfi_b_key_frame
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: .Ltmp11:
+; COMPAT-NEXT: hint #27
+; COMPAT-NEXT: .cfi_negate_ra_state
+; COMPAT-NEXT: adr x16, .Ltmp11
+; COMPAT-NEXT: hint #39
+; COMPAT-NEXT: hint #31
+; COMPAT-NEXT: ret
+;
+; V83A-LABEL: leaf_sign_all_b_key_bti:
+; V83A: // %bb.0:
+; V83A-NEXT: hint #34
+; V83A-NEXT: .cfi_b_key_frame
+; V83A-NEXT: hint #39
+; V83A-NEXT: .Ltmp11:
+; V83A-NEXT: pacibsp
+; V83A-NEXT: .cfi_negate_ra_state
+; V83A-NEXT: adr x16, .Ltmp11
+; V83A-NEXT: hint #39
+; V83A-NEXT: retab
+;
+; PAUTHLR-LABEL: leaf_sign_all_b_key_bti:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: bti c
+; PAUTHLR-NEXT: .cfi_b_key_frame
+; PAUTHLR-NEXT: .Ltmp11:
+; PAUTHLR-NEXT: pacibsppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retabsppc .Ltmp11
+ ret i32 %x
+}
+
+; Note that BTI instruction is not needed before PACIBSP.
+define i32 @leaf_sign_all_v83_b_key_bti(i32 %x) "sign-return-address"="all" "target-features"="+v8.3a" "sign-return-address-key"="b_key" "branch-target-enforcement"="true" {
+; CHECK-LABEL: leaf_sign_all_v83_b_key_bti:
+; CHECK: // %bb.0:
+; CHECK-NEXT: hint #34
+; CHECK-NEXT: .cfi_b_key_frame
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: .Ltmp12:
+; CHECK-NEXT: pacibsp
+; CHECK-NEXT: .cfi_negate_ra_state
+; CHECK-NEXT: adr x16, .Ltmp12
+; CHECK-NEXT: hint #39
+; CHECK-NEXT: retab
+;
+; PAUTHLR-LABEL: leaf_sign_all_v83_b_key_bti:
+; PAUTHLR: // %bb.0:
+; PAUTHLR-NEXT: bti c
+; PAUTHLR-NEXT: .cfi_b_key_frame
+; PAUTHLR-NEXT: .Ltmp12:
+; PAUTHLR-NEXT: pacibsppc
+; PAUTHLR-NEXT: .cfi_negate_ra_state
+; PAUTHLR-NEXT: retabsppc .Ltmp12
+ ret i32 %x
+}
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address.ll b/llvm/test/CodeGen/AArch64/sign-return-address.ll
index 5680915c7f41..1481d4beb50d 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address.ll
@@ -2,6 +2,9 @@
; RUN: llc -mtriple=aarch64 < %s | FileCheck --check-prefixes=CHECK,COMPAT %s
; RUN: llc -mtriple=aarch64 -mattr=v8.3a < %s | FileCheck --check-prefixes=CHECK,V83A %s
+; v9.5-A is not expected to change codegen without -mbranch-protection=+pc, so reuse V83A.
+; RUN: llc -mtriple=aarch64 -mattr=v9.5a < %s | FileCheck --check-prefixes=CHECK,V83A %s
+
define i32 @leaf(i32 %x) {
; CHECK-LABEL: leaf:
; CHECK: // %bb.0:
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 30e60ad92b68..866176ab0983 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1812,7 +1812,8 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
AArch64::AEK_SSVE_FP8DOT4, AArch64::AEK_LUT,
AArch64::AEK_SME_LUTv2, AArch64::AEK_SMEF8F16,
AArch64::AEK_SMEF8F32, AArch64::AEK_SMEFA64,
- AArch64::AEK_CPA};
+ AArch64::AEK_CPA, AArch64::AEK_PAUTHLR,
+ };
std::vector<StringRef> Features;
@@ -1899,6 +1900,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
EXPECT_TRUE(llvm::is_contained(Features, "+sme-f8f32"));
EXPECT_TRUE(llvm::is_contained(Features, "+sme-fa64"));
EXPECT_TRUE(llvm::is_contained(Features, "+cpa"));
+ EXPECT_TRUE(llvm::is_contained(Features, "+pauth-lr"));
// Assuming we listed every extension above, this should produce the same
// result. (note that AEK_NONE doesn't have a name so it won't be in the