Index: llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -1208,6 +1208,37 @@ MI.eraseFromParent(); return true; } + case AArch64::XPACIuntied: { + const MachineOperand &LHS = MI.getOperand(0); + const MachineOperand &RHS = MI.getOperand(1); + // If the registrs are the same, just lower to the "tied" version. + // $x0 = XPACIuntied $x0 -> $x0 = XPACI $x0. + if (LHS.getReg() == RHS.getReg()) { + MachineInstrBuilder DefMIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::XPACI)) + .add(LHS) + .add(RHS); + transferImpOps(MI, DefMIB, DefMIB); + } else { + // $x0 = XPACIuntied $x1 + // -> + // mov $x0, $x1 + // XPACI $x0. + MachineInstrBuilder DefMIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs)) + .addReg(LHS.getReg()) + .addReg(AArch64::XZR) + .add(RHS) + .addImm(0); + MachineInstrBuilder UseMIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::XPACI), + LHS.getReg()) + .addReg(LHS.getReg()); + transferImpOps(MI, UseMIB, DefMIB); + } + MI.eraseFromParent(); + return true; + } case AArch64::IRGstack: { MachineFunction &MF = *MBB.getParent(); const AArch64FunctionInfo *AFI = MF.getInfo(); Index: llvm/lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1349,7 +1349,16 @@ defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; def XPACI : ClearAuth<0, "xpaci">; + // Pseudo of the previous instruction with untied operands. Lowers to: + // mov $dst, $src + // xpaci $dst + def XPACIuntied : Pseudo<(outs GPR64:$dst), (ins GPR64:$src), []>, Sched<[]>; + 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 @@ -5850,6 +5850,23 @@ 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 = + Key == 0 || Key == 1 ? AArch64::XPACIuntied : AArch64::XPACD; + + 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/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)