diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -2012,10 +2012,10 @@ let Inst{31} = 1; } -class SignAuthOneData opcode_prefix, bits<2> opcode, string asm> - : I<(outs GPR64:$Rd), (ins GPR64:$src, GPR64sp:$Rn), asm, "\t$Rd, $Rn", - "$Rd = $src", - []>, +class SignAuthOneData opcode_prefix, bits<2> opcode, string asm, + SDPatternOperator op> + : I<(outs GPR64:$dst), (ins GPR64:$Rd, GPR64sp:$Rn), asm, "\t$Rd, $Rn", + "$dst = $Rd", [(set GPR64:$dst, (op GPR64:$Rd, opcode, GPR64sp:$Rn))]>, Sched<[WriteI, ReadI]> { bits<5> Rd; bits<5> Rn; @@ -2026,9 +2026,11 @@ let Inst{4-0} = Rd; } -class SignAuthZero opcode_prefix, bits<2> opcode, string asm> - : I<(outs GPR64:$Rd), (ins GPR64:$src), asm, "\t$Rd", "$Rd = $src", - []>, Sched<[]> { +class SignAuthZero opcode_prefix, bits<2> opcode, string asm, + SDPatternOperator op> + : I<(outs GPR64:$dst), (ins GPR64:$Rd), asm, "\t$Rd", "$dst = $Rd", + [(set GPR64:$dst, (op GPR64:$Rd, opcode, (i64 0)))]>, + Sched<[]> { bits<5> Rd; let Inst{31-15} = 0b11011010110000010; let Inst{14-12} = opcode_prefix; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1215,23 +1215,25 @@ def : InstAlias<"autib1716", (AUTIB1716), 1>; def : InstAlias<"xpaclri", (XPACLRI), 1>; - multiclass SignAuth prefix, bits<3> prefix_z, string asm> { - def IA : SignAuthOneData; - def IB : SignAuthOneData; - def DA : SignAuthOneData; - def DB : SignAuthOneData; - def IZA : SignAuthZero; - def DZA : SignAuthZero; - def IZB : SignAuthZero; - def DZB : SignAuthZero; + multiclass SignAuth prefix, bits<3> prefix_z, string asm, + SDPatternOperator op> { + def IA : SignAuthOneData; + def IB : SignAuthOneData; + def DA : SignAuthOneData; + def DB : SignAuthOneData; + def IZA : SignAuthZero; + def DZA : SignAuthZero; + def IZB : SignAuthZero; + def DZB : SignAuthZero; } - defm PAC : SignAuth<0b000, 0b010, "pac">; - defm AUT : SignAuth<0b001, 0b011, "aut">; + defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>; + defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; def XPACI : ClearAuth<0, "xpaci">; def XPACD : ClearAuth<1, "xpacd">; - def PACGA : SignAuthTwoOperand<0b1100, "pacga", null_frag>; + + def PACGA : SignAuthTwoOperand<0b1100, "pacga", int_ptrauth_sign_generic>; // Combined Instructions let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -5435,6 +5435,33 @@ I.eraseFromParent(); return true; } + case Intrinsic::ptrauth_sign: { + Register DstReg = I.getOperand(0).getReg(); + Register ValReg = I.getOperand(2).getReg(); + uint64_t Key = I.getOperand(3).getImm(); + Register DiscReg = I.getOperand(4).getReg(); + auto DiscVal = getIConstantVRegVal(DiscReg, MRI); + bool IsDiscZero = DiscVal.hasValue() && DiscVal->isNullValue(); + + if (Key > 3) + return false; + + unsigned Opcodes[][4] = { + {AArch64::PACIA, AArch64::PACIB, AArch64::PACDA, AArch64::PACDB}, + {AArch64::PACIZA, AArch64::PACIZB, AArch64::PACDZA, AArch64::PACDZB}}; + unsigned Opcode = Opcodes[IsDiscZero][Key]; + + auto PAC = MIB.buildInstr(Opcode, {DstReg}, {ValReg}); + + if (!IsDiscZero) { + PAC.addUse(DiscReg); + RBI.constrainGenericRegister(DiscReg, AArch64::GPR64spRegClass, MRI); + } + + 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-sign-generic.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-sign-generic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-sign-generic.ll @@ -0,0 +1,14 @@ +; 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 + +define i64 @test_sign_generic(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_sign_generic: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacga x0, x0, x1 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign.generic(i64 %arg, i64 %arg1) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.sign.generic(i64, i64) diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-sign.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-sign.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-sign.ll @@ -0,0 +1,77 @@ +; 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 + +define i64 @test_sign_ia(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_sign_ia: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacia x0, x1 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 0, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_sign_ia_zero(i64 %arg) { +; CHECK-LABEL: test_sign_ia_zero: +; CHECK: ; %bb.0: +; CHECK-NEXT: paciza x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 0, i64 0) + ret i64 %tmp +} + +define i64 @test_sign_ib(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_sign_ib: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacib x0, x1 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 1, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_sign_ib_zero(i64 %arg) { +; CHECK-LABEL: test_sign_ib_zero: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacizb x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 1, i64 0) + ret i64 %tmp +} + +define i64 @test_sign_da(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_sign_da: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacda x0, x1 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 2, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_sign_da_zero(i64 %arg) { +; CHECK-LABEL: test_sign_da_zero: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacdza x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 2, i64 0) + ret i64 %tmp +} + +define i64 @test_sign_db(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_sign_db: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacdb x0, x1 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 3, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_sign_db_zero(i64 %arg) { +; CHECK-LABEL: test_sign_db_zero: +; CHECK: ; %bb.0: +; CHECK-NEXT: pacdzb x0 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.sign(i64 %arg, i32 3, i64 0) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.sign(i64, i32, i64)