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