Skip to content

Commit

Permalink
[RISCV] Add CFI directives for RISCV prologue/epilog.
Browse files Browse the repository at this point in the history
In order to generate correct debug frame information, it needs to
generate CFI information in prologue and epilog.

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363120 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
hsiangkai committed Jun 12, 2019
1 parent 6a69c52 commit f0bb8b8
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 4 deletions.
1 change: 1 addition & 0 deletions lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT) {
CommentString = "#";
AlignmentIsInBytes = false;
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::DwarfCFI;
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
}
8 changes: 7 additions & 1 deletion lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) {

static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI,
const Triple &TT) {
return new RISCVMCAsmInfo(TT);
MCAsmInfo *MAI = new RISCVMCAsmInfo(TT);

unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true);
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, SP, 0);
MAI->addInitialFrameState(Inst);

return MAI;
}

static MCSubtargetInfo *createRISCVMCSubtargetInfo(const Triple &TT,
Expand Down
73 changes: 70 additions & 3 deletions lib/Target/RISCV/RISCVFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/MC/MCDwarf.h"

using namespace llvm;

Expand Down Expand Up @@ -96,6 +97,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,

MachineFrameInfo &MFI = MF.getFrameInfo();
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
const RISCVRegisterInfo *RI = STI.getRegisterInfo();
const RISCVInstrInfo *TII = STI.getInstrInfo();
MachineBasicBlock::iterator MBBI = MBB.begin();

unsigned FPReg = getFPReg(STI);
Expand All @@ -119,6 +122,12 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
// Allocate space on the stack if necessary.
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);

// Emit ".cfi_def_cfa_offset StackSize"
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);

// The frame pointer is callee-saved, and code has been generated for us to
// save it to the stack. We need to skip over the storing of callee-saved
// registers as the frame pointer must be modified after it has been saved
Expand All @@ -128,10 +137,28 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
std::advance(MBBI, CSI.size());

// Iterate over list of callee-saved registers and emit .cfi_offset
// directives.
for (const auto &Entry : CSI) {
int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
unsigned Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, RI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}

// Generate new FP.
if (hasFP(MF))
if (hasFP(MF)) {
adjustReg(MBB, MBBI, DL, FPReg, SPReg,
StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup);

// Emit ".cfi_def_cfa $fp, 0"
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
nullptr, RI->getDwarfRegNum(FPReg, true), 0));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
}

void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
Expand All @@ -141,6 +168,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
MachineFrameInfo &MFI = MF.getFrameInfo();
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
DebugLoc DL = MBBI->getDebugLoc();
const RISCVInstrInfo *TII = STI.getInstrInfo();
unsigned FPReg = getFPReg(STI);
unsigned SPReg = getSPReg(STI);

Expand All @@ -150,19 +178,58 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size());

uint64_t StackSize = MFI.getStackSize();
uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize();

// Restore the stack pointer using the value of the frame pointer. Only
// necessary if the stack pointer was modified, meaning the stack size is
// unknown.
if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) {
assert(hasFP(MF) && "frame pointer should not have been eliminated");
adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg,
-StackSize + RVFI->getVarArgsSaveSize(),
adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset,
MachineInstr::FrameDestroy);
}

if (hasFP(MF)) {
// To find the instruction restoring FP from stack.
for (auto &I = LastFrameDestroy; I != MBBI; ++I) {
if (I->mayLoad() && I->getOperand(0).isReg()) {
unsigned DestReg = I->getOperand(0).getReg();
if (DestReg == FPReg) {
// If there is frame pointer, after restoring $fp registers, we
// need adjust CFA to ($sp - FPOffset).
// Emit ".cfi_def_cfa $sp, -FPOffset"
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
nullptr, RI->getDwarfRegNum(SPReg, true), -FPOffset));
BuildMI(MBB, std::next(I), DL,
TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
break;
}
}
}
}

// Add CFI directives for callee-saved registers.
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// Iterate over list of callee-saved registers and emit .cfi_restore
// directives.
for (const auto &Entry : CSI) {
unsigned Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore(
nullptr, RI->getDwarfRegNum(Reg, true)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}

// Deallocate stack
adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);

// After restoring $sp, we need to adjust CFA to $(sp + 0)
// Emit ".cfi_def_cfa_offset 0"
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}

int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
Expand Down
66 changes: 66 additions & 0 deletions test/CodeGen/RISCV/frame-info.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32 %s
; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64 %s

define void @foo(i32 signext %size) {
; RV32-LABEL: foo:
; RV32: # %bb.0: # %entry
; RV32-NEXT: addi sp, sp, -16
; RV32-NEXT: .cfi_def_cfa_offset 16
; RV32-NEXT: sw ra, 12(sp)
; RV32-NEXT: sw s0, 8(sp)
; RV32-NEXT: .cfi_offset ra, -4
; RV32-NEXT: .cfi_offset s0, -8
; RV32-NEXT: addi s0, sp, 16
; RV32-NEXT: .cfi_def_cfa s0, 0
; RV32-NEXT: addi a0, a0, 15
; RV32-NEXT: andi a0, a0, -16
; RV32-NEXT: sub a0, sp, a0
; RV32-NEXT: mv sp, a0
; RV32-NEXT: call bar
; RV32-NEXT: addi sp, s0, -16
; RV32-NEXT: lw s0, 8(sp)
; RV32-NEXT: .cfi_def_cfa sp, 16
; RV32-NEXT: lw ra, 12(sp)
; RV32-NEXT: .cfi_restore ra
; RV32-NEXT: .cfi_restore s0
; RV32-NEXT: addi sp, sp, 16
; RV32-NEXT: .cfi_def_cfa_offset 0
; RV32-NEXT: ret
;
; RV64-LABEL: foo:
; RV64: # %bb.0: # %entry
; RV64-NEXT: addi sp, sp, -16
; RV64-NEXT: .cfi_def_cfa_offset 16
; RV64-NEXT: sd ra, 8(sp)
; RV64-NEXT: sd s0, 0(sp)
; RV64-NEXT: .cfi_offset ra, -8
; RV64-NEXT: .cfi_offset s0, -16
; RV64-NEXT: addi s0, sp, 16
; RV64-NEXT: .cfi_def_cfa s0, 0
; RV64-NEXT: addi a1, zero, 1
; RV64-NEXT: slli a1, a1, 33
; RV64-NEXT: addi a1, a1, -16
; RV64-NEXT: slli a0, a0, 32
; RV64-NEXT: srli a0, a0, 32
; RV64-NEXT: addi a0, a0, 15
; RV64-NEXT: and a0, a0, a1
; RV64-NEXT: sub a0, sp, a0
; RV64-NEXT: mv sp, a0
; RV64-NEXT: call bar
; RV64-NEXT: addi sp, s0, -16
; RV64-NEXT: ld s0, 0(sp)
; RV64-NEXT: .cfi_def_cfa sp, 16
; RV64-NEXT: ld ra, 8(sp)
; RV64-NEXT: .cfi_restore ra
; RV64-NEXT: .cfi_restore s0
; RV64-NEXT: addi sp, sp, 16
; RV64-NEXT: .cfi_def_cfa_offset 0
; RV64-NEXT: ret
entry:
%0 = alloca i8, i32 %size, align 16
call void @bar(i8* nonnull %0) #2
ret void
}

declare void @bar(i8*)

0 comments on commit f0bb8b8

Please sign in to comment.