Skip to content

Commit

Permalink
[RISCV] Preserve stack space for outgoing arguments when the function…
Browse files Browse the repository at this point in the history
… contain variable size objects

E.g.

bar (int x)
{
  char p[x];

  push outgoing variables for foo.
  call foo
}

We need to generate stack adjustment instructions for outgoing arguments by
eliminateCallFramePseudoInstr when the function contains variable size
objects to avoid outgoing variables corrupt the variable size object.

Default hasReservedCallFrame will return !hasFP().
We don't want to generate extra sp adjustment instructions when hasFP()
return true, So We override hasReservedCallFrame as !hasVarSizedObjects().

Differential Revision: https://reviews.llvm.org/D43752

llvm-svn: 327938
  • Loading branch information
ShivaChen committed Mar 20, 2018
1 parent 2330d6c commit cbd498a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 25 deletions.
51 changes: 36 additions & 15 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Expand Up @@ -43,21 +43,6 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
uint64_t StackAlign = RI->needsStackRealignment(MF) ? MFI.getMaxAlignment()
: getStackAlignment();

// Get the maximum call frame size of all the calls.
uint64_t MaxCallFrameSize = MFI.getMaxCallFrameSize();

// If we have dynamic alloca then MaxCallFrameSize needs to be aligned so
// that allocations will be aligned.
if (MFI.hasVarSizedObjects())
MaxCallFrameSize = alignTo(MaxCallFrameSize, StackAlign);

// Update maximum call frame size.
MFI.setMaxCallFrameSize(MaxCallFrameSize);

// Include call frame size in total.
if (!(hasReservedCallFrame(MF) && MFI.adjustsStack()))
FrameSize += MaxCallFrameSize;

// Make sure the frame is aligned.
FrameSize = alignTo(FrameSize, StackAlign);

Expand Down Expand Up @@ -246,3 +231,39 @@ void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
RS->addScavengingFrameIndex(RegScavFI);
}
}

// Not preserve stack space within prologue for outgoing variables when the
// function contains variable size objects and let eliminateCallFramePseudoInstr
// preserve stack space for it.
bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
return !MF.getFrameInfo().hasVarSizedObjects();
}

// Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions.
MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr(
MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const {
unsigned SPReg = RISCV::X2;
DebugLoc DL = MI->getDebugLoc();

if (!hasReservedCallFrame(MF)) {
// If space has not been reserved for a call frame, ADJCALLSTACKDOWN and
// ADJCALLSTACKUP must be converted to instructions manipulating the stack
// pointer. This is necessary when there is a variable length stack
// allocation (e.g. alloca), which means it's not possible to allocate
// space for outgoing arguments from within the function prologue.
int64_t Amount = MI->getOperand(0).getImm();

if (Amount != 0) {
// Ensure the stack remains aligned after adjustment.
Amount = alignSPAdjust(Amount);

if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN)
Amount = -Amount;

adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
}
}

return MBB.erase(MI);
}
5 changes: 2 additions & 3 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.h
Expand Up @@ -41,11 +41,10 @@ class RISCVFrameLowering : public TargetFrameLowering {

bool hasFP(const MachineFunction &MF) const override;

bool hasReservedCallFrame(const MachineFunction &MF) const override;
MachineBasicBlock::iterator
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const override {
return MBB.erase(MI);
}
MachineBasicBlock::iterator MI) const override;

protected:
const RISCVSubtarget &STI;
Expand Down
46 changes: 46 additions & 0 deletions llvm/test/CodeGen/RISCV/alloca.ll
Expand Up @@ -63,3 +63,49 @@ define void @scoped_alloca(i32 %n) nounwind {
call void @llvm.stackrestore(i8* %sp)
ret void
}

declare void @func(i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)

; Check that outgoing arguments passed on the stack do not corrupt a
; variable-sized stack object.
define void @alloca_callframe(i32 %n) nounwind {
; RV32I-LABEL: alloca_callframe:
; RV32I: # %bb.0:
; RV32I-NEXT: addi sp, sp, -16
; RV32I-NEXT: sw ra, 12(sp)
; RV32I-NEXT: sw s0, 8(sp)
; RV32I-NEXT: addi s0, sp, 16
; RV32I-NEXT: addi a0, a0, 15
; RV32I-NEXT: andi a0, a0, -16
; RV32I-NEXT: sub a0, sp, a0
; RV32I-NEXT: mv sp, a0
; RV32I-NEXT: addi sp, sp, -16
; RV32I-NEXT: addi a1, zero, 12
; RV32I-NEXT: sw a1, 12(sp)
; RV32I-NEXT: addi a1, zero, 11
; RV32I-NEXT: sw a1, 8(sp)
; RV32I-NEXT: addi a1, zero, 10
; RV32I-NEXT: sw a1, 4(sp)
; RV32I-NEXT: addi a1, zero, 9
; RV32I-NEXT: sw a1, 0(sp)
; RV32I-NEXT: lui a1, %hi(func)
; RV32I-NEXT: addi t0, a1, %lo(func)
; RV32I-NEXT: addi a1, zero, 2
; RV32I-NEXT: addi a2, zero, 3
; RV32I-NEXT: addi a3, zero, 4
; RV32I-NEXT: addi a4, zero, 5
; RV32I-NEXT: addi a5, zero, 6
; RV32I-NEXT: addi a6, zero, 7
; RV32I-NEXT: addi a7, zero, 8
; RV32I-NEXT: jalr t0
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: addi sp, s0, -16
; RV32I-NEXT: lw s0, 8(sp)
; RV32I-NEXT: lw ra, 12(sp)
; RV32I-NEXT: addi sp, sp, 16
; RV32I-NEXT: ret
%1 = alloca i8, i32 %n
call void @func(i8* %1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8,
i32 9, i32 10, i32 11, i32 12)
ret void
}
14 changes: 7 additions & 7 deletions llvm/test/CodeGen/RISCV/calling-conv.ll
Expand Up @@ -504,10 +504,10 @@ define i32 @caller_many_scalars() nounwind {
;
; RV32I-WITHFP-LABEL: caller_many_scalars:
; RV32I-WITHFP: # %bb.0:
; RV32I-WITHFP-NEXT: addi sp, sp, -32
; RV32I-WITHFP-NEXT: sw ra, 28(sp)
; RV32I-WITHFP-NEXT: sw s0, 24(sp)
; RV32I-WITHFP-NEXT: addi s0, sp, 32
; RV32I-WITHFP-NEXT: addi sp, sp, -16
; RV32I-WITHFP-NEXT: sw ra, 12(sp)
; RV32I-WITHFP-NEXT: sw s0, 8(sp)
; RV32I-WITHFP-NEXT: addi s0, sp, 16
; RV32I-WITHFP-NEXT: addi a0, zero, 8
; RV32I-WITHFP-NEXT: sw a0, 4(sp)
; RV32I-WITHFP-NEXT: sw zero, 0(sp)
Expand All @@ -522,9 +522,9 @@ define i32 @caller_many_scalars() nounwind {
; RV32I-WITHFP-NEXT: addi a7, zero, 7
; RV32I-WITHFP-NEXT: mv a4, zero
; RV32I-WITHFP-NEXT: jalr t0
; RV32I-WITHFP-NEXT: lw s0, 24(sp)
; RV32I-WITHFP-NEXT: lw ra, 28(sp)
; RV32I-WITHFP-NEXT: addi sp, sp, 32
; RV32I-WITHFP-NEXT: lw s0, 8(sp)
; RV32I-WITHFP-NEXT: lw ra, 12(sp)
; RV32I-WITHFP-NEXT: addi sp, sp, 16
; RV32I-WITHFP-NEXT: ret
%1 = call i32 @callee_many_scalars(i8 1, i16 2, i32 3, i64 4, i32 5, i32 6, i64 7, i32 8)
ret i32 %1
Expand Down

0 comments on commit cbd498a

Please sign in to comment.