summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/CFIInstrInserter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/CFIInstrInserter.cpp')
-rw-r--r--llvm/lib/CodeGen/CFIInstrInserter.cpp124
1 files changed, 124 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
new file mode 100644
index 00000000000..b83c957d7c4
--- /dev/null
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -0,0 +1,124 @@
+//===------ 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;
+ }
+}
OpenPOWER on IntegriCloud