Index: llvm/lib/Target/AArch64/AArch64InstrInfo.h =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.h +++ llvm/lib/Target/AArch64/AArch64InstrInfo.h @@ -502,6 +502,39 @@ /// Return opcode to be used for indirect calls. unsigned getBLRCallOpcode(const MachineFunction &MF); +/// Return XPAC opcode to be used for a ptrauth strip using the given key. +static inline unsigned getXPACOpcodeForKey(AArch64PACKey::ID K) { + using namespace AArch64PACKey; + switch (K) { + case IA: case IB: return AArch64::XPACI; + case DA: case DB: return AArch64::XPACD; + } +} + +/// Return AUT opcode to be used for a ptrauth auth using the given key, or its +/// AUT*Z variant that doesn't take a discriminator operand, using zero instead. +static inline unsigned getAUTOpcodeForKey(AArch64PACKey::ID K, bool Zero) { + using namespace AArch64PACKey; + switch (K) { + case IA: return Zero ? AArch64::AUTIZA : AArch64::AUTIA; + case IB: return Zero ? AArch64::AUTIZB : AArch64::AUTIB; + case DA: return Zero ? AArch64::AUTDZA : AArch64::AUTDA; + case DB: return Zero ? AArch64::AUTDZB : AArch64::AUTDB; + } +} + +/// Return PAC opcode to be used for a ptrauth auth using the given key, or its +/// PAC*Z variant that doesn't take a discriminator operand, using zero instead. +static inline unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero) { + using namespace AArch64PACKey; + switch (K) { + case IA: return Zero ? AArch64::PACIZA : AArch64::PACIA; + case IB: return Zero ? AArch64::PACIZB : AArch64::PACIB; + case DA: return Zero ? AArch64::PACDZA : AArch64::PACDA; + case DB: return Zero ? AArch64::PACDZB : AArch64::PACDB; + } +} + // struct TSFlags { #define TSFLAG_ELEMENT_SIZE_TYPE(X) (X) // 3-bits #define TSFLAG_DESTRUCTIVE_INST_TYPE(X) ((X) << 3) // 4-bits Index: llvm/lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1349,7 +1349,12 @@ defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; def XPACI : ClearAuth<0, "xpaci">; + def : Pat<(int_ptrauth_strip GPR64:$Rd, 0), (XPACI GPR64:$Rd)>; + def : Pat<(int_ptrauth_strip GPR64:$Rd, 1), (XPACI GPR64:$Rd)>; + def XPACD : ClearAuth<1, "xpacd">; + def : Pat<(int_ptrauth_strip GPR64:$Rd, 2), (XPACD GPR64:$Rd)>; + def : Pat<(int_ptrauth_strip GPR64:$Rd, 3), (XPACD GPR64:$Rd)>; def PACGA : SignAuthTwoOperand<0b1100, "pacga", int_ptrauth_sign_generic>; Index: llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp =================================================================== --- llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -5854,6 +5854,22 @@ I.eraseFromParent(); return true; } + case Intrinsic::ptrauth_strip: { + Register DstReg = I.getOperand(0).getReg(); + Register ValReg = I.getOperand(2).getReg(); + uint64_t Key = I.getOperand(3).getImm(); + + if (Key > 3) + return false; + unsigned Opcode = getXPACOpcodeForKey((AArch64PACKey::ID)Key); + + MIB.buildInstr(Opcode, {DstReg}, {ValReg}); + + RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI); + RBI.constrainGenericRegister(ValReg, AArch64::GPR64RegClass, MRI); + I.eraseFromParent(); + return true; + } case Intrinsic::frameaddress: case Intrinsic::returnaddress: { MachineFunction &MF = *I.getParent()->getParent(); Index: llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -786,6 +786,47 @@ }; } // end namespace AArch64II +//===----------------------------------------------------------------------===// +// v8.3a Pointer Authentication +// + +namespace AArch64PACKey { +enum ID : uint8_t { + IA = 0, + IB = 1, + DA = 2, + DB = 3 +}; +} // namespace AArch64PACKey + +/// Return 2-letter identifier string for numeric key ID. +inline static StringRef AArch64PACKeyIDToString(AArch64PACKey::ID KeyID) { + switch (KeyID) { + case AArch64PACKey::IA: + return StringRef("ia"); + case AArch64PACKey::IB: + return StringRef("ib"); + case AArch64PACKey::DA: + return StringRef("da"); + case AArch64PACKey::DB: + return StringRef("db"); + } +} + +/// Return numeric key ID for 2-letter identifier string. +inline static Optional +AArch64StringToPACKeyID(StringRef Name) { + if (Name == "ia") + return AArch64PACKey::IA; + if (Name == "ib") + return AArch64PACKey::IB; + if (Name == "da") + return AArch64PACKey::DA; + if (Name == "db") + return AArch64PACKey::DB; + return None; +} + namespace AArch64 { // The number of bits in a SVE register is architecturally defined // to be a multiple of this value. If has this number of bits, Index: llvm/test/CodeGen/AArch64/ptrauth-intrinsic-strip.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/ptrauth-intrinsic-strip.ll @@ -0,0 +1,43 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -global-isel=0 | FileCheck %s +; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -global-isel=1 -global-isel-abort=1 | FileCheck %s + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" + +define i64 @test_strip_ia(i64 %arg) { +; CHECK-LABEL: test_strip_ia: +; CHECK: ; %bb.0: +; CHECK-NEXT: xpaci x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.strip(i64 %arg, i32 0) + ret i64 %tmp +} + +define i64 @test_strip_ib(i64 %arg) { +; CHECK-LABEL: test_strip_ib: +; CHECK: ; %bb.0: +; CHECK-NEXT: xpaci x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.strip(i64 %arg, i32 1) + ret i64 %tmp +} + +define i64 @test_strip_da(i64 %arg) { +; CHECK-LABEL: test_strip_da: +; CHECK: ; %bb.0: +; CHECK-NEXT: xpacd x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.strip(i64 %arg, i32 2) + ret i64 %tmp +} + +define i64 @test_strip_db(i64 %arg) { +; CHECK-LABEL: test_strip_db: +; CHECK: ; %bb.0: +; CHECK-NEXT: xpacd x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.strip(i64 %arg, i32 3) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.strip(i64, i32)