Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- AArch64WinCOFFStreamer.cpp - ARM Target WinCOFF Streamer ----*- C++ -*-===//
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 "AArch64WinCOFFStreamer.h"
10
#include "llvm/MC/MCAsmBackend.h"
11
#include "llvm/MC/MCCodeEmitter.h"
12
#include "llvm/MC/MCObjectWriter.h"
13
#include "llvm/MC/MCWin64EH.h"
14
#include "llvm/MC/MCWinCOFFStreamer.h"
15
16
using namespace llvm;
17
18
namespace {
19
20
class AArch64WinCOFFStreamer : public MCWinCOFFStreamer {
21
  Win64EH::ARM64UnwindEmitter EHStreamer;
22
23
public:
24
  AArch64WinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
25
                         std::unique_ptr<MCCodeEmitter> CE,
26
                         std::unique_ptr<MCObjectWriter> OW)
27
31
      : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
28
29
  void EmitWinEHHandlerData(SMLoc Loc) override;
30
  void EmitWindowsUnwindTables() override;
31
  void FinishImpl() override;
32
};
33
34
17
void AArch64WinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) {
35
17
  MCStreamer::EmitWinEHHandlerData(Loc);
36
17
37
17
  // We have to emit the unwind info now, because this directive
38
17
  // actually switches to the .xdata section!
39
17
  EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo());
40
17
}
41
42
31
void AArch64WinCOFFStreamer::EmitWindowsUnwindTables() {
43
31
  if (!getNumWinFrameInfos())
44
17
    return;
45
14
  EHStreamer.Emit(*this);
46
14
}
47
48
31
void AArch64WinCOFFStreamer::FinishImpl() {
49
31
  EmitFrames(nullptr);
50
31
  EmitWindowsUnwindTables();
51
31
52
31
  MCWinCOFFStreamer::FinishImpl();
53
31
}
54
} // end anonymous namespace
55
56
namespace llvm {
57
58
// Helper function to common out unwind code setup for those codes that can
59
// belong to both prolog and epilog.
60
// There are three types of Windows ARM64 SEH codes.  They can
61
// 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd
62
// 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X
63
// 3) take a register and an offset/size: all others
64
void AArch64TargetWinCOFFStreamer::EmitARM64WinUnwindCode(unsigned UnwindCode,
65
                                                          int Reg,
66
140
                                                          int Offset) {
67
140
  auto &S = getStreamer();
68
140
  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
69
140
  if (!CurFrame)
70
0
    return;
71
140
  MCSymbol *Label = S.EmitCFILabel();
72
140
  auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
73
140
  if (InEpilogCFI)
74
75
    CurFrame->EpilogMap[CurrentEpilog].push_back(Inst);
75
65
  else
76
65
    CurFrame->Instructions.push_back(Inst);
77
140
}
78
79
10
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAllocStack(unsigned Size) {
80
10
  unsigned Op = Win64EH::UOP_AllocSmall;
81
10
  if (Size >= 16384)
82
2
    Op = Win64EH::UOP_AllocLarge;
83
8
  else if (Size >= 512)
84
3
    Op = Win64EH::UOP_AllocMedium;
85
10
  EmitARM64WinUnwindCode(Op, -1, Size);
86
10
}
87
88
8
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLR(int Offset) {
89
8
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR, -1, Offset);
90
8
}
91
92
2
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLRX(int Offset) {
93
2
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLRX, -1, Offset);
94
2
}
95
96
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveReg(unsigned Reg,
97
12
                                                          int Offset) {
98
12
  assert(Offset >= 0 && Offset <= 504 &&
99
12
        "Offset for save reg should be >= 0 && <= 504");
100
12
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveReg, Reg, Offset);
101
12
}
102
103
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegX(unsigned Reg,
104
10
                                                           int Offset) {
105
10
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegX, Reg, Offset);
106
10
}
107
108
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegP(unsigned Reg,
109
61
                                                           int Offset) {
110
61
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegP, Reg, Offset);
111
61
}
112
113
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegPX(unsigned Reg,
114
4
                                                            int Offset) {
115
4
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX, Reg, Offset);
116
4
}
117
118
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFReg(unsigned Reg,
119
4
                                                           int Offset) {
120
4
  assert(Offset >= 0 && Offset <= 504 &&
121
4
        "Offset for save reg should be >= 0 && <= 504");
122
4
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFReg, Reg, Offset);
123
4
}
124
125
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegX(unsigned Reg,
126
2
                                                            int Offset) {
127
2
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX, Reg, Offset);
128
2
}
129
130
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegP(unsigned Reg,
131
10
                                                            int Offset) {
132
10
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP, Reg, Offset);
133
10
}
134
135
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegPX(unsigned Reg,
136
8
                                                             int Offset) {
137
8
  EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX, Reg, Offset);
138
8
}
139
140
2
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISetFP() {
141
2
  EmitARM64WinUnwindCode(Win64EH::UOP_SetFP, -1, 0);
142
2
}
143
144
3
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAddFP(unsigned Offset) {
145
3
  assert(Offset <= 2040 && "UOP_AddFP must have offset <= 2040");
146
3
  EmitARM64WinUnwindCode(Win64EH::UOP_AddFP, -1, Offset);
147
3
}
148
149
4
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFINop() {
150
4
  EmitARM64WinUnwindCode(Win64EH::UOP_Nop, -1, 0);
151
4
}
152
153
// The functions below handle opcodes that can end up in either a prolog or
154
// an epilog, but not both.
155
14
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIPrologEnd() {
156
14
  auto &S = getStreamer();
157
14
  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
158
14
  if (!CurFrame)
159
0
    return;
160
14
161
14
  MCSymbol *Label = S.EmitCFILabel();
162
14
  CurFrame->PrologEnd = Label;
163
14
  WinEH::Instruction Inst = WinEH::Instruction(Win64EH::UOP_End, Label, -1, 0);
164
14
  auto it = CurFrame->Instructions.begin();
165
14
  CurFrame->Instructions.insert(it, Inst);
166
14
}
167
168
18
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogStart() {
169
18
  auto &S = getStreamer();
170
18
  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
171
18
  if (!CurFrame)
172
0
    return;
173
18
174
18
  InEpilogCFI = true;
175
18
  CurrentEpilog = S.EmitCFILabel();
176
18
}
177
178
18
void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogEnd() {
179
18
  auto &S = getStreamer();
180
18
  WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
181
18
  if (!CurFrame)
182
0
    return;
183
18
184
18
  InEpilogCFI = false;
185
18
  MCSymbol *Label = S.EmitCFILabel();
186
18
  WinEH::Instruction Inst = WinEH::Instruction(Win64EH::UOP_End, Label, -1, 0);
187
18
  CurFrame->EpilogMap[CurrentEpilog].push_back(Inst);
188
18
  CurrentEpilog = nullptr;
189
18
}
190
191
MCWinCOFFStreamer *createAArch64WinCOFFStreamer(
192
    MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
193
    std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter,
194
31
    bool RelaxAll, bool IncrementalLinkerCompatible) {
195
31
  auto *S = new AArch64WinCOFFStreamer(Context, std::move(MAB),
196
31
                                       std::move(Emitter), std::move(OW));
197
31
  S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible);
198
31
  return S;
199
31
}
200
201
} // end llvm namespace