Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC/MCWin64EH.cpp
Warning:line 1841, column 7
Value stored to 'HasR11' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name MCWin64EH.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -resource-dir /usr/lib/llvm-16/lib/clang/16.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/MC -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-16/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC/MCWin64EH.cpp
1//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
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 "llvm/MC/MCWin64EH.h"
10#include "llvm/ADT/Optional.h"
11#include "llvm/ADT/Twine.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCExpr.h"
14#include "llvm/MC/MCObjectStreamer.h"
15#include "llvm/MC/MCStreamer.h"
16#include "llvm/MC/MCSymbol.h"
17#include "llvm/Support/Win64EH.h"
18namespace llvm {
19class MCSection;
20}
21
22using namespace llvm;
23
24// NOTE: All relocations generated here are 4-byte image-relative.
25
26static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
27 uint8_t Count = 0;
28 for (const auto &I : Insns) {
29 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
30 default:
31 llvm_unreachable("Unsupported unwind code")::llvm::llvm_unreachable_internal("Unsupported unwind code", "llvm/lib/MC/MCWin64EH.cpp"
, 31)
;
32 case Win64EH::UOP_PushNonVol:
33 case Win64EH::UOP_AllocSmall:
34 case Win64EH::UOP_SetFPReg:
35 case Win64EH::UOP_PushMachFrame:
36 Count += 1;
37 break;
38 case Win64EH::UOP_SaveNonVol:
39 case Win64EH::UOP_SaveXMM128:
40 Count += 2;
41 break;
42 case Win64EH::UOP_SaveNonVolBig:
43 case Win64EH::UOP_SaveXMM128Big:
44 Count += 3;
45 break;
46 case Win64EH::UOP_AllocLarge:
47 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
48 break;
49 }
50 }
51 return Count;
52}
53
54static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
55 const MCSymbol *RHS) {
56 MCContext &Context = Streamer.getContext();
57 const MCExpr *Diff =
58 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
59 MCSymbolRefExpr::create(RHS, Context), Context);
60 Streamer.emitValue(Diff, 1);
61}
62
63static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
64 WinEH::Instruction &inst) {
65 uint8_t b2;
66 uint16_t w;
67 b2 = (inst.Operation & 0x0F);
68 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
69 default:
70 llvm_unreachable("Unsupported unwind code")::llvm::llvm_unreachable_internal("Unsupported unwind code", "llvm/lib/MC/MCWin64EH.cpp"
, 70)
;
71 case Win64EH::UOP_PushNonVol:
72 EmitAbsDifference(streamer, inst.Label, begin);
73 b2 |= (inst.Register & 0x0F) << 4;
74 streamer.emitInt8(b2);
75 break;
76 case Win64EH::UOP_AllocLarge:
77 EmitAbsDifference(streamer, inst.Label, begin);
78 if (inst.Offset > 512 * 1024 - 8) {
79 b2 |= 0x10;
80 streamer.emitInt8(b2);
81 w = inst.Offset & 0xFFF8;
82 streamer.emitInt16(w);
83 w = inst.Offset >> 16;
84 } else {
85 streamer.emitInt8(b2);
86 w = inst.Offset >> 3;
87 }
88 streamer.emitInt16(w);
89 break;
90 case Win64EH::UOP_AllocSmall:
91 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
92 EmitAbsDifference(streamer, inst.Label, begin);
93 streamer.emitInt8(b2);
94 break;
95 case Win64EH::UOP_SetFPReg:
96 EmitAbsDifference(streamer, inst.Label, begin);
97 streamer.emitInt8(b2);
98 break;
99 case Win64EH::UOP_SaveNonVol:
100 case Win64EH::UOP_SaveXMM128:
101 b2 |= (inst.Register & 0x0F) << 4;
102 EmitAbsDifference(streamer, inst.Label, begin);
103 streamer.emitInt8(b2);
104 w = inst.Offset >> 3;
105 if (inst.Operation == Win64EH::UOP_SaveXMM128)
106 w >>= 1;
107 streamer.emitInt16(w);
108 break;
109 case Win64EH::UOP_SaveNonVolBig:
110 case Win64EH::UOP_SaveXMM128Big:
111 b2 |= (inst.Register & 0x0F) << 4;
112 EmitAbsDifference(streamer, inst.Label, begin);
113 streamer.emitInt8(b2);
114 if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
115 w = inst.Offset & 0xFFF0;
116 else
117 w = inst.Offset & 0xFFF8;
118 streamer.emitInt16(w);
119 w = inst.Offset >> 16;
120 streamer.emitInt16(w);
121 break;
122 case Win64EH::UOP_PushMachFrame:
123 if (inst.Offset == 1)
124 b2 |= 0x10;
125 EmitAbsDifference(streamer, inst.Label, begin);
126 streamer.emitInt8(b2);
127 break;
128 }
129}
130
131static void EmitSymbolRefWithOfs(MCStreamer &streamer,
132 const MCSymbol *Base,
133 int64_t Offset) {
134 MCContext &Context = streamer.getContext();
135 const MCConstantExpr *OffExpr = MCConstantExpr::create(Offset, Context);
136 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
137 MCSymbolRefExpr::VK_COFF_IMGREL32,
138 Context);
139 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, OffExpr, Context), 4);
140}
141
142static void EmitSymbolRefWithOfs(MCStreamer &streamer,
143 const MCSymbol *Base,
144 const MCSymbol *Other) {
145 MCContext &Context = streamer.getContext();
146 const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
147 const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
148 const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
149 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
150 MCSymbolRefExpr::VK_COFF_IMGREL32,
151 Context);
152 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
153}
154
155static void EmitRuntimeFunction(MCStreamer &streamer,
156 const WinEH::FrameInfo *info) {
157 MCContext &context = streamer.getContext();
158
159 streamer.emitValueToAlignment(4);
160 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
161 EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
162 streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
163 MCSymbolRefExpr::VK_COFF_IMGREL32,
164 context), 4);
165}
166
167static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
168 // If this UNWIND_INFO already has a symbol, it's already been emitted.
169 if (info->Symbol)
170 return;
171
172 MCContext &context = streamer.getContext();
173 MCSymbol *Label = context.createTempSymbol();
174
175 streamer.emitValueToAlignment(4);
176 streamer.emitLabel(Label);
177 info->Symbol = Label;
178
179 // Upper 3 bits are the version number (currently 1).
180 uint8_t flags = 0x01;
181 if (info->ChainedParent)
182 flags |= Win64EH::UNW_ChainInfo << 3;
183 else {
184 if (info->HandlesUnwind)
185 flags |= Win64EH::UNW_TerminateHandler << 3;
186 if (info->HandlesExceptions)
187 flags |= Win64EH::UNW_ExceptionHandler << 3;
188 }
189 streamer.emitInt8(flags);
190
191 if (info->PrologEnd)
192 EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
193 else
194 streamer.emitInt8(0);
195
196 uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
197 streamer.emitInt8(numCodes);
198
199 uint8_t frame = 0;
200 if (info->LastFrameInst >= 0) {
201 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
202 assert(frameInst.Operation == Win64EH::UOP_SetFPReg)(static_cast <bool> (frameInst.Operation == Win64EH::UOP_SetFPReg
) ? void (0) : __assert_fail ("frameInst.Operation == Win64EH::UOP_SetFPReg"
, "llvm/lib/MC/MCWin64EH.cpp", 202, __extension__ __PRETTY_FUNCTION__
))
;
203 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
204 }
205 streamer.emitInt8(frame);
206
207 // Emit unwind instructions (in reverse order).
208 uint8_t numInst = info->Instructions.size();
209 for (uint8_t c = 0; c < numInst; ++c) {
210 WinEH::Instruction inst = info->Instructions.back();
211 info->Instructions.pop_back();
212 EmitUnwindCode(streamer, info->Begin, inst);
213 }
214
215 // For alignment purposes, the instruction array will always have an even
216 // number of entries, with the final entry potentially unused (in which case
217 // the array will be one longer than indicated by the count of unwind codes
218 // field).
219 if (numCodes & 1) {
220 streamer.emitInt16(0);
221 }
222
223 if (flags & (Win64EH::UNW_ChainInfo << 3))
224 EmitRuntimeFunction(streamer, info->ChainedParent);
225 else if (flags &
226 ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
227 streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
228 MCSymbolRefExpr::VK_COFF_IMGREL32,
229 context), 4);
230 else if (numCodes == 0) {
231 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
232 // a chained unwind info, if there is no handler, and if there are fewer
233 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
234 streamer.emitInt32(0);
235 }
236}
237
238void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const {
239 // Emit the unwind info structs first.
240 for (const auto &CFI : Streamer.getWinFrameInfos()) {
241 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
242 Streamer.switchSection(XData);
243 ::EmitUnwindInfo(Streamer, CFI.get());
244 }
245
246 // Now emit RUNTIME_FUNCTION entries.
247 for (const auto &CFI : Streamer.getWinFrameInfos()) {
248 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
249 Streamer.switchSection(PData);
250 EmitRuntimeFunction(Streamer, CFI.get());
251 }
252}
253
254void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
255 WinEH::FrameInfo *info,
256 bool HandlerData) const {
257 // Switch sections (the static function above is meant to be called from
258 // here and from Emit().
259 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
260 Streamer.switchSection(XData);
261
262 ::EmitUnwindInfo(Streamer, info);
263}
264
265static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
266 const MCSymbol *RHS, int Div) {
267 MCContext &Context = Streamer.getContext();
268 const MCExpr *Expr =
269 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
270 MCSymbolRefExpr::create(RHS, Context), Context);
271 if (Div != 1)
272 Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(Div, Context),
273 Context);
274 return Expr;
275}
276
277static Optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
278 const MCSymbol *LHS,
279 const MCSymbol *RHS) {
280 MCContext &Context = Streamer.getContext();
281 const MCExpr *Diff =
282 MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
283 MCSymbolRefExpr::create(RHS, Context), Context);
284 MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
285 // It should normally be possible to calculate the length of a function
286 // at this point, but it might not be possible in the presence of certain
287 // unusual constructs, like an inline asm with an alignment directive.
288 int64_t value;
289 if (!Diff->evaluateAsAbsolute(value, OS->getAssembler()))
290 return None;
291 return value;
292}
293
294static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
295 const MCSymbol *RHS) {
296 Optional<int64_t> MaybeDiff = GetOptionalAbsDifference(Streamer, LHS, RHS);
297 if (!MaybeDiff)
298 report_fatal_error("Failed to evaluate function length in SEH unwind info");
299 return *MaybeDiff;
300}
301
302static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
303 uint32_t Count = 0;
304 for (const auto &I : Insns) {
305 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
306 default:
307 llvm_unreachable("Unsupported ARM64 unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM64 unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 307)
;
308 case Win64EH::UOP_AllocSmall:
309 Count += 1;
310 break;
311 case Win64EH::UOP_AllocMedium:
312 Count += 2;
313 break;
314 case Win64EH::UOP_AllocLarge:
315 Count += 4;
316 break;
317 case Win64EH::UOP_SaveR19R20X:
318 Count += 1;
319 break;
320 case Win64EH::UOP_SaveFPLRX:
321 Count += 1;
322 break;
323 case Win64EH::UOP_SaveFPLR:
324 Count += 1;
325 break;
326 case Win64EH::UOP_SaveReg:
327 Count += 2;
328 break;
329 case Win64EH::UOP_SaveRegP:
330 Count += 2;
331 break;
332 case Win64EH::UOP_SaveRegPX:
333 Count += 2;
334 break;
335 case Win64EH::UOP_SaveRegX:
336 Count += 2;
337 break;
338 case Win64EH::UOP_SaveLRPair:
339 Count += 2;
340 break;
341 case Win64EH::UOP_SaveFReg:
342 Count += 2;
343 break;
344 case Win64EH::UOP_SaveFRegP:
345 Count += 2;
346 break;
347 case Win64EH::UOP_SaveFRegX:
348 Count += 2;
349 break;
350 case Win64EH::UOP_SaveFRegPX:
351 Count += 2;
352 break;
353 case Win64EH::UOP_SetFP:
354 Count += 1;
355 break;
356 case Win64EH::UOP_AddFP:
357 Count += 2;
358 break;
359 case Win64EH::UOP_Nop:
360 Count += 1;
361 break;
362 case Win64EH::UOP_End:
363 Count += 1;
364 break;
365 case Win64EH::UOP_SaveNext:
366 Count += 1;
367 break;
368 case Win64EH::UOP_TrapFrame:
369 Count += 1;
370 break;
371 case Win64EH::UOP_PushMachFrame:
372 Count += 1;
373 break;
374 case Win64EH::UOP_Context:
375 Count += 1;
376 break;
377 case Win64EH::UOP_ClearUnwoundToCall:
378 Count += 1;
379 break;
380 }
381 }
382 return Count;
383}
384
385// Unwind opcode encodings and restrictions are documented at
386// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
387static void ARM64EmitUnwindCode(MCStreamer &streamer,
388 const WinEH::Instruction &inst) {
389 uint8_t b, reg;
390 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
391 default:
392 llvm_unreachable("Unsupported ARM64 unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM64 unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 392)
;
393 case Win64EH::UOP_AllocSmall:
394 b = (inst.Offset >> 4) & 0x1F;
395 streamer.emitInt8(b);
396 break;
397 case Win64EH::UOP_AllocMedium: {
398 uint16_t hw = (inst.Offset >> 4) & 0x7FF;
399 b = 0xC0;
400 b |= (hw >> 8);
401 streamer.emitInt8(b);
402 b = hw & 0xFF;
403 streamer.emitInt8(b);
404 break;
405 }
406 case Win64EH::UOP_AllocLarge: {
407 uint32_t w;
408 b = 0xE0;
409 streamer.emitInt8(b);
410 w = inst.Offset >> 4;
411 b = (w & 0x00FF0000) >> 16;
412 streamer.emitInt8(b);
413 b = (w & 0x0000FF00) >> 8;
414 streamer.emitInt8(b);
415 b = w & 0x000000FF;
416 streamer.emitInt8(b);
417 break;
418 }
419 case Win64EH::UOP_SetFP:
420 b = 0xE1;
421 streamer.emitInt8(b);
422 break;
423 case Win64EH::UOP_AddFP:
424 b = 0xE2;
425 streamer.emitInt8(b);
426 b = (inst.Offset >> 3);
427 streamer.emitInt8(b);
428 break;
429 case Win64EH::UOP_Nop:
430 b = 0xE3;
431 streamer.emitInt8(b);
432 break;
433 case Win64EH::UOP_SaveR19R20X:
434 b = 0x20;
435 b |= (inst.Offset >> 3) & 0x1F;
436 streamer.emitInt8(b);
437 break;
438 case Win64EH::UOP_SaveFPLRX:
439 b = 0x80;
440 b |= ((inst.Offset - 1) >> 3) & 0x3F;
441 streamer.emitInt8(b);
442 break;
443 case Win64EH::UOP_SaveFPLR:
444 b = 0x40;
445 b |= (inst.Offset >> 3) & 0x3F;
446 streamer.emitInt8(b);
447 break;
448 case Win64EH::UOP_SaveReg:
449 assert(inst.Register >= 19 && "Saved reg must be >= 19")(static_cast <bool> (inst.Register >= 19 && "Saved reg must be >= 19"
) ? void (0) : __assert_fail ("inst.Register >= 19 && \"Saved reg must be >= 19\""
, "llvm/lib/MC/MCWin64EH.cpp", 449, __extension__ __PRETTY_FUNCTION__
))
;
450 reg = inst.Register - 19;
451 b = 0xD0 | ((reg & 0xC) >> 2);
452 streamer.emitInt8(b);
453 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
454 streamer.emitInt8(b);
455 break;
456 case Win64EH::UOP_SaveRegX:
457 assert(inst.Register >= 19 && "Saved reg must be >= 19")(static_cast <bool> (inst.Register >= 19 && "Saved reg must be >= 19"
) ? void (0) : __assert_fail ("inst.Register >= 19 && \"Saved reg must be >= 19\""
, "llvm/lib/MC/MCWin64EH.cpp", 457, __extension__ __PRETTY_FUNCTION__
))
;
458 reg = inst.Register - 19;
459 b = 0xD4 | ((reg & 0x8) >> 3);
460 streamer.emitInt8(b);
461 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
462 streamer.emitInt8(b);
463 break;
464 case Win64EH::UOP_SaveRegP:
465 assert(inst.Register >= 19 && "Saved registers must be >= 19")(static_cast <bool> (inst.Register >= 19 && "Saved registers must be >= 19"
) ? void (0) : __assert_fail ("inst.Register >= 19 && \"Saved registers must be >= 19\""
, "llvm/lib/MC/MCWin64EH.cpp", 465, __extension__ __PRETTY_FUNCTION__
))
;
466 reg = inst.Register - 19;
467 b = 0xC8 | ((reg & 0xC) >> 2);
468 streamer.emitInt8(b);
469 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
470 streamer.emitInt8(b);
471 break;
472 case Win64EH::UOP_SaveRegPX:
473 assert(inst.Register >= 19 && "Saved registers must be >= 19")(static_cast <bool> (inst.Register >= 19 && "Saved registers must be >= 19"
) ? void (0) : __assert_fail ("inst.Register >= 19 && \"Saved registers must be >= 19\""
, "llvm/lib/MC/MCWin64EH.cpp", 473, __extension__ __PRETTY_FUNCTION__
))
;
474 reg = inst.Register - 19;
475 b = 0xCC | ((reg & 0xC) >> 2);
476 streamer.emitInt8(b);
477 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
478 streamer.emitInt8(b);
479 break;
480 case Win64EH::UOP_SaveLRPair:
481 assert(inst.Register >= 19 && "Saved reg must be >= 19")(static_cast <bool> (inst.Register >= 19 && "Saved reg must be >= 19"
) ? void (0) : __assert_fail ("inst.Register >= 19 && \"Saved reg must be >= 19\""
, "llvm/lib/MC/MCWin64EH.cpp", 481, __extension__ __PRETTY_FUNCTION__
))
;
482 reg = inst.Register - 19;
483 assert((reg % 2) == 0 && "Saved reg must be 19+2*X")(static_cast <bool> ((reg % 2) == 0 && "Saved reg must be 19+2*X"
) ? void (0) : __assert_fail ("(reg % 2) == 0 && \"Saved reg must be 19+2*X\""
, "llvm/lib/MC/MCWin64EH.cpp", 483, __extension__ __PRETTY_FUNCTION__
))
;
484 reg /= 2;
485 b = 0xD6 | ((reg & 0x7) >> 2);
486 streamer.emitInt8(b);
487 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
488 streamer.emitInt8(b);
489 break;
490 case Win64EH::UOP_SaveFReg:
491 assert(inst.Register >= 8 && "Saved dreg must be >= 8")(static_cast <bool> (inst.Register >= 8 && "Saved dreg must be >= 8"
) ? void (0) : __assert_fail ("inst.Register >= 8 && \"Saved dreg must be >= 8\""
, "llvm/lib/MC/MCWin64EH.cpp", 491, __extension__ __PRETTY_FUNCTION__
))
;
492 reg = inst.Register - 8;
493 b = 0xDC | ((reg & 0x4) >> 2);
494 streamer.emitInt8(b);
495 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
496 streamer.emitInt8(b);
497 break;
498 case Win64EH::UOP_SaveFRegX:
499 assert(inst.Register >= 8 && "Saved dreg must be >= 8")(static_cast <bool> (inst.Register >= 8 && "Saved dreg must be >= 8"
) ? void (0) : __assert_fail ("inst.Register >= 8 && \"Saved dreg must be >= 8\""
, "llvm/lib/MC/MCWin64EH.cpp", 499, __extension__ __PRETTY_FUNCTION__
))
;
500 reg = inst.Register - 8;
501 b = 0xDE;
502 streamer.emitInt8(b);
503 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
504 streamer.emitInt8(b);
505 break;
506 case Win64EH::UOP_SaveFRegP:
507 assert(inst.Register >= 8 && "Saved dregs must be >= 8")(static_cast <bool> (inst.Register >= 8 && "Saved dregs must be >= 8"
) ? void (0) : __assert_fail ("inst.Register >= 8 && \"Saved dregs must be >= 8\""
, "llvm/lib/MC/MCWin64EH.cpp", 507, __extension__ __PRETTY_FUNCTION__
))
;
508 reg = inst.Register - 8;
509 b = 0xD8 | ((reg & 0x4) >> 2);
510 streamer.emitInt8(b);
511 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
512 streamer.emitInt8(b);
513 break;
514 case Win64EH::UOP_SaveFRegPX:
515 assert(inst.Register >= 8 && "Saved dregs must be >= 8")(static_cast <bool> (inst.Register >= 8 && "Saved dregs must be >= 8"
) ? void (0) : __assert_fail ("inst.Register >= 8 && \"Saved dregs must be >= 8\""
, "llvm/lib/MC/MCWin64EH.cpp", 515, __extension__ __PRETTY_FUNCTION__
))
;
516 reg = inst.Register - 8;
517 b = 0xDA | ((reg & 0x4) >> 2);
518 streamer.emitInt8(b);
519 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
520 streamer.emitInt8(b);
521 break;
522 case Win64EH::UOP_End:
523 b = 0xE4;
524 streamer.emitInt8(b);
525 break;
526 case Win64EH::UOP_SaveNext:
527 b = 0xE6;
528 streamer.emitInt8(b);
529 break;
530 case Win64EH::UOP_TrapFrame:
531 b = 0xE8;
532 streamer.emitInt8(b);
533 break;
534 case Win64EH::UOP_PushMachFrame:
535 b = 0xE9;
536 streamer.emitInt8(b);
537 break;
538 case Win64EH::UOP_Context:
539 b = 0xEA;
540 streamer.emitInt8(b);
541 break;
542 case Win64EH::UOP_ClearUnwoundToCall:
543 b = 0xEC;
544 streamer.emitInt8(b);
545 break;
546 }
547}
548
549// Returns the epilog symbol of an epilog with the exact same unwind code
550// sequence, if it exists. Otherwise, returns nullptr.
551// EpilogInstrs - Unwind codes for the current epilog.
552// Epilogs - Epilogs that potentialy match the current epilog.
553static MCSymbol*
554FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
555 const std::vector<MCSymbol *>& Epilogs,
556 const WinEH::FrameInfo *info) {
557 for (auto *EpilogStart : Epilogs) {
558 auto InstrsIter = info->EpilogMap.find(EpilogStart);
559 assert(InstrsIter != info->EpilogMap.end() &&(static_cast <bool> (InstrsIter != info->EpilogMap.end
() && "Epilog not found in EpilogMap") ? void (0) : __assert_fail
("InstrsIter != info->EpilogMap.end() && \"Epilog not found in EpilogMap\""
, "llvm/lib/MC/MCWin64EH.cpp", 560, __extension__ __PRETTY_FUNCTION__
))
560 "Epilog not found in EpilogMap")(static_cast <bool> (InstrsIter != info->EpilogMap.end
() && "Epilog not found in EpilogMap") ? void (0) : __assert_fail
("InstrsIter != info->EpilogMap.end() && \"Epilog not found in EpilogMap\""
, "llvm/lib/MC/MCWin64EH.cpp", 560, __extension__ __PRETTY_FUNCTION__
))
;
561 const auto &Instrs = InstrsIter->second.Instructions;
562
563 if (Instrs.size() != EpilogInstrs.size())
564 continue;
565
566 bool Match = true;
567 for (unsigned i = 0; i < Instrs.size(); ++i)
568 if (Instrs[i] != EpilogInstrs[i]) {
569 Match = false;
570 break;
571 }
572
573 if (Match)
574 return EpilogStart;
575 }
576 return nullptr;
577}
578
579static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
580 bool Reverse) {
581 unsigned PrevOffset = -1;
582 unsigned PrevRegister = -1;
583
584 auto VisitInstruction = [&](WinEH::Instruction &Inst) {
585 // Convert 2-byte opcodes into equivalent 1-byte ones.
586 if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
587 Inst.Operation = Win64EH::UOP_SaveFPLR;
588 Inst.Register = -1;
589 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
590 Inst.Register == 29) {
591 Inst.Operation = Win64EH::UOP_SaveFPLRX;
592 Inst.Register = -1;
593 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
594 Inst.Register == 19 && Inst.Offset <= 248) {
595 Inst.Operation = Win64EH::UOP_SaveR19R20X;
596 Inst.Register = -1;
597 } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
598 Inst.Operation = Win64EH::UOP_SetFP;
599 } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
600 Inst.Register == PrevRegister + 2 &&
601 Inst.Offset == PrevOffset + 16) {
602 Inst.Operation = Win64EH::UOP_SaveNext;
603 Inst.Register = -1;
604 Inst.Offset = 0;
605 // Intentionally not creating UOP_SaveNext for float register pairs,
606 // as current versions of Windows (up to at least 20.04) is buggy
607 // regarding SaveNext for float pairs.
608 }
609 // Update info about the previous instruction, for detecting if
610 // the next one can be made a UOP_SaveNext
611 if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
612 PrevOffset = 0;
613 PrevRegister = 19;
614 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
615 PrevOffset = 0;
616 PrevRegister = Inst.Register;
617 } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
618 PrevOffset = Inst.Offset;
619 PrevRegister = Inst.Register;
620 } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
621 PrevRegister += 2;
622 PrevOffset += 16;
623 } else {
624 PrevRegister = -1;
625 PrevOffset = -1;
626 }
627 };
628
629 // Iterate over instructions in a forward order (for prologues),
630 // backwards for epilogues (i.e. always reverse compared to how the
631 // opcodes are stored).
632 if (Reverse) {
633 for (auto It = Instructions.rbegin(); It != Instructions.rend(); It++)
634 VisitInstruction(*It);
635 } else {
636 for (WinEH::Instruction &Inst : Instructions)
637 VisitInstruction(Inst);
638 }
639}
640
641// Check if an epilog exists as a subset of the end of a prolog (backwards).
642static int
643getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
644 const std::vector<WinEH::Instruction> &Epilog) {
645 // Can't find an epilog as a subset if it is longer than the prolog.
646 if (Epilog.size() > Prolog.size())
647 return -1;
648
649 // Check that the epilog actually is a perfect match for the end (backwrds)
650 // of the prolog.
651 for (int I = Epilog.size() - 1; I >= 0; I--) {
652 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
653 return -1;
654 }
655
656 if (Epilog.size() == Prolog.size())
657 return 0;
658
659 // If the epilog was a subset of the prolog, find its offset.
660 return ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
661 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
662}
663
664static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
665 WinEH::FrameInfo::Segment *Seg,
666 int PrologCodeBytes) {
667 // Can only pack if there's one single epilog
668 if (Seg->Epilogs.size() != 1)
669 return -1;
670
671 MCSymbol *Sym = Seg->Epilogs.begin()->first;
672 const std::vector<WinEH::Instruction> &Epilog =
673 info->EpilogMap[Sym].Instructions;
674
675 // Check that the epilog actually is at the very end of the function,
676 // otherwise it can't be packed.
677 uint32_t DistanceFromEnd =
678 (uint32_t)(Seg->Offset + Seg->Length - Seg->Epilogs.begin()->second);
679 if (DistanceFromEnd / 4 != Epilog.size())
680 return -1;
681
682 int RetVal = -1;
683 // Even if we don't end up sharing opcodes with the prolog, we can still
684 // write the offset as a packed offset, if the single epilog is located at
685 // the end of the function and the offset (pointing after the prolog) fits
686 // as a packed offset.
687 if (PrologCodeBytes <= 31 &&
688 PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
689 RetVal = PrologCodeBytes;
690
691 int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
692 if (Offset < 0)
693 return RetVal;
694
695 // Check that the offset and prolog size fits in the first word; it's
696 // unclear whether the epilog count in the extension word can be taken
697 // as packed epilog offset.
698 if (Offset > 31 || PrologCodeBytes > 124)
699 return RetVal;
700
701 // As we choose to express the epilog as part of the prolog, remove the
702 // epilog from the map, so we don't try to emit its opcodes.
703 info->EpilogMap.erase(Sym);
704 return Offset;
705}
706
707static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
708 int PackedEpilogOffset) {
709 if (PackedEpilogOffset == 0) {
710 // Fully symmetric prolog and epilog, should be ok for packed format.
711 // For CR=3, the corresponding synthesized epilog actually lacks the
712 // SetFP opcode, but unwinding should work just fine despite that
713 // (if at the SetFP opcode, the unwinder considers it as part of the
714 // function body and just unwinds the full prolog instead).
715 } else if (PackedEpilogOffset == 1) {
716 // One single case of differences between prolog and epilog is allowed:
717 // The epilog can lack a single SetFP that is the last opcode in the
718 // prolog, for the CR=3 case.
719 if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
720 return false;
721 } else {
722 // Too much difference between prolog and epilog.
723 return false;
724 }
725 unsigned RegI = 0, RegF = 0;
726 int Predecrement = 0;
727 enum {
728 Start,
729 Start2,
730 IntRegs,
731 FloatRegs,
732 InputArgs,
733 StackAdjust,
734 FrameRecord,
735 End
736 } Location = Start;
737 bool StandaloneLR = false, FPLRPair = false;
738 int StackOffset = 0;
739 int Nops = 0;
740 // Iterate over the prolog and check that all opcodes exactly match
741 // the canonical order and form. A more lax check could verify that
742 // all saved registers are in the expected locations, but not enforce
743 // the order - that would work fine when unwinding from within
744 // functions, but not be exactly right if unwinding happens within
745 // prologs/epilogs.
746 for (const WinEH::Instruction &Inst : info->Instructions) {
747 switch (Inst.Operation) {
748 case Win64EH::UOP_End:
749 if (Location != Start)
750 return false;
751 Location = Start2;
752 break;
753 case Win64EH::UOP_SaveR19R20X:
754 if (Location != Start2)
755 return false;
756 Predecrement = Inst.Offset;
757 RegI = 2;
758 Location = IntRegs;
759 break;
760 case Win64EH::UOP_SaveRegX:
761 if (Location != Start2)
762 return false;
763 Predecrement = Inst.Offset;
764 if (Inst.Register == 19)
765 RegI += 1;
766 else if (Inst.Register == 30)
767 StandaloneLR = true;
768 else
769 return false;
770 // Odd register; can't be any further int registers.
771 Location = FloatRegs;
772 break;
773 case Win64EH::UOP_SaveRegPX:
774 // Can't have this in a canonical prologue. Either this has been
775 // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
776 // register pair.
777 // It can't be canonicalized into SaveR19R20X if the offset is
778 // larger than 248 bytes, but even with the maximum case with
779 // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
780 // fit into SaveR19R20X.
781 // The unwinding opcodes can't describe the otherwise seemingly valid
782 // case for RegI=1 CR=1, that would start with a
783 // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
784 // SaveLRPair.
785 return false;
786 case Win64EH::UOP_SaveRegP:
787 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
788 Inst.Register != 19 + RegI)
789 return false;
790 RegI += 2;
791 break;
792 case Win64EH::UOP_SaveReg:
793 if (Location != IntRegs || Inst.Offset != 8 * RegI)
794 return false;
795 if (Inst.Register == 19 + RegI)
796 RegI += 1;
797 else if (Inst.Register == 30)
798 StandaloneLR = true;
799 else
800 return false;
801 // Odd register; can't be any further int registers.
802 Location = FloatRegs;
803 break;
804 case Win64EH::UOP_SaveLRPair:
805 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
806 Inst.Register != 19 + RegI)
807 return false;
808 RegI += 1;
809 StandaloneLR = true;
810 Location = FloatRegs;
811 break;
812 case Win64EH::UOP_SaveFRegX:
813 // Packed unwind can't handle prologs that only save one single
814 // float register.
815 return false;
816 case Win64EH::UOP_SaveFReg:
817 if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
818 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
819 return false;
820 RegF += 1;
821 Location = InputArgs;
822 break;
823 case Win64EH::UOP_SaveFRegPX:
824 if (Location != Start2 || Inst.Register != 8)
825 return false;
826 Predecrement = Inst.Offset;
827 RegF = 2;
828 Location = FloatRegs;
829 break;
830 case Win64EH::UOP_SaveFRegP:
831 if ((Location != IntRegs && Location != FloatRegs) ||
832 Inst.Register != 8 + RegF ||
833 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
834 return false;
835 RegF += 2;
836 Location = FloatRegs;
837 break;
838 case Win64EH::UOP_SaveNext:
839 if (Location == IntRegs)
840 RegI += 2;
841 else if (Location == FloatRegs)
842 RegF += 2;
843 else
844 return false;
845 break;
846 case Win64EH::UOP_Nop:
847 if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
848 return false;
849 Location = InputArgs;
850 Nops++;
851 break;
852 case Win64EH::UOP_AllocSmall:
853 case Win64EH::UOP_AllocMedium:
854 if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
855 Location != InputArgs && Location != StackAdjust)
856 return false;
857 // Can have either a single decrement, or a pair of decrements with
858 // 4080 and another decrement.
859 if (StackOffset == 0)
860 StackOffset = Inst.Offset;
861 else if (StackOffset != 4080)
862 return false;
863 else
864 StackOffset += Inst.Offset;
865 Location = StackAdjust;
866 break;
867 case Win64EH::UOP_SaveFPLRX:
868 // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
869 // should be followed by a FPLR instead.
870 if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
871 Location != InputArgs)
872 return false;
873 StackOffset = Inst.Offset;
874 Location = FrameRecord;
875 FPLRPair = true;
876 break;
877 case Win64EH::UOP_SaveFPLR:
878 // This can only follow after a StackAdjust
879 if (Location != StackAdjust || Inst.Offset != 0)
880 return false;
881 Location = FrameRecord;
882 FPLRPair = true;
883 break;
884 case Win64EH::UOP_SetFP:
885 if (Location != FrameRecord)
886 return false;
887 Location = End;
888 break;
889 }
890 }
891 if (RegI > 10 || RegF > 8)
892 return false;
893 if (StandaloneLR && FPLRPair)
894 return false;
895 if (FPLRPair && Location != End)
896 return false;
897 if (Nops != 0 && Nops != 4)
898 return false;
899 int H = Nops == 4;
900 // There's an inconsistency regarding packed unwind info with homed
901 // parameters; according to the documentation, the epilog shouldn't have
902 // the same corresponding nops (and thus, to set the H bit, we should
903 // require an epilog which isn't exactly symmetrical - we shouldn't accept
904 // an exact mirrored epilog for those cases), but in practice,
905 // RtlVirtualUnwind behaves as if it does expect the epilogue to contain
906 // the same nops. See https://github.com/llvm/llvm-project/issues/54879.
907 // To play it safe, don't produce packed unwind info with homed parameters.
908 if (H)
909 return false;
910 int IntSZ = 8 * RegI;
911 if (StandaloneLR)
912 IntSZ += 8;
913 int FpSZ = 8 * RegF; // RegF not yet decremented
914 int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
915 if (Predecrement != SavSZ)
916 return false;
917 if (FPLRPair && StackOffset < 16)
918 return false;
919 if (StackOffset % 16)
920 return false;
921 uint32_t FrameSize = (StackOffset + SavSZ) / 16;
922 if (FrameSize > 0x1FF)
923 return false;
924 assert(RegF != 1 && "One single float reg not allowed")(static_cast <bool> (RegF != 1 && "One single float reg not allowed"
) ? void (0) : __assert_fail ("RegF != 1 && \"One single float reg not allowed\""
, "llvm/lib/MC/MCWin64EH.cpp", 924, __extension__ __PRETTY_FUNCTION__
))
;
925 if (RegF > 0)
926 RegF--; // Convert from actual number of registers, to value stored
927 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier")(static_cast <bool> (FuncLength <= 0x7FF && "FuncLength should have been checked earlier"
) ? void (0) : __assert_fail ("FuncLength <= 0x7FF && \"FuncLength should have been checked earlier\""
, "llvm/lib/MC/MCWin64EH.cpp", 927, __extension__ __PRETTY_FUNCTION__
))
;
928 int Flag = 0x01; // Function segments not supported yet
929 int CR = FPLRPair ? 3 : StandaloneLR ? 1 : 0;
930 info->PackedInfo |= Flag << 0;
931 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
932 info->PackedInfo |= (RegF & 0x7) << 13;
933 info->PackedInfo |= (RegI & 0xF) << 16;
934 info->PackedInfo |= (H & 0x1) << 20;
935 info->PackedInfo |= (CR & 0x3) << 21;
936 info->PackedInfo |= (FrameSize & 0x1FF) << 23;
937 return true;
938}
939
940static void ARM64ProcessEpilogs(WinEH::FrameInfo *info,
941 WinEH::FrameInfo::Segment *Seg,
942 uint32_t &TotalCodeBytes,
943 MapVector<MCSymbol *, uint32_t> &EpilogInfo) {
944
945 std::vector<MCSymbol *> EpilogStarts;
946 for (auto &I : Seg->Epilogs)
947 EpilogStarts.push_back(I.first);
948
949 // Epilogs processed so far.
950 std::vector<MCSymbol *> AddedEpilogs;
951 for (auto *S : EpilogStarts) {
952 MCSymbol *EpilogStart = S;
953 auto &EpilogInstrs = info->EpilogMap[S].Instructions;
954 uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
955
956 MCSymbol* MatchingEpilog =
957 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
958 int PrologOffset;
959 if (MatchingEpilog) {
960 assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&(static_cast <bool> (EpilogInfo.find(MatchingEpilog) !=
EpilogInfo.end() && "Duplicate epilog not found") ? void
(0) : __assert_fail ("EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && \"Duplicate epilog not found\""
, "llvm/lib/MC/MCWin64EH.cpp", 961, __extension__ __PRETTY_FUNCTION__
))
961 "Duplicate epilog not found")(static_cast <bool> (EpilogInfo.find(MatchingEpilog) !=
EpilogInfo.end() && "Duplicate epilog not found") ? void
(0) : __assert_fail ("EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && \"Duplicate epilog not found\""
, "llvm/lib/MC/MCWin64EH.cpp", 961, __extension__ __PRETTY_FUNCTION__
))
;
962 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
963 // Clear the unwind codes in the EpilogMap, so that they don't get output
964 // in ARM64EmitUnwindInfoForSegment().
965 EpilogInstrs.clear();
966 } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
967 EpilogInstrs)) >= 0) {
968 EpilogInfo[EpilogStart] = PrologOffset;
969 // If the segment doesn't have a prolog, an end_c will be emitted before
970 // prolog opcodes. So epilog start index in opcodes array is moved by 1.
971 if (!Seg->HasProlog)
972 EpilogInfo[EpilogStart] += 1;
973 // Clear the unwind codes in the EpilogMap, so that they don't get output
974 // in ARM64EmitUnwindInfoForSegment().
975 EpilogInstrs.clear();
976 } else {
977 EpilogInfo[EpilogStart] = TotalCodeBytes;
978 TotalCodeBytes += CodeBytes;
979 AddedEpilogs.push_back(EpilogStart);
980 }
981 }
982}
983
984static void ARM64FindSegmentsInFunction(MCStreamer &streamer,
985 WinEH::FrameInfo *info,
986 int64_t RawFuncLength) {
987 struct EpilogStartEnd {
988 MCSymbol *Start;
989 int64_t Offset;
990 int64_t End;
991 };
992 // Record Start and End of each epilog.
993 SmallVector<struct EpilogStartEnd, 4> Epilogs;
994 for (auto &I : info->EpilogMap) {
995 MCSymbol *Start = I.first;
996 auto &Instrs = I.second.Instructions;
997 int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
998 assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&(static_cast <bool> ((Epilogs.size() == 0 || Offset >=
Epilogs.back().End) && "Epilogs should be monotonically ordered"
) ? void (0) : __assert_fail ("(Epilogs.size() == 0 || Offset >= Epilogs.back().End) && \"Epilogs should be monotonically ordered\""
, "llvm/lib/MC/MCWin64EH.cpp", 999, __extension__ __PRETTY_FUNCTION__
))
999 "Epilogs should be monotonically ordered")(static_cast <bool> ((Epilogs.size() == 0 || Offset >=
Epilogs.back().End) && "Epilogs should be monotonically ordered"
) ? void (0) : __assert_fail ("(Epilogs.size() == 0 || Offset >= Epilogs.back().End) && \"Epilogs should be monotonically ordered\""
, "llvm/lib/MC/MCWin64EH.cpp", 999, __extension__ __PRETTY_FUNCTION__
))
;
1000 // Exclue the end opcode from Instrs.size() when calculating the end of the
1001 // epilog.
1002 Epilogs.push_back({Start, Offset, Offset + (int64_t)(Instrs.size() - 1) * 4});
1003 }
1004
1005 unsigned E = 0;
1006 int64_t SegLimit = 0xFFFFC;
1007 int64_t SegOffset = 0;
1008
1009 if (RawFuncLength > SegLimit) {
1010
1011 int64_t RemainingLength = RawFuncLength;
1012
1013 while (RemainingLength > SegLimit) {
1014 // Try divide the function into segments, requirements:
1015 // 1. Segment length <= 0xFFFFC;
1016 // 2. Each Prologue or Epilogue must be fully within a segment.
1017 int64_t SegLength = SegLimit;
1018 int64_t SegEnd = SegOffset + SegLength;
1019 // Keep record on symbols and offsets of epilogs in this segment.
1020 MapVector<MCSymbol *, int64_t> EpilogsInSegment;
1021
1022 while (E < Epilogs.size() && Epilogs[E].End < SegEnd) {
1023 // Epilogs within current segment.
1024 EpilogsInSegment[Epilogs[E].Start] = Epilogs[E].Offset;
1025 ++E;
1026 }
1027
1028 // At this point, we have:
1029 // 1. Put all epilogs in segments already. No action needed here; or
1030 // 2. Found an epilog that will cross segments boundry. We need to
1031 // move back current segment's end boundry, so the epilog is entirely
1032 // in the next segment; or
1033 // 3. Left at least one epilog that is entirely after this segment.
1034 // It'll be handled by the next iteration, or the last segment.
1035 if (E < Epilogs.size() && Epilogs[E].Offset <= SegEnd)
1036 // Move back current Segment's end boundry.
1037 SegLength = Epilogs[E].Offset - SegOffset;
1038
1039 auto Seg = WinEH::FrameInfo::Segment(
1040 SegOffset, SegLength, /* HasProlog */!SegOffset);
1041 Seg.Epilogs = std::move(EpilogsInSegment);
1042 info->Segments.push_back(Seg);
1043
1044 SegOffset += SegLength;
1045 RemainingLength -= SegLength;
1046 }
1047 }
1048
1049 // Add the last segment when RawFuncLength > 0xFFFFC,
1050 // or the only segment otherwise.
1051 auto LastSeg =
1052 WinEH::FrameInfo::Segment(SegOffset, RawFuncLength - SegOffset,
1053 /* HasProlog */!SegOffset);
1054 for (; E < Epilogs.size(); ++E)
1055 LastSeg.Epilogs[Epilogs[E].Start] = Epilogs[E].Offset;
1056 info->Segments.push_back(LastSeg);
1057}
1058
1059static void ARM64EmitUnwindInfoForSegment(MCStreamer &streamer,
1060 WinEH::FrameInfo *info,
1061 WinEH::FrameInfo::Segment &Seg,
1062 bool TryPacked = true) {
1063 MCContext &context = streamer.getContext();
1064 MCSymbol *Label = context.createTempSymbol();
1065
1066 streamer.emitValueToAlignment(4);
1067 streamer.emitLabel(Label);
1068 Seg.Symbol = Label;
1069 // Use the 1st segemnt's label as function's.
1070 if (Seg.Offset == 0)
1071 info->Symbol = Label;
1072
1073 bool HasProlog = Seg.HasProlog;
1074 bool HasEpilogs = (Seg.Epilogs.size() != 0);
1075
1076 uint32_t SegLength = (uint32_t)Seg.Length / 4;
1077 uint32_t PrologCodeBytes = info->PrologCodeBytes;
1078
1079 int PackedEpilogOffset = HasEpilogs ?
1080 checkARM64PackedEpilog(streamer, info, &Seg, PrologCodeBytes) : -1;
1081
1082 // TODO:
1083 // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
1084 // 2. Emit packed unwind info (.pdata only) for segments that have neithor
1085 // prolog nor epilog.
1086 if (info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
1087 uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1088 !info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
1089 // Matching prolog/epilog and no exception handlers; check if the
1090 // prolog matches the patterns that can be described by the packed
1091 // format.
1092
1093 // info->Symbol was already set even if we didn't actually write any
1094 // unwind info there. Keep using that as indicator that this unwind
1095 // info has been generated already.
1096 if (tryARM64PackedUnwind(info, SegLength, PackedEpilogOffset))
1097 return;
1098 }
1099
1100 // If the prolog is not in this segment, we need to emit an end_c, which takes
1101 // 1 byte, before prolog unwind ops.
1102 if (!HasProlog) {
1103 PrologCodeBytes += 1;
1104 if (PackedEpilogOffset >= 0)
1105 PackedEpilogOffset += 1;
1106 // If a segment has neither prolog nor epilog, "With full .xdata record,
1107 // Epilog Count = 1. Epilog Start Index points to end_c."
1108 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
1109 // TODO: We can remove this if testing shows zero epilog scope is ok with
1110 // MS unwinder.
1111 if (!HasEpilogs)
1112 // Pack the fake epilog into phantom prolog.
1113 PackedEpilogOffset = 0;
1114 }
1115
1116 uint32_t TotalCodeBytes = PrologCodeBytes;
1117
1118 // Process epilogs.
1119 MapVector<MCSymbol *, uint32_t> EpilogInfo;
1120 ARM64ProcessEpilogs(info, &Seg, TotalCodeBytes, EpilogInfo);
1121
1122 // Code Words, Epilog count, E, X, Vers, Function Length
1123 uint32_t row1 = 0x0;
1124 uint32_t CodeWords = TotalCodeBytes / 4;
1125 uint32_t CodeWordsMod = TotalCodeBytes % 4;
1126 if (CodeWordsMod)
1127 CodeWords++;
1128 uint32_t EpilogCount =
1129 PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.Epilogs.size();
1130 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
1131 if (!ExtensionWord) {
1132 row1 |= (EpilogCount & 0x1F) << 22;
1133 row1 |= (CodeWords & 0x1F) << 27;
1134 }
1135 if (info->HandlesExceptions) // X
1136 row1 |= 1 << 20;
1137 if (PackedEpilogOffset >= 0) // E
1138 row1 |= 1 << 21;
1139 row1 |= SegLength & 0x3FFFF;
1140 streamer.emitInt32(row1);
1141
1142 // Extended Code Words, Extended Epilog Count
1143 if (ExtensionWord) {
1144 // FIXME: We should be able to split unwind info into multiple sections.
1145 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
1146 report_fatal_error(
1147 "SEH unwind data splitting is only implemnted for large functions, "
1148 "cases of too many code words or too many epilogs will be done later"
1149 );
1150 uint32_t row2 = 0x0;
1151 row2 |= (CodeWords & 0xFF) << 16;
1152 row2 |= (EpilogCount & 0xFFFF);
1153 streamer.emitInt32(row2);
1154 }
1155
1156 if (PackedEpilogOffset < 0) {
1157 // Epilog Start Index, Epilog Start Offset
1158 for (auto &I : EpilogInfo) {
1159 MCSymbol *EpilogStart = I.first;
1160 uint32_t EpilogIndex = I.second;
1161 // Epilog offset within the Segment.
1162 uint32_t EpilogOffset = (uint32_t)(Seg.Epilogs[EpilogStart] - Seg.Offset);
1163 if (EpilogOffset)
1164 EpilogOffset /= 4;
1165 uint32_t row3 = EpilogOffset;
1166 row3 |= (EpilogIndex & 0x3FF) << 22;
1167 streamer.emitInt32(row3);
1168 }
1169 }
1170
1171 // Note that even for segments that have no prolog, we still need to emit
1172 // prolog unwinding opcodes so that the unwinder knows how to unwind from
1173 // such a segment.
1174 // The end_c opcode at the start indicates to the unwinder that the actual
1175 // prolog is outside of the current segment, and the unwinder shouldn't try
1176 // to check for unwinding from a partial prolog.
1177 if (!HasProlog)
1178 // Emit an end_c.
1179 streamer.emitInt8((uint8_t)0xE5);
1180
1181 // Emit prolog unwind instructions (in reverse order).
1182 for (auto Inst : llvm::reverse(info->Instructions))
1183 ARM64EmitUnwindCode(streamer, Inst);
1184
1185 // Emit epilog unwind instructions
1186 for (auto &I : Seg.Epilogs) {
1187 auto &EpilogInstrs = info->EpilogMap[I.first].Instructions;
1188 for (const WinEH::Instruction &inst : EpilogInstrs)
1189 ARM64EmitUnwindCode(streamer, inst);
1190 }
1191
1192 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
1193 assert(BytesMod >= 0)(static_cast <bool> (BytesMod >= 0) ? void (0) : __assert_fail
("BytesMod >= 0", "llvm/lib/MC/MCWin64EH.cpp", 1193, __extension__
__PRETTY_FUNCTION__))
;
1194 for (int i = 0; i < BytesMod; i++)
1195 streamer.emitInt8(0xE3);
1196
1197 if (info->HandlesExceptions)
1198 streamer.emitValue(
1199 MCSymbolRefExpr::create(info->ExceptionHandler,
1200 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
1201 4);
1202}
1203
1204// Populate the .xdata section. The format of .xdata on ARM64 is documented at
1205// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
1206static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
1207 bool TryPacked = true) {
1208 // If this UNWIND_INFO already has a symbol, it's already been emitted.
1209 if (info->Symbol)
1210 return;
1211 // If there's no unwind info here (not even a terminating UOP_End), the
1212 // unwind info is considered bogus and skipped. If this was done in
1213 // response to an explicit .seh_handlerdata, the associated trailing
1214 // handler data is left orphaned in the xdata section.
1215 if (info->empty()) {
1216 info->EmitAttempted = true;
1217 return;
1218 }
1219 if (info->EmitAttempted) {
1220 // If we tried to emit unwind info before (due to an explicit
1221 // .seh_handlerdata directive), but skipped it (because there was no
1222 // valid information to emit at the time), and it later got valid unwind
1223 // opcodes, we can't emit it here, because the trailing handler data
1224 // was already emitted elsewhere in the xdata section.
1225 streamer.getContext().reportError(
1226 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
1227 " skipped due to no unwind info at the time "
1228 "(.seh_handlerdata too early?), but the function later "
1229 "did get unwind info that can't be emitted");
1230 return;
1231 }
1232
1233 simplifyARM64Opcodes(info->Instructions, false);
1234 for (auto &I : info->EpilogMap)
1235 simplifyARM64Opcodes(I.second.Instructions, true);
1236
1237 int64_t RawFuncLength;
1238 if (!info->FuncletOrFuncEnd) {
1239 report_fatal_error("FuncletOrFuncEnd not set");
1240 } else {
1241 // FIXME: GetAbsDifference tries to compute the length of the function
1242 // immediately, before the whole file is emitted, but in general
1243 // that's impossible: the size in bytes of certain assembler directives
1244 // like .align and .fill is not known until the whole file is parsed and
1245 // relaxations are applied. Currently, GetAbsDifference fails with a fatal
1246 // error in that case. (We mostly don't hit this because inline assembly
1247 // specifying those directives is rare, and we don't normally try to
1248 // align loops on AArch64.)
1249 //
1250 // There are two potential approaches to delaying the computation. One,
1251 // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
1252 // as long as we have some conservative estimate we could use to prove
1253 // that we don't need to split the unwind data. Emitting the constant
1254 // is straightforward, but there's no existing code for estimating the
1255 // size of the function.
1256 //
1257 // The other approach would be to use a dedicated, relaxable fragment,
1258 // which could grow to accommodate splitting the unwind data if
1259 // necessary. This is more straightforward, since it automatically works
1260 // without any new infrastructure, and it's consistent with how we handle
1261 // relaxation in other contexts. But it would require some refactoring
1262 // to move parts of the pdata/xdata emission into the implementation of
1263 // a fragment. We could probably continue to encode the unwind codes
1264 // here, but we'd have to emit the pdata, the xdata header, and the
1265 // epilogue scopes later, since they depend on whether the we need to
1266 // split the unwind data.
1267 RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
1268 info->Begin);
1269 }
1270
1271 ARM64FindSegmentsInFunction(streamer, info, RawFuncLength);
1272
1273 info->PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
1274 for (auto &S : info->Segments)
1275 ARM64EmitUnwindInfoForSegment(streamer, info, S, TryPacked);
1276
1277 // Clear prolog instructions after unwind info is emitted for all segments.
1278 info->Instructions.clear();
1279}
1280
1281static uint32_t ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
1282 uint32_t Count = 0;
1283 for (const auto &I : Insns) {
1284 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1285 default:
1286 llvm_unreachable("Unsupported ARM unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 1286)
;
1287 case Win64EH::UOP_AllocSmall:
1288 Count += 1;
1289 break;
1290 case Win64EH::UOP_AllocLarge:
1291 Count += 3;
1292 break;
1293 case Win64EH::UOP_AllocHuge:
1294 Count += 4;
1295 break;
1296 case Win64EH::UOP_WideAllocMedium:
1297 Count += 2;
1298 break;
1299 case Win64EH::UOP_WideAllocLarge:
1300 Count += 3;
1301 break;
1302 case Win64EH::UOP_WideAllocHuge:
1303 Count += 4;
1304 break;
1305 case Win64EH::UOP_WideSaveRegMask:
1306 Count += 2;
1307 break;
1308 case Win64EH::UOP_SaveSP:
1309 Count += 1;
1310 break;
1311 case Win64EH::UOP_SaveRegsR4R7LR:
1312 Count += 1;
1313 break;
1314 case Win64EH::UOP_WideSaveRegsR4R11LR:
1315 Count += 1;
1316 break;
1317 case Win64EH::UOP_SaveFRegD8D15:
1318 Count += 1;
1319 break;
1320 case Win64EH::UOP_SaveRegMask:
1321 Count += 2;
1322 break;
1323 case Win64EH::UOP_SaveLR:
1324 Count += 2;
1325 break;
1326 case Win64EH::UOP_SaveFRegD0D15:
1327 Count += 2;
1328 break;
1329 case Win64EH::UOP_SaveFRegD16D31:
1330 Count += 2;
1331 break;
1332 case Win64EH::UOP_Nop:
1333 case Win64EH::UOP_WideNop:
1334 case Win64EH::UOP_End:
1335 case Win64EH::UOP_EndNop:
1336 case Win64EH::UOP_WideEndNop:
1337 Count += 1;
1338 break;
1339 case Win64EH::UOP_Custom: {
1340 int J;
1341 for (J = 3; J > 0; J--)
1342 if (I.Offset & (0xffu << (8 * J)))
1343 break;
1344 Count += J + 1;
1345 break;
1346 }
1347 }
1348 }
1349 return Count;
1350}
1351
1352static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns,
1353 bool *HasCustom = nullptr) {
1354 uint32_t Count = 0;
1355 for (const auto &I : Insns) {
1356 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1357 default:
1358 llvm_unreachable("Unsupported ARM unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 1358)
;
1359 case Win64EH::UOP_AllocSmall:
1360 case Win64EH::UOP_AllocLarge:
1361 case Win64EH::UOP_AllocHuge:
1362 Count += 2;
1363 break;
1364 case Win64EH::UOP_WideAllocMedium:
1365 case Win64EH::UOP_WideAllocLarge:
1366 case Win64EH::UOP_WideAllocHuge:
1367 Count += 4;
1368 break;
1369 case Win64EH::UOP_WideSaveRegMask:
1370 case Win64EH::UOP_WideSaveRegsR4R11LR:
1371 Count += 4;
1372 break;
1373 case Win64EH::UOP_SaveSP:
1374 Count += 2;
1375 break;
1376 case Win64EH::UOP_SaveRegMask:
1377 case Win64EH::UOP_SaveRegsR4R7LR:
1378 Count += 2;
1379 break;
1380 case Win64EH::UOP_SaveFRegD8D15:
1381 case Win64EH::UOP_SaveFRegD0D15:
1382 case Win64EH::UOP_SaveFRegD16D31:
1383 Count += 4;
1384 break;
1385 case Win64EH::UOP_SaveLR:
1386 Count += 4;
1387 break;
1388 case Win64EH::UOP_Nop:
1389 case Win64EH::UOP_EndNop:
1390 Count += 2;
1391 break;
1392 case Win64EH::UOP_WideNop:
1393 case Win64EH::UOP_WideEndNop:
1394 Count += 4;
1395 break;
1396 case Win64EH::UOP_End:
1397 // This doesn't map to any instruction
1398 break;
1399 case Win64EH::UOP_Custom:
1400 // We can't reason about what instructions this maps to; return a
1401 // phony number to make sure we don't accidentally do epilog packing.
1402 Count += 1000;
1403 if (HasCustom)
1404 *HasCustom = true;
1405 break;
1406 }
1407 }
1408 return Count;
1409}
1410
1411static void checkARMInstructions(MCStreamer &Streamer,
1412 ArrayRef<WinEH::Instruction> Insns,
1413 const MCSymbol *Begin, const MCSymbol *End,
1414 StringRef Name, StringRef Type) {
1415 if (!End)
1416 return;
1417 Optional<int64_t> MaybeDistance =
1418 GetOptionalAbsDifference(Streamer, End, Begin);
1419 if (!MaybeDistance)
1420 return;
1421 uint32_t Distance = (uint32_t)*MaybeDistance;
1422 bool HasCustom = false;
1423 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
1424 if (HasCustom)
1425 return;
1426 if (Distance != InstructionBytes) {
1427 Streamer.getContext().reportError(
1428 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1429 Twine(Distance) +
1430 " bytes of instructions in range, but .seh directives "
1431 "corresponding to " +
1432 Twine(InstructionBytes) + " bytes\n");
1433 }
1434}
1435
1436static bool isARMTerminator(const WinEH::Instruction &inst) {
1437 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1438 case Win64EH::UOP_End:
1439 case Win64EH::UOP_EndNop:
1440 case Win64EH::UOP_WideEndNop:
1441 return true;
1442 default:
1443 return false;
1444 }
1445}
1446
1447// Unwind opcode encodings and restrictions are documented at
1448// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1449static void ARMEmitUnwindCode(MCStreamer &streamer,
1450 const WinEH::Instruction &inst) {
1451 uint32_t w, lr;
1452 int i;
1453 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1454 default:
1455 llvm_unreachable("Unsupported ARM unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 1455)
;
1456 case Win64EH::UOP_AllocSmall:
1457 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1457, __extension__ __PRETTY_FUNCTION__))
;
1458 assert(inst.Offset / 4 <= 0x7f)(static_cast <bool> (inst.Offset / 4 <= 0x7f) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0x7f", "llvm/lib/MC/MCWin64EH.cpp"
, 1458, __extension__ __PRETTY_FUNCTION__))
;
1459 streamer.emitInt8(inst.Offset / 4);
1460 break;
1461 case Win64EH::UOP_WideSaveRegMask:
1462 assert((inst.Register & ~0x5fff) == 0)(static_cast <bool> ((inst.Register & ~0x5fff) == 0
) ? void (0) : __assert_fail ("(inst.Register & ~0x5fff) == 0"
, "llvm/lib/MC/MCWin64EH.cpp", 1462, __extension__ __PRETTY_FUNCTION__
))
;
1463 lr = (inst.Register >> 14) & 1;
1464 w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
1465 streamer.emitInt8((w >> 8) & 0xff);
1466 streamer.emitInt8((w >> 0) & 0xff);
1467 break;
1468 case Win64EH::UOP_SaveSP:
1469 assert(inst.Register <= 0x0f)(static_cast <bool> (inst.Register <= 0x0f) ? void (
0) : __assert_fail ("inst.Register <= 0x0f", "llvm/lib/MC/MCWin64EH.cpp"
, 1469, __extension__ __PRETTY_FUNCTION__))
;
1470 streamer.emitInt8(0xc0 | inst.Register);
1471 break;
1472 case Win64EH::UOP_SaveRegsR4R7LR:
1473 assert(inst.Register >= 4 && inst.Register <= 7)(static_cast <bool> (inst.Register >= 4 && inst
.Register <= 7) ? void (0) : __assert_fail ("inst.Register >= 4 && inst.Register <= 7"
, "llvm/lib/MC/MCWin64EH.cpp", 1473, __extension__ __PRETTY_FUNCTION__
))
;
1474 assert(inst.Offset <= 1)(static_cast <bool> (inst.Offset <= 1) ? void (0) : __assert_fail
("inst.Offset <= 1", "llvm/lib/MC/MCWin64EH.cpp", 1474, __extension__
__PRETTY_FUNCTION__))
;
1475 streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
1476 break;
1477 case Win64EH::UOP_WideSaveRegsR4R11LR:
1478 assert(inst.Register >= 8 && inst.Register <= 11)(static_cast <bool> (inst.Register >= 8 && inst
.Register <= 11) ? void (0) : __assert_fail ("inst.Register >= 8 && inst.Register <= 11"
, "llvm/lib/MC/MCWin64EH.cpp", 1478, __extension__ __PRETTY_FUNCTION__
))
;
1479 assert(inst.Offset <= 1)(static_cast <bool> (inst.Offset <= 1) ? void (0) : __assert_fail
("inst.Offset <= 1", "llvm/lib/MC/MCWin64EH.cpp", 1479, __extension__
__PRETTY_FUNCTION__))
;
1480 streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
1481 break;
1482 case Win64EH::UOP_SaveFRegD8D15:
1483 assert(inst.Register >= 8 && inst.Register <= 15)(static_cast <bool> (inst.Register >= 8 && inst
.Register <= 15) ? void (0) : __assert_fail ("inst.Register >= 8 && inst.Register <= 15"
, "llvm/lib/MC/MCWin64EH.cpp", 1483, __extension__ __PRETTY_FUNCTION__
))
;
1484 streamer.emitInt8(0xe0 | (inst.Register - 8));
1485 break;
1486 case Win64EH::UOP_WideAllocMedium:
1487 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1487, __extension__ __PRETTY_FUNCTION__))
;
1488 assert(inst.Offset / 4 <= 0x3ff)(static_cast <bool> (inst.Offset / 4 <= 0x3ff) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0x3ff", "llvm/lib/MC/MCWin64EH.cpp"
, 1488, __extension__ __PRETTY_FUNCTION__))
;
1489 w = 0xe800 | (inst.Offset / 4);
1490 streamer.emitInt8((w >> 8) & 0xff);
1491 streamer.emitInt8((w >> 0) & 0xff);
1492 break;
1493 case Win64EH::UOP_SaveRegMask:
1494 assert((inst.Register & ~0x40ff) == 0)(static_cast <bool> ((inst.Register & ~0x40ff) == 0
) ? void (0) : __assert_fail ("(inst.Register & ~0x40ff) == 0"
, "llvm/lib/MC/MCWin64EH.cpp", 1494, __extension__ __PRETTY_FUNCTION__
))
;
1495 lr = (inst.Register >> 14) & 1;
1496 w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
1497 streamer.emitInt8((w >> 8) & 0xff);
1498 streamer.emitInt8((w >> 0) & 0xff);
1499 break;
1500 case Win64EH::UOP_SaveLR:
1501 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1501, __extension__ __PRETTY_FUNCTION__))
;
1502 assert(inst.Offset / 4 <= 0x0f)(static_cast <bool> (inst.Offset / 4 <= 0x0f) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0x0f", "llvm/lib/MC/MCWin64EH.cpp"
, 1502, __extension__ __PRETTY_FUNCTION__))
;
1503 streamer.emitInt8(0xef);
1504 streamer.emitInt8(inst.Offset / 4);
1505 break;
1506 case Win64EH::UOP_SaveFRegD0D15:
1507 assert(inst.Register <= 15)(static_cast <bool> (inst.Register <= 15) ? void (0)
: __assert_fail ("inst.Register <= 15", "llvm/lib/MC/MCWin64EH.cpp"
, 1507, __extension__ __PRETTY_FUNCTION__))
;
1508 assert(inst.Offset <= 15)(static_cast <bool> (inst.Offset <= 15) ? void (0) :
__assert_fail ("inst.Offset <= 15", "llvm/lib/MC/MCWin64EH.cpp"
, 1508, __extension__ __PRETTY_FUNCTION__))
;
1509 assert(inst.Register <= inst.Offset)(static_cast <bool> (inst.Register <= inst.Offset) ?
void (0) : __assert_fail ("inst.Register <= inst.Offset",
"llvm/lib/MC/MCWin64EH.cpp", 1509, __extension__ __PRETTY_FUNCTION__
))
;
1510 streamer.emitInt8(0xf5);
1511 streamer.emitInt8((inst.Register << 4) | inst.Offset);
1512 break;
1513 case Win64EH::UOP_SaveFRegD16D31:
1514 assert(inst.Register >= 16 && inst.Register <= 31)(static_cast <bool> (inst.Register >= 16 && inst
.Register <= 31) ? void (0) : __assert_fail ("inst.Register >= 16 && inst.Register <= 31"
, "llvm/lib/MC/MCWin64EH.cpp", 1514, __extension__ __PRETTY_FUNCTION__
))
;
1515 assert(inst.Offset >= 16 && inst.Offset <= 31)(static_cast <bool> (inst.Offset >= 16 && inst
.Offset <= 31) ? void (0) : __assert_fail ("inst.Offset >= 16 && inst.Offset <= 31"
, "llvm/lib/MC/MCWin64EH.cpp", 1515, __extension__ __PRETTY_FUNCTION__
))
;
1516 assert(inst.Register <= inst.Offset)(static_cast <bool> (inst.Register <= inst.Offset) ?
void (0) : __assert_fail ("inst.Register <= inst.Offset",
"llvm/lib/MC/MCWin64EH.cpp", 1516, __extension__ __PRETTY_FUNCTION__
))
;
1517 streamer.emitInt8(0xf6);
1518 streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
1519 break;
1520 case Win64EH::UOP_AllocLarge:
1521 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1521, __extension__ __PRETTY_FUNCTION__))
;
1522 assert(inst.Offset / 4 <= 0xffff)(static_cast <bool> (inst.Offset / 4 <= 0xffff) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0xffff", "llvm/lib/MC/MCWin64EH.cpp"
, 1522, __extension__ __PRETTY_FUNCTION__))
;
1523 w = inst.Offset / 4;
1524 streamer.emitInt8(0xf7);
1525 streamer.emitInt8((w >> 8) & 0xff);
1526 streamer.emitInt8((w >> 0) & 0xff);
1527 break;
1528 case Win64EH::UOP_AllocHuge:
1529 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1529, __extension__ __PRETTY_FUNCTION__))
;
1530 assert(inst.Offset / 4 <= 0xffffff)(static_cast <bool> (inst.Offset / 4 <= 0xffffff) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0xffffff", "llvm/lib/MC/MCWin64EH.cpp"
, 1530, __extension__ __PRETTY_FUNCTION__))
;
1531 w = inst.Offset / 4;
1532 streamer.emitInt8(0xf8);
1533 streamer.emitInt8((w >> 16) & 0xff);
1534 streamer.emitInt8((w >> 8) & 0xff);
1535 streamer.emitInt8((w >> 0) & 0xff);
1536 break;
1537 case Win64EH::UOP_WideAllocLarge:
1538 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1538, __extension__ __PRETTY_FUNCTION__))
;
1539 assert(inst.Offset / 4 <= 0xffff)(static_cast <bool> (inst.Offset / 4 <= 0xffff) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0xffff", "llvm/lib/MC/MCWin64EH.cpp"
, 1539, __extension__ __PRETTY_FUNCTION__))
;
1540 w = inst.Offset / 4;
1541 streamer.emitInt8(0xf9);
1542 streamer.emitInt8((w >> 8) & 0xff);
1543 streamer.emitInt8((w >> 0) & 0xff);
1544 break;
1545 case Win64EH::UOP_WideAllocHuge:
1546 assert((inst.Offset & 3) == 0)(static_cast <bool> ((inst.Offset & 3) == 0) ? void
(0) : __assert_fail ("(inst.Offset & 3) == 0", "llvm/lib/MC/MCWin64EH.cpp"
, 1546, __extension__ __PRETTY_FUNCTION__))
;
1547 assert(inst.Offset / 4 <= 0xffffff)(static_cast <bool> (inst.Offset / 4 <= 0xffffff) ? void
(0) : __assert_fail ("inst.Offset / 4 <= 0xffffff", "llvm/lib/MC/MCWin64EH.cpp"
, 1547, __extension__ __PRETTY_FUNCTION__))
;
1548 w = inst.Offset / 4;
1549 streamer.emitInt8(0xfa);
1550 streamer.emitInt8((w >> 16) & 0xff);
1551 streamer.emitInt8((w >> 8) & 0xff);
1552 streamer.emitInt8((w >> 0) & 0xff);
1553 break;
1554 case Win64EH::UOP_Nop:
1555 streamer.emitInt8(0xfb);
1556 break;
1557 case Win64EH::UOP_WideNop:
1558 streamer.emitInt8(0xfc);
1559 break;
1560 case Win64EH::UOP_EndNop:
1561 streamer.emitInt8(0xfd);
1562 break;
1563 case Win64EH::UOP_WideEndNop:
1564 streamer.emitInt8(0xfe);
1565 break;
1566 case Win64EH::UOP_End:
1567 streamer.emitInt8(0xff);
1568 break;
1569 case Win64EH::UOP_Custom:
1570 for (i = 3; i > 0; i--)
1571 if (inst.Offset & (0xffu << (8 * i)))
1572 break;
1573 for (; i >= 0; i--)
1574 streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
1575 break;
1576 }
1577}
1578
1579// Check if an epilog exists as a subset of the end of a prolog (backwards).
1580// An epilog may end with one out of three different end opcodes; if this
1581// is the first epilog that shares opcodes with the prolog, we can tolerate
1582// that this opcode differs (and the caller will update the prolog to use
1583// the same end opcode as the epilog). If another epilog already shares
1584// opcodes with the prolog, the ending opcode must be a strict match.
1585static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1586 const std::vector<WinEH::Instruction> &Epilog,
1587 bool CanTweakProlog) {
1588 // Can't find an epilog as a subset if it is longer than the prolog.
1589 if (Epilog.size() > Prolog.size())
1590 return -1;
1591
1592 // Check that the epilog actually is a perfect match for the end (backwrds)
1593 // of the prolog.
1594 // If we can adjust the prolog afterwards, don't check that the end opcodes
1595 // match.
1596 int EndIdx = CanTweakProlog ? 1 : 0;
1597 for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
1598 // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
1599 // "push {r0-r3}".
1600 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
1601 return -1;
1602 }
1603
1604 if (CanTweakProlog) {
1605 // Check that both prolog and epilog end with an expected end opcode.
1606 if (Prolog.front().Operation != Win64EH::UOP_End)
1607 return -1;
1608 if (Epilog.back().Operation != Win64EH::UOP_End &&
1609 Epilog.back().Operation != Win64EH::UOP_EndNop &&
1610 Epilog.back().Operation != Win64EH::UOP_WideEndNop)
1611 return -1;
1612 }
1613
1614 // If the epilog was a subset of the prolog, find its offset.
1615 if (Epilog.size() == Prolog.size())
1616 return 0;
1617 return ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
1618 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
1619}
1620
1621static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
1622 int PrologCodeBytes) {
1623 // Can only pack if there's one single epilog
1624 if (info->EpilogMap.size() != 1)
1625 return -1;
1626
1627 const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
1628 // Can only pack if the epilog is unconditional
1629 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1630 return -1;
1631
1632 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1633 // Make sure we have at least the trailing end opcode
1634 if (info->Instructions.empty() || Epilog.empty())
1635 return -1;
1636
1637 // Check that the epilog actually is at the very end of the function,
1638 // otherwise it can't be packed.
1639 Optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
1640 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
1641 if (!MaybeDistance)
1642 return -1;
1643 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
1644 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
1645 if (DistanceFromEnd != InstructionBytes)
1646 return -1;
1647
1648 int RetVal = -1;
1649 // Even if we don't end up sharing opcodes with the prolog, we can still
1650 // write the offset as a packed offset, if the single epilog is located at
1651 // the end of the function and the offset (pointing after the prolog) fits
1652 // as a packed offset.
1653 if (PrologCodeBytes <= 31 &&
1654 PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
1655 RetVal = PrologCodeBytes;
1656
1657 int Offset =
1658 getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
1659 if (Offset < 0)
1660 return RetVal;
1661
1662 // Check that the offset and prolog size fits in the first word; it's
1663 // unclear whether the epilog count in the extension word can be taken
1664 // as packed epilog offset.
1665 if (Offset > 31 || PrologCodeBytes > 63)
1666 return RetVal;
1667
1668 // Replace the regular end opcode of the prolog with the one from the
1669 // epilog.
1670 info->Instructions.front() = Epilog.back();
1671
1672 // As we choose to express the epilog as part of the prolog, remove the
1673 // epilog from the map, so we don't try to emit its opcodes.
1674 info->EpilogMap.clear();
1675 return Offset;
1676}
1677
1678static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
1679 unsigned &Folded, int &IntRegs) {
1680 if (Mask & (1 << 14)) {
1681 HasLR = true;
1682 Mask &= ~(1 << 14);
1683 }
1684 if (Mask & (1 << 11)) {
1685 HasR11 = true;
1686 Mask &= ~(1 << 11);
1687 }
1688 Folded = 0;
1689 IntRegs = -1;
1690 if (!Mask)
1691 return true;
1692 int First = 0;
1693 // Shift right until we have the bits at the bottom
1694 while ((Mask & 1) == 0) {
1695 First++;
1696 Mask >>= 1;
1697 }
1698 if ((Mask & (Mask + 1)) != 0)
1699 return false; // Not a consecutive series of bits? Can't be packed.
1700 // Count the bits
1701 int N = 0;
1702 while (Mask & (1 << N))
1703 N++;
1704 if (First < 4) {
1705 if (First + N < 4)
1706 return false;
1707 Folded = 4 - First;
1708 N -= Folded;
1709 First = 4;
1710 }
1711 if (First > 4)
1712 return false; // Can't be packed
1713 if (N >= 1)
1714 IntRegs = N - 1;
1715 return true;
1716}
1717
1718static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info,
1719 uint32_t FuncLength) {
1720 int Step = 0;
1721 bool Homing = false;
1722 bool HasR11 = false;
1723 bool HasChain = false;
1724 bool HasLR = false;
1725 int IntRegs = -1; // r4 - r(4+N)
1726 int FloatRegs = -1; // d8 - d(8+N)
1727 unsigned PF = 0; // Number of extra pushed registers
1728 unsigned StackAdjust = 0;
1729 // Iterate over the prolog and check that all opcodes exactly match
1730 // the canonical order and form.
1731 for (const WinEH::Instruction &Inst : info->Instructions) {
1732 switch (Inst.Operation) {
1733 default:
1734 llvm_unreachable("Unsupported ARM unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 1734)
;
1735 case Win64EH::UOP_Custom:
1736 case Win64EH::UOP_AllocLarge:
1737 case Win64EH::UOP_AllocHuge:
1738 case Win64EH::UOP_WideAllocLarge:
1739 case Win64EH::UOP_WideAllocHuge:
1740 case Win64EH::UOP_SaveFRegD0D15:
1741 case Win64EH::UOP_SaveFRegD16D31:
1742 // Can't be packed
1743 return false;
1744 case Win64EH::UOP_SaveSP:
1745 // Can't be packed; we can't rely on restoring sp from r11 when
1746 // unwinding a packed prologue.
1747 return false;
1748 case Win64EH::UOP_SaveLR:
1749 // Can't be present in a packed prologue
1750 return false;
1751
1752 case Win64EH::UOP_End:
1753 case Win64EH::UOP_EndNop:
1754 case Win64EH::UOP_WideEndNop:
1755 if (Step != 0)
1756 return false;
1757 Step = 1;
1758 break;
1759
1760 case Win64EH::UOP_SaveRegsR4R7LR:
1761 case Win64EH::UOP_WideSaveRegsR4R11LR:
1762 // push {r4-r11,lr}
1763 if (Step != 1 && Step != 2)
1764 return false;
1765 assert(Inst.Register >= 4 && Inst.Register <= 11)(static_cast <bool> (Inst.Register >= 4 && Inst
.Register <= 11) ? void (0) : __assert_fail ("Inst.Register >= 4 && Inst.Register <= 11"
, "llvm/lib/MC/MCWin64EH.cpp", 1765, __extension__ __PRETTY_FUNCTION__
))
; // r4-rX
1766 assert(Inst.Offset <= 1)(static_cast <bool> (Inst.Offset <= 1) ? void (0) : __assert_fail
("Inst.Offset <= 1", "llvm/lib/MC/MCWin64EH.cpp", 1766, __extension__
__PRETTY_FUNCTION__))
; // Lr
1767 IntRegs = Inst.Register - 4;
1768 if (Inst.Register == 11) {
1769 HasR11 = true;
1770 IntRegs--;
1771 }
1772 if (Inst.Offset)
1773 HasLR = true;
1774 Step = 3;
1775 break;
1776
1777 case Win64EH::UOP_SaveRegMask:
1778 if (Step == 1 && Inst.Register == 0x0f) {
1779 // push {r0-r3}
1780 Homing = true;
1781 Step = 2;
1782 break;
1783 }
1784 [[fallthrough]];
1785 case Win64EH::UOP_WideSaveRegMask:
1786 if (Step != 1 && Step != 2)
1787 return false;
1788 // push {r4-r9,r11,lr}
1789 // push {r11,lr}
1790 // push {r1-r5}
1791 if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
1792 return false;
1793 Step = 3;
1794 break;
1795
1796 case Win64EH::UOP_Nop:
1797 // mov r11, sp
1798 if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
1799 return false;
1800 HasChain = true;
1801 Step = 4;
1802 break;
1803 case Win64EH::UOP_WideNop:
1804 // add.w r11, sp, #xx
1805 if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
1806 return false;
1807 HasChain = true;
1808 Step = 4;
1809 break;
1810
1811 case Win64EH::UOP_SaveFRegD8D15:
1812 if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
1813 return false;
1814 assert(Inst.Register >= 8 && Inst.Register <= 15)(static_cast <bool> (Inst.Register >= 8 && Inst
.Register <= 15) ? void (0) : __assert_fail ("Inst.Register >= 8 && Inst.Register <= 15"
, "llvm/lib/MC/MCWin64EH.cpp", 1814, __extension__ __PRETTY_FUNCTION__
))
;
1815 if (Inst.Register == 15)
1816 return false; // Can't pack this case, R==7 means no IntRegs
1817 if (IntRegs >= 0)
1818 return false;
1819 FloatRegs = Inst.Register - 8;
1820 Step = 5;
1821 break;
1822
1823 case Win64EH::UOP_AllocSmall:
1824 case Win64EH::UOP_WideAllocMedium:
1825 if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
1826 return false;
1827 if (PF > 0) // Can't have both folded and explicit stack allocation
1828 return false;
1829 if (Inst.Offset / 4 >= 0x3f4)
1830 return false;
1831 StackAdjust = Inst.Offset / 4;
1832 Step = 6;
1833 break;
1834 }
1835 }
1836 if (HasR11 && !HasChain) {
1837 if (IntRegs + 4 == 10) {
1838 // r11 stored, but not chaining; can be packed if already saving r4-r10
1839 // and we can fit r11 into this range.
1840 IntRegs++;
1841 HasR11 = false;
Value stored to 'HasR11' is never read
1842 } else
1843 return false;
1844 }
1845 if (HasChain && !HasLR)
1846 return false;
1847
1848 // Packed uneind info can't express multiple epilogues.
1849 if (info->EpilogMap.size() > 1)
1850 return false;
1851
1852 unsigned EF = 0;
1853 int Ret = 0;
1854 if (info->EpilogMap.size() == 0) {
1855 Ret = 3; // No epilogue
1856 } else {
1857 // As the prologue and epilogue aren't exact mirrors of each other,
1858 // we have to check the epilogue too and see if it matches what we've
1859 // concluded from the prologue.
1860 const WinEH::FrameInfo::Epilog &EpilogInfo =
1861 info->EpilogMap.begin()->second;
1862 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1863 return false;
1864 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1865 Optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
1866 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
1867 if (!MaybeDistance)
1868 return false;
1869 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
1870 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
1871 if (DistanceFromEnd != InstructionBytes)
1872 return false;
1873
1874 bool GotStackAdjust = false;
1875 bool GotFloatRegs = false;
1876 bool GotIntRegs = false;
1877 bool GotHomingRestore = false;
1878 bool GotLRRestore = false;
1879 bool NeedsReturn = false;
1880 bool GotReturn = false;
1881
1882 Step = 6;
1883 for (const WinEH::Instruction &Inst : Epilog) {
1884 switch (Inst.Operation) {
1885 default:
1886 llvm_unreachable("Unsupported ARM unwind code")::llvm::llvm_unreachable_internal("Unsupported ARM unwind code"
, "llvm/lib/MC/MCWin64EH.cpp", 1886)
;
1887 case Win64EH::UOP_Custom:
1888 case Win64EH::UOP_AllocLarge:
1889 case Win64EH::UOP_AllocHuge:
1890 case Win64EH::UOP_WideAllocLarge:
1891 case Win64EH::UOP_WideAllocHuge:
1892 case Win64EH::UOP_SaveFRegD0D15:
1893 case Win64EH::UOP_SaveFRegD16D31:
1894 case Win64EH::UOP_SaveSP:
1895 case Win64EH::UOP_Nop:
1896 case Win64EH::UOP_WideNop:
1897 // Can't be packed in an epilogue
1898 return false;
1899
1900 case Win64EH::UOP_AllocSmall:
1901 case Win64EH::UOP_WideAllocMedium:
1902 if (Inst.Offset / 4 >= 0x3f4)
1903 return false;
1904 if (Step == 6) {
1905 if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
1906 PF == 0 && Inst.Offset == 16) {
1907 GotHomingRestore = true;
1908 Step = 10;
1909 } else {
1910 if (StackAdjust > 0) {
1911 // Got stack adjust in prologue too; must match.
1912 if (StackAdjust != Inst.Offset / 4)
1913 return false;
1914 GotStackAdjust = true;
1915 } else if (PF == Inst.Offset / 4) {
1916 // Folded prologue, non-folded epilogue
1917 StackAdjust = Inst.Offset / 4;
1918 GotStackAdjust = true;
1919 } else {
1920 // StackAdjust == 0 in prologue, mismatch
1921 return false;
1922 }
1923 Step = 7;
1924 }
1925 } else if (Step == 7 || Step == 8 || Step == 9) {
1926 if (!Homing || Inst.Offset != 16)
1927 return false;
1928 GotHomingRestore = true;
1929 Step = 10;
1930 } else
1931 return false;
1932 break;
1933
1934 case Win64EH::UOP_SaveFRegD8D15:
1935 if (Step != 6 && Step != 7)
1936 return false;
1937 assert(Inst.Register >= 8 && Inst.Register <= 15)(static_cast <bool> (Inst.Register >= 8 && Inst
.Register <= 15) ? void (0) : __assert_fail ("Inst.Register >= 8 && Inst.Register <= 15"
, "llvm/lib/MC/MCWin64EH.cpp", 1937, __extension__ __PRETTY_FUNCTION__
))
;
1938 if (FloatRegs != (int)(Inst.Register - 8))
1939 return false;
1940 GotFloatRegs = true;
1941 Step = 8;
1942 break;
1943
1944 case Win64EH::UOP_SaveRegsR4R7LR:
1945 case Win64EH::UOP_WideSaveRegsR4R11LR: {
1946 // push {r4-r11,lr}
1947 if (Step != 6 && Step != 7 && Step != 8)
1948 return false;
1949 assert(Inst.Register >= 4 && Inst.Register <= 11)(static_cast <bool> (Inst.Register >= 4 && Inst
.Register <= 11) ? void (0) : __assert_fail ("Inst.Register >= 4 && Inst.Register <= 11"
, "llvm/lib/MC/MCWin64EH.cpp", 1949, __extension__ __PRETTY_FUNCTION__
))
; // r4-rX
1950 assert(Inst.Offset <= 1)(static_cast <bool> (Inst.Offset <= 1) ? void (0) : __assert_fail
("Inst.Offset <= 1", "llvm/lib/MC/MCWin64EH.cpp", 1950, __extension__
__PRETTY_FUNCTION__))
; // Lr
1951 if (Homing && HasLR) {
1952 // If homing and LR is backed up, we can either restore LR here
1953 // and return with Ret == 1 or 2, or return with SaveLR below
1954 if (Inst.Offset) {
1955 GotLRRestore = true;
1956 NeedsReturn = true;
1957 } else {
1958 // Expecting a separate SaveLR below
1959 }
1960 } else {
1961 if (HasLR != (Inst.Offset == 1))
1962 return false;
1963 }
1964 GotLRRestore = Inst.Offset == 1;
1965 if (IntRegs < 0) // This opcode must include r4
1966 return false;
1967 int Expected = IntRegs;
1968 if (HasChain) {
1969 // Can't express r11 here unless IntRegs describe r4-r10
1970 if (IntRegs != 6)
1971 return false;
1972 Expected++;
1973 }
1974 if (Expected != (int)(Inst.Register - 4))
1975 return false;
1976 GotIntRegs = true;
1977 Step = 9;
1978 break;
1979 }
1980
1981 case Win64EH::UOP_SaveRegMask:
1982 case Win64EH::UOP_WideSaveRegMask: {
1983 if (Step != 6 && Step != 7 && Step != 8)
1984 return false;
1985 // push {r4-r9,r11,lr}
1986 // push {r11,lr}
1987 // push {r1-r5}
1988 bool CurHasLR = false, CurHasR11 = false;
1989 int Regs;
1990 if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
1991 return false;
1992 if (EF > 0) {
1993 if (EF != PF && EF != StackAdjust)
1994 return false;
1995 }
1996 if (Homing && HasLR) {
1997 // If homing and LR is backed up, we can either restore LR here
1998 // and return with Ret == 1 or 2, or return with SaveLR below
1999 if (CurHasLR) {
2000 GotLRRestore = true;
2001 NeedsReturn = true;
2002 } else {
2003 // Expecting a separate SaveLR below
2004 }
2005 } else {
2006 if (CurHasLR != HasLR)
2007 return false;
2008 GotLRRestore = CurHasLR;
2009 }
2010 int Expected = IntRegs;
2011 if (HasChain) {
2012 // If we have chaining, the mask must have included r11.
2013 if (!CurHasR11)
2014 return false;
2015 } else if (Expected == 7) {
2016 // If we don't have chaining, the mask could still include r11,
2017 // expressed as part of IntRegs Instead.
2018 Expected--;
2019 if (!CurHasR11)
2020 return false;
2021 } else {
2022 // Neither HasChain nor r11 included in IntRegs, must not have r11
2023 // here either.
2024 if (CurHasR11)
2025 return false;
2026 }
2027 if (Expected != Regs)
2028 return false;
2029 GotIntRegs = true;
2030 Step = 9;
2031 break;
2032 }
2033
2034 case Win64EH::UOP_SaveLR:
2035 if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
2036 return false;
2037 if (!Homing || Inst.Offset != 20 || GotLRRestore)
2038 return false;
2039 GotLRRestore = true;
2040 GotHomingRestore = true;
2041 Step = 10;
2042 break;
2043
2044 case Win64EH::UOP_EndNop:
2045 case Win64EH::UOP_WideEndNop:
2046 GotReturn = true;
2047 Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
2048 [[fallthrough]];
2049 case Win64EH::UOP_End:
2050 if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
2051 return false;
2052 Step = 11;
2053 break;
2054 }
2055 }
2056
2057 if (Step != 11)
2058 return false;
2059 if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
2060 return false;
2061 if (FloatRegs >= 0 && !GotFloatRegs)
2062 return false;
2063 if (IntRegs >= 0 && !GotIntRegs)
2064 return false;
2065 if (Homing && !GotHomingRestore)
2066 return false;
2067 if (HasLR && !GotLRRestore)
2068 return false;
2069 if (NeedsReturn && !GotReturn)
2070 return false;
2071 }
2072
2073 assert(PF == 0 || EF == 0 ||(static_cast <bool> (PF == 0 || EF == 0 || StackAdjust ==
0) ? void (0) : __assert_fail ("PF == 0 || EF == 0 || StackAdjust == 0"
, "llvm/lib/MC/MCWin64EH.cpp", 2074, __extension__ __PRETTY_FUNCTION__
))
2074 StackAdjust == 0)(static_cast <bool> (PF == 0 || EF == 0 || StackAdjust ==
0) ? void (0) : __assert_fail ("PF == 0 || EF == 0 || StackAdjust == 0"
, "llvm/lib/MC/MCWin64EH.cpp", 2074, __extension__ __PRETTY_FUNCTION__
))
; // Can't have adjust in all three
2075 if (PF > 0 || EF > 0) {
2076 StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
2077 assert(StackAdjust <= 3)(static_cast <bool> (StackAdjust <= 3) ? void (0) : __assert_fail
("StackAdjust <= 3", "llvm/lib/MC/MCWin64EH.cpp", 2077, __extension__
__PRETTY_FUNCTION__))
;
2078 StackAdjust |= 0x3f0;
2079 if (PF > 0)
2080 StackAdjust |= 1 << 2;
2081 if (EF > 0)
2082 StackAdjust |= 1 << 3;
2083 }
2084
2085 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier")(static_cast <bool> (FuncLength <= 0x7FF && "FuncLength should have been checked earlier"
) ? void (0) : __assert_fail ("FuncLength <= 0x7FF && \"FuncLength should have been checked earlier\""
, "llvm/lib/MC/MCWin64EH.cpp", 2085, __extension__ __PRETTY_FUNCTION__
))
;
2086 int Flag = info->Fragment ? 0x02 : 0x01;
2087 int H = Homing ? 1 : 0;
2088 int L = HasLR ? 1 : 0;
2089 int C = HasChain ? 1 : 0;
2090 assert(IntRegs < 0 || FloatRegs < 0)(static_cast <bool> (IntRegs < 0 || FloatRegs < 0
) ? void (0) : __assert_fail ("IntRegs < 0 || FloatRegs < 0"
, "llvm/lib/MC/MCWin64EH.cpp", 2090, __extension__ __PRETTY_FUNCTION__
))
;
2091 unsigned Reg, R;
2092 if (IntRegs >= 0) {
2093 Reg = IntRegs;
2094 assert(Reg <= 7)(static_cast <bool> (Reg <= 7) ? void (0) : __assert_fail
("Reg <= 7", "llvm/lib/MC/MCWin64EH.cpp", 2094, __extension__
__PRETTY_FUNCTION__))
;
2095 R = 0;
2096 } else if (FloatRegs >= 0) {
2097 Reg = FloatRegs;
2098 assert(Reg < 7)(static_cast <bool> (Reg < 7) ? void (0) : __assert_fail
("Reg < 7", "llvm/lib/MC/MCWin64EH.cpp", 2098, __extension__
__PRETTY_FUNCTION__))
;
2099 R = 1;
2100 } else {
2101 // No int or float regs stored (except possibly R11,LR)
2102 Reg = 7;
2103 R = 1;
2104 }
2105 info->PackedInfo |= Flag << 0;
2106 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
2107 info->PackedInfo |= (Ret & 0x3) << 13;
2108 info->PackedInfo |= H << 15;
2109 info->PackedInfo |= Reg << 16;
2110 info->PackedInfo |= R << 19;
2111 info->PackedInfo |= L << 20;
2112 info->PackedInfo |= C << 21;
2113 assert(StackAdjust <= 0x3ff)(static_cast <bool> (StackAdjust <= 0x3ff) ? void (0
) : __assert_fail ("StackAdjust <= 0x3ff", "llvm/lib/MC/MCWin64EH.cpp"
, 2113, __extension__ __PRETTY_FUNCTION__))
;
2114 info->PackedInfo |= StackAdjust << 22;
2115 return true;
2116}
2117
2118// Populate the .xdata section. The format of .xdata on ARM is documented at
2119// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
2120static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
2121 bool TryPacked = true) {
2122 // If this UNWIND_INFO already has a symbol, it's already been emitted.
2123 if (info->Symbol)
2124 return;
2125 // If there's no unwind info here (not even a terminating UOP_End), the
2126 // unwind info is considered bogus and skipped. If this was done in
2127 // response to an explicit .seh_handlerdata, the associated trailing
2128 // handler data is left orphaned in the xdata section.
2129 if (info->empty()) {
2130 info->EmitAttempted = true;
2131 return;
2132 }
2133 if (info->EmitAttempted) {
2134 // If we tried to emit unwind info before (due to an explicit
2135 // .seh_handlerdata directive), but skipped it (because there was no
2136 // valid information to emit at the time), and it later got valid unwind
2137 // opcodes, we can't emit it here, because the trailing handler data
2138 // was already emitted elsewhere in the xdata section.
2139 streamer.getContext().reportError(
2140 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
2141 " skipped due to no unwind info at the time "
2142 "(.seh_handlerdata too early?), but the function later "
2143 "did get unwind info that can't be emitted");
2144 return;
2145 }
2146
2147 MCContext &context = streamer.getContext();
2148 MCSymbol *Label = context.createTempSymbol();
2149
2150 streamer.emitValueToAlignment(4);
2151 streamer.emitLabel(Label);
2152 info->Symbol = Label;
2153
2154 if (!info->PrologEnd)
2155 streamer.getContext().reportError(SMLoc(), "Prologue in " +
2156 info->Function->getName() +
2157 " not correctly terminated");
2158
2159 if (info->PrologEnd && !info->Fragment)
2160 checkARMInstructions(streamer, info->Instructions, info->Begin,
2161 info->PrologEnd, info->Function->getName(),
2162 "prologue");
2163 for (auto &I : info->EpilogMap) {
2164 MCSymbol *EpilogStart = I.first;
2165 auto &Epilog = I.second;
2166 checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
2167 info->Function->getName(), "epilogue");
2168 if (Epilog.Instructions.empty() ||
2169 !isARMTerminator(Epilog.Instructions.back()))
2170 streamer.getContext().reportError(
2171 SMLoc(), "Epilogue in " + info->Function->getName() +
2172 " not correctly terminated");
2173 }
2174
2175 Optional<int64_t> RawFuncLength;
2176 const MCExpr *FuncLengthExpr = nullptr;
2177 if (!info->FuncletOrFuncEnd) {
2178 report_fatal_error("FuncletOrFuncEnd not set");
2179 } else {
2180 // As the size of many thumb2 instructions isn't known until later,
2181 // we can't always rely on being able to calculate the absolute
2182 // length of the function here. If we can't calculate it, defer it
2183 // to a relocation.
2184 //
2185 // In such a case, we won't know if the function is too long so that
2186 // the unwind info would need to be split (but this isn't implemented
2187 // anyway).
2188 RawFuncLength =
2189 GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
2190 if (!RawFuncLength)
2191 FuncLengthExpr =
2192 GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
2193 }
2194 uint32_t FuncLength = 0;
2195 if (RawFuncLength)
2196 FuncLength = (uint32_t)*RawFuncLength / 2;
2197 if (FuncLength > 0x3FFFF)
2198 report_fatal_error("SEH unwind data splitting not yet implemented");
2199 uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
2200 uint32_t TotalCodeBytes = PrologCodeBytes;
2201
2202 if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2203 TryPacked) {
2204 // No exception handlers; check if the prolog and epilog matches the
2205 // patterns that can be described by the packed format. If we don't
2206 // know the exact function length yet, we can't do this.
2207
2208 // info->Symbol was already set even if we didn't actually write any
2209 // unwind info there. Keep using that as indicator that this unwind
2210 // info has been generated already.
2211
2212 if (tryARMPackedUnwind(streamer, info, FuncLength))
2213 return;
2214 }
2215
2216 int PackedEpilogOffset =
2217 checkARMPackedEpilog(streamer, info, PrologCodeBytes);
2218
2219 // Process epilogs.
2220 MapVector<MCSymbol *, uint32_t> EpilogInfo;
2221 // Epilogs processed so far.
2222 std::vector<MCSymbol *> AddedEpilogs;
2223
2224 bool CanTweakProlog = true;
2225 for (auto &I : info->EpilogMap) {
2226 MCSymbol *EpilogStart = I.first;
2227 auto &EpilogInstrs = I.second.Instructions;
2228 uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
2229
2230 MCSymbol *MatchingEpilog =
2231 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
2232 int PrologOffset;
2233 if (MatchingEpilog) {
2234 assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&(static_cast <bool> (EpilogInfo.find(MatchingEpilog) !=
EpilogInfo.end() && "Duplicate epilog not found") ? void
(0) : __assert_fail ("EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && \"Duplicate epilog not found\""
, "llvm/lib/MC/MCWin64EH.cpp", 2235, __extension__ __PRETTY_FUNCTION__
))
2235 "Duplicate epilog not found")(static_cast <bool> (EpilogInfo.find(MatchingEpilog) !=
EpilogInfo.end() && "Duplicate epilog not found") ? void
(0) : __assert_fail ("EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() && \"Duplicate epilog not found\""
, "llvm/lib/MC/MCWin64EH.cpp", 2235, __extension__ __PRETTY_FUNCTION__
))
;
2236 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2237 // Clear the unwind codes in the EpilogMap, so that they don't get output
2238 // in the logic below.
2239 EpilogInstrs.clear();
2240 } else if ((PrologOffset = getARMOffsetInProlog(
2241 info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2242 if (CanTweakProlog) {
2243 // Replace the regular end opcode of the prolog with the one from the
2244 // epilog.
2245 info->Instructions.front() = EpilogInstrs.back();
2246 // Later epilogs need a strict match for the end opcode.
2247 CanTweakProlog = false;
2248 }
2249 EpilogInfo[EpilogStart] = PrologOffset;
2250 // Clear the unwind codes in the EpilogMap, so that they don't get output
2251 // in the logic below.
2252 EpilogInstrs.clear();
2253 } else {
2254 EpilogInfo[EpilogStart] = TotalCodeBytes;
2255 TotalCodeBytes += CodeBytes;
2256 AddedEpilogs.push_back(EpilogStart);
2257 }
2258 }
2259
2260 // Code Words, Epilog count, F, E, X, Vers, Function Length
2261 uint32_t row1 = 0x0;
2262 uint32_t CodeWords = TotalCodeBytes / 4;
2263 uint32_t CodeWordsMod = TotalCodeBytes % 4;
2264 if (CodeWordsMod)
2265 CodeWords++;
2266 uint32_t EpilogCount =
2267 PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
2268 bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2269 if (!ExtensionWord) {
2270 row1 |= (EpilogCount & 0x1F) << 23;
2271 row1 |= (CodeWords & 0x0F) << 28;
2272 }
2273 if (info->HandlesExceptions) // X
2274 row1 |= 1 << 20;
2275 if (PackedEpilogOffset >= 0) // E
2276 row1 |= 1 << 21;
2277 if (info->Fragment) // F
2278 row1 |= 1 << 22;
2279 row1 |= FuncLength & 0x3FFFF;
2280 if (RawFuncLength)
2281 streamer.emitInt32(row1);
2282 else
2283 streamer.emitValue(
2284 MCBinaryExpr::createOr(FuncLengthExpr,
2285 MCConstantExpr::create(row1, context), context),
2286 4);
2287
2288 // Extended Code Words, Extended Epilog Count
2289 if (ExtensionWord) {
2290 // FIXME: We should be able to split unwind info into multiple sections.
2291 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2292 report_fatal_error("SEH unwind data splitting not yet implemented");
2293 uint32_t row2 = 0x0;
2294 row2 |= (CodeWords & 0xFF) << 16;
2295 row2 |= (EpilogCount & 0xFFFF);
2296 streamer.emitInt32(row2);
2297 }
2298
2299 if (PackedEpilogOffset < 0) {
2300 // Epilog Start Index, Epilog Start Offset
2301 for (auto &I : EpilogInfo) {
2302 MCSymbol *EpilogStart = I.first;
2303 uint32_t EpilogIndex = I.second;
2304
2305 Optional<int64_t> MaybeEpilogOffset =
2306 GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
2307 const MCExpr *OffsetExpr = nullptr;
2308 uint32_t EpilogOffset = 0;
2309 if (MaybeEpilogOffset)
2310 EpilogOffset = *MaybeEpilogOffset / 2;
2311 else
2312 OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
2313
2314 assert(info->EpilogMap.find(EpilogStart) != info->EpilogMap.end())(static_cast <bool> (info->EpilogMap.find(EpilogStart
) != info->EpilogMap.end()) ? void (0) : __assert_fail ("info->EpilogMap.find(EpilogStart) != info->EpilogMap.end()"
, "llvm/lib/MC/MCWin64EH.cpp", 2314, __extension__ __PRETTY_FUNCTION__
))
;
2315 unsigned Condition = info->EpilogMap[EpilogStart].Condition;
2316 assert(Condition <= 0xf)(static_cast <bool> (Condition <= 0xf) ? void (0) : __assert_fail
("Condition <= 0xf", "llvm/lib/MC/MCWin64EH.cpp", 2316, __extension__
__PRETTY_FUNCTION__))
;
2317
2318 uint32_t row3 = EpilogOffset;
2319 row3 |= Condition << 20;
2320 row3 |= (EpilogIndex & 0x3FF) << 24;
2321 if (MaybeEpilogOffset)
2322 streamer.emitInt32(row3);
2323 else
2324 streamer.emitValue(
2325 MCBinaryExpr::createOr(
2326 OffsetExpr, MCConstantExpr::create(row3, context), context),
2327 4);
2328 }
2329 }
2330
2331 // Emit prolog unwind instructions (in reverse order).
2332 uint8_t numInst = info->Instructions.size();
2333 for (uint8_t c = 0; c < numInst; ++c) {
2334 WinEH::Instruction inst = info->Instructions.back();
2335 info->Instructions.pop_back();
2336 ARMEmitUnwindCode(streamer, inst);
2337 }
2338
2339 // Emit epilog unwind instructions
2340 for (auto &I : info->EpilogMap) {
2341 auto &EpilogInstrs = I.second.Instructions;
2342 for (const WinEH::Instruction &inst : EpilogInstrs)
2343 ARMEmitUnwindCode(streamer, inst);
2344 }
2345
2346 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2347 assert(BytesMod >= 0)(static_cast <bool> (BytesMod >= 0) ? void (0) : __assert_fail
("BytesMod >= 0", "llvm/lib/MC/MCWin64EH.cpp", 2347, __extension__
__PRETTY_FUNCTION__))
;
2348 for (int i = 0; i < BytesMod; i++)
2349 streamer.emitInt8(0xFB);
2350
2351 if (info->HandlesExceptions)
2352 streamer.emitValue(
2353 MCSymbolRefExpr::create(info->ExceptionHandler,
2354 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
2355 4);
2356}
2357
2358static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
2359 const WinEH::FrameInfo *info) {
2360 MCContext &context = streamer.getContext();
2361
2362 streamer.emitValueToAlignment(4);
2363 for (const auto &S : info->Segments) {
2364 EmitSymbolRefWithOfs(streamer, info->Begin, S.Offset);
2365 if (info->PackedInfo)
2366 streamer.emitInt32(info->PackedInfo);
2367 else
2368 streamer.emitValue(
2369 MCSymbolRefExpr::create(S.Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
2370 context),
2371 4);
2372 }
2373}
2374
2375
2376static void ARMEmitRuntimeFunction(MCStreamer &streamer,
2377 const WinEH::FrameInfo *info) {
2378 MCContext &context = streamer.getContext();
2379
2380 streamer.emitValueToAlignment(4);
2381 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
2382 if (info->PackedInfo)
2383 streamer.emitInt32(info->PackedInfo);
2384 else
2385 streamer.emitValue(
2386 MCSymbolRefExpr::create(info->Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
2387 context),
2388 4);
2389}
2390
2391void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
2392 // Emit the unwind info structs first.
2393 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2394 WinEH::FrameInfo *Info = CFI.get();
2395 if (Info->empty())
2396 continue;
2397 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2398 Streamer.switchSection(XData);
2399 ARM64EmitUnwindInfo(Streamer, Info);
2400 }
2401
2402 // Now emit RUNTIME_FUNCTION entries.
2403 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2404 WinEH::FrameInfo *Info = CFI.get();
2405 // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2406 // empty here. But if a Symbol is set, we should create the corresponding
2407 // pdata entry.
2408 if (!Info->Symbol)
2409 continue;
2410 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2411 Streamer.switchSection(PData);
2412 ARM64EmitRuntimeFunction(Streamer, Info);
2413 }
2414}
2415
2416void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2417 WinEH::FrameInfo *info,
2418 bool HandlerData) const {
2419 // Called if there's an .seh_handlerdata directive before the end of the
2420 // function. This forces writing the xdata record already here - and
2421 // in this case, the function isn't actually ended already, but the xdata
2422 // record needs to know the function length. In these cases, if the funclet
2423 // end hasn't been marked yet, the xdata function length won't cover the
2424 // whole function, only up to this point.
2425 if (!info->FuncletOrFuncEnd) {
2426 Streamer.switchSection(info->TextSection);
2427 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2428 }
2429 // Switch sections (the static function above is meant to be called from
2430 // here and from Emit().
2431 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2432 Streamer.switchSection(XData);
2433 ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2434}
2435
2436void llvm::Win64EH::ARMUnwindEmitter::Emit(MCStreamer &Streamer) const {
2437 // Emit the unwind info structs first.
2438 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2439 WinEH::FrameInfo *Info = CFI.get();
2440 if (Info->empty())
2441 continue;
2442 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2443 Streamer.switchSection(XData);
2444 ARMEmitUnwindInfo(Streamer, Info);
2445 }
2446
2447 // Now emit RUNTIME_FUNCTION entries.
2448 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2449 WinEH::FrameInfo *Info = CFI.get();
2450 // ARMEmitUnwindInfo above clears the info struct, so we can't check
2451 // empty here. But if a Symbol is set, we should create the corresponding
2452 // pdata entry.
2453 if (!Info->Symbol)
2454 continue;
2455 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2456 Streamer.switchSection(PData);
2457 ARMEmitRuntimeFunction(Streamer, Info);
2458 }
2459}
2460
2461void llvm::Win64EH::ARMUnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2462 WinEH::FrameInfo *info,
2463 bool HandlerData) const {
2464 // Called if there's an .seh_handlerdata directive before the end of the
2465 // function. This forces writing the xdata record already here - and
2466 // in this case, the function isn't actually ended already, but the xdata
2467 // record needs to know the function length. In these cases, if the funclet
2468 // end hasn't been marked yet, the xdata function length won't cover the
2469 // whole function, only up to this point.
2470 if (!info->FuncletOrFuncEnd) {
2471 Streamer.switchSection(info->TextSection);
2472 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2473 }
2474 // Switch sections (the static function above is meant to be called from
2475 // here and from Emit().
2476 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2477 Streamer.switchSection(XData);
2478 ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2479}