Skip to content

Commit 898963b

Browse files
authored
[AArch64] Fix missing register definitions in homogeneous epilog lowering (#171118)
The lowering for HOM_Epilog did not transfer explicit register defs from the pseudo-instruction to the generated helper calls. MachineVerifier would complain if a following tail call uses one of the restored CSRs. This scenario occurs in code generated by the Swift compiler, where X20 is used to pass swiftself. This patch fixes the issue by adding the missing defs back to the helper call as implicit defs.
1 parent 9fc1c49 commit 898963b

File tree

2 files changed

+45
-10
lines changed

2 files changed

+45
-10
lines changed

llvm/lib/Target/AArch64/AArch64LowerHomogeneousPrologEpilog.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,27 +483,28 @@ bool AArch64LowerHomogeneousPE::lowerEpilog(
483483
assert(MI.getOpcode() == AArch64::HOM_Epilog);
484484

485485
auto Return = NextMBBI;
486+
MachineInstr *HelperCall = nullptr;
486487
if (shouldUseFrameHelper(MBB, NextMBBI, Regs, FrameHelperType::EpilogTail)) {
487488
// When MBB ends with a return, emit a tail-call to the epilog helper
488489
auto *EpilogTailHelper =
489490
getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::EpilogTail);
490-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::TCRETURNdi))
491-
.addGlobalAddress(EpilogTailHelper)
492-
.addImm(0)
493-
.setMIFlag(MachineInstr::FrameDestroy)
494-
.copyImplicitOps(MI)
495-
.copyImplicitOps(*Return);
491+
HelperCall = BuildMI(MBB, MBBI, DL, TII->get(AArch64::TCRETURNdi))
492+
.addGlobalAddress(EpilogTailHelper)
493+
.addImm(0)
494+
.setMIFlag(MachineInstr::FrameDestroy)
495+
.copyImplicitOps(MI)
496+
.copyImplicitOps(*Return);
496497
NextMBBI = std::next(Return);
497498
Return->removeFromParent();
498499
} else if (shouldUseFrameHelper(MBB, NextMBBI, Regs,
499500
FrameHelperType::Epilog)) {
500501
// The default epilog helper case.
501502
auto *EpilogHelper =
502503
getOrCreateFrameHelper(M, MMI, Regs, FrameHelperType::Epilog);
503-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
504-
.addGlobalAddress(EpilogHelper)
505-
.setMIFlag(MachineInstr::FrameDestroy)
506-
.copyImplicitOps(MI);
504+
HelperCall = BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL))
505+
.addGlobalAddress(EpilogHelper)
506+
.setMIFlag(MachineInstr::FrameDestroy)
507+
.copyImplicitOps(MI);
507508
} else {
508509
// Fall back to no-helper.
509510
for (int I = 0; I < Size - 2; I += 2)
@@ -512,6 +513,12 @@ bool AArch64LowerHomogeneousPE::lowerEpilog(
512513
emitLoad(MF, MBB, MBBI, *TII, Regs[Size - 2], Regs[Size - 1], Size, true);
513514
}
514515

516+
// Make sure all explicit definitions are preserved in the helper call;
517+
// implicit ones are already handled by copyImplicitOps.
518+
if (HelperCall)
519+
for (auto &Def : MBBI->defs())
520+
HelperCall->addRegisterDefined(Def.getReg(),
521+
MF.getRegInfo().getTargetRegisterInfo());
515522
MBBI->removeFromParent();
516523
return true;
517524
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# RUN: llc -verify-machineinstrs -mtriple=arm64-applie-ios7.0 -start-before=aarch64-lower-homogeneous-prolog-epilog -homogeneous-prolog-epilog %s
2+
#
3+
# This test ensures defined registers are preserved after lowering homogeneous
4+
# epilog into helper calls. Without the fix, the verifier would complain about
5+
# X20 being used by use_x20 without being defined.
6+
--- |
7+
define void @foo() {
8+
entry:
9+
ret void
10+
}
11+
declare void @use_x20()
12+
...
13+
---
14+
name: foo
15+
alignment: 4
16+
tracksRegLiveness: true
17+
liveins:
18+
- { reg: '$x0' }
19+
- { reg: '$x20' }
20+
body: |
21+
bb.0:
22+
liveins: $x0, $x20, $lr, $x19, $x20
23+
frame-setup HOM_Prolog $lr, $fp, $x19, $x20, 16
24+
$sp = frame-setup SUBXri $sp, 32, 0
25+
bb.1:
26+
$sp = frame-destroy ADDXri $sp, 32, 0
27+
$lr, $fp, $x19, $x20 = frame-destroy HOM_Epilog
28+
TCRETURNdi @use_x20, 0, csr_aarch64_aapcs, implicit $sp, implicit $x20

0 commit comments

Comments
 (0)