Skip to content

Commit 98c6aa7

Browse files
authored
[LoongArch] Implement LoongArchRegisterInfo::canRealignStack() (#76913)
This patch fixes the crash issue in the test: CodeGen/LoongArch/can-not-realign-stack.ll Register allocator may spill virtual registers to the stack, which introduces stack alignment requirements (when the size of spilled registers exceeds the default alignment size of the stack). If a function does not have stack alignment requirements before register allocation, registers used for stack alignment will not be preserved. Therefore, we should implement `canRealignStack()` to inform the register allocator whether it is allowed to perform stack realignment operations.
1 parent f499472 commit 98c6aa7

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "LoongArch.h"
1616
#include "LoongArchInstrInfo.h"
1717
#include "LoongArchSubtarget.h"
18+
#include "MCTargetDesc/LoongArchBaseInfo.h"
1819
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
1920
#include "llvm/CodeGen/MachineFrameInfo.h"
2021
#include "llvm/CodeGen/MachineFunction.h"
@@ -194,3 +195,25 @@ bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
194195
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getFixed());
195196
return false;
196197
}
198+
199+
bool LoongArchRegisterInfo::canRealignStack(const MachineFunction &MF) const {
200+
if (!TargetRegisterInfo::canRealignStack(MF))
201+
return false;
202+
203+
const MachineRegisterInfo *MRI = &MF.getRegInfo();
204+
const LoongArchFrameLowering *TFI = getFrameLowering(MF);
205+
206+
// Stack realignment requires a frame pointer. If we already started
207+
// register allocation with frame pointer elimination, it is too late now.
208+
if (!MRI->canReserveReg(LoongArch::R22))
209+
return false;
210+
211+
// We may also need a base pointer if there are dynamic allocas or stack
212+
// pointer adjustments around calls.
213+
if (TFI->hasReservedCallFrame(MF))
214+
return true;
215+
216+
// A base pointer is required and allowed. Check that it isn't too late to
217+
// reserve it.
218+
return MRI->canReserveReg(LoongArchABI::getBPReg());
219+
}

llvm/lib/Target/LoongArch/LoongArchRegisterInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct LoongArchRegisterInfo : public LoongArchGenRegisterInfo {
5151
bool requiresFrameIndexScavenging(const MachineFunction &MF) const override {
5252
return true;
5353
}
54+
bool canRealignStack(const MachineFunction &MF) const override;
5455
};
5556
} // end namespace llvm
5657

llvm/test/CodeGen/LoongArch/can-not-realign-stack.ll

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,60 @@
1-
; REQUIRES: expensive_checks
2-
; RUN: llc --mtriple=loongarch64 --frame-pointer=none --mattr=+lasx < %s
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
2+
; RUN: llc --mtriple=loongarch64 --frame-pointer=none --mattr=+lasx < %s | FileCheck %s
33

4-
; XFAIL: *
4+
;; This test is checking that when a function allows stack realignment and
5+
;; realignment needs were not detected before register allocation (at this
6+
;; point, fp is not preserved), but realignment is required during register
7+
;; allocation, the stack should not undergo realignment.
58

6-
;; FIXME: This test will crash with expensive check. The subsequent patch will
7-
;; address and fix this issue.
9+
;; Ensure that the `bstrins.d $sp, $zero, n, 0` instruction is not generated.
10+
;; n = log2(realign_size) - 1
811

912
%struct.S = type { [64 x i16] }
1013

1114
define dso_local noundef signext i32 @main() nounwind {
15+
; CHECK-LABEL: main:
16+
; CHECK: # %bb.0: # %entry
17+
; CHECK-NEXT: addi.d $sp, $sp, -272
18+
; CHECK-NEXT: st.d $ra, $sp, 264 # 8-byte Folded Spill
19+
; CHECK-NEXT: st.d $fp, $sp, 256 # 8-byte Folded Spill
20+
; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI0_0)
21+
; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI0_0)
22+
; CHECK-NEXT: xvld $xr0, $a0, 0
23+
; CHECK-NEXT: xvst $xr0, $sp, 96 # 32-byte Folded Spill
24+
; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI0_1)
25+
; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI0_1)
26+
; CHECK-NEXT: xvld $xr1, $a0, 0
27+
; CHECK-NEXT: xvst $xr1, $sp, 64 # 32-byte Folded Spill
28+
; CHECK-NEXT: xvst $xr1, $sp, 224
29+
; CHECK-NEXT: xvst $xr0, $sp, 192
30+
; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI0_2)
31+
; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI0_2)
32+
; CHECK-NEXT: xvld $xr0, $a0, 0
33+
; CHECK-NEXT: xvst $xr0, $sp, 32 # 32-byte Folded Spill
34+
; CHECK-NEXT: xvst $xr0, $sp, 160
35+
; CHECK-NEXT: pcalau12i $a0, %pc_hi20(.LCPI0_3)
36+
; CHECK-NEXT: addi.d $a0, $a0, %pc_lo12(.LCPI0_3)
37+
; CHECK-NEXT: xvld $xr0, $a0, 0
38+
; CHECK-NEXT: xvst $xr0, $sp, 0 # 32-byte Folded Spill
39+
; CHECK-NEXT: xvst $xr0, $sp, 128
40+
; CHECK-NEXT: addi.d $fp, $sp, 128
41+
; CHECK-NEXT: move $a0, $fp
42+
; CHECK-NEXT: bl %plt(foo)
43+
; CHECK-NEXT: xvld $xr0, $sp, 64 # 32-byte Folded Reload
44+
; CHECK-NEXT: xvst $xr0, $sp, 224
45+
; CHECK-NEXT: xvld $xr0, $sp, 96 # 32-byte Folded Reload
46+
; CHECK-NEXT: xvst $xr0, $sp, 192
47+
; CHECK-NEXT: xvld $xr0, $sp, 32 # 32-byte Folded Reload
48+
; CHECK-NEXT: xvst $xr0, $sp, 160
49+
; CHECK-NEXT: xvld $xr0, $sp, 0 # 32-byte Folded Reload
50+
; CHECK-NEXT: xvst $xr0, $sp, 128
51+
; CHECK-NEXT: move $a0, $fp
52+
; CHECK-NEXT: bl %plt(bar)
53+
; CHECK-NEXT: move $a0, $zero
54+
; CHECK-NEXT: ld.d $fp, $sp, 256 # 8-byte Folded Reload
55+
; CHECK-NEXT: ld.d $ra, $sp, 264 # 8-byte Folded Reload
56+
; CHECK-NEXT: addi.d $sp, $sp, 272
57+
; CHECK-NEXT: ret
1258
entry:
1359
%s = alloca %struct.S, align 2
1460
call void @llvm.lifetime.start.p0(i64 128, ptr nonnull %s)

0 commit comments

Comments
 (0)