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