Skip to content

Commit

Permalink
NanoMips: Frame pointer setup
Browse files Browse the repository at this point in the history
If function uses FP, it will now point to address -4096 from the
beginning of function's stack. After FP setup following offsets
will be relative to SP if function has no var-sized objects. If it
has var-sized objects offsets will be relative to FP.
Also, stack realignment now happens with INS instruction.
  • Loading branch information
Nikola Peric authored and Nikola Peric committed Apr 12, 2023
1 parent 9a56b55 commit fc5fa13
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 49 deletions.
10 changes: 10 additions & 0 deletions llvm/lib/Target/Mips/MipsRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,21 @@ Register MipsRegisterInfo::
getFrameRegister(const MachineFunction &MF) const {
const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
bool IsN64 =
static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsN64();
bool IsP32 =
static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsP32();

// If function doesn't have var-sized objects and function doesn't need stack
// realignment but frame pointer elimination is disabled we want offsets to be
// relative to sp instead of fp
if (Subtarget.hasNanoMips())
if (!MFI.hasVarSizedObjects() && !TRI->hasStackRealignment(MF) &&
MF.getTarget().Options.DisableFramePointerElim(MF))
return Mips::SP_NM;

if (Subtarget.inMips16Mode())
return TFI->hasFP(MF) ? Mips::S0 : Mips::SP;
else
Expand Down
57 changes: 40 additions & 17 deletions llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,23 +569,40 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,

// if framepointer enabled, set it to point to the stack pointer.
if (hasFP(MF)) {
// Insert instruction "move $fp, $sp" at this location.
BuildMI(MBB, MBBI, dl, TII.get(MOVE), FP).addReg(SP).addReg(ZERO)
.setMIFlag(MachineInstr::FrameSetup);

if (MipsFI->isTwoStepStackSetup(MF))
// If we have two-step stack setup insert instruction "move $fp, $sp"
// after the second stack setup also
BuildMI(MBB, MBBI_2, dl, TII.get(MOVE), FP)
if (STI.hasNanoMips()) {

BuildMI(MBB, MBBI_2, dl, TII.get(ADDiu), FP)
.addReg(SP)
.addImm(-4096 + StackSize);

// emit ".cfi_def_cfa_register $fp"
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FP, true)));
BuildMI(MBB, MBBI_2, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);

// emit ".cfi_def_cfa_offset 4096"
unsigned CFIIndex_1 =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 4096));
BuildMI(MBB, MBBI_2, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex_1);

} else {
// Insert instruction "move $fp, $sp" at this location.
BuildMI(MBB, MBBI, dl, TII.get(MOVE), FP)
.addReg(SP)
.addReg(ZERO)
.setMIFlag(MachineInstr::FrameSetup);

// emit ".cfi_def_cfa_register $fp"
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FP, true)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// emit ".cfi_def_cfa_register $fp"
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MRI->getDwarfRegNum(FP, true)));
BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}

if (RegInfo.hasStackRealignment(MF)) {
// addiu $Reg, $zero, -MaxAlignment
Expand All @@ -595,13 +612,19 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
"Function's alignment size requirement is not supported.");
int64_t MaxAlign = -(int64_t)MFI.getMaxAlign().value();

if (ABI.IsP32())
BuildMI(MBB, MBBI, dl, TII.get(Mips::Li_NM), VR).addImm(MaxAlign);
else
if (ABI.IsP32()) {
uint64_t MaxAlignment = MFI.getMaxAlign().value();
BuildMI(MBB, MBBI, dl, TII.get(Mips::INS_NM), SP)
.addReg(ZERO)
.addImm(0)
.addImm(Log2_64(MaxAlignment))
.addReg(SP);
} else {
BuildMI(MBB, MBBI, dl, TII.get(ADDiu), VR)
.addReg(ZERO)
.addImm(MaxAlign);
BuildMI(MBB, MBBI, dl, TII.get(AND), SP).addReg(SP).addReg(VR);
BuildMI(MBB, MBBI, dl, TII.get(AND), SP).addReg(SP).addReg(VR);
}

if (hasBP(MF)) {
// move $s7, $sp
Expand Down Expand Up @@ -759,7 +782,7 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
unsigned MOVE = ABI.GetGPRMoveOp();

// if framepointer enabled, restore the stack pointer.
if (hasFP(MF)) {
if (hasFP(MF) && !STI.hasNanoMips()) {
// Find the first instruction that restores a callee-saved register.
MachineBasicBlock::iterator I = MBBI;

Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/Mips/MipsSEISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ bool MipsSEDAGToDAGISel::selectIntAddrLSL2MM(SDValue Addr, SDValue &Base,

bool MipsSEDAGToDAGISel::selectIntAddrSImm9(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
return selectAddrFrameIndex(Addr, Base, Offset) ||
selectAddrFrameIndexOffset(Addr, Base, Offset, 9);
return selectAddrFrameIndexOffset(Addr, Base, Offset, 9) &&
!isa<FrameIndexSDNode>(Base);
}

bool MipsSEDAGToDAGISel::selectIntAddrSImm10(SDValue Addr, SDValue &Base,
Expand Down Expand Up @@ -541,7 +541,8 @@ bool MipsSEDAGToDAGISel::selectAddrFrameIndexUOffset(

bool MipsSEDAGToDAGISel::selectIntAddrUImm12(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
return selectAddrFrameIndexUOffset(Addr, Base, Offset, 12, 0);
return selectAddrFrameIndex(Addr, Base, Offset) ||
selectAddrFrameIndexUOffset(Addr, Base, Offset, 12, 0);
}

// A load/store 'x' indexed (reg + reg)
Expand Down
29 changes: 22 additions & 7 deletions llvm/lib/Target/Mips/MipsSERegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI();
const MipsRegisterInfo *RegInfo =
static_cast<const MipsRegisterInfo *>(MF.getSubtarget().getRegisterInfo());
const MipsSubtarget &STI =
*static_cast<const MipsSubtarget *>(&MF.getSubtarget());

const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
int MinCSFI = 0;
Expand Down Expand Up @@ -220,14 +222,25 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
bool IsKill = false;
int64_t Offset;

if (MipsFI->isTwoStepStackSetup(MF)) {
if (STI.hasNanoMips()) {

int64_t CalleeSavedStackSize = MipsFI->getCalleeSavedStackSize();
if (MipsFI->isTwoStepStackSetup(MF)) {

if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)
Offset = SPOffset + (int64_t)CalleeSavedStackSize;
else
Offset = SPOffset + StackSize;
int64_t CalleeSavedStackSize = MipsFI->getCalleeSavedStackSize();
if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)
Offset = SPOffset + (int64_t)CalleeSavedStackSize;
else if (FrameReg == Mips::FP_NM)
Offset = SPOffset + 4096;
else
Offset = SPOffset + StackSize;

} else {

if (FrameReg == Mips::FP_NM)
Offset = SPOffset + 4096;
else
Offset = SPOffset + StackSize;
}

} else
Offset = SPOffset + (int64_t)StackSize;
Expand Down Expand Up @@ -258,7 +271,9 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
// TODO: This doesn't work well for nanoMIPS, because it has unsigned
// offsets and this check assumes signed.
if (OffsetBitSize < 16 && isInt<16>(Offset) &&
(!isIntN(OffsetBitSize, Offset) || !isAligned(OffsetAlign, Offset))) {
(STI.hasNanoMips() ? !isUIntN(OffsetBitSize, Offset)
: !isIntN(OffsetBitSize, Offset) ||
!isAligned(OffsetAlign, Offset))) {
// If we have an offset that needs to fit into a signed n-bit immediate
// (where n < 16) and doesn't, but does fit into 16-bits then use an ADDiu
MachineBasicBlock &MBB = *MI.getParent();
Expand Down
121 changes: 121 additions & 0 deletions llvm/test/CodeGen/Mips/nanomips/frame_pointer.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
; RUN: llc -mtriple=nanomips -asm-show-inst -verify-machineinstrs < %s | FileCheck %s

; Check if fp is set correctly if function wants to use it.
; We want it to point to -4096 from the beginning of the stack.
define void @test1(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) #0 {
entry:
; CHECK: save 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
; CHECK: addiu $fp, $sp, -4032
; CHECK: sw $a0, 32($sp)
; CHECK: restore.jrc 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
%d.addr = alloca i32, align 4
%e.addr = alloca i32, align 4
%f.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
store i32 %d, i32* %d.addr, align 4
store i32 %e, i32* %e.addr, align 4
store i32 %f, i32* %f.addr, align 4
call void asm sideeffect "", "~{$16},~{$17},~{$18},~{$19},~{$20},~{$1}"()

ret void
}

; Check if offsets after fp setup are relative to fp if varible-sized
; objects are present in function.
declare void @callee2(i8*)
define void @test2(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) #0 {
entry:
; CHECK: save 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
; CHECK: addiu $fp, $sp, -4032
; CHECK: sw $a0, 4064($fp)
; CHECK: restore.jrc 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
%d.addr = alloca i32, align 4
%e.addr = alloca i32, align 4
%f.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
store i32 %d, i32* %d.addr, align 4
store i32 %e, i32* %e.addr, align 4
store i32 %f, i32* %f.addr, align 4

%0 = alloca i8, i32 %a
call void @callee2(i8* %0)

call void asm sideeffect "", "~{$16},~{$17},~{$18},~{$19},~{$20},~{$1}"()

ret void
}

; Check if offsets after fp setup stays relative to sp if
; function needs stack realignment
declare void @callee3(i32*)
define void @test3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) #0 {
entry:
; CHECK: save 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
; CHECK: addiu $fp, $sp, -4032
; CHECK: sw $a0, 32($sp)
; CHECK: restore.jrc 64, $fp, $ra, $s0, $s1, $s2, $s3, $s4
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
%d.addr = alloca i32, align 4
%e.addr = alloca i32, align 4
%f.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
store i32 %d, i32* %d.addr, align 4
store i32 %e, i32* %e.addr, align 4
store i32 %f, i32* %f.addr, align 4

%0 = alloca i32, align 64
call void @callee3(i32 *%0)

call void asm sideeffect "", "~{$16},~{$17},~{$18},~{$19},~{$20},~{$1}"()

ret void
}

; Check if offsets after fp setup are relative to BasePtr if varible-sized
; objects are present in function and function needs stack realignment
declare void @callee4(i8*, i32*)
define void @test4(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) #0 {
entry:
; CHECK: save 192, $fp, $ra, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
; CHECK: addiu $fp, $sp, -3904
; CHECK: sw $a0, 148($s7)
; CHECK: restore.jrc 192, $fp, $ra, $s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%c.addr = alloca i32, align 4
%d.addr = alloca i32, align 4
%e.addr = alloca i32, align 4
%f.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
store i32 %c, i32* %c.addr, align 4
store i32 %d, i32* %d.addr, align 4
store i32 %e, i32* %e.addr, align 4
store i32 %f, i32* %f.addr, align 4

%0 = alloca i8, i32 %a
%1 = alloca i32, align 64
call void @callee4(i8* %0, i32 *%1)

call void asm sideeffect "", "~{$16},~{$17},~{$18},~{$19},~{$20},~{$1}"()

ret void
}

attributes #0 = {"frame-pointer"="all"}
!llvm.module.flags = !{!0}
!0 = !{i32 7, !"frame-pointer", i32 2}
13 changes: 13 additions & 0 deletions llvm/test/CodeGen/Mips/nanomips/stack_realignment.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; RUN: llc -mtriple=nanomips -asm-show-inst -verify-machineinstrs < %s | FileCheck %s

; Check if stack realignment is done using INS instruction
; if function needs it.
declare void @callee(i32*)
define void @test() {
entry:
; CHECK: ins $sp, $zero, 0, 6
%0 = alloca i32, align 64
call void @callee(i32 *%0)
ret void
}

22 changes: 0 additions & 22 deletions llvm/test/CodeGen/Mips/nanomips/two-step-stack-setup.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,3 @@ define void @test1() {
; CHECK: addiu $sp, $sp, 4096
; CHECK: restore.jrc 32, $s0, $s1, $s2, $s3, $s4
}

; Check if there are two instructions for storing sp in fp
; if function uses fp and two-step stack setup is present
define void @test2() #0 {
; CHECK: save 32, $fp, $ra, $s0, $s1, $s2, $s3, $s4
; CHECK: or $fp, $sp, $zero
; CHECK: addiu $sp, $sp, -4096
; CHECK: or $fp, $sp, $zero
%foo = alloca [4096 x i8], align 1
%1 = getelementptr inbounds [4096 x i8], [4096 x i8]* %foo, i32 0, i32 0
call void asm sideeffect "", "r,~{$16},~{$17},~{$18},~{$19},~{$20},~{$1}"(i8* %1)
ret void
; CHECK: addiu $sp, $sp, 4096
; CHECK: restore.jrc 32, $fp, $ra, $s0, $s1, $s2, $s3, $s4
}

attributes #0 = { "frame-pointer"="all"}

!llvm.module.flags = !{!0}

!0 = !{i32 7, !"frame-pointer", i32 2}

0 comments on commit fc5fa13

Please sign in to comment.