https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/130809
>From fc7f86658c912322aa699e3e432f1d32516f2f1e Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Mon, 10 Mar 2025 15:14:55 +0300 Subject: [PATCH 1/7] [AArch64][PAC] Precommit tests on merging MOVaddr/LOADgotAUTH with PAC* --- .../GlobalISel/ptrauth-constant-in-code.ll | 74 +++++++++++++++++++ .../AArch64/ptrauth-constant-in-code.ll | 69 +++++++++++++++++ 2 files changed, 143 insertions(+) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll index 12a3448111fcb..b7c52fc72c418 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll @@ -78,6 +78,80 @@ define ptr @foo() { ret ptr ptrauth (ptr @g, i32 0) } +;--- finalize-isel.ll + +; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \ +; RUN: -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \ +; RUN: FileCheck --check-prefixes=ISEL,ISEL-ELF %s +; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \ +; RUN: -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \ +; RUN: FileCheck --check-prefixes=ISEL %s + +@const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] +@const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] + +define void @store_signed_const_local(ptr %dest) { +; ISEL-LABEL: name: store_signed_const_local +; ISEL: body: +; ISEL: %0:gpr64common = COPY $x0 +; ISEL-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 +; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-NEXT: %4:gpr64 = PACDA %10, %2 +; ISEL-NEXT: %14:gpr64 = COPY %4 +; ISEL-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +define void @store_signed_const_got(ptr %dest) { +; ISEL-ELF-LABEL: name: store_signed_const_got +; ISEL-ELF: body: +; ISEL-ELF: %0:gpr64common = COPY $x0 +; ISEL-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got +; ISEL-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 +; ISEL-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-ELF-NEXT: %4:gpr64 = PACDA %6, %2 +; ISEL-ELF-NEXT: %10:gpr64 = COPY %4 +; ISEL-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-ELF-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +define void @store_signed_arg(ptr %dest, ptr %p) { +; ISEL-LABEL: name: store_signed_arg +; ISEL: body: +; ISEL: %0:gpr64common = COPY $x0 +; ISEL-NEXT: %1:gpr64common = COPY $x1 +; ISEL-NEXT: %3:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-NEXT: %6:gpr64common = ADDXri %1, 8, 0 +; Check that no implicit defs are added to PACDA instruction. +; ISEL-NEXT: %8:gpr64 = PACDA %6, %3{{$}} +; ISEL-NEXT: %10:gpr64 = COPY %8 +; ISEL-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1 + %p.offset.i = ptrtoint ptr %p.offset to i64 + %signed.i = call i64 @llvm.ptrauth.sign(i64 %p.offset.i, i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} + ;--- ok.ll ; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \ diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll index 76339a7cc5791..182e8f3d016e9 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll @@ -69,6 +69,75 @@ define ptr @foo() { ret ptr ptrauth (ptr @g, i32 0) } +;--- finalize-isel.ll + +; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \ +; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL,ISEL-ELF %s +; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \ +; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL %s + +@const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] +@const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] + +define void @store_signed_const_local(ptr %dest) { +; ISEL-LABEL: name: store_signed_const_local +; ISEL: body: +; ISEL: %0:gpr64common = COPY $x0 +; ISEL-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 +; ISEL-NEXT: %3:gpr64 = PACDA %2, killed %1 +; ISEL-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +define void @store_signed_const_got(ptr %dest) { +; ISEL-ELF-LABEL: name: store_signed_const_got +; ISEL-ELF: body: +; ISEL-ELF: %0:gpr64common = COPY $x0 +; ISEL-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv +; ISEL-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 +; ISEL-ELF-NEXT: %4:gpr64 = PACDA %3, killed %1 +; ISEL-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-ELF-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +define void @store_signed_arg(ptr %dest, ptr %p) { +; ISEL-LABEL: name: store_signed_arg +; ISEL: body: +; ISEL: %1:gpr64common = COPY $x1 +; ISEL-NEXT: %0:gpr64common = COPY $x0 +; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-NEXT: %3:gpr64common = ADDXri %1, 8, 0 +; Check that no implicit defs are added to PACDA instruction. +; ISEL-NEXT: %4:gpr64 = PACDA %3, killed %2{{$}} +; ISEL-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-NEXT: RET_ReallyLR + %dest.i = ptrtoint ptr %dest to i64 + %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) + %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1 + %p.offset.i = ptrtoint ptr %p.offset to i64 + %signed.i = call i64 @llvm.ptrauth.sign(i64 %p.offset.i, i32 2, i64 %discr) + %signed.ptr = inttoptr i64 %signed.i to ptr + store ptr %signed.ptr, ptr %dest + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} + ;--- ok.ll ; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \ >From bdf2bc1d2a6b295fbb713e2ecbb500a01b3127f4 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Mon, 10 Mar 2025 15:14:55 +0300 Subject: [PATCH 2/7] [AArch64][PAC] Combine signing with address materialization In pauthtest ABI, it is common to store a pointer signed with address diversity to a heap-allocated object (namely, storing a signed pointer to VTable as part of new object construction). This patch tries to prevent introducing a signing oracle by combining pointer materialization and its (re)signing into a single pseudo instruction which is not expanded until AsmPrinter, if possible. One of the typical patterns is materializing an unsigned pointer with `MOVaddr` pseudo and then signing it with `PAC[ID][AB]` instruction, which can be moved far away from `MOVaddr` by one of the passes in the machine pipeline. As the storage address is not a `Constant` value, one cannot simply emit a `ptrauth` constant in the frontend, which would be selected into `MOVaddrPAC` pseudo. Another pattern is fetching a pointer to VTable from a signed GOT entry using `LOADgotAUTH` pseudo, authenticating and checking it, and then re-signing after adding an offset. This commit adds an instruction insertion hook for `PAC[ID][AB]` which detects the above patterns and replaces it either with `MOVaddrPAC` or `LOADgotPAC` instruction. --- .../Target/AArch64/AArch64ISelLowering.cpp | 82 +++++++++++++++++++ llvm/lib/Target/AArch64/AArch64ISelLowering.h | 2 + llvm/lib/Target/AArch64/AArch64InstrInfo.h | 33 ++++++++ llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 + .../GlobalISel/ptrauth-constant-in-code.ll | 8 +- .../AArch64/ptrauth-constant-in-code.ll | 8 +- 6 files changed, 131 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 581f152776026..cd39dbab3207e 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3058,6 +3058,78 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI, MI.getOperand(0).getReg()) .addReg(AArch64::XZR); BB->remove_instr(&MI); + + return BB; +} + +MachineBasicBlock * +AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); + const DebugLoc &DL = MI.getDebugLoc(); + + MachineInstr *AddrInstr = nullptr; + int64_t Offset = 0; + // Try to find the address-setting instruction, accumulating the offset + // along the way. If any unknown pattern is found, keep everything as-is. + MachineOperand *CurOp = &MI.getOperand(1); + while (CurOp) { + MachineOperand *Def = MRI.getOneDef(CurOp->getReg()); + if (!Def) + return BB; + MachineInstr *DefMI = Def->getParent(); + assert(DefMI != nullptr); + + switch (DefMI->getOpcode()) { + case AArch64::COPY: + CurOp = &DefMI->getOperand(1); + break; + case AArch64::ADDXri: + if (DefMI->getOperand(3).getImm() != 0) // shifts are not handled + return BB; + CurOp = &DefMI->getOperand(1); + Offset += DefMI->getOperand(2).getImm(); + break; + case AArch64::MOVaddr: + case AArch64::LOADgotAUTH: + AddrInstr = DefMI; + CurOp = nullptr; + break; + default: + return BB; + } + } + + unsigned NewOpcode = AddrInstr->getOpcode() == AArch64::LOADgotAUTH + ? AArch64::LOADgotPAC + : AArch64::MOVaddrPAC; + MachineOperand &AddrOp = AddrInstr->getOperand(1); + unsigned TargetFlags = AddrOp.getTargetFlags() & ~AArch64II::MO_PAGE; + Offset += AddrOp.getOffset(); + + // MOVaddrPAC and LOADgotPAC pseudos are expanded so that they use X16/X17 + // internally, thus their restrictions on the register class of $AddrDisc + // operand are stricter than those of real PAC* instructions. + // If the original instruction accepts a discriminator operand, make sure + // it is moved out of X16/X17. + Register DiscReg = AArch64::XZR; + if (!isPACWithZeroDisc(MI.getOpcode())) { + DiscReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass); + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), DiscReg) + .addReg(MI.getOperand(2).getReg()); + } + + BuildMI(*BB, MI, DL, TII->get(NewOpcode)) + .addGlobalAddress(AddrOp.getGlobal(), Offset, TargetFlags) + .addImm(getKeyForPACOpcode(MI.getOpcode())) + .addReg(DiscReg) + .addImm(0); + + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg()) + .addReg(AArch64::X16); + + MI.removeFromParent(); return BB; } @@ -3159,6 +3231,16 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter( return EmitZTInstr(MI, BB, AArch64::ZERO_T, /*Op0IsDef=*/true); case AArch64::MOVT_TIZ_PSEUDO: return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true); + + case AArch64::PACDA: + case AArch64::PACDB: + case AArch64::PACIA: + case AArch64::PACIB: + case AArch64::PACDZA: + case AArch64::PACDZB: + case AArch64::PACIZA: + case AArch64::PACIZB: + return tryRewritingPAC(MI, BB); } } diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index e0b6c1b8c0baf..f7cad2879affd 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -181,6 +181,8 @@ class AArch64TargetLowering : public TargetLowering { MachineBasicBlock *BB) const; MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI, MachineBasicBlock *BB) const; + MachineBasicBlock *tryRewritingPAC(MachineInstr &MI, + MachineBasicBlock *BB) const; MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr &MI, diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h index 7c255da333e4b..3858d8ee67dea 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h @@ -790,6 +790,39 @@ static inline unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero) { llvm_unreachable("Unhandled AArch64PACKey::ID enum"); } +static inline AArch64PACKey::ID getKeyForPACOpcode(unsigned Opcode) { + switch (Opcode) { + case AArch64::PACDA: + case AArch64::PACDZA: + return AArch64PACKey::DA; + case AArch64::PACDB: + case AArch64::PACDZB: + return AArch64PACKey::DB; + case AArch64::PACIA: + case AArch64::PACIZA: + return AArch64PACKey::IA; + case AArch64::PACIB: + case AArch64::PACIZB: + return AArch64PACKey::IB; + } + llvm_unreachable("Unhandled PAC opcode"); +} + +static inline bool isPACWithZeroDisc(unsigned Opcode) { + switch (Opcode) { + case AArch64::PACDA: + case AArch64::PACDB: + case AArch64::PACIA: + case AArch64::PACIB: + return false; + case AArch64::PACDZA: + case AArch64::PACDZB: + case AArch64::PACIZA: + case AArch64::PACIZB: + return true; + } + llvm_unreachable("Unhandled PAC opcode"); +} // struct TSFlags { #define TSFLAG_ELEMENT_SIZE_TYPE(X) (X) // 3-bits #define TSFLAG_DESTRUCTIVE_INST_TYPE(X) ((X) << 3) // 4-bits diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 400ffff5d567f..8e8569ffba846 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2018,7 +2018,9 @@ let Predicates = [HasPAuth] in { def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>; } + let usesCustomInserter = true in defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>; + defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; def XPACI : ClearAuth<0, "xpaci">; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll index b7c52fc72c418..4ef5cc7981924 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll @@ -96,7 +96,9 @@ define void @store_signed_const_local(ptr %dest) { ; ISEL: %0:gpr64common = COPY $x0 ; ISEL-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 ; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-NEXT: %4:gpr64 = PACDA %10, %2 +; ISEL-NEXT: %15:gpr64noip = COPY %2 +; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17 +; ISEL-NEXT: %4:gpr64 = COPY $x16 ; ISEL-NEXT: %14:gpr64 = COPY %4 ; ISEL-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest) ; ISEL-NEXT: RET_ReallyLR @@ -115,7 +117,9 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got ; ISEL-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 ; ISEL-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-ELF-NEXT: %4:gpr64 = PACDA %6, %2 +; ISEL-ELF-NEXT: %12:gpr64noip = COPY %2 +; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16 ; ISEL-ELF-NEXT: %10:gpr64 = COPY %4 ; ISEL-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) ; ISEL-ELF-NEXT: RET_ReallyLR diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll index 182e8f3d016e9..e59f7925b7e02 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll @@ -85,7 +85,9 @@ define void @store_signed_const_local(ptr %dest) { ; ISEL: %0:gpr64common = COPY $x0 ; ISEL-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 ; ISEL-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 -; ISEL-NEXT: %3:gpr64 = PACDA %2, killed %1 +; ISEL-NEXT: %4:gpr64noip = COPY %1 +; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17 +; ISEL-NEXT: %3:gpr64 = COPY $x16 ; ISEL-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest) ; ISEL-NEXT: RET_ReallyLR %dest.i = ptrtoint ptr %dest to i64 @@ -103,7 +105,9 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 ; ISEL-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv ; ISEL-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 -; ISEL-ELF-NEXT: %4:gpr64 = PACDA %3, killed %1 +; ISEL-ELF-NEXT: %5:gpr64noip = COPY %1 +; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16 ; ISEL-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) ; ISEL-ELF-NEXT: RET_ReallyLR %dest.i = ptrtoint ptr %dest to i64 >From d17dd7dc2b6441ff3949716d744ae0b293a05d1e Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Thu, 27 Mar 2025 16:45:34 +0300 Subject: [PATCH 3/7] Test generated asm, remove dead LOADgotAUTH --- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 + .../GlobalISel/ptrauth-constant-in-code.ll | 117 ++++++++++++------ .../AArch64/ptrauth-constant-in-code.ll | 109 +++++++++++----- .../CodeGen/AArch64/ptrauth-tiny-model-pic.ll | 4 +- .../AArch64/ptrauth-tiny-model-static.ll | 4 +- 5 files changed, 165 insertions(+), 71 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 8e8569ffba846..ba94a3de68bb1 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2168,6 +2168,8 @@ let Predicates = [HasPAuth] in { def LOADgotAUTH : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), []>, Sched<[WriteI, ReadI]> { + // Make it possible to eliminate dead instruction after folding it into LOADgotPAC. + let hasSideEffects = 0; let Defs = [X16,X17,NZCV]; let Size = 44; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll index 4ef5cc7981924..a92179a3f3fe8 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll @@ -82,26 +82,45 @@ define ptr @foo() { ; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \ ; RUN: -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \ -; RUN: FileCheck --check-prefixes=ISEL,ISEL-ELF %s +; RUN: FileCheck --check-prefixes=ISEL-MIR,ISEL-MIR-ELF %s ; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \ ; RUN: -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \ -; RUN: FileCheck --check-prefixes=ISEL %s +; RUN: FileCheck --check-prefixes=ISEL-MIR %s +; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \ +; RUN: -verify-machineinstrs -global-isel-abort=1 -asm-verbose=0 | \ +; RUN: FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-ELF %s +; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \ +; RUN: -verify-machineinstrs -global-isel-abort=1 -asm-verbose=0 | \ +; RUN: FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-MACHO %s @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] define void @store_signed_const_local(ptr %dest) { -; ISEL-LABEL: name: store_signed_const_local -; ISEL: body: -; ISEL: %0:gpr64common = COPY $x0 -; ISEL-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 -; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-NEXT: %15:gpr64noip = COPY %2 -; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17 -; ISEL-NEXT: %4:gpr64 = COPY $x16 -; ISEL-NEXT: %14:gpr64 = COPY %4 -; ISEL-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest) -; ISEL-NEXT: RET_ReallyLR +; ISEL-MIR-LABEL: name: store_signed_const_local +; ISEL-MIR: body: +; ISEL-MIR: %0:gpr64common = COPY $x0 +; ISEL-MIR-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 +; ISEL-MIR-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %15:gpr64noip = COPY %2 +; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17 +; ISEL-MIR-NEXT: %4:gpr64 = COPY $x16 +; ISEL-MIR-NEXT: %14:gpr64 = COPY %4 +; ISEL-MIR-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-MIR-NEXT: RET_ReallyLR +; +; ISEL-ASM-LABEL: store_signed_const_local: +; ISEL-ASM-NEXT: .cfi_startproc +; ISEL-ASM-NEXT: mov x8, x0 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: adrp x16, const_table_local +; ISEL-ASM-ELF-NEXT: add x16, x16, :lo12:const_table_local +; ISEL-ASM-MACHO-NEXT: adrp x16, _const_table_local@PAGE +; ISEL-ASM-MACHO-NEXT: add x16, x16, _const_table_local@PAGEOFF +; ISEL-ASM-NEXT: add x16, x16, #8 +; ISEL-ASM-NEXT: pacda x16, x8 +; ISEL-ASM-NEXT: str x16, [x0] +; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr) @@ -111,18 +130,37 @@ define void @store_signed_const_local(ptr %dest) { } define void @store_signed_const_got(ptr %dest) { -; ISEL-ELF-LABEL: name: store_signed_const_got -; ISEL-ELF: body: -; ISEL-ELF: %0:gpr64common = COPY $x0 -; ISEL-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got -; ISEL-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 -; ISEL-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-ELF-NEXT: %12:gpr64noip = COPY %2 -; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv -; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16 -; ISEL-ELF-NEXT: %10:gpr64 = COPY %4 -; ISEL-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) -; ISEL-ELF-NEXT: RET_ReallyLR +; ISEL-MIR-ELF-LABEL: name: store_signed_const_got +; ISEL-MIR-ELF: body: +; ISEL-MIR-ELF: %0:gpr64common = COPY $x0 +; ISEL-MIR-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got +; ISEL-MIR-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 +; ISEL-MIR-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-ELF-NEXT: %12:gpr64noip = COPY %2 +; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-MIR-ELF-NEXT: %4:gpr64 = COPY $x16 +; ISEL-MIR-ELF-NEXT: %10:gpr64 = COPY %4 +; ISEL-MIR-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-MIR-ELF-NEXT: RET_ReallyLR +; +; ISEL-ASM-ELF-LABEL: store_signed_const_got: +; ISEL-ASM-ELF-NEXT: .cfi_startproc +; ISEL-ASM-ELF-NEXT: mov x8, x0 +; ISEL-ASM-ELF-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: adrp x17, :got_auth:const_table_got +; ISEL-ASM-ELF-NEXT: add x17, x17, :got_auth_lo12:const_table_got +; ISEL-ASM-ELF-NEXT: ldr x16, [x17] +; ISEL-ASM-ELF-NEXT: autda x16, x17 +; ISEL-ASM-ELF-NEXT: mov x17, x16 +; ISEL-ASM-ELF-NEXT: xpacd x17 +; ISEL-ASM-ELF-NEXT: cmp x16, x17 +; ISEL-ASM-ELF-NEXT: b.eq .Lauth_success_0 +; ISEL-ASM-ELF-NEXT: brk #0xc472 +; ISEL-ASM-ELF-NEXT: .Lauth_success_0: +; ISEL-ASM-ELF-NEXT: add x16, x16, #8 +; ISEL-ASM-ELF-NEXT: pacda x16, x8 +; ISEL-ASM-ELF-NEXT: str x16, [x0] +; ISEL-ASM-ELF-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr) @@ -132,17 +170,26 @@ define void @store_signed_const_got(ptr %dest) { } define void @store_signed_arg(ptr %dest, ptr %p) { -; ISEL-LABEL: name: store_signed_arg -; ISEL: body: -; ISEL: %0:gpr64common = COPY $x0 -; ISEL-NEXT: %1:gpr64common = COPY $x1 -; ISEL-NEXT: %3:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-NEXT: %6:gpr64common = ADDXri %1, 8, 0 +; ISEL-MIR-LABEL: name: store_signed_arg +; ISEL-MIR: body: +; ISEL-MIR: %0:gpr64common = COPY $x0 +; ISEL-MIR-NEXT: %1:gpr64common = COPY $x1 +; ISEL-MIR-NEXT: %3:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %6:gpr64common = ADDXri %1, 8, 0 ; Check that no implicit defs are added to PACDA instruction. -; ISEL-NEXT: %8:gpr64 = PACDA %6, %3{{$}} -; ISEL-NEXT: %10:gpr64 = COPY %8 -; ISEL-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) -; ISEL-NEXT: RET_ReallyLR +; ISEL-MIR-NEXT: %8:gpr64 = PACDA %6, %3{{$}} +; ISEL-MIR-NEXT: %10:gpr64 = COPY %8 +; ISEL-MIR-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) +; ISEL-MIR-NEXT: RET_ReallyLR +; +; ISEL-ASM-LABEL: store_signed_arg: +; ISEL-ASM-NEXT: .cfi_startproc +; ISEL-ASM-NEXT: mov x8, x0 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-NEXT: add x9, x1, #8 +; ISEL-ASM-NEXT: pacda x9, x8 +; ISEL-ASM-NEXT: str x9, [x0] +; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1 diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll index e59f7925b7e02..64ddd9f262233 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll @@ -72,24 +72,41 @@ define ptr @foo() { ;--- finalize-isel.ll ; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \ -; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL,ISEL-ELF %s +; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL-MIR,ISEL-MIR-ELF %s ; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \ -; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL %s +; RUN: -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL-MIR %s +; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \ +; RUN: -verify-machineinstrs -asm-verbose=0 | FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-ELF %s +; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \ +; RUN: -verify-machineinstrs -asm-verbose=0 | FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-MACHO %s @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] define void @store_signed_const_local(ptr %dest) { -; ISEL-LABEL: name: store_signed_const_local -; ISEL: body: -; ISEL: %0:gpr64common = COPY $x0 -; ISEL-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 -; ISEL-NEXT: %4:gpr64noip = COPY %1 -; ISEL-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17 -; ISEL-NEXT: %3:gpr64 = COPY $x16 -; ISEL-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest) -; ISEL-NEXT: RET_ReallyLR +; ISEL-MIR-LABEL: name: store_signed_const_local +; ISEL-MIR: body: +; ISEL-MIR: %0:gpr64common = COPY $x0 +; ISEL-MIR-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 +; ISEL-MIR-NEXT: %4:gpr64noip = COPY %1 +; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17 +; ISEL-MIR-NEXT: %3:gpr64 = COPY $x16 +; ISEL-MIR-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-MIR-NEXT: RET_ReallyLR +; +; ISEL-ASM-LABEL: store_signed_const_local: +; ISEL-ASM-NEXT: .cfi_startproc +; ISEL-ASM-NEXT: mov x8, x0 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: adrp x16, const_table_local +; ISEL-ASM-ELF-NEXT: add x16, x16, :lo12:const_table_local +; ISEL-ASM-MACHO-NEXT: adrp x16, _const_table_local@PAGE +; ISEL-ASM-MACHO-NEXT: add x16, x16, _const_table_local@PAGEOFF +; ISEL-ASM-NEXT: add x16, x16, #8 +; ISEL-ASM-NEXT: pacda x16, x8 +; ISEL-ASM-NEXT: str x16, [x0] +; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr) @@ -99,17 +116,36 @@ define void @store_signed_const_local(ptr %dest) { } define void @store_signed_const_got(ptr %dest) { -; ISEL-ELF-LABEL: name: store_signed_const_got -; ISEL-ELF: body: -; ISEL-ELF: %0:gpr64common = COPY $x0 -; ISEL-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv -; ISEL-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 -; ISEL-ELF-NEXT: %5:gpr64noip = COPY %1 -; ISEL-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv -; ISEL-ELF-NEXT: %4:gpr64 = COPY $x16 -; ISEL-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) -; ISEL-ELF-NEXT: RET_ReallyLR +; ISEL-MIR-ELF-LABEL: name: store_signed_const_got +; ISEL-MIR-ELF: body: +; ISEL-MIR-ELF: %0:gpr64common = COPY $x0 +; ISEL-MIR-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv +; ISEL-MIR-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 +; ISEL-MIR-ELF-NEXT: %5:gpr64noip = COPY %1 +; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-MIR-ELF-NEXT: %4:gpr64 = COPY $x16 +; ISEL-MIR-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-MIR-ELF-NEXT: RET_ReallyLR +; +; ISEL-ASM-ELF-LABEL: store_signed_const_got: +; ISEL-ASM-ELF-NEXT: .cfi_startproc +; ISEL-ASM-ELF-NEXT: mov x8, x0 +; ISEL-ASM-ELF-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: adrp x17, :got_auth:const_table_got +; ISEL-ASM-ELF-NEXT: add x17, x17, :got_auth_lo12:const_table_got +; ISEL-ASM-ELF-NEXT: ldr x16, [x17] +; ISEL-ASM-ELF-NEXT: autda x16, x17 +; ISEL-ASM-ELF-NEXT: mov x17, x16 +; ISEL-ASM-ELF-NEXT: xpacd x17 +; ISEL-ASM-ELF-NEXT: cmp x16, x17 +; ISEL-ASM-ELF-NEXT: b.eq .Lauth_success_0 +; ISEL-ASM-ELF-NEXT: brk #0xc472 +; ISEL-ASM-ELF-NEXT: .Lauth_success_0: +; ISEL-ASM-ELF-NEXT: add x16, x16, #8 +; ISEL-ASM-ELF-NEXT: pacda x16, x8 +; ISEL-ASM-ELF-NEXT: str x16, [x0] +; ISEL-ASM-ELF-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr) @@ -119,16 +155,25 @@ define void @store_signed_const_got(ptr %dest) { } define void @store_signed_arg(ptr %dest, ptr %p) { -; ISEL-LABEL: name: store_signed_arg -; ISEL: body: -; ISEL: %1:gpr64common = COPY $x1 -; ISEL-NEXT: %0:gpr64common = COPY $x0 -; ISEL-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 -; ISEL-NEXT: %3:gpr64common = ADDXri %1, 8, 0 +; ISEL-MIR-LABEL: name: store_signed_arg +; ISEL-MIR: body: +; ISEL-MIR: %1:gpr64common = COPY $x1 +; ISEL-MIR-NEXT: %0:gpr64common = COPY $x0 +; ISEL-MIR-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %3:gpr64common = ADDXri %1, 8, 0 ; Check that no implicit defs are added to PACDA instruction. -; ISEL-NEXT: %4:gpr64 = PACDA %3, killed %2{{$}} -; ISEL-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) -; ISEL-NEXT: RET_ReallyLR +; ISEL-MIR-NEXT: %4:gpr64 = PACDA %3, killed %2{{$}} +; ISEL-MIR-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) +; ISEL-MIR-NEXT: RET_ReallyLR +; +; ISEL-ASM-LABEL: store_signed_arg: +; ISEL-ASM-NEXT: .cfi_startproc +; ISEL-ASM-NEXT: mov x8, x0 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 +; ISEL-ASM-NEXT: add x9, x1, #8 +; ISEL-ASM-NEXT: pacda x9, x8 +; ISEL-ASM-NEXT: str x9, [x0] +; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234) %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1 diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll index 9d13714bbefe3..cb8f1f4021eea 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll @@ -34,7 +34,6 @@ define dso_preemptable void @foo1() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_0: ; TRAP-NEXT: mov x8, x16 -; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: adr x17, :got_auth:dst ; NOTRAP-NEXT: ldr x9, [x17] ; NOTRAP-NEXT: autda x9, x17 @@ -47,6 +46,7 @@ define dso_preemptable void @foo1() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_1: ; TRAP-NEXT: mov x9, x16 +; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: strb w8, [x9] ; CHECK-NEXT: ret @@ -106,7 +106,6 @@ define dso_preemptable void @foo3() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_4: ; TRAP-NEXT: mov x8, x16 -; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: adr x17, :got_auth:ptr ; NOTRAP-NEXT: ldr x9, [x17] ; NOTRAP-NEXT: autda x9, x17 @@ -119,6 +118,7 @@ define dso_preemptable void @foo3() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_5: ; TRAP-NEXT: mov x9, x16 +; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: ldr x9, [x9] ; CHECK-NEXT: strb w8, [x9] ; CHECK-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll index 2d098b70acccc..0bf54ab49381e 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll @@ -34,7 +34,6 @@ define dso_local void @foo1() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_0: ; TRAP-NEXT: mov x8, x16 -; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: adr x17, :got_auth:dst ; NOTRAP-NEXT: ldr x9, [x17] ; NOTRAP-NEXT: autda x9, x17 @@ -47,6 +46,7 @@ define dso_local void @foo1() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_1: ; TRAP-NEXT: mov x9, x16 +; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: strb w8, [x9] ; CHECK-NEXT: ret @@ -106,7 +106,6 @@ define dso_local void @foo3() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_4: ; TRAP-NEXT: mov x8, x16 -; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: adr x17, :got_auth:ptr ; NOTRAP-NEXT: ldr x9, [x17] ; NOTRAP-NEXT: autda x9, x17 @@ -119,6 +118,7 @@ define dso_local void @foo3() { ; TRAP-NEXT: brk #0xc472 ; TRAP-NEXT: .Lauth_success_5: ; TRAP-NEXT: mov x9, x16 +; CHECK-NEXT: ldrb w8, [x8] ; CHECK-NEXT: ldr x9, [x9] ; CHECK-NEXT: strb w8, [x9] ; CHECK-NEXT: ret >From 936ded1bf8b3cd4f008b0e7ffe4ed7da1179c9f7 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Wed, 21 May 2025 21:52:51 +0300 Subject: [PATCH 4/7] Fix tests after rebase --- .../AArch64/GlobalISel/ptrauth-constant-in-code.ll | 8 ++++---- llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll index a92179a3f3fe8..ca637224014ad 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll @@ -101,7 +101,7 @@ define void @store_signed_const_local(ptr %dest) { ; ISEL-MIR: body: ; ISEL-MIR: %0:gpr64common = COPY $x0 ; ISEL-MIR-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 -; ISEL-MIR-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %2:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-NEXT: %15:gpr64noip = COPY %2 ; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17 ; ISEL-MIR-NEXT: %4:gpr64 = COPY $x16 @@ -135,7 +135,7 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-MIR-ELF: %0:gpr64common = COPY $x0 ; ISEL-MIR-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got ; ISEL-MIR-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 -; ISEL-MIR-ELF-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-ELF-NEXT: %2:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-ELF-NEXT: %12:gpr64noip = COPY %2 ; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv ; ISEL-MIR-ELF-NEXT: %4:gpr64 = COPY $x16 @@ -174,7 +174,7 @@ define void @store_signed_arg(ptr %dest, ptr %p) { ; ISEL-MIR: body: ; ISEL-MIR: %0:gpr64common = COPY $x0 ; ISEL-MIR-NEXT: %1:gpr64common = COPY $x1 -; ISEL-MIR-NEXT: %3:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %3:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-NEXT: %6:gpr64common = ADDXri %1, 8, 0 ; Check that no implicit defs are added to PACDA instruction. ; ISEL-MIR-NEXT: %8:gpr64 = PACDA %6, %3{{$}} @@ -185,8 +185,8 @@ define void @store_signed_arg(ptr %dest, ptr %p) { ; ISEL-ASM-LABEL: store_signed_arg: ; ISEL-ASM-NEXT: .cfi_startproc ; ISEL-ASM-NEXT: mov x8, x0 -; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-NEXT: add x9, x1, #8 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-NEXT: pacda x9, x8 ; ISEL-ASM-NEXT: str x9, [x0] ; ISEL-ASM-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll index 64ddd9f262233..cfded6aa53b4b 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll @@ -87,7 +87,7 @@ define void @store_signed_const_local(ptr %dest) { ; ISEL-MIR-LABEL: name: store_signed_const_local ; ISEL-MIR: body: ; ISEL-MIR: %0:gpr64common = COPY $x0 -; ISEL-MIR-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %1:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 ; ISEL-MIR-NEXT: %4:gpr64noip = COPY %1 ; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17 @@ -119,7 +119,7 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-MIR-ELF-LABEL: name: store_signed_const_got ; ISEL-MIR-ELF: body: ; ISEL-MIR-ELF: %0:gpr64common = COPY $x0 -; ISEL-MIR-ELF-NEXT: %1:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-ELF-NEXT: %1:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv ; ISEL-MIR-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 ; ISEL-MIR-ELF-NEXT: %5:gpr64noip = COPY %1 @@ -159,7 +159,7 @@ define void @store_signed_arg(ptr %dest, ptr %p) { ; ISEL-MIR: body: ; ISEL-MIR: %1:gpr64common = COPY $x1 ; ISEL-MIR-NEXT: %0:gpr64common = COPY $x0 -; ISEL-MIR-NEXT: %2:gpr64common = PAUTH_BLEND %0, 1234 +; ISEL-MIR-NEXT: %2:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-NEXT: %3:gpr64common = ADDXri %1, 8, 0 ; Check that no implicit defs are added to PACDA instruction. ; ISEL-MIR-NEXT: %4:gpr64 = PACDA %3, killed %2{{$}} @@ -169,8 +169,8 @@ define void @store_signed_arg(ptr %dest, ptr %p) { ; ISEL-ASM-LABEL: store_signed_arg: ; ISEL-ASM-NEXT: .cfi_startproc ; ISEL-ASM-NEXT: mov x8, x0 -; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-NEXT: add x9, x1, #8 +; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-NEXT: pacda x9, x8 ; ISEL-ASM-NEXT: str x9, [x0] ; ISEL-ASM-NEXT: ret >From 5e3a6e4ccad4594212217235da63e9ee2ccc5e33 Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Wed, 21 May 2025 22:31:55 +0300 Subject: [PATCH 5/7] Prevent immediate modifier substitution --- .../Target/AArch64/AArch64ISelLowering.cpp | 108 ++++++++++-------- .../GlobalISel/ptrauth-constant-in-code.ll | 25 ++-- .../AArch64/ptrauth-constant-in-code.ll | 25 ++-- 3 files changed, 93 insertions(+), 65 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index cd39dbab3207e..f58fc22e39264 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3069,62 +3069,80 @@ AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); const DebugLoc &DL = MI.getDebugLoc(); - MachineInstr *AddrInstr = nullptr; - int64_t Offset = 0; - // Try to find the address-setting instruction, accumulating the offset - // along the way. If any unknown pattern is found, keep everything as-is. - MachineOperand *CurOp = &MI.getOperand(1); - while (CurOp) { - MachineOperand *Def = MRI.getOneDef(CurOp->getReg()); - if (!Def) - return BB; - MachineInstr *DefMI = Def->getParent(); - assert(DefMI != nullptr); - - switch (DefMI->getOpcode()) { - case AArch64::COPY: - CurOp = &DefMI->getOperand(1); - break; - case AArch64::ADDXri: - if (DefMI->getOperand(3).getImm() != 0) // shifts are not handled - return BB; - CurOp = &DefMI->getOperand(1); - Offset += DefMI->getOperand(2).getImm(); - break; - case AArch64::MOVaddr: - case AArch64::LOADgotAUTH: - AddrInstr = DefMI; - CurOp = nullptr; - break; - default: - return BB; + // Find the unique register definition, skipping copies. + auto GetUniqueDef = [&MRI](Register Reg) { + for (;;) { + MachineInstr *Def = MRI.getUniqueVRegDef(Reg); + if (!Def || Def->getOpcode() != AArch64::COPY) + return Def; + + Reg = Def->getOperand(1).getReg(); } - } + }; + // Find the unique register definition, skipping copies and increments. + auto GetUniqueDefPlusOffset = + [GetUniqueDef](Register Reg, int64_t &Offset) -> MachineInstr * { + for (;;) { + MachineInstr *Def = GetUniqueDef(Reg); + if (!Def || Def->getOpcode() != AArch64::ADDXri) + return Def; + + if (Def->getOperand(3).getImm() != 0) + return nullptr; // shifted immediates are not handled + Reg = Def->getOperand(1).getReg(); + Offset += Def->getOperand(2).getImm(); + } + }; + + // Try to find a known address-setting instruction, accumulating the offset + // along the way. If no known pattern is found, keep everything as-is. + + int64_t AddrOffset = 0; + MachineInstr *AddrDefInstr = + GetUniqueDefPlusOffset(MI.getOperand(1).getReg(), AddrOffset); + if (!AddrDefInstr) + return BB; - unsigned NewOpcode = AddrInstr->getOpcode() == AArch64::LOADgotAUTH - ? AArch64::LOADgotPAC - : AArch64::MOVaddrPAC; - MachineOperand &AddrOp = AddrInstr->getOperand(1); + unsigned NewOpcode; + if (AddrDefInstr->getOpcode() == AArch64::LOADgotAUTH) + NewOpcode = AArch64::LOADgotPAC; + else if (AddrDefInstr->getOpcode() == AArch64::MOVaddr) + NewOpcode = AArch64::MOVaddrPAC; + else + return BB; // Unknown opcode. + + MachineOperand &AddrOp = AddrDefInstr->getOperand(1); unsigned TargetFlags = AddrOp.getTargetFlags() & ~AArch64II::MO_PAGE; - Offset += AddrOp.getOffset(); + const GlobalValue *GV = AddrOp.getGlobal(); + AddrOffset += AddrOp.getOffset(); + + // Detect discriminator blend computation, if any. + Register RegDisc = isPACWithZeroDisc(MI.getOpcode()) + ? AArch64::XZR + : MI.getOperand(2).getReg(); + unsigned IntDisc = 0; + MachineInstr *MaybeBlendDef = + RegDisc == AArch64::XZR ? nullptr : GetUniqueDef(RegDisc); + if (MaybeBlendDef && MaybeBlendDef->getOpcode() == AArch64::MOVKXi && + MaybeBlendDef->getOperand(3).getImm() == 48) { + RegDisc = MaybeBlendDef->getOperand(1).getReg(); + IntDisc = MaybeBlendDef->getOperand(2).getImm(); + } // MOVaddrPAC and LOADgotPAC pseudos are expanded so that they use X16/X17 // internally, thus their restrictions on the register class of $AddrDisc // operand are stricter than those of real PAC* instructions. - // If the original instruction accepts a discriminator operand, make sure - // it is moved out of X16/X17. - Register DiscReg = AArch64::XZR; - if (!isPACWithZeroDisc(MI.getOpcode())) { - DiscReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass); - BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), DiscReg) - .addReg(MI.getOperand(2).getReg()); + if (RegDisc != AArch64::XZR) { + Register TmpReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass); + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(RegDisc); + RegDisc = TmpReg; } BuildMI(*BB, MI, DL, TII->get(NewOpcode)) - .addGlobalAddress(AddrOp.getGlobal(), Offset, TargetFlags) + .addGlobalAddress(GV, AddrOffset, TargetFlags) .addImm(getKeyForPACOpcode(MI.getOpcode())) - .addReg(DiscReg) - .addImm(0); + .addReg(RegDisc) + .addImm(IntDisc); BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg()) .addReg(AArch64::X16); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll index ca637224014ad..2640ed7400722 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll @@ -96,14 +96,19 @@ define ptr @foo() { @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] +; Test that after post-processing in finalize-isel, MOVaddrPAC (or LOADgotPAC, +; respectively) has both $AddrDisc and $Disc operands set. MOVaddr (or LOADgotAUTH, +; respectively) and MOVKXi are not used anymore and are dead-code-eliminated +; by the later passes. + define void @store_signed_const_local(ptr %dest) { ; ISEL-MIR-LABEL: name: store_signed_const_local ; ISEL-MIR: body: ; ISEL-MIR: %0:gpr64common = COPY $x0 ; ISEL-MIR-NEXT: %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 ; ISEL-MIR-NEXT: %2:gpr64common = MOVKXi %0, 1234, 48 -; ISEL-MIR-NEXT: %15:gpr64noip = COPY %2 -; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 0, implicit-def $x16, implicit-def $x17 +; ISEL-MIR-NEXT: %15:gpr64noip = COPY %0 +; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %15, 1234, implicit-def $x16, implicit-def $x17 ; ISEL-MIR-NEXT: %4:gpr64 = COPY $x16 ; ISEL-MIR-NEXT: %14:gpr64 = COPY %4 ; ISEL-MIR-NEXT: STRXui %14, %0, 0 :: (store (p0) into %ir.dest) @@ -111,14 +116,14 @@ define void @store_signed_const_local(ptr %dest) { ; ; ISEL-ASM-LABEL: store_signed_const_local: ; ISEL-ASM-NEXT: .cfi_startproc -; ISEL-ASM-NEXT: mov x8, x0 -; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-ELF-NEXT: adrp x16, const_table_local ; ISEL-ASM-ELF-NEXT: add x16, x16, :lo12:const_table_local ; ISEL-ASM-MACHO-NEXT: adrp x16, _const_table_local@PAGE ; ISEL-ASM-MACHO-NEXT: add x16, x16, _const_table_local@PAGEOFF ; ISEL-ASM-NEXT: add x16, x16, #8 -; ISEL-ASM-NEXT: pacda x16, x8 +; ISEL-ASM-NEXT: mov x17, x0 +; ISEL-ASM-NEXT: movk x17, #1234, lsl #48 +; ISEL-ASM-NEXT: pacda x16, x17 ; ISEL-ASM-NEXT: str x16, [x0] ; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 @@ -136,8 +141,8 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-MIR-ELF-NEXT: %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got ; ISEL-MIR-ELF-NEXT: %6:gpr64common = ADDXri %7, 8, 0 ; ISEL-MIR-ELF-NEXT: %2:gpr64common = MOVKXi %0, 1234, 48 -; ISEL-MIR-ELF-NEXT: %12:gpr64noip = COPY %2 -; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-MIR-ELF-NEXT: %12:gpr64noip = COPY %0 +; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 1234, implicit-def $x16, implicit-def $x17, implicit-def $nzcv ; ISEL-MIR-ELF-NEXT: %4:gpr64 = COPY $x16 ; ISEL-MIR-ELF-NEXT: %10:gpr64 = COPY %4 ; ISEL-MIR-ELF-NEXT: STRXui %10, %0, 0 :: (store (p0) into %ir.dest) @@ -145,8 +150,6 @@ define void @store_signed_const_got(ptr %dest) { ; ; ISEL-ASM-ELF-LABEL: store_signed_const_got: ; ISEL-ASM-ELF-NEXT: .cfi_startproc -; ISEL-ASM-ELF-NEXT: mov x8, x0 -; ISEL-ASM-ELF-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-ELF-NEXT: adrp x17, :got_auth:const_table_got ; ISEL-ASM-ELF-NEXT: add x17, x17, :got_auth_lo12:const_table_got ; ISEL-ASM-ELF-NEXT: ldr x16, [x17] @@ -158,7 +161,9 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-ASM-ELF-NEXT: brk #0xc472 ; ISEL-ASM-ELF-NEXT: .Lauth_success_0: ; ISEL-ASM-ELF-NEXT: add x16, x16, #8 -; ISEL-ASM-ELF-NEXT: pacda x16, x8 +; ISEL-ASM-ELF-NEXT: mov x17, x0 +; ISEL-ASM-ELF-NEXT: movk x17, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: pacda x16, x17 ; ISEL-ASM-ELF-NEXT: str x16, [x0] ; ISEL-ASM-ELF-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll index cfded6aa53b4b..4c61de8ee6d86 100644 --- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll +++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll @@ -83,28 +83,33 @@ define ptr @foo() { @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null] @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null] +; Test that after post-processing in finalize-isel, MOVaddrPAC (or LOADgotPAC, +; respectively) has both $AddrDisc and $Disc operands set. MOVaddr (or LOADgotAUTH, +; respectively) and MOVKXi are not used anymore and are dead-code-eliminated +; by the later passes. + define void @store_signed_const_local(ptr %dest) { ; ISEL-MIR-LABEL: name: store_signed_const_local ; ISEL-MIR: body: ; ISEL-MIR: %0:gpr64common = COPY $x0 ; ISEL-MIR-NEXT: %1:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-NEXT: %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8 -; ISEL-MIR-NEXT: %4:gpr64noip = COPY %1 -; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 0, implicit-def $x16, implicit-def $x17 +; ISEL-MIR-NEXT: %4:gpr64noip = COPY %0 +; ISEL-MIR-NEXT: MOVaddrPAC @const_table_local + 8, 2, %4, 1234, implicit-def $x16, implicit-def $x17 ; ISEL-MIR-NEXT: %3:gpr64 = COPY $x16 ; ISEL-MIR-NEXT: STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest) ; ISEL-MIR-NEXT: RET_ReallyLR ; ; ISEL-ASM-LABEL: store_signed_const_local: ; ISEL-ASM-NEXT: .cfi_startproc -; ISEL-ASM-NEXT: mov x8, x0 -; ISEL-ASM-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-ELF-NEXT: adrp x16, const_table_local ; ISEL-ASM-ELF-NEXT: add x16, x16, :lo12:const_table_local ; ISEL-ASM-MACHO-NEXT: adrp x16, _const_table_local@PAGE ; ISEL-ASM-MACHO-NEXT: add x16, x16, _const_table_local@PAGEOFF ; ISEL-ASM-NEXT: add x16, x16, #8 -; ISEL-ASM-NEXT: pacda x16, x8 +; ISEL-ASM-NEXT: mov x17, x0 +; ISEL-ASM-NEXT: movk x17, #1234, lsl #48 +; ISEL-ASM-NEXT: pacda x16, x17 ; ISEL-ASM-NEXT: str x16, [x0] ; ISEL-ASM-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 @@ -122,16 +127,14 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-MIR-ELF-NEXT: %1:gpr64common = MOVKXi %0, 1234, 48 ; ISEL-MIR-ELF-NEXT: %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv ; ISEL-MIR-ELF-NEXT: %3:gpr64common = ADDXri killed %2, 8, 0 -; ISEL-MIR-ELF-NEXT: %5:gpr64noip = COPY %1 -; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 0, implicit-def $x16, implicit-def $x17, implicit-def $nzcv +; ISEL-MIR-ELF-NEXT: %5:gpr64noip = COPY %0 +; ISEL-MIR-ELF-NEXT: LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 1234, implicit-def $x16, implicit-def $x17, implicit-def $nzcv ; ISEL-MIR-ELF-NEXT: %4:gpr64 = COPY $x16 ; ISEL-MIR-ELF-NEXT: STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest) ; ISEL-MIR-ELF-NEXT: RET_ReallyLR ; ; ISEL-ASM-ELF-LABEL: store_signed_const_got: ; ISEL-ASM-ELF-NEXT: .cfi_startproc -; ISEL-ASM-ELF-NEXT: mov x8, x0 -; ISEL-ASM-ELF-NEXT: movk x8, #1234, lsl #48 ; ISEL-ASM-ELF-NEXT: adrp x17, :got_auth:const_table_got ; ISEL-ASM-ELF-NEXT: add x17, x17, :got_auth_lo12:const_table_got ; ISEL-ASM-ELF-NEXT: ldr x16, [x17] @@ -143,7 +146,9 @@ define void @store_signed_const_got(ptr %dest) { ; ISEL-ASM-ELF-NEXT: brk #0xc472 ; ISEL-ASM-ELF-NEXT: .Lauth_success_0: ; ISEL-ASM-ELF-NEXT: add x16, x16, #8 -; ISEL-ASM-ELF-NEXT: pacda x16, x8 +; ISEL-ASM-ELF-NEXT: mov x17, x0 +; ISEL-ASM-ELF-NEXT: movk x17, #1234, lsl #48 +; ISEL-ASM-ELF-NEXT: pacda x16, x17 ; ISEL-ASM-ELF-NEXT: str x16, [x0] ; ISEL-ASM-ELF-NEXT: ret %dest.i = ptrtoint ptr %dest to i64 >From cc84853393fdc8764e09dc5d108d5db9ed94247a Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Tue, 3 Jun 2025 19:20:05 +0300 Subject: [PATCH 6/7] Refactor --- .../Target/AArch64/AArch64ISelLowering.cpp | 102 ++++++++++-------- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 1 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 3 +- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index f58fc22e39264..a3f10e9d6b825 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3062,6 +3062,54 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI, return BB; } +// Helper function to find the instruction that defined a virtual register, +// stripping and accumulating optional offset. +// If unable to find such instruction, returns nullptr (Offset is unspecified). +static MachineInstr *stripAndAccumulateOffset(const MachineRegisterInfo &MRI, + Register Reg, int64_t &Offset) { + Offset = 0; + while (Reg.isVirtual()) { + MachineInstr *DefMI = MRI.getVRegDef(Reg); + assert(DefMI && "Virtual register definition not found"); + unsigned Opcode = DefMI->getOpcode(); + + if (Opcode == AArch64::COPY) { + Reg = DefMI->getOperand(1).getReg(); + continue; + } + + // If this is neither a copy, nor inc/dec instruction, we are done. + if (Opcode != AArch64::ADDXri && Opcode != AArch64::SUBXri) + return DefMI; + // Inc/dec with shifted immediates are not handled. + if (DefMI->getOperand(3).getImm() != 0) + return DefMI; + + int64_t Imm = DefMI->getOperand(2).getImm(); + Offset += (Opcode == AArch64::ADDXri) ? Imm : -Imm; + + Reg = DefMI->getOperand(1).getReg(); + } + return nullptr; +} + +static std::pair<Register, unsigned> +detectBlendComponents(const MachineRegisterInfo &MRI, Register Reg) { + int64_t Offset = 0; + MachineInstr *MaybeBlend = stripAndAccumulateOffset(MRI, Reg, Offset); + // This should be a plain copy, without adding any offset. + if (!MaybeBlend || Offset != 0) + return std::make_pair(Reg, 0); + + // Detect blend(addr, imm) which is lowered as MOVK addr, #imm, 48. + if (MaybeBlend->getOpcode() != AArch64::MOVKXi || + MaybeBlend->getOperand(3).getImm() != 48) + return std::make_pair(Reg, 0); + + return std::make_pair(MaybeBlend->getOperand(1).getReg(), + MaybeBlend->getOperand(2).getImm()); +} + MachineBasicBlock * AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, MachineBasicBlock *BB) const { @@ -3069,37 +3117,12 @@ AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); const DebugLoc &DL = MI.getDebugLoc(); - // Find the unique register definition, skipping copies. - auto GetUniqueDef = [&MRI](Register Reg) { - for (;;) { - MachineInstr *Def = MRI.getUniqueVRegDef(Reg); - if (!Def || Def->getOpcode() != AArch64::COPY) - return Def; - - Reg = Def->getOperand(1).getReg(); - } - }; - // Find the unique register definition, skipping copies and increments. - auto GetUniqueDefPlusOffset = - [GetUniqueDef](Register Reg, int64_t &Offset) -> MachineInstr * { - for (;;) { - MachineInstr *Def = GetUniqueDef(Reg); - if (!Def || Def->getOpcode() != AArch64::ADDXri) - return Def; - - if (Def->getOperand(3).getImm() != 0) - return nullptr; // shifted immediates are not handled - Reg = Def->getOperand(1).getReg(); - Offset += Def->getOperand(2).getImm(); - } - }; - // Try to find a known address-setting instruction, accumulating the offset // along the way. If no known pattern is found, keep everything as-is. int64_t AddrOffset = 0; MachineInstr *AddrDefInstr = - GetUniqueDefPlusOffset(MI.getOperand(1).getReg(), AddrOffset); + stripAndAccumulateOffset(MRI, MI.getOperand(1).getReg(), AddrOffset); if (!AddrDefInstr) return BB; @@ -3116,32 +3139,25 @@ AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, const GlobalValue *GV = AddrOp.getGlobal(); AddrOffset += AddrOp.getOffset(); - // Detect discriminator blend computation, if any. - Register RegDisc = isPACWithZeroDisc(MI.getOpcode()) - ? AArch64::XZR - : MI.getOperand(2).getReg(); - unsigned IntDisc = 0; - MachineInstr *MaybeBlendDef = - RegDisc == AArch64::XZR ? nullptr : GetUniqueDef(RegDisc); - if (MaybeBlendDef && MaybeBlendDef->getOpcode() == AArch64::MOVKXi && - MaybeBlendDef->getOperand(3).getImm() == 48) { - RegDisc = MaybeBlendDef->getOperand(1).getReg(); - IntDisc = MaybeBlendDef->getOperand(2).getImm(); - } + // Analyze the discriminator operand. + Register OriginalDisc = isPACWithZeroDisc(MI.getOpcode()) + ? AArch64::XZR + : MI.getOperand(2).getReg(); + auto [AddrDisc, IntDisc] = detectBlendComponents(MRI, OriginalDisc); // MOVaddrPAC and LOADgotPAC pseudos are expanded so that they use X16/X17 // internally, thus their restrictions on the register class of $AddrDisc - // operand are stricter than those of real PAC* instructions. - if (RegDisc != AArch64::XZR) { + // operand are stricter than those of MOVKXi and PAC* instructions. + if (AddrDisc != AArch64::XZR) { Register TmpReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass); - BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(RegDisc); - RegDisc = TmpReg; + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(AddrDisc); + AddrDisc = TmpReg; } BuildMI(*BB, MI, DL, TII->get(NewOpcode)) .addGlobalAddress(GV, AddrOffset, TargetFlags) .addImm(getKeyForPACOpcode(MI.getOpcode())) - .addReg(RegDisc) + .addReg(AddrDisc) .addImm(IntDisc); BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg()) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index f7cad2879affd..6310ca819fa2c 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -181,6 +181,7 @@ class AArch64TargetLowering : public TargetLowering { MachineBasicBlock *BB) const; MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI, MachineBasicBlock *BB) const; + MachineBasicBlock *tryRewritingPAC(MachineInstr &MI, MachineBasicBlock *BB) const; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index ba94a3de68bb1..25bdcf31869da 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2168,7 +2168,8 @@ let Predicates = [HasPAuth] in { def LOADgotAUTH : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), []>, Sched<[WriteI, ReadI]> { - // Make it possible to eliminate dead instruction after folding it into LOADgotPAC. + // Make it possible to eliminate dead instruction after folding it + // into LOADgotPAC. let hasSideEffects = 0; let Defs = [X16,X17,NZCV]; let Size = 44; >From b4c02aee3c14172aad2594ce56f3d93d94af30db Mon Sep 17 00:00:00 2001 From: Anatoly Trosinenko <atrosine...@accesssoftek.com> Date: Mon, 9 Jun 2025 17:05:56 +0300 Subject: [PATCH 7/7] Rework fixupBlendComponents to simplify later reuse --- .../Target/AArch64/AArch64ISelLowering.cpp | 74 +++++++++++-------- llvm/lib/Target/AArch64/AArch64ISelLowering.h | 5 ++ 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index a3f10e9d6b825..dd2285e47f86b 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -3093,21 +3093,40 @@ static MachineInstr *stripAndAccumulateOffset(const MachineRegisterInfo &MRI, return nullptr; } -static std::pair<Register, unsigned> -detectBlendComponents(const MachineRegisterInfo &MRI, Register Reg) { +void AArch64TargetLowering::fixupBlendComponents( + MachineInstr &MI, MachineBasicBlock *BB, MachineOperand &IntDiscOp, + MachineOperand &AddrDiscOp, const TargetRegisterClass *AddrDiscRC) const { + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); + const DebugLoc &DL = MI.getDebugLoc(); + + Register AddrDisc = AddrDiscOp.getReg(); + int64_t IntDisc = IntDiscOp.getImm(); + + assert(IntDisc == 0 && "Blend components are already expanded"); + int64_t Offset = 0; - MachineInstr *MaybeBlend = stripAndAccumulateOffset(MRI, Reg, Offset); - // This should be a plain copy, without adding any offset. - if (!MaybeBlend || Offset != 0) - return std::make_pair(Reg, 0); + MachineInstr *MaybeBlend = stripAndAccumulateOffset(MRI, AddrDisc, Offset); + + // Detect blend(addr, imm) which is lowered as MOVK addr, #imm, #48. + // The result of MOVK may be copied, but without adding any offset. + if (MaybeBlend && Offset == 0 && MaybeBlend->getOpcode() == AArch64::MOVKXi && + MaybeBlend->getOperand(3).getImm() == 48) { + AddrDisc = MaybeBlend->getOperand(1).getReg(); + IntDisc = MaybeBlend->getOperand(2).getImm(); + } - // Detect blend(addr, imm) which is lowered as MOVK addr, #imm, 48. - if (MaybeBlend->getOpcode() != AArch64::MOVKXi || - MaybeBlend->getOperand(3).getImm() != 48) - return std::make_pair(Reg, 0); + if (AddrDisc == AArch64::NoRegister) + AddrDisc = AArch64::XZR; - return std::make_pair(MaybeBlend->getOperand(1).getReg(), - MaybeBlend->getOperand(2).getImm()); + if (AddrDisc != AArch64::XZR && MRI.getRegClass(AddrDisc) != AddrDiscRC) { + Register TmpReg = MRI.createVirtualRegister(AddrDiscRC); + BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(AddrDisc); + AddrDisc = TmpReg; + } + + AddrDiscOp.setReg(AddrDisc); + IntDiscOp.setImm(IntDisc); } MachineBasicBlock * @@ -3139,26 +3158,17 @@ AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI, const GlobalValue *GV = AddrOp.getGlobal(); AddrOffset += AddrOp.getOffset(); - // Analyze the discriminator operand. - Register OriginalDisc = isPACWithZeroDisc(MI.getOpcode()) - ? AArch64::XZR - : MI.getOperand(2).getReg(); - auto [AddrDisc, IntDisc] = detectBlendComponents(MRI, OriginalDisc); - - // MOVaddrPAC and LOADgotPAC pseudos are expanded so that they use X16/X17 - // internally, thus their restrictions on the register class of $AddrDisc - // operand are stricter than those of MOVKXi and PAC* instructions. - if (AddrDisc != AArch64::XZR) { - Register TmpReg = MRI.createVirtualRegister(&AArch64::GPR64noipRegClass); - BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), TmpReg).addReg(AddrDisc); - AddrDisc = TmpReg; - } - - BuildMI(*BB, MI, DL, TII->get(NewOpcode)) - .addGlobalAddress(GV, AddrOffset, TargetFlags) - .addImm(getKeyForPACOpcode(MI.getOpcode())) - .addReg(AddrDisc) - .addImm(IntDisc); + Register DiscReg = isPACWithZeroDisc(MI.getOpcode()) + ? AArch64::XZR + : MI.getOperand(2).getReg(); + + MachineInstr *NewMI = BuildMI(*BB, MI, DL, TII->get(NewOpcode)) + .addGlobalAddress(GV, AddrOffset, TargetFlags) + .addImm(getKeyForPACOpcode(MI.getOpcode())) + .addReg(DiscReg) + .addImm(0); + fixupBlendComponents(*NewMI, BB, NewMI->getOperand(3), NewMI->getOperand(2), + &AArch64::GPR64noipRegClass); BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg()) .addReg(AArch64::X16); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 6310ca819fa2c..933fa3be759f0 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -182,6 +182,11 @@ class AArch64TargetLowering : public TargetLowering { MachineBasicBlock *EmitGetSMESaveSize(MachineInstr &MI, MachineBasicBlock *BB) const; + void fixupBlendComponents(MachineInstr &MI, MachineBasicBlock *BB, + MachineOperand &IntDiscOp, + MachineOperand &AddrDiscOp, + const TargetRegisterClass *AddrDiscRC) const; + MachineBasicBlock *tryRewritingPAC(MachineInstr &MI, MachineBasicBlock *BB) const; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits