From 8d2ae795f6ea100c9d915379e124b7fc24628483 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Thu, 21 Dec 2023 11:36:42 -0800 Subject: [PATCH 1/3] [AArch64][PAC] Lower auth/resign into checked sequence. This introduces 3 hardening modes in the authentication step of auth/resign lowering: - unchecked, which uses the AUT instructions as-is - poison, which detects authentication failure (using an XPAC+CMP sequence), explicitly yielding the XPAC result rather than the AUT result, to avoid leaking - trap, which additionally traps on authentication failure, using BRK #0xC470 + key (IA C470, IB C471, DA C472, DB C473.) Not all modes are necessarily useful in all contexts, and there are more performant alternative lowerings in specific contexts (e.g., when I/D TBI enablement is a target ABI guarantee.) This is controlled by the `ptrauth-auth-traps` function attributes, and can be overridden using `-aarch64-ptrauth-auth-checks=`. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 229 +++++++ .../Target/AArch64/AArch64ISelDAGToDAG.cpp | 102 +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td | 32 +- .../GISel/AArch64InstructionSelector.cpp | 58 ++ ...trauth-intrinsic-auth-resign-with-blend.ll | 254 +++++++ .../AArch64/ptrauth-intrinsic-auth-resign.ll | 638 ++++++++++++++++++ 6 files changed, 1312 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 1e60ce9c40df8..c49b8b5f5f398 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -68,6 +68,15 @@ using namespace llvm; +enum PtrauthCheckMode { Default, Unchecked, Poison, Trap }; +static cl::opt PtrauthAuthChecks( + "aarch64-ptrauth-auth-checks", cl::Hidden, + cl::values(clEnumValN(Unchecked, "none", "don't test for failure"), + clEnumValN(Poison, "poison", "poison on failure"), + clEnumValN(Trap, "trap", "trap on failure")), + cl::desc("Check pointer authentication auth/resign failures"), + cl::init(Default)); + #define DEBUG_TYPE "asm-printer" namespace { @@ -130,6 +139,10 @@ class AArch64AsmPrinter : public AsmPrinter { // Emit the sequence for BLRA (authenticate + branch). void emitPtrauthBranch(const MachineInstr *MI); + + // Emit the sequence for AUT or AUTPAC. + void emitPtrauthAuthResign(const MachineInstr *MI); + // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc. unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc, unsigned &InstsEmitted); @@ -1623,6 +1636,217 @@ unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc, return AArch64::X17; } +void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { + unsigned InstsEmitted = 0; + const bool IsAUTPAC = MI->getOpcode() == AArch64::AUTPAC; + + // We can expand AUT/AUTPAC into 3 possible sequences: + // - unchecked: + // autia x16, x0 + // pacib x16, x1 ; if AUTPAC + // + // - checked and clearing: + // mov x17, x0 + // movk x17, #disc, lsl #48 + // autia x16, x17 + // mov x17, x16 + // xpaci x17 + // cmp x16, x17 + // b.eq Lsuccess + // mov x16, x17 + // b Lend + // Lsuccess: + // mov x17, x1 + // movk x17, #disc, lsl #48 + // pacib x16, x17 + // Lend: + // Where we only emit the AUT if we started with an AUT. + // + // - checked and trapping: + // mov x17, x0 + // movk x17, #disc, lsl #48 + // autia x16, x0 + // mov x17, x16 + // xpaci x17 + // cmp x16, x17 + // b.eq Lsuccess + // brk #<0xc470 + aut key> + // Lsuccess: + // mov x17, x1 + // movk x17, #disc, lsl #48 + // pacib x16, x17 ; if AUTPAC + // Where the b.eq skips over the trap if the PAC is valid. + // + // This sequence is expensive, but we need more information to be able to + // do better. + // + // We can't TBZ the poison bit because EnhancedPAC2 XORs the PAC bits + // on failure. + // We can't TST the PAC bits because we don't always know how the address + // space is setup for the target environment (and the bottom PAC bit is + // based on that). + // Either way, we also don't always know whether TBI is enabled or not for + // the specific target environment. + + // By default, auth/resign sequences check for auth failures. + bool ShouldCheck = true; + // In the checked sequence, we only trap if explicitly requested. + bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps"); + + // However, command-line flags can override this, for experimentation. + switch (PtrauthAuthChecks) { + case PtrauthCheckMode::Default: + break; + case PtrauthCheckMode::Unchecked: + ShouldCheck = ShouldTrap = false; + break; + case PtrauthCheckMode::Poison: + ShouldCheck = true; + ShouldTrap = false; + break; + case PtrauthCheckMode::Trap: + ShouldCheck = ShouldTrap = true; + break; + } + + auto AUTKey = (AArch64PACKey::ID)MI->getOperand(0).getImm(); + uint64_t AUTDisc = MI->getOperand(1).getImm(); + unsigned AUTAddrDisc = MI->getOperand(2).getReg(); + + unsigned XPACOpc = getXPACOpcodeForKey(AUTKey); + + // Compute aut discriminator into x17 + assert(isUInt<16>(AUTDisc)); + unsigned AUTDiscReg = + emitPtrauthDiscriminator(AUTDisc, AUTAddrDisc, InstsEmitted); + bool AUTZero = AUTDiscReg == AArch64::XZR; + unsigned AUTOpc = getAUTOpcodeForKey(AUTKey, AUTZero); + + // autiza x16 ; if AUTZero + // autia x16, x17 ; if !AUTZero + MCInst AUTInst; + AUTInst.setOpcode(AUTOpc); + AUTInst.addOperand(MCOperand::createReg(AArch64::X16)); + AUTInst.addOperand(MCOperand::createReg(AArch64::X16)); + if (!AUTZero) + AUTInst.addOperand(MCOperand::createReg(AUTDiscReg)); + EmitToStreamer(*OutStreamer, AUTInst); + ++InstsEmitted; + + // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done. + if (!IsAUTPAC && (!ShouldCheck || !ShouldTrap)) { + assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); + return; + } + + MCSymbol *EndSym = nullptr; + + // Checked sequences do an additional strip-and-compare. + if (ShouldCheck) { + MCSymbol *SuccessSym = createTempSymbol("auth_success_"); + + // XPAC has tied src/dst: use x17 as a temporary copy. + // mov x17, x16 + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) + .addReg(AArch64::X17) + .addReg(AArch64::XZR) + .addReg(AArch64::X16) + .addImm(0)); + ++InstsEmitted; + + // xpaci x17 + EmitToStreamer( + *OutStreamer, + MCInstBuilder(XPACOpc).addReg(AArch64::X17).addReg(AArch64::X17)); + ++InstsEmitted; + + // cmp x16, x17 + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs) + .addReg(AArch64::XZR) + .addReg(AArch64::X16) + .addReg(AArch64::X17) + .addImm(0)); + ++InstsEmitted; + + // b.eq Lsuccess + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::Bcc) + .addImm(AArch64CC::EQ) + .addExpr(MCSymbolRefExpr::create( + SuccessSym, OutContext))); + ++InstsEmitted; + + if (ShouldTrap) { + // Trapping sequences do a 'brk'. + // brk #<0xc470 + aut key> + EmitToStreamer(*OutStreamer, + MCInstBuilder(AArch64::BRK).addImm(0xc470 | AUTKey)); + ++InstsEmitted; + } else { + // Non-trapping checked sequences return the stripped result in x16, + // skipping over the PAC if there is one. + + // FIXME: can we simply return the AUT result, already in x16? without.. + // ..traps this is usable as an oracle anyway, based on high bits + // mov x17, x16 + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) + .addReg(AArch64::X16) + .addReg(AArch64::XZR) + .addReg(AArch64::X17) + .addImm(0)); + ++InstsEmitted; + + if (IsAUTPAC) { + EndSym = createTempSymbol("resign_end_"); + + // b Lend + EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B) + .addExpr(MCSymbolRefExpr::create( + EndSym, OutContext))); + ++InstsEmitted; + } + } + + // If the auth check succeeds, we can continue. + // Lsuccess: + OutStreamer->emitLabel(SuccessSym); + } + + // We already emitted unchecked and checked-but-non-trapping AUTs. + // That left us with trapping AUTs, and AUTPACs. + // Trapping AUTs don't need PAC: we're done. + if (!IsAUTPAC) { + assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); + return; + } + + auto PACKey = (AArch64PACKey::ID)MI->getOperand(3).getImm(); + uint64_t PACDisc = MI->getOperand(4).getImm(); + unsigned PACAddrDisc = MI->getOperand(5).getReg(); + + // Compute pac discriminator into x17 + assert(isUInt<16>(PACDisc)); + unsigned PACDiscReg = + emitPtrauthDiscriminator(PACDisc, PACAddrDisc, InstsEmitted); + bool PACZero = PACDiscReg == AArch64::XZR; + unsigned PACOpc = getPACOpcodeForKey(PACKey, PACZero); + + // pacizb x16 ; if PACZero + // pacib x16, x17 ; if !PACZero + MCInst PACInst; + PACInst.setOpcode(PACOpc); + PACInst.addOperand(MCOperand::createReg(AArch64::X16)); + PACInst.addOperand(MCOperand::createReg(AArch64::X16)); + if (!PACZero) + PACInst.addOperand(MCOperand::createReg(PACDiscReg)); + EmitToStreamer(*OutStreamer, PACInst); + ++InstsEmitted; + + assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); + // Lend: + if (EndSym) + OutStreamer->emitLabel(EndSym); +} + void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) { unsigned InstsEmitted = 0; unsigned BrTarget = MI->getOperand(0).getReg(); @@ -2056,6 +2280,11 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { return; } + case AArch64::AUT: + case AArch64::AUTPAC: + emitPtrauthAuthResign(MI); + return; + case AArch64::LOADauthptrstatic: LowerLOADauthptrstatic(*MI); return; diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index b9c57d1975b6f..55cc106c08b95 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -366,6 +366,9 @@ class AArch64DAGToDAGISel : public SelectionDAGISel { bool tryIndexedLoad(SDNode *N); + void SelectPtrauthAuth(SDNode *N); + void SelectPtrauthResign(SDNode *N); + bool trySelectStackSlotTagP(SDNode *N); void SelectTagP(SDNode *N); @@ -1481,6 +1484,96 @@ void AArch64DAGToDAGISel::SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc, ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops)); } +static std::tuple +extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG) { + SDLoc DL(Disc); + SDValue AddrDisc; + SDValue ConstDisc; + + // If this is a blend, remember the constant and address discriminators. + // Otherwise, it's either a constant discriminator, or a non-blended + // address discriminator. + if (Disc->getOpcode() == ISD::INTRINSIC_WO_CHAIN && + Disc->getConstantOperandVal(0) == Intrinsic::ptrauth_blend) { + AddrDisc = Disc->getOperand(1); + ConstDisc = Disc->getOperand(2); + } else { + ConstDisc = Disc; + } + + // If the constant discriminator (either the blend RHS, or the entire + // discriminator value) isn't a 16-bit constant, bail out, and let the + // discriminator be computed separately. + auto *ConstDiscN = dyn_cast(ConstDisc); + if (!ConstDiscN || !isUInt<16>(ConstDiscN->getZExtValue())) + return std::make_tuple(DAG->getTargetConstant(0, DL, MVT::i64), Disc); + + // If there's no address discriminator, use XZR directly. + if (!AddrDisc) + AddrDisc = DAG->getRegister(AArch64::XZR, MVT::i64); + + return std::make_tuple( + DAG->getTargetConstant(ConstDiscN->getZExtValue(), DL, MVT::i64), + AddrDisc); +} + +void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) { + SDLoc DL(N); + // IntrinsicID is operand #0 + SDValue Val = N->getOperand(1); + SDValue AUTKey = N->getOperand(2); + SDValue AUTDisc = N->getOperand(3); + + unsigned AUTKeyC = cast(AUTKey)->getZExtValue(); + AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64); + + SDValue AUTAddrDisc, AUTConstDisc; + std::tie(AUTConstDisc, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, CurDAG); + + SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X16, Val, SDValue()); + SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, X16Copy.getValue(1)}; + + SDNode *AUT = CurDAG->getMachineNode(AArch64::AUT, DL, MVT::i64, Ops); + ReplaceNode(N, AUT); + return; +} + +void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) { + SDLoc DL(N); + // IntrinsicID is operand #0 + SDValue Val = N->getOperand(1); + SDValue AUTKey = N->getOperand(2); + SDValue AUTDisc = N->getOperand(3); + SDValue PACKey = N->getOperand(4); + SDValue PACDisc = N->getOperand(5); + + unsigned AUTKeyC = cast(AUTKey)->getZExtValue(); + unsigned PACKeyC = cast(PACKey)->getZExtValue(); + + AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64); + PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64); + + SDValue AUTAddrDisc, AUTConstDisc; + std::tie(AUTConstDisc, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, CurDAG); + + SDValue PACAddrDisc, PACConstDisc; + std::tie(PACConstDisc, PACAddrDisc) = + extractPtrauthBlendDiscriminators(PACDisc, CurDAG); + + SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, + AArch64::X16, Val, SDValue()); + + SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey, + PACConstDisc, PACAddrDisc, X16Copy.getValue(1)}; + + SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops); + ReplaceNode(N, AUTPAC); + return; +} + bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) { LoadSDNode *LD = cast(N); if (LD->isUnindexed()) @@ -5437,6 +5530,15 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) { case Intrinsic::aarch64_tagp: SelectTagP(Node); return; + + case Intrinsic::ptrauth_auth: + SelectPtrauthAuth(Node); + return; + + case Intrinsic::ptrauth_resign: + SelectPtrauthResign(Node); + return; + case Intrinsic::aarch64_neon_tbl2: SelectTable(Node, 2, VT == MVT::v8i8 ? AArch64::TBLv8i8Two : AArch64::TBLv16i8Two, diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 643bcc33f9201..51da812eeef4f 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1776,6 +1776,37 @@ let Predicates = [HasPAuth] in { defm LDRAA : AuthLoad<0, "ldraa", simm10Scaled>; defm LDRAB : AuthLoad<1, "ldrab", simm10Scaled>; + // AUT pseudo. + // This directly manipulates x16/x17, which are the only registers the OS + // guarantees are safe to use for sensitive operations. + def AUT : Pseudo<(outs), (ins i32imm:$Key, i64imm:$Disc, GPR64noip:$AddrDisc), + []>, Sched<[WriteI, ReadI]> { + let isCodeGenOnly = 1; + let hasSideEffects = 1; + let mayStore = 0; + let mayLoad = 0; + let Size = 32; + let Defs = [X16,X17,NZCV]; + let Uses = [X16]; + } + + // AUT and re-PAC a value, using different keys/data. + // This directly manipulates x16/x17, which are the only registers the OS + // guarantees are safe to use for sensitive operations. + def AUTPAC + : Pseudo<(outs), + (ins i32imm:$AUTKey, i64imm:$AUTDisc, GPR64noip:$AUTAddrDisc, + i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc), + []>, Sched<[WriteI, ReadI]> { + let isCodeGenOnly = 1; + let hasSideEffects = 1; + let mayStore = 0; + let mayLoad = 0; + let Size = 48; + let Defs = [X16,X17,NZCV]; + let Uses = [X16]; + } + // Materialize a signed global address, with adrp+add and PAC. def MOVaddrPAC : Pseudo<(outs), (ins i64imm:$Addr, i32imm:$Key, @@ -1833,7 +1864,6 @@ let Predicates = [HasPAuth] in { tcGPR64:$AddrDisc), (AUTH_TCRETURN_BTI tcGPRx16x17:$dst, imm:$FPDiff, imm:$Key, imm:$Disc, tcGPR64:$AddrDisc)>; - } // v9.5-A pointer authentication extensions diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 009928a8a7488..f57bc4fddfbb2 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -6507,6 +6507,64 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I, I.eraseFromParent(); return true; } + case Intrinsic::ptrauth_resign: { + Register DstReg = I.getOperand(0).getReg(); + Register ValReg = I.getOperand(2).getReg(); + uint64_t AUTKey = I.getOperand(3).getImm(); + Register AUTDisc = I.getOperand(4).getReg(); + uint64_t PACKey = I.getOperand(5).getImm(); + Register PACDisc = I.getOperand(6).getReg(); + + Register AUTAddrDisc = AUTDisc; + uint16_t AUTConstDiscC = 0; + std::tie(AUTConstDiscC, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, MRI); + + Register PACAddrDisc = PACDisc; + uint16_t PACConstDiscC = 0; + std::tie(PACConstDiscC, PACAddrDisc) = + extractPtrauthBlendDiscriminators(PACDisc, MRI); + + MIB.buildCopy({AArch64::X16}, {ValReg}); + MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {}); + MIB.buildInstr(AArch64::AUTPAC) + .addImm(AUTKey) + .addImm(AUTConstDiscC) + .addUse(AUTAddrDisc) + .addImm(PACKey) + .addImm(PACConstDiscC) + .addUse(PACAddrDisc) + .constrainAllUses(TII, TRI, RBI); + MIB.buildCopy({DstReg}, Register(AArch64::X16)); + + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + I.eraseFromParent(); + return true; + } + case Intrinsic::ptrauth_auth: { + Register DstReg = I.getOperand(0).getReg(); + Register ValReg = I.getOperand(2).getReg(); + uint64_t AUTKey = I.getOperand(3).getImm(); + Register AUTDisc = I.getOperand(4).getReg(); + + Register AUTAddrDisc = AUTDisc; + uint16_t AUTConstDiscC = 0; + std::tie(AUTConstDiscC, AUTAddrDisc) = + extractPtrauthBlendDiscriminators(AUTDisc, MRI); + + MIB.buildCopy({AArch64::X16}, {ValReg}); + MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {}); + MIB.buildInstr(AArch64::AUT) + .addImm(AUTKey) + .addImm(AUTConstDiscC) + .addUse(AUTAddrDisc) + .constrainAllUses(TII, TRI, RBI); + MIB.buildCopy({DstReg}, Register(AArch64::X16)); + + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + I.eraseFromParent(); + return true; + } case Intrinsic::frameaddress: case Intrinsic::returnaddress: { MachineFunction &MF = *I.getParent()->getParent(); diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll new file mode 100644 index 0000000000000..3b93acd8e46f7 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll @@ -0,0 +1,254 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefix=CHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefix=CHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_auth_blend(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_blend: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, x1 +; UNCHECKED-NEXT: movk x17, #65535, lsl #48 +; UNCHECKED-NEXT: autda x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_blend: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, x1 +; CHECKED-NEXT: movk x17, #65535, lsl #48 +; CHECKED-NEXT: autda x16, x17 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_blend: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, x1 +; TRAP-NEXT: movk x17, #65535, lsl #48 +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_0 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_0: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 65535) + %tmp1 = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 %tmp0) + ret i64 %tmp1 +} + +define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_blend: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, x1 +; UNCHECKED-NEXT: movk x17, #12345, lsl #48 +; UNCHECKED-NEXT: autda x16, x17 +; UNCHECKED-NEXT: mov x17, x2 +; UNCHECKED-NEXT: movk x17, #56789, lsl #48 +; UNCHECKED-NEXT: pacdb x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_blend: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, x1 +; CHECKED-NEXT: movk x17, #12345, lsl #48 +; CHECKED-NEXT: autda x16, x17 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_0 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_0 +; CHECKED-NEXT: Lauth_success_0: +; CHECKED-NEXT: mov x17, x2 +; CHECKED-NEXT: movk x17, #56789, lsl #48 +; CHECKED-NEXT: pacdb x16, x17 +; CHECKED-NEXT: Lresign_end_0: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_blend: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, x1 +; TRAP-NEXT: movk x17, #12345, lsl #48 +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_1 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_1: +; TRAP-NEXT: mov x17, x2 +; TRAP-NEXT: movk x17, #56789, lsl #48 +; TRAP-NEXT: pacdb x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 12345) + %tmp1 = call i64 @llvm.ptrauth.blend(i64 %arg2, i64 56789) + %tmp2 = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %tmp0, i32 3, i64 %tmp1) + ret i64 %tmp2 +} + +define i64 @test_resign_blend_and_const(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_resign_blend_and_const: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, x1 +; UNCHECKED-NEXT: movk x17, #12345, lsl #48 +; UNCHECKED-NEXT: autda x16, x17 +; UNCHECKED-NEXT: mov x17, #56789 ; =0xddd5 +; UNCHECKED-NEXT: pacdb x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_blend_and_const: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, x1 +; CHECKED-NEXT: movk x17, #12345, lsl #48 +; CHECKED-NEXT: autda x16, x17 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_1 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_1 +; CHECKED-NEXT: Lauth_success_1: +; CHECKED-NEXT: mov x17, #56789 ; =0xddd5 +; CHECKED-NEXT: pacdb x16, x17 +; CHECKED-NEXT: Lresign_end_1: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_blend_and_const: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, x1 +; TRAP-NEXT: movk x17, #12345, lsl #48 +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_2 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_2: +; TRAP-NEXT: mov x17, #56789 ; =0xddd5 +; TRAP-NEXT: pacdb x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 12345) + %tmp1 = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %tmp0, i32 3, i64 56789) + ret i64 %tmp1 +} + +define i64 @test_resign_blend_and_addr(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_blend_and_addr: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, x1 +; UNCHECKED-NEXT: movk x17, #12345, lsl #48 +; UNCHECKED-NEXT: autda x16, x17 +; UNCHECKED-NEXT: pacdb x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_blend_and_addr: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, x1 +; CHECKED-NEXT: movk x17, #12345, lsl #48 +; CHECKED-NEXT: autda x16, x17 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_2 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_2 +; CHECKED-NEXT: Lauth_success_2: +; CHECKED-NEXT: pacdb x16, x2 +; CHECKED-NEXT: Lresign_end_2: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_blend_and_addr: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, x1 +; TRAP-NEXT: movk x17, #12345, lsl #48 +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_3 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_3: +; TRAP-NEXT: pacdb x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 12345) + %tmp1 = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %tmp0, i32 3, i64 %arg2) + ret i64 %tmp1 +} + +define i64 @test_auth_too_large_discriminator(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_too_large_discriminator: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov w8, #65536 ; =0x10000 +; UNCHECKED-NEXT: bfi x1, x8, #48, #16 +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_too_large_discriminator: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov w8, #65536 ; =0x10000 +; CHECKED-NEXT: bfi x1, x8, #48, #16 +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_too_large_discriminator: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov w8, #65536 ; =0x10000 +; TRAP-NEXT: bfi x1, x8, #48, #16 +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_4 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_4: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 65536) + %tmp1 = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 %tmp0) + ret i64 %tmp1 +} + +declare i64 @llvm.ptrauth.auth(i64, i32, i64) +declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64) +declare i64 @llvm.ptrauth.blend(i64, i64) diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll new file mode 100644 index 0000000000000..62c9fba853adb --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign.ll @@ -0,0 +1,638 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefix=CHECKED +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: | FileCheck %s --check-prefix=CHECKED + +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP +; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_auth_ia(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autia x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autia x16, x1 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autia x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_0 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_0: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_ia_zero(i64 %arg) { +; UNCHECKED-LABEL: test_auth_ia_zero: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autiza x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_ia_zero: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autiza x16 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_ia_zero: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autiza x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_1 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_1: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_ib(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_ib: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autib x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_ib: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autib x16, x1 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_ib: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autib x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_2 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_2: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 1, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_ib_zero(i64 %arg) { +; UNCHECKED-LABEL: test_auth_ib_zero: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autizb x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_ib_zero: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autizb x16 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_ib_zero: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autizb x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_3 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_3: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 1, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_da(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_da: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_da: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_da: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_4 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_4: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_da_zero(i64 %arg) { +; UNCHECKED-LABEL: test_auth_da_zero: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autdza x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_da_zero: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autdza x16 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_da_zero: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autdza x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_5 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_5: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_db(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_auth_db: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autdb x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_db: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autdb x16, x1 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_db: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autdb x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_6 +; TRAP-NEXT: brk #0xc473 +; TRAP-NEXT: Lauth_success_6: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 3, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_db_zero(i64 %arg) { +; UNCHECKED-LABEL: test_auth_db_zero: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autdzb x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_db_zero: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autdzb x16 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_db_zero: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autdzb x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_7 +; TRAP-NEXT: brk #0xc473 +; TRAP-NEXT: Lauth_success_7: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 3, i64 0) + ret i64 %tmp +} + +;; Note that this might seem like a no-op but is actually a valid way to enforce +;; the validity of a signature. +define i64 @test_resign_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_ia_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autia x16, x1 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_ia_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autia x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_0 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_0 +; CHECKED-NEXT: Lauth_success_0: +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_0: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_ia_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autia x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_8 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_8: +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 0, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_ib_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autib x16, x1 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_ib_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autib x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_1 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_1 +; CHECKED-NEXT: Lauth_success_1: +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_1: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_ib_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autib x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_9 +; TRAP-NEXT: brk #0xc471 +; TRAP-NEXT: Lauth_success_9: +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 1, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_da_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_da_ia: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: pacia x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_da_ia: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_2 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_2 +; CHECKED-NEXT: Lauth_success_2: +; CHECKED-NEXT: pacia x16, x2 +; CHECKED-NEXT: Lresign_end_2: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_da_ia: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_10 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_10: +; TRAP-NEXT: pacia x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_db_da(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_db_da: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autdb x16, x1 +; UNCHECKED-NEXT: pacda x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_db_da: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autdb x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_3 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_3 +; CHECKED-NEXT: Lauth_success_3: +; CHECKED-NEXT: pacda x16, x2 +; CHECKED-NEXT: Lresign_end_3: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_db_da: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autdb x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_11 +; TRAP-NEXT: brk #0xc473 +; TRAP-NEXT: Lauth_success_11: +; TRAP-NEXT: pacda x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 3, i64 %arg1, i32 2, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_iza_db(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_iza_db: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autiza x16 +; UNCHECKED-NEXT: pacdb x16, x2 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_iza_db: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autiza x16 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_4 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_4 +; CHECKED-NEXT: Lauth_success_4: +; CHECKED-NEXT: pacdb x16, x2 +; CHECKED-NEXT: Lresign_end_4: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_iza_db: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autiza x16 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_12 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_12: +; TRAP-NEXT: pacdb x16, x2 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 0, i64 0, i32 3, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) { +; UNCHECKED-LABEL: test_resign_da_dzb: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: pacdzb x16 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_da_dzb: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_5 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_5 +; CHECKED-NEXT: Lauth_success_5: +; CHECKED-NEXT: pacdzb x16 +; CHECKED-NEXT: Lresign_end_5: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_da_dzb: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_13 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_13: +; TRAP-NEXT: pacdzb x16 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %arg1, i32 3, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_trap_attribute(i64 %arg, i64 %arg1) "ptrauth-auth-traps" { +; UNCHECKED-LABEL: test_auth_trap_attribute: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autia x16, x1 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_trap_attribute: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autia x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpaci x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_6 +; CHECKED-NEXT: brk #0xc470 +; CHECKED-NEXT: Lauth_success_6: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_trap_attribute: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autia x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_14 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_14: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_ia_constdisc(i64 %arg) { +; UNCHECKED-LABEL: test_auth_ia_constdisc: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: mov x17, #256 ; =0x100 +; UNCHECKED-NEXT: autia x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_auth_ia_constdisc: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: mov x17, #256 ; =0x100 +; CHECKED-NEXT: autia x16, x17 +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_auth_ia_constdisc: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: mov x17, #256 ; =0x100 +; TRAP-NEXT: autia x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_15 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: Lauth_success_15: +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 256) + ret i64 %tmp +} + +define i64 @test_resign_da_constdisc(i64 %arg, i64 %arg1) { +; UNCHECKED-LABEL: test_resign_da_constdisc: +; UNCHECKED: ; %bb.0: +; UNCHECKED-NEXT: mov x16, x0 +; UNCHECKED-NEXT: autda x16, x1 +; UNCHECKED-NEXT: mov x17, #256 ; =0x100 +; UNCHECKED-NEXT: pacda x16, x17 +; UNCHECKED-NEXT: mov x0, x16 +; UNCHECKED-NEXT: ret +; +; CHECKED-LABEL: test_resign_da_constdisc: +; CHECKED: ; %bb.0: +; CHECKED-NEXT: mov x16, x0 +; CHECKED-NEXT: autda x16, x1 +; CHECKED-NEXT: mov x17, x16 +; CHECKED-NEXT: xpacd x17 +; CHECKED-NEXT: cmp x16, x17 +; CHECKED-NEXT: b.eq Lauth_success_7 +; CHECKED-NEXT: mov x16, x17 +; CHECKED-NEXT: b Lresign_end_6 +; CHECKED-NEXT: Lauth_success_7: +; CHECKED-NEXT: mov x17, #256 ; =0x100 +; CHECKED-NEXT: pacda x16, x17 +; CHECKED-NEXT: Lresign_end_6: +; CHECKED-NEXT: mov x0, x16 +; CHECKED-NEXT: ret +; +; TRAP-LABEL: test_resign_da_constdisc: +; TRAP: ; %bb.0: +; TRAP-NEXT: mov x16, x0 +; TRAP-NEXT: autda x16, x1 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq Lauth_success_16 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: Lauth_success_16: +; TRAP-NEXT: mov x17, #256 ; =0x100 +; TRAP-NEXT: pacda x16, x17 +; TRAP-NEXT: mov x0, x16 +; TRAP-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %arg1, i32 2, i64 256) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.auth(i64, i32, i64) +declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64) From e97643fc72b52f25a9e856e259607aaf18045ceb Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 24 Oct 2022 08:39:10 -0700 Subject: [PATCH 2/3] [AArch64] Add FPAC feature. --- llvm/lib/Target/AArch64/AArch64Features.td | 3 +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 ++ 2 files changed, 5 insertions(+) diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td index 832e44fe117e2..a1ae0873fc190 100644 --- a/llvm/lib/Target/AArch64/AArch64Features.td +++ b/llvm/lib/Target/AArch64/AArch64Features.td @@ -185,6 +185,9 @@ def FeatureJS : ExtensionWithMArch<"jsconv", "JS", "FEAT_JSCVT", "Enable Armv8.3-A JavaScript FP conversion instructions", [FeatureFPARMv8]>; +def FeatureFPAC : Extension<"fpac", "FPAC", "FEAT_FPAC", + "Enable v8.3-A Pointer Authentication Faulting enhancement">; + def FeatureCCIDX : Extension<"ccidx", "CCIDX", "FEAT_CCIDX", "Enable Armv8.3-A Extend of the CCSIDR number of sets">; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 51da812eeef4f..711329251ddf2 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -276,6 +276,8 @@ def HasMatMulFP32 : Predicate<"Subtarget->hasMatMulFP32()">, AssemblerPredicateWithAll<(all_of FeatureMatMulFP32), "f32mm">; def HasMatMulFP64 : Predicate<"Subtarget->hasMatMulFP64()">, AssemblerPredicateWithAll<(all_of FeatureMatMulFP64), "f64mm">; +def HasFPAC : Predicate<"Subtarget->hasFPAC())">, + AssemblerPredicateWithAll<(all_of FeatureFPAC), "fpac">; def HasXS : Predicate<"Subtarget->hasXS()">, AssemblerPredicateWithAll<(all_of FeatureXS), "xs">; def HasWFxT : Predicate<"Subtarget->hasWFxT()">, From 557cd75f4b8f144eb8f7586994f66815d3b4bc2c Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 24 Oct 2022 08:36:13 -0700 Subject: [PATCH 3/3] [AArch64][PAC] Don't emit auth/resign checks when targeting FPAC. When the FPAC feature is present, we can rely on its faulting behavior to avoid emitting the expensive authentication failure check sequence ourvelves. In which case we emit the same sequence as a plain unchecked auth/resign. --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 5 + llvm/test/CodeGen/AArch64/ptrauth-fpac.ll | 374 ++++++++++++++++++ 2 files changed, 379 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-fpac.ll diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index c49b8b5f5f398..6d4f417de4165 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1693,6 +1693,11 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { // In the checked sequence, we only trap if explicitly requested. bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps"); + // On an FPAC CPU, you get traps whether you want them or not: there's + // no point in emitting checks or traps. + if (STI->hasFPAC()) + ShouldCheck = ShouldTrap = false; + // However, command-line flags can override this, for experimentation. switch (PtrauthAuthChecks) { case PtrauthCheckMode::Default: diff --git a/llvm/test/CodeGen/AArch64/ptrauth-fpac.ll b/llvm/test/CodeGen/AArch64/ptrauth-fpac.ll new file mode 100644 index 0000000000000..6afe1a93d986e --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-fpac.ll @@ -0,0 +1,374 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs | FileCheck %s --check-prefixes=ALL,NOFPAC +; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+fpac -verify-machineinstrs | FileCheck %s --check-prefixes=ALL,FPAC + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_auth_ia(i64 %arg, i64 %arg1) { +; ALL-LABEL: test_auth_ia: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autia x16, x1 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_ia_zero(i64 %arg) { +; ALL-LABEL: test_auth_ia_zero: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autiza x16 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_ib(i64 %arg, i64 %arg1) { +; ALL-LABEL: test_auth_ib: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autib x16, x1 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 1, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_ib_zero(i64 %arg) { +; ALL-LABEL: test_auth_ib_zero: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autizb x16 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 1, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_da(i64 %arg, i64 %arg1) { +; ALL-LABEL: test_auth_da: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autda x16, x1 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_da_zero(i64 %arg) { +; ALL-LABEL: test_auth_da_zero: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autdza x16 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_db(i64 %arg, i64 %arg1) { +; ALL-LABEL: test_auth_db: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autdb x16, x1 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 3, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_auth_db_zero(i64 %arg) { +; ALL-LABEL: test_auth_db_zero: +; ALL: ; %bb.0: +; ALL-NEXT: mov x16, x0 +; ALL-NEXT: autdzb x16 +; ALL-NEXT: mov x0, x16 +; ALL-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 3, i64 0) + ret i64 %tmp +} + +; Note that this might seem like a no-op but is actually a valid way to enforce +; the validity of a signature. +define i64 @test_resign_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_ia_ia: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autia x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpaci x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_0 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_0 +; NOFPAC-NEXT: Lauth_success_0: +; NOFPAC-NEXT: pacia x16, x2 +; NOFPAC-NEXT: Lresign_end_0: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_ia_ia: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autia x16, x1 +; FPAC-NEXT: pacia x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 0, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_ib_ia: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autib x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpaci x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_1 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_1 +; NOFPAC-NEXT: Lauth_success_1: +; NOFPAC-NEXT: pacia x16, x2 +; NOFPAC-NEXT: Lresign_end_1: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_ib_ia: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autib x16, x1 +; FPAC-NEXT: pacia x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 1, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_da_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_da_ia: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autda x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_2 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_2 +; NOFPAC-NEXT: Lauth_success_2: +; NOFPAC-NEXT: pacia x16, x2 +; NOFPAC-NEXT: Lresign_end_2: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_da_ia: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autda x16, x1 +; FPAC-NEXT: pacia x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_db_ia(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_db_ia: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autdb x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_3 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_3 +; NOFPAC-NEXT: Lauth_success_3: +; NOFPAC-NEXT: pacia x16, x2 +; NOFPAC-NEXT: Lresign_end_3: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_db_ia: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autdb x16, x1 +; FPAC-NEXT: pacia x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 3, i64 %arg1, i32 0, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_db_ib(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_db_ib: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autdb x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_4 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_4 +; NOFPAC-NEXT: Lauth_success_4: +; NOFPAC-NEXT: pacib x16, x2 +; NOFPAC-NEXT: Lresign_end_4: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_db_ib: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autdb x16, x1 +; FPAC-NEXT: pacib x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 3, i64 %arg1, i32 1, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_db_da(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_db_da: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autdb x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_5 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_5 +; NOFPAC-NEXT: Lauth_success_5: +; NOFPAC-NEXT: pacda x16, x2 +; NOFPAC-NEXT: Lresign_end_5: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_db_da: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autdb x16, x1 +; FPAC-NEXT: pacda x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 3, i64 %arg1, i32 2, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_db_db(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_db_db: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autdb x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_6 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_6 +; NOFPAC-NEXT: Lauth_success_6: +; NOFPAC-NEXT: pacdb x16, x2 +; NOFPAC-NEXT: Lresign_end_6: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_db_db: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autdb x16, x1 +; FPAC-NEXT: pacdb x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 3, i64 %arg1, i32 3, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_iza_db(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_iza_db: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autiza x16 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpaci x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_7 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_7 +; NOFPAC-NEXT: Lauth_success_7: +; NOFPAC-NEXT: pacdb x16, x2 +; NOFPAC-NEXT: Lresign_end_7: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_iza_db: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autiza x16 +; FPAC-NEXT: pacdb x16, x2 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 0, i64 0, i32 3, i64 %arg2) + ret i64 %tmp +} + +define i64 @test_resign_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) { +; NOFPAC-LABEL: test_resign_da_dzb: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autda x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpacd x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_8 +; NOFPAC-NEXT: mov x16, x17 +; NOFPAC-NEXT: b Lresign_end_8 +; NOFPAC-NEXT: Lauth_success_8: +; NOFPAC-NEXT: pacdzb x16 +; NOFPAC-NEXT: Lresign_end_8: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_resign_da_dzb: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autda x16, x1 +; FPAC-NEXT: pacdzb x16 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.resign(i64 %arg, i32 2, i64 %arg1, i32 3, i64 0) + ret i64 %tmp +} + +define i64 @test_auth_trap_attribute(i64 %arg, i64 %arg1) "ptrauth-auth-traps" { +; NOFPAC-LABEL: test_auth_trap_attribute: +; NOFPAC: ; %bb.0: +; NOFPAC-NEXT: mov x16, x0 +; NOFPAC-NEXT: autia x16, x1 +; NOFPAC-NEXT: mov x17, x16 +; NOFPAC-NEXT: xpaci x17 +; NOFPAC-NEXT: cmp x16, x17 +; NOFPAC-NEXT: b.eq Lauth_success_9 +; NOFPAC-NEXT: brk #0xc470 +; NOFPAC-NEXT: Lauth_success_9: +; NOFPAC-NEXT: mov x0, x16 +; NOFPAC-NEXT: ret +; +; FPAC-LABEL: test_auth_trap_attribute: +; FPAC: ; %bb.0: +; FPAC-NEXT: mov x16, x0 +; FPAC-NEXT: autia x16, x1 +; FPAC-NEXT: mov x0, x16 +; FPAC-NEXT: ret + %tmp = call i64 @llvm.ptrauth.auth(i64 %arg, i32 0, i64 %arg1) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.auth(i64, i32, i64) +declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)