summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/CFIInstrInserter.cpp
blob: b83c957d7c47095e0222435de5c03781782ab113 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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