| //===------ 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; |
| } |
| } |