1 //===-- AArch64WinCOFFStreamer.cpp - ARM Target WinCOFF Streamer ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "AArch64WinCOFFStreamer.h"
10 #include "llvm/MC/MCAsmBackend.h"
11 #include "llvm/MC/MCAssembler.h"
12 #include "llvm/MC/MCCodeEmitter.h"
13 #include "llvm/MC/MCObjectWriter.h"
14 #include "llvm/MC/MCWin64EH.h"
15 #include "llvm/MC/MCWinCOFFStreamer.h"
21 class AArch64WinCOFFStreamer
: public MCWinCOFFStreamer
{
22 Win64EH::ARM64UnwindEmitter EHStreamer
;
25 AArch64WinCOFFStreamer(MCContext
&C
, std::unique_ptr
<MCAsmBackend
> AB
,
26 std::unique_ptr
<MCCodeEmitter
> CE
,
27 std::unique_ptr
<MCObjectWriter
> OW
)
28 : MCWinCOFFStreamer(C
, std::move(AB
), std::move(CE
), std::move(OW
)) {}
30 void emitWinEHHandlerData(SMLoc Loc
) override
;
31 void emitWindowsUnwindTables() override
;
32 void emitWindowsUnwindTables(WinEH::FrameInfo
*Frame
) override
;
33 void finishImpl() override
;
36 void AArch64WinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc
) {
37 MCStreamer::emitWinEHHandlerData(Loc
);
39 // We have to emit the unwind info now, because this directive
40 // actually switches to the .xdata section!
41 EHStreamer
.EmitUnwindInfo(*this, getCurrentWinFrameInfo(),
42 /* HandlerData = */ true);
45 void AArch64WinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo
*Frame
) {
46 EHStreamer
.EmitUnwindInfo(*this, Frame
, /* HandlerData = */ false);
49 void AArch64WinCOFFStreamer::emitWindowsUnwindTables() {
50 if (!getNumWinFrameInfos())
52 EHStreamer
.Emit(*this);
55 void AArch64WinCOFFStreamer::finishImpl() {
57 emitWindowsUnwindTables();
59 MCWinCOFFStreamer::finishImpl();
61 } // end anonymous namespace
63 // Helper function to common out unwind code setup for those codes that can
64 // belong to both prolog and epilog.
65 // There are three types of Windows ARM64 SEH codes. They can
66 // 1) take no operands: SEH_Nop, SEH_PrologEnd, SEH_EpilogStart, SEH_EpilogEnd
67 // 2) take an offset: SEH_StackAlloc, SEH_SaveFPLR, SEH_SaveFPLR_X
68 // 3) take a register and an offset/size: all others
69 void AArch64TargetWinCOFFStreamer::emitARM64WinUnwindCode(unsigned UnwindCode
,
70 int Reg
, int Offset
) {
71 auto &S
= getStreamer();
72 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
75 auto Inst
= WinEH::Instruction(UnwindCode
, /*Label=*/nullptr, Reg
, Offset
);
77 CurFrame
->EpilogMap
[CurrentEpilog
].Instructions
.push_back(Inst
);
79 CurFrame
->Instructions
.push_back(Inst
);
82 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAllocStack(unsigned Size
) {
83 unsigned Op
= Win64EH::UOP_AllocSmall
;
85 Op
= Win64EH::UOP_AllocLarge
;
87 Op
= Win64EH::UOP_AllocMedium
;
88 emitARM64WinUnwindCode(Op
, -1, Size
);
91 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveR19R20X(int Offset
) {
92 emitARM64WinUnwindCode(Win64EH::UOP_SaveR19R20X
, -1, Offset
);
95 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFPLR(int Offset
) {
96 emitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR
, -1, Offset
);
99 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFPLRX(int Offset
) {
100 emitARM64WinUnwindCode(Win64EH::UOP_SaveFPLRX
, -1, Offset
);
103 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveReg(unsigned Reg
,
105 assert(Offset
>= 0 && Offset
<= 504 &&
106 "Offset for save reg should be >= 0 && <= 504");
107 emitARM64WinUnwindCode(Win64EH::UOP_SaveReg
, Reg
, Offset
);
110 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegX(unsigned Reg
,
112 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegX
, Reg
, Offset
);
115 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegP(unsigned Reg
,
117 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegP
, Reg
, Offset
);
120 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveRegPX(unsigned Reg
,
122 emitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX
, Reg
, Offset
);
125 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveLRPair(unsigned Reg
,
127 emitARM64WinUnwindCode(Win64EH::UOP_SaveLRPair
, Reg
, Offset
);
130 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFReg(unsigned Reg
,
132 assert(Offset
>= 0 && Offset
<= 504 &&
133 "Offset for save reg should be >= 0 && <= 504");
134 emitARM64WinUnwindCode(Win64EH::UOP_SaveFReg
, Reg
, Offset
);
137 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegX(unsigned Reg
,
139 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX
, Reg
, Offset
);
142 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegP(unsigned Reg
,
144 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP
, Reg
, Offset
);
147 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveFRegPX(unsigned Reg
,
149 emitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX
, Reg
, Offset
);
152 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISetFP() {
153 emitARM64WinUnwindCode(Win64EH::UOP_SetFP
, -1, 0);
156 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIAddFP(unsigned Offset
) {
157 assert(Offset
<= 2040 && "UOP_AddFP must have offset <= 2040");
158 emitARM64WinUnwindCode(Win64EH::UOP_AddFP
, -1, Offset
);
161 void AArch64TargetWinCOFFStreamer::emitARM64WinCFINop() {
162 emitARM64WinUnwindCode(Win64EH::UOP_Nop
, -1, 0);
165 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveNext() {
166 emitARM64WinUnwindCode(Win64EH::UOP_SaveNext
, -1, 0);
169 // The functions below handle opcodes that can end up in either a prolog or
170 // an epilog, but not both.
171 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPrologEnd() {
172 auto &S
= getStreamer();
173 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
177 MCSymbol
*Label
= S
.emitCFILabel();
178 CurFrame
->PrologEnd
= Label
;
179 WinEH::Instruction Inst
=
180 WinEH::Instruction(Win64EH::UOP_End
, /*Label=*/nullptr, -1, 0);
181 auto it
= CurFrame
->Instructions
.begin();
182 CurFrame
->Instructions
.insert(it
, Inst
);
185 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogStart() {
186 auto &S
= getStreamer();
187 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
192 CurrentEpilog
= S
.emitCFILabel();
195 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIEpilogEnd() {
196 auto &S
= getStreamer();
197 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
202 WinEH::Instruction Inst
=
203 WinEH::Instruction(Win64EH::UOP_End
, /*Label=*/nullptr, -1, 0);
204 CurFrame
->EpilogMap
[CurrentEpilog
].Instructions
.push_back(Inst
);
205 MCSymbol
*Label
= S
.emitCFILabel();
206 CurFrame
->EpilogMap
[CurrentEpilog
].End
= Label
;
207 CurrentEpilog
= nullptr;
210 void AArch64TargetWinCOFFStreamer::emitARM64WinCFITrapFrame() {
211 emitARM64WinUnwindCode(Win64EH::UOP_TrapFrame
, -1, 0);
214 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIMachineFrame() {
215 emitARM64WinUnwindCode(Win64EH::UOP_PushMachFrame
, -1, 0);
218 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIContext() {
219 emitARM64WinUnwindCode(Win64EH::UOP_Context
, -1, 0);
222 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIECContext() {
223 emitARM64WinUnwindCode(Win64EH::UOP_ECContext
, -1, 0);
226 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIClearUnwoundToCall() {
227 emitARM64WinUnwindCode(Win64EH::UOP_ClearUnwoundToCall
, -1, 0);
230 void AArch64TargetWinCOFFStreamer::emitARM64WinCFIPACSignLR() {
231 emitARM64WinUnwindCode(Win64EH::UOP_PACSignLR
, -1, 0);
234 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegI(unsigned Reg
,
236 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegI
, Reg
, Offset
);
239 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIP(unsigned Reg
,
241 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIP
, Reg
, Offset
);
244 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegD(unsigned Reg
,
246 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegD
, Reg
, Offset
);
249 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDP(unsigned Reg
,
251 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDP
, Reg
, Offset
);
254 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQ(unsigned Reg
,
256 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQ
, Reg
, Offset
);
259 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQP(unsigned Reg
,
261 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQP
, Reg
, Offset
);
264 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIX(unsigned Reg
,
266 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIX
, Reg
, Offset
);
269 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegIPX(unsigned Reg
,
271 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegIPX
, Reg
, Offset
);
274 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDX(unsigned Reg
,
276 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDX
, Reg
, Offset
);
279 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegDPX(unsigned Reg
,
281 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegDPX
, Reg
, Offset
);
284 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQX(unsigned Reg
,
286 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQX
, Reg
, Offset
);
289 void AArch64TargetWinCOFFStreamer::emitARM64WinCFISaveAnyRegQPX(unsigned Reg
,
291 emitARM64WinUnwindCode(Win64EH::UOP_SaveAnyRegQPX
, Reg
, Offset
);
295 llvm::createAArch64WinCOFFStreamer(MCContext
&Context
,
296 std::unique_ptr
<MCAsmBackend
> MAB
,
297 std::unique_ptr
<MCObjectWriter
> OW
,
298 std::unique_ptr
<MCCodeEmitter
> Emitter
) {
299 return new AArch64WinCOFFStreamer(Context
, std::move(MAB
), std::move(Emitter
),