LLVM 20.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
71 std::unique_ptr<MCAsmBackend> &&MAB,
72 std::unique_ptr<MCObjectWriter> &&OW,
73 std::unique_ptr<MCCodeEmitter> &&Emitter) {
74 return new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),
75 std::move(OW));
76}
77
78namespace {
79class ARMTargetWinCOFFStreamer : public llvm::ARMTargetStreamer {
80private:
81 // True if we are processing SEH directives in an epilogue.
82 bool InEpilogCFI = false;
83
84 // Symbol of the current epilog for which we are processing SEH directives.
85 MCSymbol *CurrentEpilog = nullptr;
86
87public:
88 ARMTargetWinCOFFStreamer(llvm::MCStreamer &S) : ARMTargetStreamer(S) {}
89
90 // The unwind codes on ARM Windows are documented at
91 // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
92 void emitARMWinCFIAllocStack(unsigned Size, bool Wide) override;
93 void emitARMWinCFISaveRegMask(unsigned Mask, bool Wide) override;
94 void emitARMWinCFISaveSP(unsigned Reg) override;
95 void emitARMWinCFISaveFRegs(unsigned First, unsigned Last) override;
96 void emitARMWinCFISaveLR(unsigned Offset) override;
97 void emitARMWinCFIPrologEnd(bool Fragment) override;
98 void emitARMWinCFINop(bool Wide) override;
99 void emitARMWinCFIEpilogStart(unsigned Condition) override;
100 void emitARMWinCFIEpilogEnd() override;
101 void emitARMWinCFICustom(unsigned Opcode) override;
102
103private:
104 void emitARMWinUnwindCode(unsigned UnwindCode, int Reg, int Offset);
105};
106
107// Helper function to common out unwind code setup for those codes that can
108// belong to both prolog and epilog.
109void ARMTargetWinCOFFStreamer::emitARMWinUnwindCode(unsigned UnwindCode,
110 int Reg, int Offset) {
111 auto &S = getStreamer();
112 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
113 if (!CurFrame)
114 return;
115 MCSymbol *Label = S.emitCFILabel();
116 auto Inst = WinEH::Instruction(UnwindCode, Label, Reg, Offset);
117 if (InEpilogCFI)
118 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
119 else
120 CurFrame->Instructions.push_back(Inst);
121}
122
123void ARMTargetWinCOFFStreamer::emitARMWinCFIAllocStack(unsigned Size,
124 bool Wide) {
125 unsigned Op = Win64EH::UOP_AllocSmall;
126 if (!Wide) {
127 if (Size / 4 > 0xffff)
129 else if (Size / 4 > 0x7f)
131 } else {
133 if (Size / 4 > 0xffff)
135 else if (Size / 4 > 0x3ff)
137 }
138 emitARMWinUnwindCode(Op, -1, Size);
139}
140
141void ARMTargetWinCOFFStreamer::emitARMWinCFISaveRegMask(unsigned Mask,
142 bool Wide) {
143 assert(Mask != 0);
144 int Lr = (Mask & 0x4000) ? 1 : 0;
145 Mask &= ~0x4000;
146 if (Wide)
147 assert((Mask & ~0x1fff) == 0);
148 else
149 assert((Mask & ~0x00ff) == 0);
150 if (Mask && ((Mask + (1 << 4)) & Mask) == 0) {
151 if (Wide && (Mask & 0x1000) == 0 && (Mask & 0xff) == 0xf0) {
152 // One continuous range from r4 to r8-r11
153 for (int I = 11; I >= 8; I--) {
154 if (Mask & (1 << I)) {
155 emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegsR4R11LR, I, Lr);
156 return;
157 }
158 }
159 // If it actually was from r4 to r4-r7, continue below.
160 } else if (!Wide) {
161 // One continuous range from r4 to r4-r7
162 for (int I = 7; I >= 4; I--) {
163 if (Mask & (1 << I)) {
164 emitARMWinUnwindCode(Win64EH::UOP_SaveRegsR4R7LR, I, Lr);
165 return;
166 }
167 }
168 llvm_unreachable("logic error");
169 }
170 }
171 Mask |= Lr << 14;
172 if (Wide)
173 emitARMWinUnwindCode(Win64EH::UOP_WideSaveRegMask, Mask, 0);
174 else
175 emitARMWinUnwindCode(Win64EH::UOP_SaveRegMask, Mask, 0);
176}
177
178void ARMTargetWinCOFFStreamer::emitARMWinCFISaveSP(unsigned Reg) {
179 emitARMWinUnwindCode(Win64EH::UOP_SaveSP, Reg, 0);
180}
181
182void ARMTargetWinCOFFStreamer::emitARMWinCFISaveFRegs(unsigned First,
183 unsigned Last) {
184 assert(First <= Last);
185 assert(First >= 16 || Last < 16);
186 assert(First <= 31 && Last <= 31);
187 if (First == 8)
188 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD8D15, Last, 0);
189 else if (First <= 15)
190 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD0D15, First, Last);
191 else
192 emitARMWinUnwindCode(Win64EH::UOP_SaveFRegD16D31, First, Last);
193}
194
195void ARMTargetWinCOFFStreamer::emitARMWinCFISaveLR(unsigned Offset) {
196 emitARMWinUnwindCode(Win64EH::UOP_SaveLR, 0, Offset);
197}
198
199void ARMTargetWinCOFFStreamer::emitARMWinCFINop(bool Wide) {
200 if (Wide)
201 emitARMWinUnwindCode(Win64EH::UOP_WideNop, -1, 0);
202 else
203 emitARMWinUnwindCode(Win64EH::UOP_Nop, -1, 0);
204}
205
206void ARMTargetWinCOFFStreamer::emitARMWinCFIPrologEnd(bool Fragment) {
207 auto &S = getStreamer();
208 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
209 if (!CurFrame)
210 return;
211
212 MCSymbol *Label = S.emitCFILabel();
213 CurFrame->PrologEnd = Label;
214 WinEH::Instruction Inst =
215 WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0);
216 auto it = CurFrame->Instructions.begin();
217 CurFrame->Instructions.insert(it, Inst);
218 CurFrame->Fragment = Fragment;
219}
220
221void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogStart(unsigned Condition) {
222 auto &S = getStreamer();
223 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
224 if (!CurFrame)
225 return;
226
227 InEpilogCFI = true;
228 CurrentEpilog = S.emitCFILabel();
229 CurFrame->EpilogMap[CurrentEpilog].Condition = Condition;
230}
231
232void ARMTargetWinCOFFStreamer::emitARMWinCFIEpilogEnd() {
233 auto &S = getStreamer();
234 WinEH::FrameInfo *CurFrame = S.EnsureValidWinFrameInfo(SMLoc());
235 if (!CurFrame)
236 return;
237
238 if (!CurrentEpilog) {
239 S.getContext().reportError(SMLoc(), "Stray .seh_endepilogue in " +
240 CurFrame->Function->getName());
241 return;
242 }
243
244 std::vector<WinEH::Instruction> &Epilog =
245 CurFrame->EpilogMap[CurrentEpilog].Instructions;
246
247 unsigned UnwindCode = Win64EH::UOP_End;
248 if (!Epilog.empty()) {
249 WinEH::Instruction EndInstr = Epilog.back();
250 if (EndInstr.Operation == Win64EH::UOP_Nop) {
251 UnwindCode = Win64EH::UOP_EndNop;
252 Epilog.pop_back();
253 } else if (EndInstr.Operation == Win64EH::UOP_WideNop) {
254 UnwindCode = Win64EH::UOP_WideEndNop;
255 Epilog.pop_back();
256 }
257 }
258
259 InEpilogCFI = false;
260 WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0);
261 CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst);
262 MCSymbol *Label = S.emitCFILabel();
263 CurFrame->EpilogMap[CurrentEpilog].End = Label;
264 CurrentEpilog = nullptr;
265}
266
267void ARMTargetWinCOFFStreamer::emitARMWinCFICustom(unsigned Opcode) {
268 emitARMWinUnwindCode(Win64EH::UOP_Custom, 0, Opcode);
269}
270
271} // end anonymous namespace
272
274 return new ARMTargetWinCOFFStreamer(S);
275}
dxil DXContainer Global Emitter
uint64_t Size
#define I(x, y, z)
Definition: MD5.cpp:58
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:83
Streaming machine code generation interface.
Definition: MCStreamer.h:213
virtual void emitWindowsUnwindTables()
virtual void emitWinEHHandlerData(SMLoc Loc=SMLoc())
Definition: MCStreamer.cpp:845
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
StringRef getName() const
getName - Get the symbol name.
Definition: MCSymbol.h:205
Target specific streamer interface.
Definition: MCStreamer.h:94
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:125
@ 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:480
@ 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:1873
MCTargetStreamer * createARMObjectTargetWinCOFFStreamer(MCStreamer &S)
MCStreamer * createARMWinCOFFStreamer(MCContext &Context, std::unique_ptr< MCAsmBackend > &&MAB, std::unique_ptr< MCObjectWriter > &&OW, std::unique_ptr< MCCodeEmitter > &&Emitter)
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