Skip to content

Commit 2e25d75

Browse files
committed
[AArch64][GlobalISel] Fix llvm.returnaddress(0) selection when LR is clobbered.
The code was originally ported from SelectionDAG, which does CSE behind the scenes automatically. When copying the return address from LR live into the function, we need to make sure to use the single copy on function entry. Any later copy from LR could be using clobbered junk. Implement this by caching the copy in the per-MF state in the selector. Should hopefully fix the AArch64 sanitiser buildbot failure.
1 parent 97d000d commit 2e25d75

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class AArch64InstructionSelector : public InstructionSelector {
6363
// cache it here for each run of the selector.
6464
ProduceNonFlagSettingCondBr =
6565
!MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening);
66+
MFReturnAddr = Register();
6667
}
6768

6869
private:
@@ -123,7 +124,7 @@ class AArch64InstructionSelector : public InstructionSelector {
123124
MachineRegisterInfo &MRI) const;
124125
bool selectIntrinsicWithSideEffects(MachineInstr &I,
125126
MachineRegisterInfo &MRI) const;
126-
bool selectIntrinsic(MachineInstr &I, MachineRegisterInfo &MRI) const;
127+
bool selectIntrinsic(MachineInstr &I, MachineRegisterInfo &MRI);
127128
bool selectVectorICmp(MachineInstr &I, MachineRegisterInfo &MRI) const;
128129
bool selectIntrinsicTrunc(MachineInstr &I, MachineRegisterInfo &MRI) const;
129130
bool selectIntrinsicRound(MachineInstr &I, MachineRegisterInfo &MRI) const;
@@ -295,6 +296,11 @@ class AArch64InstructionSelector : public InstructionSelector {
295296

296297
bool ProduceNonFlagSettingCondBr = false;
297298

299+
// Some cached values used during selection.
300+
// We use LR as a live-in register, and we keep track of it here as it can be
301+
// clobbered by calls.
302+
Register MFReturnAddr;
303+
298304
#define GET_GLOBALISEL_PREDICATES_DECL
299305
#include "AArch64GenGlobalISel.inc"
300306
#undef GET_GLOBALISEL_PREDICATES_DECL
@@ -4079,8 +4085,8 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
40794085
return true;
40804086
}
40814087

4082-
bool AArch64InstructionSelector::selectIntrinsic(
4083-
MachineInstr &I, MachineRegisterInfo &MRI) const {
4088+
bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
4089+
MachineRegisterInfo &MRI) {
40844090
unsigned IntrinID = findIntrinsicID(I);
40854091
if (!IntrinID)
40864092
return false;
@@ -4138,10 +4144,20 @@ bool AArch64InstructionSelector::selectIntrinsic(
41384144
RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI);
41394145

41404146
if (Depth == 0 && IntrinID == Intrinsic::returnaddress) {
4147+
if (MFReturnAddr) {
4148+
MIRBuilder.buildCopy({DstReg}, MFReturnAddr);
4149+
I.eraseFromParent();
4150+
return true;
4151+
}
41414152
MFI.setReturnAddressIsTaken(true);
41424153
MF.addLiveIn(AArch64::LR, &AArch64::GPR64spRegClass);
41434154
I.getParent()->addLiveIn(AArch64::LR);
4144-
MIRBuilder.buildCopy({DstReg}, {Register(AArch64::LR)});
4155+
// Insert the copy from LR/X30 into the entry block, before it can be
4156+
// clobbered by anything.
4157+
MachineIRBuilder EntryBuilder(MF);
4158+
EntryBuilder.setInstr(*MF.begin()->begin());
4159+
EntryBuilder.buildCopy({DstReg}, {Register(AArch64::LR)});
4160+
MFReturnAddr = DstReg;
41454161
I.eraseFromParent();
41464162
return true;
41474163
}

llvm/test/CodeGen/AArch64/GlobalISel/select-returnaddr.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ entry:
99
ret i8* %0
1010
}
1111

12+
define i8* @rt0_call_clobber(i32 %x) nounwind readnone {
13+
entry:
14+
; CHECK-LABEL: rt0_call_clobber:
15+
; CHECK: stp x20, x19, [sp, #-32]!
16+
; CHECK: stp x29, x30, [sp, #16]
17+
; CHECK: mov x19, x30
18+
; CHECK: bl _foo
19+
; CHECK: ldp x29, x30, [sp, #16]
20+
; CHECK: mov x0, x19
21+
%ret = call i32 @foo()
22+
%0 = tail call i8* @llvm.returnaddress(i32 0)
23+
ret i8* %0
24+
}
25+
1226
define i8* @rt2() nounwind readnone {
1327
entry:
1428
; CHECK-LABEL: rt2:
@@ -19,4 +33,6 @@ entry:
1933
ret i8* %0
2034
}
2135

36+
37+
declare i32 @foo()
2238
declare i8* @llvm.returnaddress(i32) nounwind readnone

0 commit comments

Comments
 (0)