[llvm] [AArch64][PAC] Mark $Scratch operand of AUTxMxN as earlyclobber (PR #173999)
Anatoly Trosinenko via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 29 07:55:36 PST 2026
https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/173999
>From 007fccabe8deee634e2ddc18eafb544f6b0621bb Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Tue, 30 Dec 2025 18:29:19 +0300
Subject: [PATCH 1/3] [AArch64][PAC] Mark $Scratch operand of AUTxMxN as
earlyclobber
This fixes an assertions when emitting code at `-O0`.
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f3cd613a6bd99..5ad0f92b0dfd7 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2195,10 +2195,21 @@ let Predicates = [HasPAuth] in {
let Uses = [X16];
}
+ // AsmPrinter can clobber the $AddrDisc register as long as it is marked
+ // "killed", otherwise an assertion checks that $Scratch != $AddrDisc.
+ // The problem is that it is always correct to *omit* the "killed" flag,
+ // thus an instruction like this can be passed to AsmPrinter:
+ //
+ // $x8, $x9 = AUTxMxN $x8, 0, 51756, $x9, implicit-def $nzcv
+ //
+ // While it is possible to check if "$Scratch == $AddrDisc OR $AddrDisc
+ // is killed" instead, it is easier and more straightforward to mark
+ // $Scratch as @earlyclobber. Furthermore, this would be mandatory for a
+ // (hypotetical at the time of writing this comment) AUTPACxMxN pseudo.
def AUTxMxN : Pseudo<(outs GPR64:$AuthVal, GPR64common:$Scratch),
(ins GPR64:$Val, i32imm:$Key,
i64imm:$Disc, GPR64:$AddrDisc),
- [], "$AuthVal = $Val">, Sched<[WriteI, ReadI]> {
+ [], "$AuthVal = $Val, at earlyclobber $Scratch">, Sched<[WriteI, ReadI]> {
let isCodeGenOnly = 1;
let hasSideEffects = 1;
let mayStore = 0;
>From f6a86957d8bbe707dd9ca393d1274fde92b0a139 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 8 Jan 2026 15:36:25 +0300
Subject: [PATCH 2/3] Improve the comment wording a bit
---
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 5ad0f92b0dfd7..5acbfb8971079 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2195,17 +2195,17 @@ let Predicates = [HasPAuth] in {
let Uses = [X16];
}
- // AsmPrinter can clobber the $AddrDisc register as long as it is marked
- // "killed", otherwise an assertion checks that $Scratch != $AddrDisc.
- // The problem is that it is always correct to *omit* the "killed" flag,
- // thus an instruction like this can be passed to AsmPrinter:
+ // AArch64AsmPrinter can clobber the $AddrDisc register as long as it is
+ // marked "killed", otherwise an assertion in emitPtrauthDiscriminator checks
+ // that $Scratch != $AddrDisc. The problem is that it is always correct to
+ // *omit* the "killed" flag, thus an instruction like this is valid:
//
- // $x8, $x9 = AUTxMxN $x8, 0, 51756, $x9, implicit-def $nzcv
+ // $x8, $x9 = AUTxMxN $x8, 0, 12345, /* is actually killed */ $x9, implicit-def $nzcv
+ // // $x9 is dead past this point
//
- // While it is possible to check if "$Scratch == $AddrDisc OR $AddrDisc
- // is killed" instead, it is easier and more straightforward to mark
- // $Scratch as @earlyclobber. Furthermore, this would be mandatory for a
- // (hypotetical at the time of writing this comment) AUTPACxMxN pseudo.
+ // While it is possible to allow emitPtrauthDiscriminator to clobber $Scratch
+ // iff ($AddrDisc is killed OR $Scratch == $AddrDisc), it is easier and more
+ // straightforward to mark $Scratch as @earlyclobber.
def AUTxMxN : Pseudo<(outs GPR64:$AuthVal, GPR64common:$Scratch),
(ins GPR64:$Val, i32imm:$Key,
i64imm:$Disc, GPR64:$AddrDisc),
>From 1b35218f935a9b31d92700ecf9ae3d1cccc32a12 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 29 Jan 2026 18:48:33 +0300
Subject: [PATCH 3/3] Test case: check generated MIR output
---
llvm/test/CodeGen/AArch64/ptrauth-isel.ll | 61 +++++++++++++++++++++--
1 file changed, 57 insertions(+), 4 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
index 7011b946aad74..6ecfb5852f790 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
@@ -1,12 +1,12 @@
; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
-; RUN: | FileCheck %s --check-prefixes=DAGISEL
+; RUN: | FileCheck %s --check-prefixes=DAGISEL,DAGISEL-DARWIN
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
-; RUN: | FileCheck %s --check-prefixes=GISEL
+; RUN: | FileCheck %s --check-prefixes=GISEL,GISEL-DARWIN
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
-; RUN: | FileCheck %s --check-prefixes=DAGISEL
+; RUN: | FileCheck %s --check-prefixes=DAGISEL,DAGISEL-GNU
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
-; RUN: | FileCheck %s --check-prefixes=GISEL
+; RUN: | FileCheck %s --check-prefixes=GISEL,GISEL-GNU
; Check MIR produced by the instruction selector to validate properties that
; cannot be reliably tested by only inspecting the final asm output.
@@ -267,3 +267,56 @@ exit:
%signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc)
ret i64 %signed
}
+
+; On non-Darwin platforms, AUTxMxN allows allocating arbitrary scratch registers.
+; To simplify expansion of AUTxMxN in AArch64AsmPrinter, $Scratch operand
+; should be marked as @earlyclobber, which is checked by this test case.
+define i64 @autxmxn_earlyclobbered_scratch(i64 %addr, i64 %disc) {
+ ; DAGISEL-DARWIN-LABEL: name: autxmxn_earlyclobbered_scratch
+ ; DAGISEL-DARWIN: bb.0.entry:
+ ; DAGISEL-DARWIN-NEXT: liveins: $x0, $x1
+ ; DAGISEL-DARWIN-NEXT: {{ $}}
+ ; DAGISEL-DARWIN-NEXT: [[COPY:%[0-9]+]]:gpr64noip = COPY $x1
+ ; DAGISEL-DARWIN-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+ ; DAGISEL-DARWIN-NEXT: $x16 = COPY [[COPY1]]
+ ; DAGISEL-DARWIN-NEXT: AUTx16x17 2, 0, [[COPY]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+ ; DAGISEL-DARWIN-NEXT: [[COPY2:%[0-9]+]]:gpr64all = COPY $x16
+ ; DAGISEL-DARWIN-NEXT: $x0 = COPY [[COPY2]]
+ ; DAGISEL-DARWIN-NEXT: RET_ReallyLR implicit $x0
+ ;
+ ; GISEL-DARWIN-LABEL: name: autxmxn_earlyclobbered_scratch
+ ; GISEL-DARWIN: bb.1.entry:
+ ; GISEL-DARWIN-NEXT: liveins: $x0, $x1
+ ; GISEL-DARWIN-NEXT: {{ $}}
+ ; GISEL-DARWIN-NEXT: [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+ ; GISEL-DARWIN-NEXT: [[COPY1:%[0-9]+]]:gpr64noip = COPY $x1
+ ; GISEL-DARWIN-NEXT: $x16 = COPY [[COPY]]
+ ; GISEL-DARWIN-NEXT: $x17 = IMPLICIT_DEF
+ ; GISEL-DARWIN-NEXT: AUTx16x17 2, 0, [[COPY1]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+ ; GISEL-DARWIN-NEXT: [[COPY2:%[0-9]+]]:gpr64 = COPY $x16
+ ; GISEL-DARWIN-NEXT: $x0 = COPY [[COPY2]]
+ ; GISEL-DARWIN-NEXT: RET_ReallyLR implicit $x0
+ ;
+ ; DAGISEL-GNU-LABEL: name: autxmxn_earlyclobbered_scratch
+ ; DAGISEL-GNU: bb.0.entry:
+ ; DAGISEL-GNU-NEXT: liveins: $x0, $x1
+ ; DAGISEL-GNU-NEXT: {{ $}}
+ ; DAGISEL-GNU-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+ ; DAGISEL-GNU-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+ ; DAGISEL-GNU-NEXT: %2:gpr64, early-clobber %3:gpr64common = AUTxMxN [[COPY1]], 2, 0, [[COPY]], implicit-def dead $nzcv
+ ; DAGISEL-GNU-NEXT: $x0 = COPY %2
+ ; DAGISEL-GNU-NEXT: RET_ReallyLR implicit $x0
+ ;
+ ; GISEL-GNU-LABEL: name: autxmxn_earlyclobbered_scratch
+ ; GISEL-GNU: bb.1.entry:
+ ; GISEL-GNU-NEXT: liveins: $x0, $x1
+ ; GISEL-GNU-NEXT: {{ $}}
+ ; GISEL-GNU-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+ ; GISEL-GNU-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+ ; GISEL-GNU-NEXT: %2:gpr64, early-clobber %3:gpr64common = AUTxMxN [[COPY]], 2, 0, [[COPY1]], implicit-def dead $nzcv
+ ; GISEL-GNU-NEXT: $x0 = COPY %2
+ ; GISEL-GNU-NEXT: RET_ReallyLR implicit $x0
+entry:
+ %auted = call i64 @llvm.ptrauth.auth(i64 %addr, i32 2, i64 %disc)
+ ret i64 %auted
+}
More information about the llvm-commits
mailing list