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/MCCodeEmitter.h"
12 #include "llvm/MC/MCObjectWriter.h"
13 #include "llvm/MC/MCWin64EH.h"
14 #include "llvm/MC/MCWinCOFFStreamer.h"
20 class AArch64WinCOFFStreamer
: public MCWinCOFFStreamer
{
21 Win64EH::ARM64UnwindEmitter EHStreamer
;
24 AArch64WinCOFFStreamer(MCContext
&C
, std::unique_ptr
<MCAsmBackend
> AB
,
25 std::unique_ptr
<MCCodeEmitter
> CE
,
26 std::unique_ptr
<MCObjectWriter
> OW
)
27 : MCWinCOFFStreamer(C
, std::move(AB
), std::move(CE
), std::move(OW
)) {}
29 void EmitWinEHHandlerData(SMLoc Loc
) override
;
30 void EmitWindowsUnwindTables() override
;
31 void FinishImpl() override
;
34 void AArch64WinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc
) {
35 MCStreamer::EmitWinEHHandlerData(Loc
);
37 // We have to emit the unwind info now, because this directive
38 // actually switches to the .xdata section!
39 EHStreamer
.EmitUnwindInfo(*this, getCurrentWinFrameInfo());
42 void AArch64WinCOFFStreamer::EmitWindowsUnwindTables() {
43 if (!getNumWinFrameInfos())
45 EHStreamer
.Emit(*this);
48 void AArch64WinCOFFStreamer::FinishImpl() {
50 EmitWindowsUnwindTables();
52 MCWinCOFFStreamer::FinishImpl();
54 } // end anonymous namespace
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
,
67 auto &S
= getStreamer();
68 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
71 MCSymbol
*Label
= S
.EmitCFILabel();
72 auto Inst
= WinEH::Instruction(UnwindCode
, Label
, Reg
, Offset
);
74 CurFrame
->EpilogMap
[CurrentEpilog
].push_back(Inst
);
76 CurFrame
->Instructions
.push_back(Inst
);
79 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAllocStack(unsigned Size
) {
80 unsigned Op
= Win64EH::UOP_AllocSmall
;
82 Op
= Win64EH::UOP_AllocLarge
;
84 Op
= Win64EH::UOP_AllocMedium
;
85 EmitARM64WinUnwindCode(Op
, -1, Size
);
88 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLR(int Offset
) {
89 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR
, -1, Offset
);
92 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLRX(int Offset
) {
93 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLRX
, -1, Offset
);
96 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveReg(unsigned Reg
,
98 assert(Offset
>= 0 && Offset
<= 504 &&
99 "Offset for save reg should be >= 0 && <= 504");
100 EmitARM64WinUnwindCode(Win64EH::UOP_SaveReg
, Reg
, Offset
);
103 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegX(unsigned Reg
,
105 EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegX
, Reg
, Offset
);
108 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegP(unsigned Reg
,
110 EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegP
, Reg
, Offset
);
113 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveRegPX(unsigned Reg
,
115 EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX
, Reg
, Offset
);
118 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFReg(unsigned Reg
,
120 assert(Offset
>= 0 && Offset
<= 504 &&
121 "Offset for save reg should be >= 0 && <= 504");
122 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFReg
, Reg
, Offset
);
125 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegX(unsigned Reg
,
127 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegX
, Reg
, Offset
);
130 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegP(unsigned Reg
,
132 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegP
, Reg
, Offset
);
135 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFRegPX(unsigned Reg
,
137 EmitARM64WinUnwindCode(Win64EH::UOP_SaveFRegPX
, Reg
, Offset
);
140 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISetFP() {
141 EmitARM64WinUnwindCode(Win64EH::UOP_SetFP
, -1, 0);
144 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIAddFP(unsigned Offset
) {
145 assert(Offset
<= 2040 && "UOP_AddFP must have offset <= 2040");
146 EmitARM64WinUnwindCode(Win64EH::UOP_AddFP
, -1, Offset
);
149 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFINop() {
150 EmitARM64WinUnwindCode(Win64EH::UOP_Nop
, -1, 0);
153 // The functions below handle opcodes that can end up in either a prolog or
154 // an epilog, but not both.
155 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIPrologEnd() {
156 auto &S
= getStreamer();
157 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
161 MCSymbol
*Label
= S
.EmitCFILabel();
162 CurFrame
->PrologEnd
= Label
;
163 WinEH::Instruction Inst
= WinEH::Instruction(Win64EH::UOP_End
, Label
, -1, 0);
164 auto it
= CurFrame
->Instructions
.begin();
165 CurFrame
->Instructions
.insert(it
, Inst
);
168 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogStart() {
169 auto &S
= getStreamer();
170 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
175 CurrentEpilog
= S
.EmitCFILabel();
178 void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIEpilogEnd() {
179 auto &S
= getStreamer();
180 WinEH::FrameInfo
*CurFrame
= S
.EnsureValidWinFrameInfo(SMLoc());
185 MCSymbol
*Label
= S
.EmitCFILabel();
186 WinEH::Instruction Inst
= WinEH::Instruction(Win64EH::UOP_End
, Label
, -1, 0);
187 CurFrame
->EpilogMap
[CurrentEpilog
].push_back(Inst
);
188 CurrentEpilog
= nullptr;
191 MCWinCOFFStreamer
*createAArch64WinCOFFStreamer(
192 MCContext
&Context
, std::unique_ptr
<MCAsmBackend
> MAB
,
193 std::unique_ptr
<MCObjectWriter
> OW
, std::unique_ptr
<MCCodeEmitter
> Emitter
,
194 bool RelaxAll
, bool IncrementalLinkerCompatible
) {
195 auto *S
= new AArch64WinCOFFStreamer(Context
, std::move(MAB
),
196 std::move(Emitter
), std::move(OW
));
197 S
->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible
);
201 } // end llvm namespace