[llvm] AArch64: Don't duplicate the branch's implicit defs in call pseudo expansion (PR #225064)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 04:27:11 PDT 2026
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/225064
These pseudo expansions started with an implicit LR def and are replaced with a
new instruction with a different LR def. Previously this would copy the old
instruction's operand list, merging with the newly build instruction def list.
Avoid creating a redundant def with inconsistent dead flags. This avoids failing
a future verifier check.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
>From 72fb4b9fee5877305370e449d77f5dd94638f2d7 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 18 Sep 2026 19:20:01 +0200
Subject: [PATCH] AArch64: Don't duplicate the branch's implicit defs in call
pseudo expansion
These pseudo expansions started with an implicit LR def and are replaced with a
new instruction with a different LR def. Previously this would copy the old
instruction's operand list, merging with the newly build instruction def list.
Avoid creating a redundant def with inconsistent dead flags. This avoids failing
a future verifier check.
Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
.../AArch64/AArch64ExpandPseudoInsts.cpp | 12 ++++++----
.../AArch64/blr-bti-preserves-operands.mir | 4 ++--
.../AArch64/expand-blr-rvmarker-pseudo.mir | 24 +++++++++----------
llvm/test/CodeGen/AArch64/kcfi-bti.ll | 2 +-
4 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
index bcd61e191e17f5..742721a2df16db 100644
--- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
@@ -899,10 +899,14 @@ static MachineInstr *createCallWithOps(MachineBasicBlock &MBB,
unsigned Opcode,
ArrayRef<MachineOperand> ExplicitOps,
unsigned RegMaskStartIdx) {
- // Build the MI, with explicit operands first (including the call target).
- MachineInstr *Call = BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(Opcode))
- .add(ExplicitOps)
- .getInstr();
+ // Be careful not to duplicate the LR def which the original instruction
+ // already carries.
+ MachineFunction &MF = *MBB.getParent();
+ MachineInstr *Call =
+ MF.CreateMachineInstr(TII->get(Opcode), MBBI->getDebugLoc(),
+ /*NoImplicit=*/true);
+ MBB.insert(MBBI, Call);
+ MachineInstrBuilder(MF, Call).add(ExplicitOps);
// Register arguments are added during ISel, but cannot be added as explicit
// operands of the branch as it expects to be B <target> which is only one
diff --git a/llvm/test/CodeGen/AArch64/blr-bti-preserves-operands.mir b/llvm/test/CodeGen/AArch64/blr-bti-preserves-operands.mir
index 7f290cbe084b0f..ed782fde4d10cb 100644
--- a/llvm/test/CodeGen/AArch64/blr-bti-preserves-operands.mir
+++ b/llvm/test/CodeGen/AArch64/blr-bti-preserves-operands.mir
@@ -9,8 +9,8 @@
# The arguments to the call must become implicit arguments, because the branch
# only expects to get 1 explicit operand which is the branch target.
-# CHECK: BUNDLE implicit-def dead $lr, implicit-def $sp, implicit $sp, implicit $x0, implicit $w1 {
-# CHECK: BL @_setjmp, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp
+# CHECK: BUNDLE implicit-def dead $lr, implicit-def $sp, implicit $x0, implicit $w1, implicit $sp {
+# CHECK: BL @_setjmp, csr_aarch64_aapcs, implicit $x0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp
# CHECK: HINT 36
# CHECK: }
diff --git a/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir b/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir
index 530bb92e88e39d..ee874905aa904b 100644
--- a/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir
+++ b/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir
@@ -45,7 +45,7 @@
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $x0, implicit $sp, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BLR $x0, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BLR $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -67,8 +67,8 @@ body: |
# CHECK: bb.0:
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
-# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $sp, implicit $x0, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $x0, implicit $sp, implicit $xzr, implicit $fp {
+# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit $x0, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -87,8 +87,8 @@ body: |
# CHECK: bb.0:
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
-# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $fp, implicit $sp, implicit $x0, implicit $x1, implicit $x2, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit $x1, implicit $x2, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0
+# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $fp, implicit $x0, implicit $x1, implicit $x2, implicit $sp, implicit $xzr, implicit $fp {
+# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit $x0, implicit $x1, implicit $x2, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0
# CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -107,8 +107,8 @@ body: |
# CHECK: bb.0:
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
-# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $sp, implicit $w0, implicit $w1, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $w0, implicit $w1, implicit $sp, implicit $xzr, implicit $fp {
+# CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -128,8 +128,8 @@ body: |
# CHECK: bb.0:
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
-# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $x8, implicit $sp, implicit $w0, implicit $w1, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BLR $x8, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $x8, implicit $w0, implicit $w1, implicit $sp, implicit $xzr, implicit $fp {
+# CHECK-NEXT: BLR $x8, csr_aarch64_aapcs, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -150,8 +150,8 @@ body: |
# CHECK: bb.0:
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
-# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit $sp, implicit undef $x0, implicit $xzr, implicit $fp {
-# CHECK-NEXT: BL @foo, csr_darwin_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit undef $x0, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit-def $fp, implicit undef $x0, implicit $sp, implicit $xzr, implicit $fp {
+# CHECK-NEXT: BL @foo, csr_darwin_aarch64_aapcs, implicit undef $x0, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0
# CHECK-NEXT: BL @objc_retainAutoreleasedReturnValue, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
@@ -172,7 +172,7 @@ body: |
# CHECK-NEXT: liveins:
# CHECK-NEXT: {{ $}}
# CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $sp, implicit-def dead $x0, implicit $x0, implicit $sp {
-# CHECK-NEXT: BLR $x0, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
+# CHECK-NEXT: BLR $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0
# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp
# CHECK-NEXT: }
# CHECK-NEXT: RET undef $lr, implicit killed $w0
diff --git a/llvm/test/CodeGen/AArch64/kcfi-bti.ll b/llvm/test/CodeGen/AArch64/kcfi-bti.ll
index 1ac894fa09015b..ed4b14fb83ff24 100644
--- a/llvm/test/CodeGen/AArch64/kcfi-bti.ll
+++ b/llvm/test/CodeGen/AArch64/kcfi-bti.ll
@@ -49,7 +49,7 @@ define void @f2(ptr noundef %x) #1 !kcfi_type !2 {
; KCFI: BUNDLE{{.*}} {
; KCFI-NEXT: KCFI_CHECK $x0, 12345678, implicit-def $x9, implicit-def $x16, implicit-def $x17, implicit-def $nzcv
-; KCFI-NEXT: BLR killed $x0, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp
+; KCFI-NEXT: BLR killed $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp
; KCFI-NEXT: HINT 36
; KCFI-NEXT: }
More information about the llvm-commits
mailing list