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 @@ -889,6 +889,10 @@ def timm64_0_65535 : Operand, TImmLeaf; + +def imm64_0_65535 : Operand, ImmLeaf; } def imm0_255 : Operand, ImmLeaf, Sched<[]>; } +//----------------------------------------------------------------------------- +// v8.3 Pointer Authentication late patterns + +let Predicates = [HasPAuth] in { +def : Pat<(int_ptrauth_blend GPR64:$Rd, imm64_0_65535:$imm), + (MOVKXi GPR64:$Rd, (trunc_imm imm64_0_65535:$imm), 48)>; +def : Pat<(int_ptrauth_blend GPR64:$Rd, GPR64:$Rn), + (BFMXri GPR64:$Rd, GPR64:$Rn, 16, 15)>; +} + +//----------------------------------------------------------------------------- + // This gets lowered into an instruction sequence of 20 bytes let Defs = [X16, X17], mayStore = 1, isCodeGenOnly = 1, Size = 20 in def StoreSwiftAsyncContext 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 @@ -5976,6 +5976,25 @@ I.eraseFromParent(); return true; } + case Intrinsic::ptrauth_blend: { + MachineFunction &MF = *I.getParent()->getParent(); + auto RHS = getIConstantVRegVal(I.getOperand(3).getReg(), MRI); + if (RHS && (RHS->getZExtValue() <= 0xffff)) { + I.setDesc(TII.get(AArch64::MOVKXi)); + I.removeOperand(3); + I.removeOperand(1); + MachineInstrBuilder(MF, I) + .addImm(RHS->getZExtValue() & 0xffff) + .addImm(48) + .constrainAllUses(TII, TRI, RBI); + } else { + I.setDesc(TII.get(AArch64::BFMXri)); + I.removeOperand(1); + MachineInstrBuilder(MF, I).addImm(16).addImm(15).constrainAllUses( + TII, TRI, RBI); + } + return true; + } case Intrinsic::frameaddress: case Intrinsic::returnaddress: { MachineFunction &MF = *I.getParent()->getParent(); diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-blend.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-blend.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-blend.ll @@ -0,0 +1,46 @@ +; 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_blend(i64 %arg, i64 %arg1) { +; CHECK-LABEL: test_blend: +; CHECK: ; %bb.0: +; CHECK-NEXT: bfi x0, x1, #48, #16 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.blend(i64 %arg, i64 %arg1) + ret i64 %tmp +} + +define i64 @test_blend_constant(i64 %arg) { +; CHECK-LABEL: test_blend_constant: +; CHECK: ; %bb.0: +; CHECK-NEXT: movk x0, #12345, lsl #48 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345) + ret i64 %tmp +} + +; Blend isn't commutative. +define i64 @test_blend_constant_swapped(i64 %arg) { +; CHECK-LABEL: test_blend_constant_swapped: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov w8, #12345 +; CHECK-NEXT: bfi x8, x0, #48, #16 +; CHECK-NEXT: mov x0, x8 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.blend(i64 12345, i64 %arg) + ret i64 %tmp +} + +; Blends of constants wider than 16 bits truncate the constant. +define i64 @test_blend_constant_wide(i64 %arg) { +; CHECK-LABEL: test_blend_constant_wide: +; CHECK: ; %bb.0: +; CHECK-NEXT: mov w8, #65536 +; CHECK-NEXT: bfi x0, x8, #48, #16 +; CHECK-NEXT: ret + %tmp = call i64 @llvm.ptrauth.blend(i64 %arg, i64 65536) + ret i64 %tmp +} + +declare i64 @llvm.ptrauth.blend(i64, i64)