LLVM 19.0.0git
ARMWinCOFFStreamer.cpp
Go to the documentation of this file.
1//===-- ARMWinCOFFStreamer.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 "ARMMCTargetDesc.h"
11#include "llvm/MC/MCAssembler.h"
13#include "llvm/MC/MCContext.h"
15#include "llvm/MC/MCWin64EH.h"
17
18using namespace llvm;
19
20namespace {
21class ARMWinCOFFStreamer : public MCWinCOFFStreamer {
23
24public:
25 ARMWinCOFFStreamer(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)) {}
29
30 void emitWinEHHandlerData(SMLoc Loc) override;
31 void emitWindowsUnwindTables() override;
32 void emitWindowsUnwindTables(WinEH::FrameInfo *Frame) override;
33
34 void emitThumbFunc(MCSymbol *Symbol) override;
35 void finishImpl() override;
36};
37
38void ARMWinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {
40
41 // We have to emit the unwind info now, because this directive
42 // actually switches to the .xdata section!
43 EHStreamer.EmitUnwindInfo(*this, getCurrentWinFrameInfo(),
44 /* HandlerData = */ true);
45}
46
47void ARMWinCOFFStreamer::emitWindowsUnwindTables(WinEH::FrameInfo *Frame) {
48 EHStreamer.EmitUnwindInfo(*this, Frame, /* HandlerData = */ false);
49}
50
51void ARMWinCOFFStreamer::emitWindowsUnwindTables() {
52 if (!getNumWinFrameInfos())
53 return;
54 EHStreamer.Emit(*this);
55}
56
57void ARMWinCOFFStreamer::emitThumbFunc(MCSymbol *Symbol) {
58 getAssembler().setIsThumbFunc(Symbol);
59}
60
61void ARMWinCOFFStreamer::finishImpl() {
62 emitFrames(nullptr);
63 emitWindowsUnwindTables();
64
66}
67}
68
70 MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB,
71 std::unique_ptr<MCObjectWriter> &&OW,
72 std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
73 bool IncrementalLinkerCompatible) {
74 auto *S = new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),
75 std::move(OW));
76 S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible);
77 return S;
78}
79
80namespace {
81class ARMTargetWinCOFFStreamer : public llvm::ARMTargetStreamer {
82private:
83 // True if we are processing SEH directives in an epilogue.
84 bool InEpilogCFI = false;
85
86 // Symbol of the current epilog for which we are processing SEH directives.
87 MCSymbol *CurrentEpilog = nullptr;
88
89public:
90 ARMTargetWinCOFFStreamer(llvm::MCStreamer &S) : ARMTargetStreamer(S) {}
91
92 // The unwind codes on ARM Windows are documented at
93 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
94 void emitARMWinCFIAllocStack(unsigned Size, bool Wide) override;
95 void emitARMWinCFISaveRegMask(unsigned Mask, bool Wide) override;
96 void emitARMWinCFISaveSP(unsigned Reg) override;
97 void emitARMWinCFISaveFRegs(unsigned First, unsigned Last) override;
98 void emitARMWinCFISaveLR(unsigned Offset) override;
99 void emitARMWinCFIPrologEnd(bool Fragment) override;
100 void emitARMWinCFINop(bool Wide) override;
101 void emitARMWinCFIEpilogStart(unsigned Condition) override;
102 void emitARMWinCFIEpilogEnd() override;
103 void emitARMWinCFICustom(unsigned Opcode) override;
104
105private:
106 void emitARMWinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
107};
108
109// Helper function to common out unwind code setup for those codes that can
110// belong to both prolog and epilog.
111void ARMTargetWinCOFFStreamer::emitARMWinUnwindCode(unsigned UnwindCode,
112 int Reg, int Offset) {
113 auto &S = getStreamer();
114 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
115 if (!CurFrame)
116 return;
117 MCSymbol *Label = S.emitCFILabel();
118 auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
119 if (InEpilogCFI)
120 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
121 else
122 CurFrame->Instructions.push_back(Inst);
123}
124
125void ARMTargetWinCOFFStreamer::emitARMWinCFIAllocStack(unsigned Size,
126 bool Wide) {
127 unsigned Op = Win64EH::UOP_AllocSmall;
128 if (!Wide) {
129 if (Size / 4 > 0xffff)
131 else if (Size / 4 > 0x7f)
133 } else {
135 if (Size / 4 > 0xffff)
137 else if (Size / 4 > 0x3ff)
139 }
140 emitARMWinUnwindCode(Op, -1, Size);
141}
142
143void ARMTargetWinCOFFStreamer::emitARMWinCFISaveRegMask(unsigned Mask,
144 bool Wide) {
145 assert(Mask != 0);
146 int Lr = (Mask & 0x4000) ? 1 : 0;
147 Mask &= ~0x4000;
148 if (Wide)
149 assert((Mask & ~0x1fff) == 0);
150 else
151 assert((Mask & ~0x00ff) == 0);
152 if (Mask && ((Mask + (1 << 4)) & Mask) == 0) {
153 if (Wide && (Mask & 0x1000) == 0 && (Mask & 0xff) == 0xf0) {
154 // One continuous range from r4 to r8-r11
155 for (int I = 11; I >= 8; I--) {
156 if (Mask & (1 << I)) {
157 emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegsR4R11LR, I, Lr);
158 return;
159 }
160 }
161 // If it actually was from r4 to r4-r7, continue below.
162 } else if (!Wide) {
163 // One continuous range from r4 to r4-r7
164 for (int I = 7; I >= 4; I--) {
165 if (Mask & (1 << I)) {
166 emitARMWinUnwindCode(Win64EH::UOP_SaveRegsR4R7LR, I, Lr);
167 return;
168 }
169 }
170 llvm_unreachable("logic error");
171 }
172 }
173 Mask |= Lr << 14;
174 if (Wide)
175 emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegMask, Mask, 0);
176 else
177 emitARMWinUnwindCode(Win64EH::UOP_SaveRegMask, Mask, 0);
178}
179
180void ARMTargetWinCOFFStreamer::emitARMWinCFISaveSP(unsigned Reg) {
181 emitARMWinUnwindCode(Win64EH::UOP_SaveSP, Reg, 0);
182}
183
184void ARMTargetWinCOFFStreamer::emitARMWinCFISaveFRegs(unsigned First,
185 unsigned Last) {
186 assert(First <= Last);
187 assert(First >= 16 || Last < 16);
188 assert(First <= 31 && Last <= 31);
189 if (First == 8)
190 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD8D15, Last, 0);
191 else if (First <= 15)
192 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD0D15, First, Last);
193 else
194 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD16D31, First, Last);
195}
196
197void ARMTargetWinCOFFStreamer::emitARMWinCFISaveLR(unsigned Offset) {
198 emitARMWinUnwindCode(Win64EH::UOP_SaveLR, 0, Offset);
199}
200
201void ARMTargetWinCOFFStreamer::emitARMWinCFINop(bool Wide) {
202 if (Wide)
203 emitARMWinUnwindCode(Win64EH::UOP_WideNop, -1, 0);
204 else
205 emitARMWinUnwindCode(Win64EH::UOP_Nop, -1, 0);
206}
207
208void ARMTargetWinCOFFStreamer::emitARMWinCFIPrologEnd(bool Fragment) {
209 auto &S = getStreamer();
210 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
211 if (!CurFrame)
212 return;
213
214 MCSymbol *Label = S.emitCFILabel();
215 CurFrame->PrologEnd = Label;
216 WinEH::Instruction Inst =
217 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
218 auto it = CurFrame->Instructions.begin();
219 CurFrame->Instructions.insert(it, Inst);
220 CurFrame->Fragment = Fragment;
221}
222
223void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogStart(unsigned Condition) {
224 auto &S = getStreamer();
225 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
226 if (!CurFrame)
227 return;
228
229 InEpilogCFI = true;
230 CurrentEpilog = S.emitCFILabel();
231 CurFrame->EpilogMap[CurrentEpilog].Condition = Condition;
232}
233
234void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {
235 auto &S = getStreamer();
236 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
237 if (!CurFrame)
238 return;
239
240 if (!CurrentEpilog) {
241 S.getContext().reportError(SMLoc(), "Stray .seh_endepilogue in " +
242 CurFrame->Function->getName());
243 return;
244 }
245
246 std::vector<WinEH::Instruction> &Epilog =
247 CurFrame->EpilogMap[CurrentEpilog].Instructions;
248
249 unsigned UnwindCode = Win64EH::UOP_End;
250 if (!Epilog.empty()) {
251 WinEH::Instruction EndInstr = Epilog.back();
252 if (EndInstr.Operation == Win64EH::UOP_Nop) {
253 UnwindCode = Win64EH::UOP_EndNop;
254 Epilog.pop_back();
255 } else if (EndInstr.Operation == Win64EH::UOP_WideNop) {
256 UnwindCode = Win64EH::UOP_WideEndNop;
257 Epilog.pop_back();
258 }
259 }
260
261 InEpilogCFI = false;
262 WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);
263 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
264 MCSymbol *Label = S.emitCFILabel();
265 CurFrame->EpilogMap[CurrentEpilog].End = Label;
266 CurrentEpilog = nullptr;
267}
268
269void ARMTargetWinCOFFStreamer::emitARMWinCFICustom(unsigned Opcode) {
270 emitARMWinUnwindCode(Win64EH::UOP_Custom, 0, Opcode);
271}
272
273} // end anonymous namespace
274
276 return new ARMTargetWinCOFFStreamer(S);
277}
dxil DXContainer Global Emitter
uint64_t Size
#define I(x, y, z)
Definition: MD5.cpp:58
LLVMContext & Context
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
virtual void emitARMWinCFISaveSP(unsigned Reg)
virtual void emitARMWinCFISaveLR(unsigned Offset)
virtual void emitARMWinCFIAllocStack(unsigned Size, bool Wide)
virtual void emitARMWinCFICustom(unsigned Opcode)
virtual void emitARMWinCFISaveRegMask(unsigned Mask, bool Wide)
virtual void emitARMWinCFIEpilogEnd()
virtual void emitARMWinCFIPrologEnd(bool Fragment)
virtual void emitARMWinCFISaveFRegs(unsigned First, unsigned Last)
virtual void emitARMWinCFIEpilogStart(unsigned Condition)
virtual void emitARMWinCFINop(bool Wide)
This class represents an Operation in the Expression.
Emits exception handling directives.
Definition: EHStreamer.h:30
Context object for machine code objects.
Definition: MCContext.h:81
Streaming machine code generation interface.
Definition: MCStreamer.h:212
virtual void emitWindowsUnwindTables()
virtual void emitWinEHHandlerData(SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:808
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:40
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:205
Target specific streamer interface.
Definition: MCStreamer.h:93
void emitThumbFunc(MCSymbol *Func) override
Note in the output that the specified Func is a Thumb mode function (ARM target only).
void finishImpl() override
Streamer specific finalization.
void emitWinEHHandlerData(SMLoc Loc) override
Represents a location in source code.
Definition: SMLoc.h:23
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
Definition: BitmaskEnum.h:121
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
@ UOP_WideEndNop
Definition: Win64EH.h:106
@ UOP_SaveRegsR4R7LR
Definition: Win64EH.h:95
@ UOP_WideAllocMedium
Definition: Win64EH.h:89
@ UOP_AllocHuge
Definition: Win64EH.h:88
@ UOP_SaveFRegD0D15
Definition: Win64EH.h:100
@ UOP_WideSaveRegsR4R11LR
Definition: Win64EH.h:96
@ UOP_WideAllocHuge
Definition: Win64EH.h:91
@ UOP_AllocLarge
Definition: Win64EH.h:31
@ UOP_SaveRegMask
Definition: Win64EH.h:98
@ UOP_AllocSmall
Definition: Win64EH.h:32
@ UOP_SaveFRegD8D15
Definition: Win64EH.h:97
@ UOP_WideAllocLarge
Definition: Win64EH.h:90
@ UOP_WideSaveRegMask
Definition: Win64EH.h:93
@ UOP_SaveFRegD16D31
Definition: Win64EH.h:101
@ CE
Windows NT (Windows on ARM)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
MCStreamer * createARMWinCOFFStreamer(MCContext &Context, std::unique_ptr< MCAsmBackend > &&MAB, std::unique_ptr< MCObjectWriter > &&OW, std::unique_ptr< MCCodeEmitter > &&Emitter, bool RelaxAll, bool IncrementalLinkerCompatible)
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1849
MCTargetStreamer * createARMObjectTargetWinCOFFStreamer(MCStreamer &S)
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
std::vector< Instruction > Instructions
Definition: MCWinEH.h:58
const MCSymbol * Function
Definition: MCWinEH.h:44
const MCSymbol * PrologEnd
Definition: MCWinEH.h:45
MapVector< MCSymbol *, Epilog > EpilogMap
Definition: MCWinEH.h:64