blob: b83c957d7c47095e0222435de5c03781782ab113 [file] [log] [blame]
//===------ CFIInstrInserter.cpp - Insert additional CFI instructions -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Insert CFI instructions at the beginnings of basic blocks if needed. CFI
// instructions are inserted if basic blocks have incorrect offset or register
// set by prevoius blocks.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
namespace {
class CFIInstrInserter : public MachineFunctionPass {
public:
CFIInstrInserter() : MachineFunctionPass(ID) {
initializeCFIInstrInserterPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
static char ID;
private:
StringRef getPassName() const override { return "CFI Instruction Inserter"; }
// Check if incoming CFI information of a basic block matches outgoing CFI
// information of the previous block. If it doesn't, insert CFI instruction at
// the beginning of the block that corrects the CFA calculation rule for that
// block.
void CorrectCFA(MachineFunction &MF);
// Return the cfa offset value that should be set at the beginning of MBB if
// needed. The negated value is needed when creating CFI instructions that set
// absolute offset.
int getCorrectCFAOffset(MachineBasicBlock &MBB) {
return -MBB.getIncomingCFAOffset();
}
// Were any CFI instructions inserted
bool InsertedCFIInstr = false;
};
}
char CFIInstrInserter::ID = 0;
INITIALIZE_PASS(CFIInstrInserter, "cfiinstrinserter",
"Check CFI info and insert CFI instructions if needed", false,
false)
FunctionPass *llvm::createCFIInstrInserter() { return new CFIInstrInserter(); }
bool CFIInstrInserter::runOnMachineFunction(MachineFunction &MF) {
bool NeedsDwarfCFI = (MF.getMMI().hasDebugInfo() ||
MF.getFunction()->needsUnwindTableEntry()) &&
(!MF.getTarget().getTargetTriple().isOSDarwin() &&
!MF.getTarget().getTargetTriple().isOSWindows());
if (!NeedsDwarfCFI) return false;
// Insert appropriate CFI instructions for each MBB if CFA calculation rule
// needs to be corrected for that MBB.
CorrectCFA(MF);
return InsertedCFIInstr;
}
void CFIInstrInserter::CorrectCFA(MachineFunction &MF) {
MachineBasicBlock &FirstMBB = MF.front();
MachineBasicBlock *PrevMBB = &FirstMBB;
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
InsertedCFIInstr = false;
for (auto &MBB : MF) {
// Skip the first MBB in a function
if (MBB.getNumber() == FirstMBB.getNumber()) continue;
auto MBBI = MBB.begin();
DebugLoc DL = MBB.findDebugLoc(MBBI);
if (PrevMBB->getOutgoingCFAOffset() != MBB.getIncomingCFAOffset()) {
// If both outgoing offset and register of a previous block don't match
// incoming offset and register of this block, add a def_cfa instruction
// with the correct offset and register for this block.
if (PrevMBB->getOutgoingCFARegister() != MBB.getIncomingCFARegister()) {
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
nullptr, MBB.getIncomingCFARegister(), getCorrectCFAOffset(MBB)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// If outgoing offset of a previous block doesn't match incoming offset
// of this block, add a def_cfa_offset instruction with the correct
// offset for this block.
} else {
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(
nullptr, getCorrectCFAOffset(MBB)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
InsertedCFIInstr = true;
// If outgoing register of a previous block doesn't match incoming
// register of this block, add a def_cfa_register instruction with the
// correct register for this block.
} else if (PrevMBB->getOutgoingCFARegister() !=
MBB.getIncomingCFARegister()) {
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
nullptr, MBB.getIncomingCFARegister()));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
InsertedCFIInstr = true;
}
PrevMBB = &MBB;
}
}