[clang] [llvm] [AArch64] Support for 9.5-A PAuthLR (PR #75947)
Tomas Matheson via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 19 08:57:14 PST 2023
https://github.com/tmatheson-arm updated https://github.com/llvm/llvm-project/pull/75947
>From d3201659d87260acaf1d20a96705e290caf21693 Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Thu, 2 Feb 2023 13:19:05 +0000
Subject: [PATCH 1/3] [AArch64] add missing test case for v9.4-A
---
clang/test/Preprocessor/aarch64-target-features.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c
index db89aa7b608ad5..b3da54162da04b 100644
--- a/clang/test/Preprocessor/aarch64-target-features.c
+++ b/clang/test/Preprocessor/aarch64-target-features.c
@@ -600,6 +600,7 @@
// RUN: %clang -target aarch64-none-elf -march=armv9.1-a -x c -E -dM %s -o - | FileCheck --check-prefixes=CHECK-V81-OR-LATER,CHECK-V83-OR-LATER,CHECK-V85-OR-LATER %s
// RUN: %clang -target aarch64-none-elf -march=armv9.2-a -x c -E -dM %s -o - | FileCheck --check-prefixes=CHECK-V81-OR-LATER,CHECK-V83-OR-LATER,CHECK-V85-OR-LATER %s
// RUN: %clang -target aarch64-none-elf -march=armv9.3-a -x c -E -dM %s -o - | FileCheck --check-prefixes=CHECK-V81-OR-LATER,CHECK-V83-OR-LATER,CHECK-V85-OR-LATER %s
+// RUN: %clang -target aarch64-none-elf -march=armv9.4-a -x c -E -dM %s -o - | FileCheck --check-prefixes=CHECK-V81-OR-LATER,CHECK-V83-OR-LATER,CHECK-V85-OR-LATER %s
// RUN: %clang -target aarch64-none-elf -march=armv9.5-a -x c -E -dM %s -o - | FileCheck --check-prefixes=CHECK-V81-OR-LATER,CHECK-V83-OR-LATER,CHECK-V85-OR-LATER %s
// CHECK-V81-OR-LATER: __ARM_FEATURE_ATOMICS 1
// CHECK-V85-OR-LATER: __ARM_FEATURE_BTI 1
>From 1d4208d53830e0ef8dadad9be12e7ef2b53c6190 Mon Sep 17 00:00:00 2001
From: Oliver Stannard <oliver.stannard at arm.com>
Date: Wed, 1 Feb 2023 18:16:07 +0000
Subject: [PATCH 2/3] [AArch64] Add FEAT_PAuthLR assembler support
Add assembly/disassembly support for the new PAuthLR instructions
introduced in Armv9.5-A:
- AUTIASPPC/AUTIBSPPC
- PACIASPPC/PACIBSPPC
- PACNBIASPPC/PACNBIBSPPC
- RETAASPPC/RETABSPPC
- PACM
Documentation for these instructions can be found here:
https://developer.arm.com/documentation/ddi0602/2023-09/Base-Instructions/
---
llvm/lib/Target/AArch64/AArch64.td | 7 +-
.../lib/Target/AArch64/AArch64InstrFormats.td | 74 +++++++++
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 39 +++++
llvm/lib/Target/AArch64/AArch64SchedA64FX.td | 2 +-
.../Target/AArch64/AArch64SchedNeoverseN2.td | 2 +-
.../AArch64/AsmParser/AArch64AsmParser.cpp | 28 ++++
.../Disassembler/AArch64Disassembler.cpp | 18 +++
.../MCTargetDesc/AArch64AsmBackend.cpp | 14 ++
.../MCTargetDesc/AArch64ELFObjectWriter.cpp | 4 +
.../AArch64/MCTargetDesc/AArch64FixupKinds.h | 5 +
.../MCTargetDesc/AArch64MCCodeEmitter.cpp | 28 ++++
.../MC/AArch64/armv9.5a-pauthlr-diagnostics.s | 57 +++++++
llvm/test/MC/AArch64/armv9.5a-pauthlr-reloc.s | 12 ++
llvm/test/MC/AArch64/armv9.5a-pauthlr.s | 151 ++++++++++++++++++
.../Disassembler/AArch64/armv9.5a-pauthlr.txt | 78 +++++++++
15 files changed, 516 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/MC/AArch64/armv9.5a-pauthlr-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/armv9.5a-pauthlr-reloc.s
create mode 100644 llvm/test/MC/AArch64/armv9.5a-pauthlr.s
create mode 100644 llvm/test/MC/Disassembler/AArch64/armv9.5a-pauthlr.txt
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index c600bcaab2b3ea..95e171109b4eb0 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -622,6 +622,11 @@ def FeatureLdpAlignedOnly : SubtargetFeature<"ldp-aligned-only", "HasLdpAlignedO
def FeatureStpAlignedOnly : SubtargetFeature<"stp-aligned-only", "HasStpAlignedOnly",
"true", "In order to emit stp, first check if the store will be aligned to 2 * element_size">;
+// AArch64 2023 Architecture Extensions (v9.5-A)
+
+def FeaturePAuthLR : SubtargetFeature<"pauth-lr", "HasPAuthLR",
+ "true", "Enable Armv9.5-A PAC enhancements (FEAT_PAuth_LR)">;
+
//===----------------------------------------------------------------------===//
// Architectures.
//
@@ -807,7 +812,7 @@ def SMEUnsupported : AArch64Unsupported {
SME2Unsupported.F);
}
-let F = [HasPAuth] in
+let F = [HasPAuth, HasPAuthLR] in
def PAUnsupported : AArch64Unsupported;
include "AArch64SchedA53.td"
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 68e87f491a09e4..92bf9f4ec2a21b 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2368,6 +2368,80 @@ class ClearAuth<bits<1> data, string asm>
let Inst{4-0} = Rd;
}
+// v9.5-A FEAT_PAuth_LR
+
+class SignAuthFixedRegs<bits<5> opcode2, bits<6> opcode, string asm>
+ : I<(outs), (ins), asm, "", "", []>,
+ Sched<[WriteI, ReadI]> {
+ let Inst{31} = 0b1; // sf
+ let Inst{30} = 0b1;
+ let Inst{29} = 0b0; // S
+ let Inst{28-21} = 0b11010110;
+ let Inst{20-16} = opcode2;
+ let Inst{15-10} = opcode;
+ let Inst{9-5} = 0b11111; // Rn
+ let Inst{4-0} = 0b11110; // Rd
+}
+
+def PAuthPCRelLabel16Operand : PCRelLabel<16> {
+ let Name = "PAuthPCRelLabel16";
+ let PredicateMethod = "isPAuthPCRelLabel16Operand";
+}
+def am_pauth_pcrel : Operand<OtherVT> {
+ let EncoderMethod = "getPAuthPCRelOpValue";
+ let DecoderMethod = "DecodePCRelLabel16";
+ let PrintMethod = "printAlignedLabel";
+ let ParserMatchClass = PAuthPCRelLabel16Operand;
+ let OperandType = "OPERAND_PCREL";
+}
+
+class SignAuthPCRel<bits<2> opc, string asm>
+ : I<(outs), (ins am_pauth_pcrel:$label), asm, "\t$label", "", []>,
+ Sched<[]> {
+ bits<16> label;
+ let Inst{31} = 0b1; // sf
+ let Inst{30-23} = 0b11100111;
+ let Inst{22-21} = opc;
+ let Inst{20-5} = label; // imm
+ let Inst{4-0} = 0b11111; // Rd
+}
+
+class SignAuthOneReg<bits<5> opcode2, bits<6> opcode, string asm>
+ : I<(outs), (ins GPR64:$Rn), asm, "\t$Rn", "", []>,
+ Sched<[]> {
+ bits<5> Rn;
+ let Inst{31} = 0b1; // sf
+ let Inst{30} = 0b1;
+ let Inst{29} = 0b0; // S
+ let Inst{28-21} = 0b11010110;
+ let Inst{20-16} = opcode2;
+ let Inst{15-10} = opcode;
+ let Inst{9-5} = Rn;
+ let Inst{4-0} = 0b11110; // Rd
+}
+
+class SignAuthReturnPCRel<bits<3> opc, bits<5> op2, string asm>
+ : I<(outs), (ins am_pauth_pcrel:$label), asm, "\t$label", "", []>,
+ Sched<[WriteAtomic]> {
+ bits<16> label;
+ let Inst{31-24} = 0b01010101;
+ let Inst{23-21} = opc;
+ let Inst{20-5} = label; // imm16
+ let Inst{4-0} = op2;
+}
+
+class SignAuthReturnReg<bits<6> op3, string asm>
+ : I<(outs), (ins GPR64common:$Rm), asm, "\t$Rm", "", []>,
+ Sched<[WriteAtomic]> {
+ bits<5> Rm;
+ let Inst{31-25} = 0b1101011;
+ let Inst{24-21} = 0b0010; // opc
+ let Inst{20-16} = 0b11111; // op2
+ let Inst{15-10} = op3;
+ let Inst{9-5} = 0b11111; // Rn
+ let Inst{4-0} = Rm; // op4 (Rm)
+}
+
// Base class for the Armv8.4-A 8 and 16-bit flag manipulation instructions
class BaseFlagManipulation<bit sf, bit sz, dag iops, string asm, string ops>
: I<(outs), iops, asm, ops, "", []>,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 44b0337fe78791..b379d2d2375bec 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -61,6 +61,9 @@ def HasLOR : Predicate<"Subtarget->hasLOR()">,
def HasPAuth : Predicate<"Subtarget->hasPAuth()">,
AssemblerPredicateWithAll<(all_of FeaturePAuth), "pauth">;
+def HasPAuthLR : Predicate<"Subtarget->hasPAuthLR()">,
+ AssemblerPredicateWithAll<(all_of FeaturePAuthLR), "pauth-lr">;
+
def HasJS : Predicate<"Subtarget->hasJS()">,
AssemblerPredicateWithAll<(all_of FeatureJS), "jsconv">;
@@ -1644,6 +1647,42 @@ let Predicates = [HasPAuth] in {
}
+// v9.5-A pointer authentication extensions
+
+// Always accept "pacm" as an alias for "hint #39", but don't emit it when
+// disassembling if we don't have the pauth-lr feature.
+let CRm = 0b0100 in {
+ def PACM : SystemNoOperands<0b111, "hint\t#39">;
+}
+def : InstAlias<"pacm", (PACM), 0>;
+
+let Predicates = [HasPAuthLR] in {
+ let Defs = [LR], Uses = [LR, SP] in {
+ // opcode2, opcode, asm
+ def PACIASPPC : SignAuthFixedRegs<0b00001, 0b101000, "paciasppc">;
+ def PACIBSPPC : SignAuthFixedRegs<0b00001, 0b101001, "pacibsppc">;
+ def PACNBIASPPC : SignAuthFixedRegs<0b00001, 0b100000, "pacnbiasppc">;
+ def PACNBIBSPPC : SignAuthFixedRegs<0b00001, 0b100001, "pacnbibsppc">;
+ // opc, asm
+ def AUTIASPPCi : SignAuthPCRel<0b00, "autiasppc">;
+ def AUTIBSPPCi : SignAuthPCRel<0b01, "autibsppc">;
+ // opcode2, opcode, asm
+ def AUTIASPPCr : SignAuthOneReg<0b00001, 0b100100, "autiasppc">;
+ def AUTIBSPPCr : SignAuthOneReg<0b00001, 0b100101, "autibsppc">;
+ }
+
+ let Uses = [LR, SP], isReturn = 1, isTerminator = 1, isBarrier = 1 in {
+ // opc, op2, asm
+ def RETAASPPCi : SignAuthReturnPCRel<0b000, 0b11111, "retaasppc">;
+ def RETABSPPCi : SignAuthReturnPCRel<0b001, 0b11111, "retabsppc">;
+ // op3, asm
+ def RETAASPPCr : SignAuthReturnReg<0b000010, "retaasppc">;
+ def RETABSPPCr : SignAuthReturnReg<0b000011, "retabsppc">;
+ }
+ def : InstAlias<"pacm", (PACM), 1>;
+}
+
+
// v8.3a floating point conversion for javascript
let Predicates = [HasJS, HasFPARMv8], Defs = [NZCV] in
def FJCVTZS : BaseFPToIntegerUnscaled<0b01, 0b11, 0b110, FPR64, GPR32,
diff --git a/llvm/lib/Target/AArch64/AArch64SchedA64FX.td b/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
index 65b97ff6956a11..a381743b938258 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
@@ -24,7 +24,7 @@ def A64FXModel : SchedMachineModel {
[HasSVE2, HasSVE2AES, HasSVE2SM4, HasSVE2SHA3, HasSVE2BitPerm, HasPAuth,
HasSVE2orSME, HasMTE, HasMatMulInt8, HasBF16, HasSME2, HasSME2p1, HasSVE2p1,
HasSVE2p1_or_HasSME2p1, HasSMEF16F16, HasSSVE_FP8FMA, HasSMEF8F16, HasSMEF8F32,
- HasSMEFA64];
+ HasSMEFA64, HasPAuthLR];
let FullInstRWOverlapCheck = 0;
}
diff --git a/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td b/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
index 503de3bee2b867..3a42a695984116 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
@@ -19,7 +19,7 @@ def NeoverseN2Model : SchedMachineModel {
let CompleteModel = 1;
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
- [HasSVE2p1]);
+ [HasSVE2p1, HasPAuthLR]);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 238269cf27bd78..bb4fc6735eefc9 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1689,6 +1689,21 @@ class AArch64Operand : public MCParsedAsmOperand {
return DiagnosticPredicateTy::Match;
}
+ bool isPAuthPCRelLabel16Operand() const {
+ // PAuth PCRel16 operands are similar to regular branch targets, but only
+ // negative values are allowed for concrete immediates as signing instr
+ // should be in a lower address.
+ if (!isImm())
+ return false;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE)
+ return true;
+ int64_t Val = MCE->getValue();
+ if (Val & 0b11)
+ return false;
+ return (Val <= 0) && (Val > -(1 << 18));
+ }
+
void addExpr(MCInst &Inst, const MCExpr *Expr) const {
// Add as immediates when possible. Null MCExpr = 0.
if (!Expr)
@@ -1990,6 +2005,19 @@ class AArch64Operand : public MCParsedAsmOperand {
Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
}
+ void addPAuthPCRelLabel16Operands(MCInst &Inst, unsigned N) const {
+ // PC-relative operands don't encode the low bits, so shift them off
+ // here. If it's a label, however, just put it on directly as there's
+ // not enough information now to do anything.
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
+ if (!MCE) {
+ addExpr(Inst, getImm());
+ return;
+ }
+ Inst.addOperand(MCOperand::createImm(MCE->getValue() >> 2));
+ }
+
void addPCRelLabel19Operands(MCInst &Inst, unsigned N) const {
// Branch operands don't encode the low bits, so shift them off
// here. If it's a label, however, just put it on directly as there's
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index cf2d3879292d19..423d5cf4d70449 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -165,6 +165,9 @@ static DecodeStatus DecodeFixedPointScaleImm32(MCInst &Inst, unsigned Imm,
static DecodeStatus DecodeFixedPointScaleImm64(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
+static DecodeStatus DecodePCRelLabel16(MCInst &Inst, unsigned Imm,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
uint64_t Address,
const MCDisassembler *Decoder);
@@ -887,6 +890,21 @@ static DecodeStatus DecodeFixedPointScaleImm64(MCInst &Inst, unsigned Imm,
return Success;
}
+static DecodeStatus DecodePCRelLabel16(MCInst &Inst, unsigned Imm,
+ uint64_t Addr,
+ const MCDisassembler *Decoder) {
+ // Immediate is encoded as the top 16-bits of an unsigned 18-bit negative
+ // PC-relative offset.
+ int64_t ImmVal = Imm;
+ if (ImmVal < 0 || ImmVal > (1 << 16))
+ return Fail;
+ ImmVal = -ImmVal;
+ if (!Decoder->tryAddingSymbolicOperand(Inst, (ImmVal << 2), Addr,
+ /*IsBranch=*/ false, 0, 0, 4))
+ Inst.addOperand(MCOperand::createImm(ImmVal));
+ return Success;
+}
+
static DecodeStatus DecodePCRelLabel19(MCInst &Inst, unsigned Imm,
uint64_t Addr,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
index a6900b8963bb39..1fded848dc89ed 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
@@ -67,6 +67,7 @@ class AArch64AsmBackend : public MCAsmBackend {
{"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_movw", 5, 16, 0},
{"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal},
+ {"fixup_aarch64_pcrel_branch16", 5, 16, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal},
{"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal},
{"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}};
@@ -121,6 +122,7 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
+ case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
@@ -314,6 +316,17 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
return (Value >> 2) & 0x3fff;
+ case AArch64::fixup_aarch64_pcrel_branch16:
+ // Unsigned PC-relative offset, so invert the negative immediate.
+ SignedValue = -SignedValue;
+ Value = static_cast<uint64_t>(SignedValue);
+ // Check valid 18-bit unsigned range.
+ if (SignedValue < 0 || SignedValue > ((1<<18)-1))
+ Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
+ // Low two bits are not encoded (4-byte alignment assumed).
+ if (Value & 0b11)
+ Ctx.reportError(Fixup.getLoc(), "fixup not sufficiently aligned");
+ return (Value >> 2) & 0xffff;
case AArch64::fixup_aarch64_pcrel_branch26:
case AArch64::fixup_aarch64_pcrel_call26:
if (TheTriple.isOSBinFormatCOFF() && !IsResolved && SignedValue != 0) {
@@ -380,6 +393,7 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con
case AArch64::fixup_aarch64_movw:
case AArch64::fixup_aarch64_pcrel_branch14:
+ case AArch64::fixup_aarch64_pcrel_branch16:
case AArch64::fixup_aarch64_add_imm12:
case AArch64::fixup_aarch64_ldst_imm12_scale1:
case AArch64::fixup_aarch64_ldst_imm12_scale2:
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
index 9de40661298cca..496ab18e9b1954 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp
@@ -186,6 +186,10 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx,
return R_CLS(LD_PREL_LO19);
case AArch64::fixup_aarch64_pcrel_branch14:
return R_CLS(TSTBR14);
+ case AArch64::fixup_aarch64_pcrel_branch16:
+ Ctx.reportError(Fixup.getLoc(),
+ "relocation of PAC/AUT instructions is not supported");
+ return ELF::R_AARCH64_NONE;
case AArch64::fixup_aarch64_pcrel_branch19:
return R_CLS(CONDBR19);
default:
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h
index 767dd880552013..fdee2d5ad2bf30 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64FixupKinds.h
@@ -43,6 +43,11 @@ enum Fixups {
// The high 14 bits of a 21-bit pc-relative immediate.
fixup_aarch64_pcrel_branch14,
+ // The high 16 bits of a 18-bit unsigned PC-relative immediate. Used by
+ // pointer authentication, only within a function, so no relocation can be
+ // generated.
+ fixup_aarch64_pcrel_branch16,
+
// The high 19 bits of a 21-bit pc-relative immediate. Same encoding as
// fixup_aarch64_pcrel_adrhi, except this is use by b.cc and generates
// relocations directly when necessary.
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index dbc4323a860f5c..8054c00727599b 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -88,6 +88,12 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ /// getPAuthPCRelOpValue - Return the encoded value for a pointer
+ /// authentication pc-relative operand.
+ uint32_t getPAuthPCRelOpValue(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
/// getLoadLiteralOpValue - Return the encoded value for a load-literal
/// pc-relative address.
uint32_t getLoadLiteralOpValue(const MCInst &MI, unsigned OpIdx,
@@ -327,6 +333,28 @@ uint32_t AArch64MCCodeEmitter::getCondBranchTargetOpValue(
return 0;
}
+/// getPAuthPCRelOpValue - Return the encoded value for a pointer
+/// authentication pc-relative operand.
+uint32_t AArch64MCCodeEmitter::getPAuthPCRelOpValue(
+ const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpIdx);
+
+ // If the destination is an immediate, invert sign as it's a negative value
+ // that should be encoded as unsigned
+ if (MO.isImm())
+ return -(MO.getImm());
+ assert(MO.isExpr() && "Unexpected target type!");
+
+ MCFixupKind Kind = MCFixupKind(AArch64::fixup_aarch64_pcrel_branch16);
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));
+
+ ++MCNumFixups;
+
+ // All of the information is in the fixup.
+ return 0;
+}
+
/// getLoadLiteralOpValue - Return the encoded value for a load-literal
/// pc-relative address.
uint32_t
diff --git a/llvm/test/MC/AArch64/armv9.5a-pauthlr-diagnostics.s b/llvm/test/MC/AArch64/armv9.5a-pauthlr-diagnostics.s
new file mode 100644
index 00000000000000..d06183be9da3e1
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.5a-pauthlr-diagnostics.s
@@ -0,0 +1,57 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+pauth-lr 2>&1 < %s | FileCheck %s
+
+ autiasppc #2
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: autiasppc #2
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ autiasppc #1<<17
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: autiasppc #1<<17
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ autiasppc #-2
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: autiasppc #-2
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ autiasppc w0
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: autiasppc w0
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ autiasppc sp
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: autiasppc sp
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retabsppc #2
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retabsppc #2
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retabsppc #(1<<17)
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retabsppc #(1<<17)
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retabsppc #-2
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retabsppc #-2
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retaasppc w0
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retaasppc w0
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retaasppc sp
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retaasppc sp
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ retaasppc xzr
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected label or encodable integer pc offset
+// CHECK-NEXT: retaasppc xzr
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
diff --git a/llvm/test/MC/AArch64/armv9.5a-pauthlr-reloc.s b/llvm/test/MC/AArch64/armv9.5a-pauthlr-reloc.s
new file mode 100644
index 00000000000000..c10142a1997664
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.5a-pauthlr-reloc.s
@@ -0,0 +1,12 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+pauth-lr -filetype=obj -o /dev/null 2>&1 < %s | FileCheck %s
+
+ autiasppc undef_label
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: relocation of PAC/AUT instructions is not supported
+// CHECK-NEXT: autiasppc undef_label
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
+ autibsppc undef_label
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: relocation of PAC/AUT instructions is not supported
+// CHECK-NEXT: autibsppc undef_label
+// CHECK-NOT: [[@LINE-3]]:{{[0-9]+}}:
+
diff --git a/llvm/test/MC/AArch64/armv9.5a-pauthlr.s b/llvm/test/MC/AArch64/armv9.5a-pauthlr.s
new file mode 100644
index 00000000000000..24e9c449846832
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.5a-pauthlr.s
@@ -0,0 +1,151 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+pauth-lr < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+pauth-lr < %s \
+// RUN: | llvm-objdump -d --mattr=+pauth-lr - | FileCheck %s --check-prefix=CHECK-DISASS
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+pauth-lr < %s \
+// RUN: | llvm-objdump -d --mattr=-pauth-lr - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+// Label at address 4, so we can test that the address shows up in the
+// disassembly.
+ nop
+label1:
+
+ paciasppc
+// CHECK-INST: paciasppc
+// CHECK-DISASS: paciasppc
+// CHECK-ENCODING: [0xfe,0xa3,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac1a3fe <unknown>
+
+ pacibsppc
+// CHECK-INST: pacibsppc
+// CHECK-DISASS: pacibsppc
+// CHECK-ENCODING: [0xfe,0xa7,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac1a7fe <unknown>
+
+ pacnbiasppc
+// CHECK-INST: pacnbiasppc
+// CHECK-DISASS: pacnbiasppc
+// CHECK-ENCODING: [0xfe,0x83,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac183fe <unknown>
+
+ pacnbibsppc
+// CHECK-INST: pacnbibsppc
+// CHECK-DISASS: pacnbibsppc
+// CHECK-ENCODING: [0xfe,0x87,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac187fe <unknown>
+
+ autiasppc label1
+// CHECK-INST: autiasppc label1
+// CHECK-DISASS: autiasppc 0x4 <label1>
+// CHECK-ENCODING: [0bAAA11111,A,0b100AAAAA,0xf3]
+// CHECK-ENCODING: fixup A - offset: 0, value: label1, kind: fixup_aarch64_pcrel_branch16
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: f380009f <unknown>
+
+ autibsppc label1
+// CHECK-INST: autibsppc label1
+// CHECK-DISASS: autibsppc 0x4 <label1>
+// CHECK-ENCODING: [0bAAA11111,A,0b101AAAAA,0xf3]
+// CHECK-ENCODING: fixup A - offset: 0, value: label1, kind: fixup_aarch64_pcrel_branch16
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: f3a000bf <unknown>
+
+ autibsppc #0
+// CHECK-INST: autibsppc #0
+// CHECK-DISASS: autibsppc 0x1c <label1+0x18>
+// CHECK-ENCODING: [0x1f,0x00,0xa0,0xf3]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: f3a0001f <unknown>
+
+ autibsppc #-(1<<18)+4
+// CHECK-INST: autibsppc #-262140
+// CHECK-DISASS: autibsppc 0xfffffffffffc0024 <label1+0xfffffffffffc0020>
+// CHECK-ENCODING: [0xff,0xff,0xbf,0xf3]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: f3bfffff <unknown>
+
+ autiasppc x0
+// CHECK-INST: autiasppc x0
+// CHECK-DISASS: autiasppc x0
+// CHECK-ENCODING: [0x1e,0x90,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac1901e <unknown>
+
+ autibsppc x1
+// CHECK-INST: autibsppc x1
+// CHECK-DISASS: autibsppc x1
+// CHECK-ENCODING: [0x3e,0x94,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac1943e <unknown>
+
+ autiasppc xzr
+// CHECK-INST: autiasppc xzr
+// CHECK-DISASS: autiasppc xzr
+// CHECK-ENCODING: [0xfe,0x93,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac193fe <unknown>
+
+ autibsppc xzr
+// CHECK-INST: autibsppc xzr
+// CHECK-DISASS: autibsppc xzr
+// CHECK-ENCODING: [0xfe,0x97,0xc1,0xda]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: dac197fe <unknown>
+
+
+ retaasppc label1
+// CHECK-INST: retaasppc label1
+// CHECK-DISASS: retaasppc 0x4 <label1>
+// CHECK-ENCODING: [0bAAA11111,A,0b000AAAAA,0x55]
+// CHECK-ENCODING: // fixup A - offset: 0, value: label1, kind: fixup_aarch64_pcrel_branch16
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: 5500019f <unknown>
+
+ retabsppc label1
+// CHECK-INST: retabsppc label1
+// CHECK-DISASS: retabsppc 0x4 <label1>
+// CHECK-ENCODING: [0bAAA11111,A,0b001AAAAA,0x55]
+// CHECK-ENCODING: // fixup A - offset: 0, value: label1, kind: fixup_aarch64_pcrel_branch16
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: 552001bf <unknown>
+
+ retaasppc #0
+// CHECK-INST: retaasppc #0
+// CHECK-DISASS: retaasppc 0x3c <label1+0x38>
+// CHECK-ENCODING: [0x1f,0x00,0x00,0x55]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: 5500001f <unknown>
+
+ retaasppc #-(1<<18)+4
+// CHECK-INST: retaasppc #-262140
+// CHECK-DISASS: retaasppc 0xfffffffffffc0044 <label1+0xfffffffffffc0040>
+// CHECK-ENCODING: [0xff,0xff,0x1f,0x55]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: 551fffff <unknown>
+
+ retaasppc x2
+// CHECK-INST: retaasppc x2
+// CHECK-DISASS: retaasppc x2
+// CHECK-ENCODING: [0xe2,0x0b,0x5f,0xd6]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: d65f0be2 <unknown>
+
+ retabsppc x3
+// CHECK-INST: retabsppc x3
+// CHECK-DISASS: retabsppc x3
+// CHECK-ENCODING: [0xe3,0x0f,0x5f,0xd6]
+// CHECK-ERROR: instruction requires: pauth-lr
+// CHECK-UNKNOWN: d65f0fe3 <unknown>
+
+ pacm
+// CHECK-INST: pacm
+// CHECK-DISASS: pacm
+// CHECK-ENCODING: [0xff,0x24,0x03,0xd5]
+// CHECK-ERROR-NOT: instruction requires:
+// CHECK-UNKNOWN: d50324ff hint #39
diff --git a/llvm/test/MC/Disassembler/AArch64/armv9.5a-pauthlr.txt b/llvm/test/MC/Disassembler/AArch64/armv9.5a-pauthlr.txt
new file mode 100644
index 00000000000000..caf1fde2c2b7c2
--- /dev/null
+++ b/llvm/test/MC/Disassembler/AArch64/armv9.5a-pauthlr.txt
@@ -0,0 +1,78 @@
+# RUN: llvm-mc -triple aarch64 -disassemble -mattr=+pauth-lr < %s | FileCheck %s
+# RUN: not llvm-mc -triple aarch64 -disassemble < %s 2>&1 | FileCheck %s --check-prefix=NO-PAUTHLR
+
+[0xfe,0xa3,0xc1,0xda]
+# CHECK: paciasppc
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xfe,0xa7,0xc1,0xda]
+# CHECK: pacibsppc
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xfe,0x83,0xc1,0xda]
+# CHECK: pacnbiasppc
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xfe,0x87,0xc1,0xda]
+# CHECK: pacnbibsppc
+# NO-PAUTHLR: invalid instruction encoding
+
+[0x9f,0x00,0x80,0xf3]
+# CHECK: autiasppc #-16
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xbf,0x00,0xa0,0xf3]
+# CHECK: autibsppc #-20
+# NO-PAUTHLR: invalid instruction encoding
+
+[0x1f,0x00,0xa0,0xf3]
+# CHECK: autibsppc #0
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xff,0xff,0xbf,0xf3]
+# CHECK: autibsppc #-262140
+# NO-PAUTHLR: invalid instruction encoding
+
+[0x1e,0x90,0xc1,0xda]
+# CHECK: autiasppc x0
+# NO-PAUTHLR: invalid instruction encoding
+
+[0x3e,0x94,0xc1,0xda]
+# CHECK: autibsppc x1
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xfe,0x93,0xc1,0xda]
+# CHECK: autiasppc xzr
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xfe,0x97,0xc1,0xda]
+# CHECK: autibsppc xzr
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xbf,0x01,0x00,0x55]
+# CHECK: retaasppc #-52
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xdf,0x01,0x20,0x55]
+# CHECK: retabsppc #-56
+# NO-PAUTHLR: invalid instruction encoding
+
+[0x1f,0x00,0x00,0x55]
+# CHECK: retaasppc #0
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xff,0xff,0x1f,0x55]
+# CHECK: retaasppc #-262140
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xe2,0x0b,0x5f,0xd6]
+# CHECK: retaasppc x2
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xe3,0x0f,0x5f,0xd6]
+# CHECK: retabsppc x3
+# NO-PAUTHLR: invalid instruction encoding
+
+[0xff,0x24,0x03,0xd5]
+# CHECK: pacm
+# NO-PAUTHLR: hint #39
>From 61454797fcc4c1f2c181949a5fc00969e33387f4 Mon Sep 17 00:00:00 2001
From: Tomas Matheson <tomas.matheson at arm.com>
Date: Fri, 16 Jun 2023 11:10:37 +0100
Subject: [PATCH 3/3] [AArch64] Codegen support for FEAT_PAuthLR
- Adds a new +pc option to -mbranch-protection that will enable
the use of PC as a diversifier in PAC branch protection code.
- When +pauth-lr is enabled (-march=armv9.5a+pauth-lr) in combination
with -mbranch-protection=pac-ret+pc, the new 9.5-a instructions
(pacibsppc, retaasppc, etc) are used.
Documentation for the relevant instructions can be found here:
https://developer.arm.com/documentation/ddi0602/2023-09/Base-Instructions/
Co-authored-by: Lucas Prates <lucas.prates at arm.com>
---
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Basic/TargetInfo.h | 1 +
clang/include/clang/Driver/Options.td | 2 +
clang/lib/Basic/Targets/AArch64.cpp | 1 +
clang/lib/Basic/Targets/ARM.cpp | 1 +
clang/lib/CodeGen/CodeGenModule.cpp | 3 +
clang/lib/CodeGen/Targets/AArch64.cpp | 2 +
clang/lib/Driver/ToolChains/Clang.cpp | 7 +-
.../CodeGen/aarch64-branch-protection-attr.c | 28 +
clang/test/Driver/aarch64-pauth-lr.c | 23 +
clang/test/Driver/aarch64-v95a.c | 8 +
.../llvm/TargetParser/AArch64TargetParser.h | 2 +
.../llvm/TargetParser/ARMTargetParserCommon.h | 1 +
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 11 +
.../AArch64/AArch64MachineFunctionInfo.cpp | 28 +-
.../AArch64/AArch64MachineFunctionInfo.h | 18 +
.../lib/Target/AArch64/AArch64PointerAuth.cpp | 87 ++-
.../TargetParser/ARMTargetParserCommon.cpp | 6 +-
.../AArch64/sign-return-address-pauth-lr.ll | 542 ++++++++++++++++++
.../CodeGen/AArch64/sign-return-address.ll | 3 +
.../TargetParser/TargetParserTest.cpp | 5 +-
21 files changed, 755 insertions(+), 25 deletions(-)
create mode 100644 clang/test/Driver/aarch64-pauth-lr.c
create mode 100644 llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 152d9f65f86dbe..21abc346cf17ac 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 aa0f5023104a1a..ac3c324c6c29c4 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1372,6 +1372,7 @@ class TargetInfo : public TransferrableTargetInfo,
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 1b02087425b751..965d402af2d7b3 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -6999,6 +6999,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 def16c032c869e..3ee39133fcee72 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 ce7e4d4639ceac..6e1842fc64e505 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 7ad26ace328ab2..3800462637c74a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1111,6 +1111,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 be5145daa00b7f..7102d190fe008b 100644
--- a/clang/lib/CodeGen/Targets/AArch64.cpp
+++ b/clang/lib/CodeGen/Targets/AArch64.cpp
@@ -136,6 +136,8 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
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 de9fd5eaa1e020..4783affd3220bc 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 3c2714e2feda24..8ab3e17ade4264 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 00000000000000..2e1b530fc9895b
--- /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 6044a4f155db02..cc3cf8ca92375a 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
@@ -13,3 +16,8 @@
// RUN: %clang -target aarch64_be -mbig-endian -march=armv9.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A-BE %s
// GENERICV95A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a"
+// ===== Features supported on aarch64 =====
+
+// 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 56c32fae712cef..ad1e29650f0024 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -173,6 +173,7 @@ enum ArchExtKind : unsigned {
AEK_SMEF8F16 = 69, // FEAT_SME_F8F16
AEK_SMEF8F32 = 70, // FEAT_SME_F8F32
AEK_SMEFA64 = 71, // FEAT_SME_FA64
+ AEK_PAUTHLR = 73, // FEAT_PAuth_LR
AEK_NUM_EXTENSIONS
};
using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
@@ -295,6 +296,7 @@ inline constexpr ExtensionInfo Extensions[] = {
{"sme-f8f16", AArch64::AEK_SMEF8F16, "+sme-f8f16", "-sme-f8f16", FEAT_INIT, "+sme2,+fp8", 0},
{"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},
+ {"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 e3d9ffc1d4db52..1e4187c6fb111e 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 7d71c316bcb0a2..0f15e5123d430d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -8779,12 +8779,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 9da59ef2a8062b..1a8c71888a852f 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 219f83cfd32e0e..cd4a18bfbc23a8 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 @@ class AArch64FunctionInfo final : public MachineFunctionInfo {
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 7576d2a899d1af..c0a486a8c7d06b 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)
+ .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,38 @@ 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 10b80cad434727..6d3a59d532fd3d 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 00000000000000..a78fa853d99dc4
--- /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 5680915c7f414c..1481d4beb50d6a 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 e2b9712b511eca..7fd80e56ffd554 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1811,7 +1811,9 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
AArch64::AEK_SSVE_FP8DOT2, AArch64::AEK_FP8DOT4,
AArch64::AEK_SSVE_FP8DOT4, AArch64::AEK_LUT,
AArch64::AEK_SME_LUTv2, AArch64::AEK_SMEF8F16,
- AArch64::AEK_SMEF8F32, AArch64::AEK_SMEFA64};
+ AArch64::AEK_SMEF8F32, AArch64::AEK_SMEFA64,
+ AArch64::AEK_PAUTHLR,
+ };
std::vector<StringRef> Features;
@@ -1897,6 +1899,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
EXPECT_TRUE(llvm::is_contained(Features, "+sme-f8f16"));
EXPECT_TRUE(llvm::is_contained(Features, "+sme-f8f32"));
EXPECT_TRUE(llvm::is_contained(Features, "+sme-fa64"));
+ 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
More information about the llvm-commits
mailing list