xref: /freebsd/contrib/llvm-project/llvm/lib/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h"
10*700637cbSDimitry Andric #include "llvm/ADT/ArrayRef.h"
11*700637cbSDimitry Andric #include "llvm/MC/MCContext.h"
12*700637cbSDimitry Andric #include "llvm/MC/MCDwarf.h"
13*700637cbSDimitry Andric #include "llvm/MC/MCInst.h"
14*700637cbSDimitry Andric #include "llvm/MC/MCInstrInfo.h"
15*700637cbSDimitry Andric #include "llvm/MC/MCStreamer.h"
16*700637cbSDimitry Andric #include <optional>
17*700637cbSDimitry Andric 
18*700637cbSDimitry Andric using namespace llvm;
19*700637cbSDimitry Andric 
updateReceiver(const std::optional<MCInst> & NewInst)20*700637cbSDimitry Andric void CFIFunctionFrameStreamer::updateReceiver(
21*700637cbSDimitry Andric     const std::optional<MCInst> &NewInst) {
22*700637cbSDimitry Andric   assert(hasUnfinishedDwarfFrameInfo() &&
23*700637cbSDimitry Andric          "should have an unfinished DWARF frame here");
24*700637cbSDimitry Andric   assert(!FrameIndices.empty() &&
25*700637cbSDimitry Andric          "there should be an index available for the current frame");
26*700637cbSDimitry Andric   assert(FrameIndices.size() == LastInstructions.size());
27*700637cbSDimitry Andric   assert(LastInstructions.size() == LastDirectiveIndices.size());
28*700637cbSDimitry Andric 
29*700637cbSDimitry Andric   auto Frames = getDwarfFrameInfos();
30*700637cbSDimitry Andric   assert(FrameIndices.back() < Frames.size());
31*700637cbSDimitry Andric   unsigned LastDirectiveIndex = LastDirectiveIndices.back();
32*700637cbSDimitry Andric   unsigned CurrentDirectiveIndex =
33*700637cbSDimitry Andric       Frames[FrameIndices.back()].Instructions.size();
34*700637cbSDimitry Andric   assert(CurrentDirectiveIndex >= LastDirectiveIndex);
35*700637cbSDimitry Andric 
36*700637cbSDimitry Andric   const MCDwarfFrameInfo *LastFrame = &Frames[FrameIndices.back()];
37*700637cbSDimitry Andric   ArrayRef<MCCFIInstruction> Directives;
38*700637cbSDimitry Andric   if (LastDirectiveIndex < CurrentDirectiveIndex) {
39*700637cbSDimitry Andric     Directives = ArrayRef<MCCFIInstruction>(LastFrame->Instructions);
40*700637cbSDimitry Andric     Directives =
41*700637cbSDimitry Andric         Directives.drop_front(LastDirectiveIndex)
42*700637cbSDimitry Andric             .drop_back(LastFrame->Instructions.size() - CurrentDirectiveIndex);
43*700637cbSDimitry Andric   }
44*700637cbSDimitry Andric 
45*700637cbSDimitry Andric   auto MaybeLastInstruction = LastInstructions.back();
46*700637cbSDimitry Andric   if (MaybeLastInstruction)
47*700637cbSDimitry Andric     // The directives are associated with an instruction.
48*700637cbSDimitry Andric     Receiver->emitInstructionAndDirectives(*MaybeLastInstruction, Directives);
49*700637cbSDimitry Andric   else
50*700637cbSDimitry Andric     // The directives are the prologue directives.
51*700637cbSDimitry Andric     Receiver->startFunctionFrame(false /* TODO: should put isEH here */,
52*700637cbSDimitry Andric                                  Directives);
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric   // Update the internal state for the top frame.
55*700637cbSDimitry Andric   LastInstructions.back() = NewInst;
56*700637cbSDimitry Andric   LastDirectiveIndices.back() = CurrentDirectiveIndex;
57*700637cbSDimitry Andric }
58*700637cbSDimitry Andric 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)59*700637cbSDimitry Andric void CFIFunctionFrameStreamer::emitInstruction(const MCInst &Inst,
60*700637cbSDimitry Andric                                                const MCSubtargetInfo &STI) {
61*700637cbSDimitry Andric   if (hasUnfinishedDwarfFrameInfo())
62*700637cbSDimitry Andric     // Send the last instruction with the unsent directives already in the frame
63*700637cbSDimitry Andric     // to the receiver.
64*700637cbSDimitry Andric     updateReceiver(Inst);
65*700637cbSDimitry Andric }
66*700637cbSDimitry Andric 
emitCFIStartProcImpl(MCDwarfFrameInfo & Frame)67*700637cbSDimitry Andric void CFIFunctionFrameStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
68*700637cbSDimitry Andric   LastInstructions.push_back(std::nullopt);
69*700637cbSDimitry Andric   LastDirectiveIndices.push_back(0);
70*700637cbSDimitry Andric   FrameIndices.push_back(getNumFrameInfos());
71*700637cbSDimitry Andric 
72*700637cbSDimitry Andric   MCStreamer::emitCFIStartProcImpl(Frame);
73*700637cbSDimitry Andric }
74*700637cbSDimitry Andric 
emitCFIEndProcImpl(MCDwarfFrameInfo & CurFrame)75*700637cbSDimitry Andric void CFIFunctionFrameStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame) {
76*700637cbSDimitry Andric   // Send the last instruction with the final directives of the current frame to
77*700637cbSDimitry Andric   // the receiver.
78*700637cbSDimitry Andric   updateReceiver(std::nullopt);
79*700637cbSDimitry Andric 
80*700637cbSDimitry Andric   assert(!FrameIndices.empty() && "There should be at least one frame to pop");
81*700637cbSDimitry Andric   LastDirectiveIndices.pop_back();
82*700637cbSDimitry Andric   LastInstructions.pop_back();
83*700637cbSDimitry Andric   FrameIndices.pop_back();
84*700637cbSDimitry Andric 
85*700637cbSDimitry Andric   Receiver->finishFunctionFrame();
86*700637cbSDimitry Andric 
87*700637cbSDimitry Andric   MCStreamer::emitCFIEndProcImpl(CurFrame);
88*700637cbSDimitry Andric }
89