/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/CodeGen/CFIInstrInserter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===------ CFIInstrInserter.cpp - Insert additional CFI instructions -----===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | /// \file This pass verifies incoming and outgoing CFA information of basic |
10 | | /// blocks. CFA information is information about offset and register set by CFI |
11 | | /// directives, valid at the start and end of a basic block. This pass checks |
12 | | /// that outgoing information of predecessors matches incoming information of |
13 | | /// their successors. Then it checks if blocks have correct CFA calculation rule |
14 | | /// set and inserts additional CFI instruction at their beginnings if they |
15 | | /// don't. CFI instructions are inserted if basic blocks have incorrect offset |
16 | | /// or register set by previous blocks, as a result of a non-linear layout of |
17 | | /// blocks in a function. |
18 | | //===----------------------------------------------------------------------===// |
19 | | |
20 | | #include "llvm/ADT/DepthFirstIterator.h" |
21 | | #include "llvm/CodeGen/MachineFunctionPass.h" |
22 | | #include "llvm/CodeGen/MachineInstrBuilder.h" |
23 | | #include "llvm/CodeGen/MachineModuleInfo.h" |
24 | | #include "llvm/CodeGen/Passes.h" |
25 | | #include "llvm/CodeGen/TargetFrameLowering.h" |
26 | | #include "llvm/CodeGen/TargetInstrInfo.h" |
27 | | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
28 | | #include "llvm/Target/TargetMachine.h" |
29 | | using namespace llvm; |
30 | | |
31 | | static cl::opt<bool> VerifyCFI("verify-cfiinstrs", |
32 | | cl::desc("Verify Call Frame Information instructions"), |
33 | | cl::init(false), |
34 | | cl::Hidden); |
35 | | |
36 | | namespace { |
37 | | class CFIInstrInserter : public MachineFunctionPass { |
38 | | public: |
39 | | static char ID; |
40 | | |
41 | 6.79k | CFIInstrInserter() : MachineFunctionPass(ID) { |
42 | 6.79k | initializeCFIInstrInserterPass(*PassRegistry::getPassRegistry()); |
43 | 6.79k | } |
44 | | |
45 | 6.73k | void getAnalysisUsage(AnalysisUsage &AU) const override { |
46 | 6.73k | AU.setPreservesAll(); |
47 | 6.73k | MachineFunctionPass::getAnalysisUsage(AU); |
48 | 6.73k | } |
49 | | |
50 | 96.4k | bool runOnMachineFunction(MachineFunction &MF) override { |
51 | 96.4k | if (!MF.getMMI().hasDebugInfo() && |
52 | 96.4k | !MF.getFunction().needsUnwindTableEntry()95.4k ) |
53 | 29.6k | return false; |
54 | 66.7k | |
55 | 66.7k | MBBVector.resize(MF.getNumBlockIDs()); |
56 | 66.7k | calculateCFAInfo(MF); |
57 | 66.7k | |
58 | 66.7k | if (VerifyCFI) { |
59 | 4 | if (unsigned ErrorNum = verify(MF)) |
60 | 2 | report_fatal_error("Found " + Twine(ErrorNum) + |
61 | 2 | " in/out CFI information errors."); |
62 | 66.7k | } |
63 | 66.7k | bool insertedCFI = insertCFIInstrs(MF); |
64 | 66.7k | MBBVector.clear(); |
65 | 66.7k | return insertedCFI; |
66 | 66.7k | } |
67 | | |
68 | | private: |
69 | | struct MBBCFAInfo { |
70 | | MachineBasicBlock *MBB; |
71 | | /// Value of cfa offset valid at basic block entry. |
72 | | int IncomingCFAOffset = -1; |
73 | | /// Value of cfa offset valid at basic block exit. |
74 | | int OutgoingCFAOffset = -1; |
75 | | /// Value of cfa register valid at basic block entry. |
76 | | unsigned IncomingCFARegister = 0; |
77 | | /// Value of cfa register valid at basic block exit. |
78 | | unsigned OutgoingCFARegister = 0; |
79 | | /// If in/out cfa offset and register values for this block have already |
80 | | /// been set or not. |
81 | | bool Processed = false; |
82 | | }; |
83 | | |
84 | | /// Contains cfa offset and register values valid at entry and exit of basic |
85 | | /// blocks. |
86 | | std::vector<MBBCFAInfo> MBBVector; |
87 | | |
88 | | /// Calculate cfa offset and register values valid at entry and exit for all |
89 | | /// basic blocks in a function. |
90 | | void calculateCFAInfo(MachineFunction &MF); |
91 | | /// Calculate cfa offset and register values valid at basic block exit by |
92 | | /// checking the block for CFI instructions. Block's incoming CFA info remains |
93 | | /// the same. |
94 | | void calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo); |
95 | | /// Update in/out cfa offset and register values for successors of the basic |
96 | | /// block. |
97 | | void updateSuccCFAInfo(MBBCFAInfo &MBBInfo); |
98 | | |
99 | | /// Check if incoming CFA information of a basic block matches outgoing CFA |
100 | | /// information of the previous block. If it doesn't, insert CFI instruction |
101 | | /// at the beginning of the block that corrects the CFA calculation rule for |
102 | | /// that block. |
103 | | bool insertCFIInstrs(MachineFunction &MF); |
104 | | /// Return the cfa offset value that should be set at the beginning of a MBB |
105 | | /// if needed. The negated value is needed when creating CFI instructions that |
106 | | /// set absolute offset. |
107 | 505 | int getCorrectCFAOffset(MachineBasicBlock *MBB) { |
108 | 505 | return -MBBVector[MBB->getNumber()].IncomingCFAOffset; |
109 | 505 | } |
110 | | |
111 | | void report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); |
112 | | /// Go through each MBB in a function and check that outgoing offset and |
113 | | /// register of its predecessors match incoming offset and register of that |
114 | | /// MBB, as well as that incoming offset and register of its successors match |
115 | | /// outgoing offset and register of the MBB. |
116 | | unsigned verify(MachineFunction &MF); |
117 | | }; |
118 | | } // namespace |
119 | | |
120 | | char CFIInstrInserter::ID = 0; |
121 | | INITIALIZE_PASS(CFIInstrInserter, "cfi-instr-inserter", |
122 | | "Check CFA info and insert CFI instructions if needed", false, |
123 | | false) |
124 | 6.78k | FunctionPass *llvm::createCFIInstrInserter() { return new CFIInstrInserter(); } |
125 | | |
126 | 66.7k | void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) { |
127 | 66.7k | // Initial CFA offset value i.e. the one valid at the beginning of the |
128 | 66.7k | // function. |
129 | 66.7k | int InitialOffset = |
130 | 66.7k | MF.getSubtarget().getFrameLowering()->getInitialCFAOffset(MF); |
131 | 66.7k | // Initial CFA register value i.e. the one valid at the beginning of the |
132 | 66.7k | // function. |
133 | 66.7k | unsigned InitialRegister = |
134 | 66.7k | MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF); |
135 | 66.7k | |
136 | 66.7k | // Initialize MBBMap. |
137 | 78.6k | for (MachineBasicBlock &MBB : MF) { |
138 | 78.6k | MBBCFAInfo MBBInfo; |
139 | 78.6k | MBBInfo.MBB = &MBB; |
140 | 78.6k | MBBInfo.IncomingCFAOffset = InitialOffset; |
141 | 78.6k | MBBInfo.OutgoingCFAOffset = InitialOffset; |
142 | 78.6k | MBBInfo.IncomingCFARegister = InitialRegister; |
143 | 78.6k | MBBInfo.OutgoingCFARegister = InitialRegister; |
144 | 78.6k | MBBVector[MBB.getNumber()] = MBBInfo; |
145 | 78.6k | } |
146 | 66.7k | |
147 | 66.7k | // Set in/out cfa info for all blocks in the function. This traversal is based |
148 | 66.7k | // on the assumption that the first block in the function is the entry block |
149 | 66.7k | // i.e. that it has initial cfa offset and register values as incoming CFA |
150 | 66.7k | // information. |
151 | 78.6k | for (MachineBasicBlock &MBB : MF) { |
152 | 78.6k | if (MBBVector[MBB.getNumber()].Processed) continue11.9k ; |
153 | 66.7k | updateSuccCFAInfo(MBBVector[MBB.getNumber()]); |
154 | 66.7k | } |
155 | 66.7k | } |
156 | | |
157 | 78.6k | void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) { |
158 | 78.6k | // Outgoing cfa offset set by the block. |
159 | 78.6k | int SetOffset = MBBInfo.IncomingCFAOffset; |
160 | 78.6k | // Outgoing cfa register set by the block. |
161 | 78.6k | unsigned SetRegister = MBBInfo.IncomingCFARegister; |
162 | 78.6k | const std::vector<MCCFIInstruction> &Instrs = |
163 | 78.6k | MBBInfo.MBB->getParent()->getFrameInstructions(); |
164 | 78.6k | |
165 | 78.6k | // Determine cfa offset and register set by the block. |
166 | 447k | for (MachineInstr &MI : *MBBInfo.MBB) { |
167 | 447k | if (MI.isCFIInstruction()) { |
168 | 17.6k | unsigned CFIIndex = MI.getOperand(0).getCFIIndex(); |
169 | 17.6k | const MCCFIInstruction &CFI = Instrs[CFIIndex]; |
170 | 17.6k | switch (CFI.getOperation()) { |
171 | 17.6k | case MCCFIInstruction::OpDefCfaRegister: |
172 | 715 | SetRegister = CFI.getRegister(); |
173 | 715 | break; |
174 | 17.6k | case MCCFIInstruction::OpDefCfaOffset: |
175 | 10.6k | SetOffset = CFI.getOffset(); |
176 | 10.6k | break; |
177 | 17.6k | case MCCFIInstruction::OpAdjustCfaOffset: |
178 | 1.66k | SetOffset += CFI.getOffset(); |
179 | 1.66k | break; |
180 | 17.6k | case MCCFIInstruction::OpDefCfa: |
181 | 708 | SetRegister = CFI.getRegister(); |
182 | 708 | SetOffset = CFI.getOffset(); |
183 | 708 | break; |
184 | 17.6k | case MCCFIInstruction::OpRememberState: |
185 | 0 | // TODO: Add support for handling cfi_remember_state. |
186 | | #ifndef NDEBUG |
187 | | report_fatal_error( |
188 | | "Support for cfi_remember_state not implemented! Value of CFA " |
189 | | "may be incorrect!\n"); |
190 | | #endif |
191 | | break; |
192 | 17.6k | case MCCFIInstruction::OpRestoreState: |
193 | 0 | // TODO: Add support for handling cfi_restore_state. |
194 | | #ifndef NDEBUG |
195 | | report_fatal_error( |
196 | | "Support for cfi_restore_state not implemented! Value of CFA may " |
197 | | "be incorrect!\n"); |
198 | | #endif |
199 | | break; |
200 | 17.6k | // Other CFI directives do not affect CFA value. |
201 | 17.6k | case MCCFIInstruction::OpSameValue: |
202 | 3.86k | case MCCFIInstruction::OpOffset: |
203 | 3.86k | case MCCFIInstruction::OpRelOffset: |
204 | 3.86k | case MCCFIInstruction::OpEscape: |
205 | 3.86k | case MCCFIInstruction::OpRestore: |
206 | 3.86k | case MCCFIInstruction::OpUndefined: |
207 | 3.86k | case MCCFIInstruction::OpRegister: |
208 | 3.86k | case MCCFIInstruction::OpWindowSave: |
209 | 3.86k | case MCCFIInstruction::OpNegateRAState: |
210 | 3.86k | case MCCFIInstruction::OpGnuArgsSize: |
211 | 3.86k | break; |
212 | 17.6k | } |
213 | 17.6k | } |
214 | 447k | } |
215 | 78.6k | |
216 | 78.6k | MBBInfo.Processed = true; |
217 | 78.6k | |
218 | 78.6k | // Update outgoing CFA info. |
219 | 78.6k | MBBInfo.OutgoingCFAOffset = SetOffset; |
220 | 78.6k | MBBInfo.OutgoingCFARegister = SetRegister; |
221 | 78.6k | } |
222 | | |
223 | 66.7k | void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) { |
224 | 66.7k | SmallVector<MachineBasicBlock *, 4> Stack; |
225 | 66.7k | Stack.push_back(MBBInfo.MBB); |
226 | 66.7k | |
227 | 79.1k | do { |
228 | 79.1k | MachineBasicBlock *Current = Stack.pop_back_val(); |
229 | 79.1k | MBBCFAInfo &CurrentInfo = MBBVector[Current->getNumber()]; |
230 | 79.1k | if (CurrentInfo.Processed) |
231 | 467 | continue; |
232 | 78.6k | |
233 | 78.6k | calculateOutgoingCFAInfo(CurrentInfo); |
234 | 78.6k | for (auto *Succ : CurrentInfo.MBB->successors()) { |
235 | 17.3k | MBBCFAInfo &SuccInfo = MBBVector[Succ->getNumber()]; |
236 | 17.3k | if (!SuccInfo.Processed) { |
237 | 12.3k | SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset; |
238 | 12.3k | SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister; |
239 | 12.3k | Stack.push_back(Succ); |
240 | 12.3k | } |
241 | 17.3k | } |
242 | 79.1k | } while (!Stack.empty()); |
243 | 66.7k | } |
244 | | |
245 | 66.7k | bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) { |
246 | 66.7k | const MBBCFAInfo *PrevMBBInfo = &MBBVector[MF.front().getNumber()]; |
247 | 66.7k | const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); |
248 | 66.7k | bool InsertedCFIInstr = false; |
249 | 66.7k | |
250 | 78.6k | for (MachineBasicBlock &MBB : MF) { |
251 | 78.6k | // Skip the first MBB in a function |
252 | 78.6k | if (MBB.getNumber() == MF.front().getNumber()) continue66.7k ; |
253 | 11.9k | |
254 | 11.9k | const MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()]; |
255 | 11.9k | auto MBBI = MBBInfo.MBB->begin(); |
256 | 11.9k | DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI); |
257 | 11.9k | |
258 | 11.9k | if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) { |
259 | 505 | // If both outgoing offset and register of a previous block don't match |
260 | 505 | // incoming offset and register of this block, add a def_cfa instruction |
261 | 505 | // with the correct offset and register for this block. |
262 | 505 | if (PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) { |
263 | 46 | unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( |
264 | 46 | nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB))); |
265 | 46 | BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
266 | 46 | .addCFIIndex(CFIIndex); |
267 | 46 | // If outgoing offset of a previous block doesn't match incoming offset |
268 | 46 | // of this block, add a def_cfa_offset instruction with the correct |
269 | 46 | // offset for this block. |
270 | 459 | } else { |
271 | 459 | unsigned CFIIndex = |
272 | 459 | MF.addFrameInst(MCCFIInstruction::createDefCfaOffset( |
273 | 459 | nullptr, getCorrectCFAOffset(&MBB))); |
274 | 459 | BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
275 | 459 | .addCFIIndex(CFIIndex); |
276 | 459 | } |
277 | 505 | InsertedCFIInstr = true; |
278 | 505 | // If outgoing register of a previous block doesn't match incoming |
279 | 505 | // register of this block, add a def_cfa_register instruction with the |
280 | 505 | // correct register for this block. |
281 | 11.4k | } else if (PrevMBBInfo->OutgoingCFARegister != |
282 | 11.4k | MBBInfo.IncomingCFARegister) { |
283 | 2 | unsigned CFIIndex = |
284 | 2 | MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( |
285 | 2 | nullptr, MBBInfo.IncomingCFARegister)); |
286 | 2 | BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) |
287 | 2 | .addCFIIndex(CFIIndex); |
288 | 2 | InsertedCFIInstr = true; |
289 | 2 | } |
290 | 11.9k | PrevMBBInfo = &MBBInfo; |
291 | 11.9k | } |
292 | 66.7k | return InsertedCFIInstr; |
293 | 66.7k | } |
294 | | |
295 | 2 | void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) { |
296 | 2 | errs() << "*** Inconsistent CFA register and/or offset between pred and succ " |
297 | 2 | "***\n"; |
298 | 2 | errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() |
299 | 2 | << " in " << Pred.MBB->getParent()->getName() |
300 | 2 | << " outgoing CFA Reg:" << Pred.OutgoingCFARegister << "\n"; |
301 | 2 | errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() |
302 | 2 | << " in " << Pred.MBB->getParent()->getName() |
303 | 2 | << " outgoing CFA Offset:" << Pred.OutgoingCFAOffset << "\n"; |
304 | 2 | errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() |
305 | 2 | << " incoming CFA Reg:" << Succ.IncomingCFARegister << "\n"; |
306 | 2 | errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() |
307 | 2 | << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n"; |
308 | 2 | } |
309 | | |
310 | 4 | unsigned CFIInstrInserter::verify(MachineFunction &MF) { |
311 | 4 | unsigned ErrorNum = 0; |
312 | 13 | for (auto *CurrMBB : depth_first(&MF)) { |
313 | 13 | const MBBCFAInfo &CurrMBBInfo = MBBVector[CurrMBB->getNumber()]; |
314 | 13 | for (MachineBasicBlock *Succ : CurrMBB->successors()) { |
315 | 13 | const MBBCFAInfo &SuccMBBInfo = MBBVector[Succ->getNumber()]; |
316 | 13 | // Check that incoming offset and register values of successors match the |
317 | 13 | // outgoing offset and register values of CurrMBB |
318 | 13 | if (SuccMBBInfo.IncomingCFAOffset != CurrMBBInfo.OutgoingCFAOffset || |
319 | 13 | SuccMBBInfo.IncomingCFARegister != CurrMBBInfo.OutgoingCFARegister11 ) { |
320 | 3 | // Inconsistent offsets/registers are ok for 'noreturn' blocks because |
321 | 3 | // we don't generate epilogues inside such blocks. |
322 | 3 | if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock()) |
323 | 1 | continue; |
324 | 2 | report(CurrMBBInfo, SuccMBBInfo); |
325 | 2 | ErrorNum++; |
326 | 2 | } |
327 | 13 | } |
328 | 13 | } |
329 | 4 | return ErrorNum; |
330 | 4 | } |