[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