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/Passes.h" 24 #include "llvm/CodeGen/TargetFrameLowering.h" 25 #include "llvm/CodeGen/TargetInstrInfo.h" 26 #include "llvm/CodeGen/TargetSubtargetInfo.h" 27 #include "llvm/InitializePasses.h" 28 #include "llvm/MC/MCContext.h" 29 #include "llvm/MC/MCDwarf.h" 30 using namespace llvm; 31 32 static cl::opt<bool> VerifyCFI("verify-cfiinstrs", 33 cl::desc("Verify Call Frame Information instructions"), 34 cl::init(false), 35 cl::Hidden); 36 37 namespace { 38 class CFIInstrInserter : public MachineFunctionPass { 39 public: 40 static char ID; 41 42 CFIInstrInserter() : MachineFunctionPass(ID) { 43 initializeCFIInstrInserterPass(*PassRegistry::getPassRegistry()); 44 } 45 46 void getAnalysisUsage(AnalysisUsage &AU) const override { 47 AU.setPreservesAll(); 48 MachineFunctionPass::getAnalysisUsage(AU); 49 } 50 51 bool runOnMachineFunction(MachineFunction &MF) override { 52 if (!MF.needsFrameMoves()) 53 return false; 54 55 MBBVector.resize(MF.getNumBlockIDs()); 56 calculateCFAInfo(MF); 57 58 if (VerifyCFI) { 59 if (unsigned ErrorNum = verify(MF)) 60 report_fatal_error("Found " + Twine(ErrorNum) + 61 " in/out CFI information errors."); 62 } 63 bool insertedCFI = insertCFIInstrs(MF); 64 MBBVector.clear(); 65 return insertedCFI; 66 } 67 68 private: 69 struct MBBCFAInfo { 70 MachineBasicBlock *MBB; 71 /// Value of cfa offset valid at basic block entry. 72 int64_t IncomingCFAOffset = -1; 73 /// Value of cfa offset valid at basic block exit. 74 int64_t 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 /// Set of callee saved registers saved at basic block entry. 80 BitVector IncomingCSRSaved; 81 /// Set of callee saved registers saved at basic block exit. 82 BitVector OutgoingCSRSaved; 83 /// If in/out cfa offset and register values for this block have already 84 /// been set or not. 85 bool Processed = false; 86 }; 87 88 #define INVALID_REG UINT_MAX 89 #define INVALID_OFFSET INT_MAX 90 /// contains the location where CSR register is saved. 91 struct CSRSavedLocation { 92 CSRSavedLocation(std::optional<unsigned> R, std::optional<int> O) 93 : Reg(R), Offset(O) {} 94 std::optional<unsigned> Reg; 95 std::optional<int> Offset; 96 }; 97 98 /// Contains cfa offset and register values valid at entry and exit of basic 99 /// blocks. 100 std::vector<MBBCFAInfo> MBBVector; 101 102 /// Map the callee save registers to the locations where they are saved. 103 SmallDenseMap<unsigned, CSRSavedLocation, 16> CSRLocMap; 104 105 /// Calculate cfa offset and register values valid at entry and exit for all 106 /// basic blocks in a function. 107 void calculateCFAInfo(MachineFunction &MF); 108 /// Calculate cfa offset and register values valid at basic block exit by 109 /// checking the block for CFI instructions. Block's incoming CFA info remains 110 /// the same. 111 void calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo); 112 /// Update in/out cfa offset and register values for successors of the basic 113 /// block. 114 void updateSuccCFAInfo(MBBCFAInfo &MBBInfo); 115 116 /// Check if incoming CFA information of a basic block matches outgoing CFA 117 /// information of the previous block. If it doesn't, insert CFI instruction 118 /// at the beginning of the block that corrects the CFA calculation rule for 119 /// that block. 120 bool insertCFIInstrs(MachineFunction &MF); 121 /// Return the cfa offset value that should be set at the beginning of a MBB 122 /// if needed. The negated value is needed when creating CFI instructions that 123 /// set absolute offset. 124 int64_t getCorrectCFAOffset(MachineBasicBlock *MBB) { 125 return MBBVector[MBB->getNumber()].IncomingCFAOffset; 126 } 127 128 void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); 129 void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ); 130 /// Go through each MBB in a function and check that outgoing offset and 131 /// register of its predecessors match incoming offset and register of that 132 /// MBB, as well as that incoming offset and register of its successors match 133 /// outgoing offset and register of the MBB. 134 unsigned verify(MachineFunction &MF); 135 }; 136 } // namespace 137 138 char CFIInstrInserter::ID = 0; 139 INITIALIZE_PASS(CFIInstrInserter, "cfi-instr-inserter", 140 "Check CFA info and insert CFI instructions if needed", false, 141 false) 142 FunctionPass *llvm::createCFIInstrInserter() { return new CFIInstrInserter(); } 143 144 void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) { 145 const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); 146 // Initial CFA offset value i.e. the one valid at the beginning of the 147 // function. 148 int InitialOffset = 149 MF.getSubtarget().getFrameLowering()->getInitialCFAOffset(MF); 150 // Initial CFA register value i.e. the one valid at the beginning of the 151 // function. 152 Register InitialRegister = 153 MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF); 154 InitialRegister = TRI.getDwarfRegNum(InitialRegister, true); 155 unsigned NumRegs = TRI.getNumSupportedRegs(MF); 156 157 // Initialize MBBMap. 158 for (MachineBasicBlock &MBB : MF) { 159 MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()]; 160 MBBInfo.MBB = &MBB; 161 MBBInfo.IncomingCFAOffset = InitialOffset; 162 MBBInfo.OutgoingCFAOffset = InitialOffset; 163 MBBInfo.IncomingCFARegister = InitialRegister; 164 MBBInfo.OutgoingCFARegister = InitialRegister; 165 MBBInfo.IncomingCSRSaved.resize(NumRegs); 166 MBBInfo.OutgoingCSRSaved.resize(NumRegs); 167 } 168 CSRLocMap.clear(); 169 170 // Set in/out cfa info for all blocks in the function. This traversal is based 171 // on the assumption that the first block in the function is the entry block 172 // i.e. that it has initial cfa offset and register values as incoming CFA 173 // information. 174 updateSuccCFAInfo(MBBVector[MF.front().getNumber()]); 175 } 176 177 void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) { 178 // Outgoing cfa offset set by the block. 179 int64_t SetOffset = MBBInfo.IncomingCFAOffset; 180 // Outgoing cfa register set by the block. 181 unsigned SetRegister = MBBInfo.IncomingCFARegister; 182 MachineFunction *MF = MBBInfo.MBB->getParent(); 183 const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions(); 184 const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo(); 185 unsigned NumRegs = TRI.getNumSupportedRegs(*MF); 186 BitVector CSRSaved(NumRegs), CSRRestored(NumRegs); 187 188 #ifndef NDEBUG 189 int RememberState = 0; 190 #endif 191 192 // Determine cfa offset and register set by the block. 193 for (MachineInstr &MI : *MBBInfo.MBB) { 194 if (MI.isCFIInstruction()) { 195 std::optional<unsigned> CSRReg; 196 std::optional<int64_t> CSROffset; 197 unsigned CFIIndex = MI.getOperand(0).getCFIIndex(); 198 const MCCFIInstruction &CFI = Instrs[CFIIndex]; 199 switch (CFI.getOperation()) { 200 case MCCFIInstruction::OpDefCfaRegister: 201 SetRegister = CFI.getRegister(); 202 break; 203 case MCCFIInstruction::OpDefCfaOffset: 204 SetOffset = CFI.getOffset(); 205 break; 206 case MCCFIInstruction::OpAdjustCfaOffset: 207 SetOffset += CFI.getOffset(); 208 break; 209 case MCCFIInstruction::OpDefCfa: 210 SetRegister = CFI.getRegister(); 211 SetOffset = CFI.getOffset(); 212 break; 213 case MCCFIInstruction::OpOffset: 214 CSROffset = CFI.getOffset(); 215 break; 216 case MCCFIInstruction::OpRegister: 217 CSRReg = CFI.getRegister2(); 218 break; 219 case MCCFIInstruction::OpRelOffset: 220 CSROffset = CFI.getOffset() - SetOffset; 221 break; 222 case MCCFIInstruction::OpRestore: 223 CSRRestored.set(CFI.getRegister()); 224 break; 225 case MCCFIInstruction::OpLLVMDefAspaceCfa: 226 // TODO: Add support for handling cfi_def_aspace_cfa. 227 #ifndef NDEBUG 228 report_fatal_error( 229 "Support for cfi_llvm_def_aspace_cfa not implemented! Value of CFA " 230 "may be incorrect!\n"); 231 #endif 232 break; 233 case MCCFIInstruction::OpRememberState: 234 // TODO: Add support for handling cfi_remember_state. 235 #ifndef NDEBUG 236 // Currently we need cfi_remember_state and cfi_restore_state to be in 237 // the same BB, so it will not impact outgoing CFA. 238 ++RememberState; 239 if (RememberState != 1) 240 MF->getContext().reportError( 241 SMLoc(), 242 "Support for cfi_remember_state not implemented! Value of CFA " 243 "may be incorrect!\n"); 244 #endif 245 break; 246 case MCCFIInstruction::OpRestoreState: 247 // TODO: Add support for handling cfi_restore_state. 248 #ifndef NDEBUG 249 --RememberState; 250 if (RememberState != 0) 251 MF->getContext().reportError( 252 SMLoc(), 253 "Support for cfi_restore_state not implemented! Value of CFA may " 254 "be incorrect!\n"); 255 #endif 256 break; 257 // Other CFI directives do not affect CFA value. 258 case MCCFIInstruction::OpUndefined: 259 case MCCFIInstruction::OpSameValue: 260 case MCCFIInstruction::OpEscape: 261 case MCCFIInstruction::OpWindowSave: 262 case MCCFIInstruction::OpNegateRAState: 263 case MCCFIInstruction::OpGnuArgsSize: 264 case MCCFIInstruction::OpLabel: 265 break; 266 } 267 if (CSRReg || CSROffset) { 268 auto It = CSRLocMap.find(CFI.getRegister()); 269 if (It == CSRLocMap.end()) { 270 CSRLocMap.insert( 271 {CFI.getRegister(), CSRSavedLocation(CSRReg, CSROffset)}); 272 } else if (It->second.Reg != CSRReg || It->second.Offset != CSROffset) { 273 llvm_unreachable("Different saved locations for the same CSR"); 274 } 275 CSRSaved.set(CFI.getRegister()); 276 } 277 } 278 } 279 280 #ifndef NDEBUG 281 if (RememberState != 0) 282 MF->getContext().reportError( 283 SMLoc(), 284 "Support for cfi_remember_state not implemented! Value of CFA may be " 285 "incorrect!\n"); 286 #endif 287 288 MBBInfo.Processed = true; 289 290 // Update outgoing CFA info. 291 MBBInfo.OutgoingCFAOffset = SetOffset; 292 MBBInfo.OutgoingCFARegister = SetRegister; 293 294 // Update outgoing CSR info. 295 BitVector::apply([](auto x, auto y, auto z) { return (x | y) & ~z; }, 296 MBBInfo.OutgoingCSRSaved, MBBInfo.IncomingCSRSaved, CSRSaved, 297 CSRRestored); 298 } 299 300 void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) { 301 SmallVector<MachineBasicBlock *, 4> Stack; 302 Stack.push_back(MBBInfo.MBB); 303 304 do { 305 MachineBasicBlock *Current = Stack.pop_back_val(); 306 MBBCFAInfo &CurrentInfo = MBBVector[Current->getNumber()]; 307 calculateOutgoingCFAInfo(CurrentInfo); 308 for (auto *Succ : CurrentInfo.MBB->successors()) { 309 MBBCFAInfo &SuccInfo = MBBVector[Succ->getNumber()]; 310 if (!SuccInfo.Processed) { 311 SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset; 312 SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister; 313 SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved; 314 Stack.push_back(Succ); 315 } 316 } 317 } while (!Stack.empty()); 318 } 319 320 bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) { 321 const MBBCFAInfo *PrevMBBInfo = &MBBVector[MF.front().getNumber()]; 322 const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 323 bool InsertedCFIInstr = false; 324 325 BitVector SetDifference; 326 for (MachineBasicBlock &MBB : MF) { 327 // Skip the first MBB in a function 328 if (MBB.getNumber() == MF.front().getNumber()) continue; 329 330 const MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()]; 331 auto MBBI = MBBInfo.MBB->begin(); 332 DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI); 333 334 // If the current MBB will be placed in a unique section, a full DefCfa 335 // must be emitted. 336 const bool ForceFullCFA = MBB.isBeginSection(); 337 338 if ((PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset && 339 PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) || 340 ForceFullCFA) { 341 // If both outgoing offset and register of a previous block don't match 342 // incoming offset and register of this block, or if this block begins a 343 // section, add a def_cfa instruction with the correct offset and 344 // register for this block. 345 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( 346 nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB))); 347 BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 348 .addCFIIndex(CFIIndex); 349 InsertedCFIInstr = true; 350 } else if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) { 351 // If outgoing offset of a previous block doesn't match incoming offset 352 // of this block, add a def_cfa_offset instruction with the correct 353 // offset for this block. 354 unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset( 355 nullptr, getCorrectCFAOffset(&MBB))); 356 BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 357 .addCFIIndex(CFIIndex); 358 InsertedCFIInstr = true; 359 } else if (PrevMBBInfo->OutgoingCFARegister != 360 MBBInfo.IncomingCFARegister) { 361 unsigned CFIIndex = 362 MF.addFrameInst(MCCFIInstruction::createDefCfaRegister( 363 nullptr, MBBInfo.IncomingCFARegister)); 364 BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 365 .addCFIIndex(CFIIndex); 366 InsertedCFIInstr = true; 367 } 368 369 if (ForceFullCFA) { 370 MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMovesFullCFA( 371 *MBBInfo.MBB, MBBI); 372 InsertedCFIInstr = true; 373 PrevMBBInfo = &MBBInfo; 374 continue; 375 } 376 377 BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference, 378 PrevMBBInfo->OutgoingCSRSaved, MBBInfo.IncomingCSRSaved); 379 for (int Reg : SetDifference.set_bits()) { 380 unsigned CFIIndex = 381 MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg)); 382 BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 383 .addCFIIndex(CFIIndex); 384 InsertedCFIInstr = true; 385 } 386 387 BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference, 388 MBBInfo.IncomingCSRSaved, PrevMBBInfo->OutgoingCSRSaved); 389 for (int Reg : SetDifference.set_bits()) { 390 auto it = CSRLocMap.find(Reg); 391 assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap"); 392 unsigned CFIIndex; 393 CSRSavedLocation RO = it->second; 394 if (!RO.Reg && RO.Offset) { 395 CFIIndex = MF.addFrameInst( 396 MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset)); 397 } else if (RO.Reg && !RO.Offset) { 398 CFIIndex = MF.addFrameInst( 399 MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg)); 400 } else { 401 llvm_unreachable("RO.Reg and RO.Offset cannot both be valid/invalid"); 402 } 403 BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) 404 .addCFIIndex(CFIIndex); 405 InsertedCFIInstr = true; 406 } 407 408 PrevMBBInfo = &MBBInfo; 409 } 410 return InsertedCFIInstr; 411 } 412 413 void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred, 414 const MBBCFAInfo &Succ) { 415 errs() << "*** Inconsistent CFA register and/or offset between pred and succ " 416 "***\n"; 417 errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() 418 << " in " << Pred.MBB->getParent()->getName() 419 << " outgoing CFA Reg:" << Pred.OutgoingCFARegister << "\n"; 420 errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() 421 << " in " << Pred.MBB->getParent()->getName() 422 << " outgoing CFA Offset:" << Pred.OutgoingCFAOffset << "\n"; 423 errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() 424 << " incoming CFA Reg:" << Succ.IncomingCFARegister << "\n"; 425 errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() 426 << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n"; 427 } 428 429 void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred, 430 const MBBCFAInfo &Succ) { 431 errs() << "*** Inconsistent CSR Saved between pred and succ in function " 432 << Pred.MBB->getParent()->getName() << " ***\n"; 433 errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber() 434 << " outgoing CSR Saved: "; 435 for (int Reg : Pred.OutgoingCSRSaved.set_bits()) 436 errs() << Reg << " "; 437 errs() << "\n"; 438 errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber() 439 << " incoming CSR Saved: "; 440 for (int Reg : Succ.IncomingCSRSaved.set_bits()) 441 errs() << Reg << " "; 442 errs() << "\n"; 443 } 444 445 unsigned CFIInstrInserter::verify(MachineFunction &MF) { 446 unsigned ErrorNum = 0; 447 for (auto *CurrMBB : depth_first(&MF)) { 448 const MBBCFAInfo &CurrMBBInfo = MBBVector[CurrMBB->getNumber()]; 449 for (MachineBasicBlock *Succ : CurrMBB->successors()) { 450 const MBBCFAInfo &SuccMBBInfo = MBBVector[Succ->getNumber()]; 451 // Check that incoming offset and register values of successors match the 452 // outgoing offset and register values of CurrMBB 453 if (SuccMBBInfo.IncomingCFAOffset != CurrMBBInfo.OutgoingCFAOffset || 454 SuccMBBInfo.IncomingCFARegister != CurrMBBInfo.OutgoingCFARegister) { 455 // Inconsistent offsets/registers are ok for 'noreturn' blocks because 456 // we don't generate epilogues inside such blocks. 457 if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock()) 458 continue; 459 reportCFAError(CurrMBBInfo, SuccMBBInfo); 460 ErrorNum++; 461 } 462 // Check that IncomingCSRSaved of every successor matches the 463 // OutgoingCSRSaved of CurrMBB 464 if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) { 465 reportCSRError(CurrMBBInfo, SuccMBBInfo); 466 ErrorNum++; 467 } 468 } 469 } 470 return ErrorNum; 471 } 472