LLVM 23.0.0git
MCWin64EH.cpp
Go to the documentation of this file.
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/Twine.h"
11#include "llvm/MC/MCAssembler.h"
12#include "llvm/MC/MCContext.h"
13#include "llvm/MC/MCExpr.h"
15#include "llvm/MC/MCStreamer.h"
16#include "llvm/MC/MCSymbol.h"
17#include "llvm/MC/MCValue.h"
20
21namespace llvm {
22class MCSection;
23}
24
25using namespace llvm;
26
27namespace {
28/// MCExpr that represents the epilog unwind code in an unwind table.
29class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr {
30 const WinEH::FrameInfo &FrameInfo;
31 const MCSymbol *UnwindV2Start;
32 const MCSymbol *EpilogEnd;
33 uint8_t EpilogSize;
34 SMLoc Loc;
35
36 MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo &FrameInfo,
37 const WinEH::FrameInfo::Epilog &Epilog,
38 uint8_t EpilogSize_)
39 : FrameInfo(FrameInfo), UnwindV2Start(Epilog.UnwindV2Start),
40 EpilogEnd(Epilog.End), EpilogSize(EpilogSize_), Loc(Epilog.Loc) {
41 assert(UnwindV2Start && "Epilog must have a start");
42 assert(EpilogEnd && "Epilog must have an end");
43 }
44
45public:
46 static MCUnwindV2EpilogTargetExpr *
47 create(const WinEH::FrameInfo &FrameInfo,
48 const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_,
49 MCContext &Ctx) {
50 return new (Ctx) MCUnwindV2EpilogTargetExpr(FrameInfo, Epilog, EpilogSize_);
51 }
52
53 void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
54 OS << ":epilog:";
55 UnwindV2Start->print(OS, MAI);
56 }
57
58 bool evaluateAsRelocatableImpl(MCValue &Res,
59 const MCAssembler *Asm) const override;
60
61 void visitUsedExpr(MCStreamer &Streamer) const override {
62 // Contains no sub-expressions.
63 }
64
65 MCFragment *findAssociatedFragment() const override {
66 return UnwindV2Start->getFragment();
67 }
68};
69} // namespace
70
71// NOTE: All relocations generated here are 4-byte image-relative.
72
73static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
74 uint8_t Count = 0;
75 for (const auto &I : Insns) {
76 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
77 default:
78 llvm_unreachable("Unsupported unwind code");
83 Count += 1;
84 break;
87 Count += 2;
88 break;
91 Count += 3;
92 break;
94 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
95 break;
96 }
97 }
98 return Count;
99}
100
101static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
102 const MCSymbol *RHS) {
103 MCContext &Context = Streamer.getContext();
104 const MCExpr *Diff =
106 MCSymbolRefExpr::create(RHS, Context), Context);
107 Streamer.emitValue(Diff, 1);
108}
109
110/// Emit a 16-bit (2-byte LE) label difference. If the difference is
111/// evaluatable at this point, validate that it fits in [0, UINT16_MAX]
112/// and emit it as a constant; otherwise emit a 16-bit fixup.
113static void EmitAbsDifference16(MCStreamer &Streamer, const MCSymbol *LHS,
114 const MCSymbol *RHS) {
115 MCContext &Context = Streamer.getContext();
116 const MCExpr *Diff =
118 MCSymbolRefExpr::create(RHS, Context), Context);
119 int64_t Value;
120 if (Diff->evaluateAsAbsolute(
121 Value, static_cast<MCObjectStreamer &>(Streamer).getAssembler())) {
122 if (Value < 0 || Value > UINT16_MAX)
123 Context.reportError(
124 SMLoc(),
125 "Label difference out of 16-bit unsigned range for V3 unwind info");
126 }
127 // Always emit a 2-byte value so subsequent emission stays in sync; if a
128 // diagnostic was reported, the object file will be discarded by the caller.
129 Streamer.emitValue(Diff, 2);
130}
131
132static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
133 WinEH::Instruction &inst) {
134 uint8_t b2;
135 uint16_t w;
136 b2 = (inst.Operation & 0x0F);
137 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
138 default:
139 llvm_unreachable("Unsupported unwind code");
141 // Reachable from hand-written .s if a UOP_Push2 ends up in a V1/V2
142 // frame (e.g. via a per-function `.seh_unwindversion` downgrade after
143 // `.seh_push2regs`). Emit a recoverable diagnostic and skip the op so
144 // the assembler doesn't keep writing malformed bytes.
145 streamer.getContext().reportError(
146 SMLoc(), "UOP_Push2 (PUSH2 with two registers) requires V3 unwind "
147 "info. Use `.seh_unwindversion 3`.");
148 return;
150 EmitAbsDifference(streamer, inst.Label, begin);
151 b2 |= (inst.Register & 0x0F) << 4;
152 streamer.emitInt8(b2);
153 break;
155 EmitAbsDifference(streamer, inst.Label, begin);
156 if (inst.Offset > 512 * 1024 - 8) {
157 b2 |= 0x10;
158 streamer.emitInt8(b2);
159 w = inst.Offset & 0xFFF8;
160 streamer.emitInt16(w);
161 w = inst.Offset >> 16;
162 } else {
163 streamer.emitInt8(b2);
164 w = inst.Offset >> 3;
165 }
166 streamer.emitInt16(w);
167 break;
169 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
170 EmitAbsDifference(streamer, inst.Label, begin);
171 streamer.emitInt8(b2);
172 break;
174 EmitAbsDifference(streamer, inst.Label, begin);
175 streamer.emitInt8(b2);
176 break;
179 b2 |= (inst.Register & 0x0F) << 4;
180 EmitAbsDifference(streamer, inst.Label, begin);
181 streamer.emitInt8(b2);
182 w = inst.Offset >> 3;
184 w >>= 1;
185 streamer.emitInt16(w);
186 break;
189 b2 |= (inst.Register & 0x0F) << 4;
190 EmitAbsDifference(streamer, inst.Label, begin);
191 streamer.emitInt8(b2);
193 w = inst.Offset & 0xFFF0;
194 else
195 w = inst.Offset & 0xFFF8;
196 streamer.emitInt16(w);
197 w = inst.Offset >> 16;
198 streamer.emitInt16(w);
199 break;
201 if (inst.Offset == 1)
202 b2 |= 0x10;
203 EmitAbsDifference(streamer, inst.Label, begin);
204 streamer.emitInt8(b2);
205 break;
206 }
207}
208
209static void EmitSymbolRefWithOfs(MCStreamer &streamer,
210 const MCSymbol *Base,
211 int64_t Offset) {
212 MCContext &Context = streamer.getContext();
213 const MCConstantExpr *OffExpr = MCConstantExpr::create(Offset, Context);
214 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
216 Context);
217 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, OffExpr, Context), 4);
218}
219
220static void EmitSymbolRefWithOfs(MCStreamer &streamer,
221 const MCSymbol *Base,
222 const MCSymbol *Other) {
223 MCContext &Context = streamer.getContext();
224 const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
225 const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
226 const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
227 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
229 Context);
230 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
231}
232
233static void EmitRuntimeFunction(MCStreamer &streamer,
234 const WinEH::FrameInfo *info) {
235 MCContext &context = streamer.getContext();
236
237 streamer.emitValueToAlignment(Align(4));
238 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
239 EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
240 streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
242 context), 4);
243}
244
245static std::optional<int64_t>
247 const MCSymbol *RHS) {
248 MCContext &Context = Assembler.getContext();
249 const MCExpr *Diff =
251 MCSymbolRefExpr::create(RHS, Context), Context);
252 // It should normally be possible to calculate the length of a function
253 // at this point, but it might not be possible in the presence of certain
254 // unusual constructs, like an inline asm with an alignment directive.
255 int64_t value;
256 if (!Diff->evaluateAsAbsolute(value, Assembler))
257 return std::nullopt;
258 return value;
259}
260
261//===----------------------------------------------------------------------===//
262// V3 UNWIND_INFO Emission
263// See https://learn.microsoft.com/en-us/cpp/build/x64-unwind-information-v3
264//===----------------------------------------------------------------------===//
265
266/// Encode a single WinEH::Instruction as V3 WOD bytes.
267/// Appends encoded bytes to Out.
270 switch (static_cast<Win64EH::UnwindOpcodes>(Inst.Operation)) {
272 // WOD_PUSH: 1 byte, bits [2:0] = 4, bits [7:3] = register (5-bit)
273 uint8_t Reg = Inst.Register & 0x1F;
274 Out.push_back((Reg << 3) | Win64EH::WOD_PUSH);
275 break;
276 }
278 // WOD_ALLOC_SMALL: 1 byte, bits [3:0] = 8, bits [7:4] = (size/8 - 1)
279 // V1/V2 stores (size-8)/8 in OpInfo; actual size = Offset.
280 // Inst.Offset is the raw allocation size.
281 if (Inst.Offset < 8 || Inst.Offset > 128 || Inst.Offset % 8 != 0)
283 "UOP_AllocSmall outside expected range or alignment");
284 uint8_t Encoded = ((Inst.Offset / 8 - 1) & 0x0F);
285 Out.push_back((Encoded << 4) | Win64EH::WOD_ALLOC_SMALL);
286 break;
287 }
289 if (Inst.Offset > 512 * 1024 - 8) {
290 // WOD_ALLOC_HUGE: 5 bytes, byte[0] = 1, bytes[1:4] = LE32(size)
292 uint32_t Size = Inst.Offset;
293 Out.push_back(Size & 0xFF);
294 Out.push_back((Size >> 8) & 0xFF);
295 Out.push_back((Size >> 16) & 0xFF);
296 Out.push_back((Size >> 24) & 0xFF);
297 } else {
298 // WOD_ALLOC_LARGE: 3 bytes, byte[0] = 2, bytes[1:2] = LE16(size/8)
300 uint16_t Scaled = Inst.Offset / 8;
301 Out.push_back(Scaled & 0xFF);
302 Out.push_back((Scaled >> 8) & 0xFF);
303 }
304 break;
305 }
307 // WOD_SET_FPREG: 2 bytes, byte[0] = 0, byte[1] = reg(4) | (offset/16)(4)
308 // The frame register field is only 4 bits, so EGPR (R16-R31) cannot be
309 // used as the frame pointer in V3 unwind info.
310 if (Inst.Register > 0x0F)
312 "SET_FPREG frame register does not fit in 4 bits");
314 uint8_t Reg = Inst.Register & 0x0F;
315 uint8_t Off = (Inst.Offset / 16) & 0x0F;
316 Out.push_back(Reg | (Off << 4));
317 break;
318 }
320 // WOD_SAVE_NONVOL: 3 bytes, bits [2:0] = 6, bits [7:3] = reg,
321 // bytes[1:2] = LE16(displacement/8)
322 uint8_t Reg = Inst.Register & 0x1F;
323 Out.push_back((Reg << 3) | Win64EH::WOD_SAVE_NONVOL);
324 uint16_t Disp = Inst.Offset / 8;
325 Out.push_back(Disp & 0xFF);
326 Out.push_back((Disp >> 8) & 0xFF);
327 break;
328 }
330 // WOD_SAVE_NONVOL_FAR: 5 bytes, bits [2:0] = 5, bits [7:3] = reg,
331 // bytes[1:4] = LE32(displacement)
332 uint8_t Reg = Inst.Register & 0x1F;
333 Out.push_back((Reg << 3) | Win64EH::WOD_SAVE_NONVOL_FAR);
334 uint32_t Disp = Inst.Offset;
335 Out.push_back(Disp & 0xFF);
336 Out.push_back((Disp >> 8) & 0xFF);
337 Out.push_back((Disp >> 16) & 0xFF);
338 Out.push_back((Disp >> 24) & 0xFF);
339 break;
340 }
342 // WOD_SAVE_XMM128: 3 bytes, bits [3:0] = 10, bits [7:4] = reg,
343 // bytes[1:2] = LE16(displacement/16)
344 // The XMM register field is only 4 bits, so XMM16-XMM31 (AVX-512 EVEX)
345 // cannot be encoded. Such registers are caller-saved on Win64 and should
346 // never reach here from codegen.
347 if (Inst.Register > 0x0F)
349 "SAVE_XMM128 register does not fit in 4 bits (XMM16-31 unsupported)");
350 uint8_t Reg = Inst.Register & 0x0F;
351 Out.push_back((Reg << 4) | Win64EH::WOD_SAVE_XMM128);
352 uint16_t Disp = Inst.Offset / 16;
353 Out.push_back(Disp & 0xFF);
354 Out.push_back((Disp >> 8) & 0xFF);
355 break;
356 }
358 // WOD_SAVE_XMM128_FAR: 5 bytes, bits [3:0] = 9, bits [7:4] = reg,
359 // bytes[1:4] = LE32(displacement)
360 if (Inst.Register > 0x0F)
361 reportFatalInternalError("SAVE_XMM128_FAR register does not fit in 4 "
362 "bits (XMM16-31 unsupported)");
363 uint8_t Reg = Inst.Register & 0x0F;
364 Out.push_back((Reg << 4) | Win64EH::WOD_SAVE_XMM128_FAR);
365 uint32_t Disp = Inst.Offset;
366 Out.push_back(Disp & 0xFF);
367 Out.push_back((Disp >> 8) & 0xFF);
368 Out.push_back((Disp >> 16) & 0xFF);
369 Out.push_back((Disp >> 24) & 0xFF);
370 break;
371 }
373 // WOD_PUSH_CANONICAL_FRAME: 2 bytes, byte[0] = 3, byte[1] = type
375 Out.push_back(Inst.Offset == 1 ? 1 : 0);
376 break;
377 }
378 case Win64EH::UOP_Push2: {
379 uint8_t Reg1 = Inst.Register & 0x1F;
380 uint8_t Reg2 = Inst.Register2 & 0x1F;
381 // Optimization: if registers are consecutive, use WOD_PUSH_CONSECUTIVE_2
382 // (opcode 7, 1 byte) instead of WOD_PUSH2 (opcode 32, 2 bytes).
383 if (Reg2 == Reg1 + 1) {
384 // WOD_PUSH_CONSECUTIVE_2: bits [2:0] = 111b, bits [7:3] = Register
386 } else {
387 // WOD_PUSH2: 2 bytes
388 // Byte 0: [5:0] = 100000b (opcode 32), [7:6] = Register1[1:0]
389 // Byte 1: [2:0] = Register1[4:2], [7:3] = Register2
390 Out.push_back(((Reg1 & 0x03) << 6) | Win64EH::WOD_PUSH2);
391 Out.push_back(((Reg2 & 0x1F) << 3) | ((Reg1 >> 2) & 0x07));
392 }
393 break;
394 }
395 default:
396 llvm_unreachable("Unsupported unwind operation for V3 encoding");
397 }
398}
399
400/// Try to find Needle as a contiguous subsequence within Haystack.
401/// Returns the byte offset if found, or std::nullopt.
402static std::optional<uint16_t> FindInPool(ArrayRef<uint8_t> Haystack,
403 ArrayRef<uint8_t> Needle) {
404 assert(!Needle.empty() && "FindInPool called with empty Needle");
405 auto It = std::search(Haystack.begin(), Haystack.end(), Needle.begin(),
406 Needle.end());
407 if (It == Haystack.end())
408 return std::nullopt;
409 return static_cast<uint16_t>(std::distance(Haystack.begin(), It));
410}
411
412/// Compare the relative IP offset arrays of two epilogs.
415 const MCAssembler &Asm) {
416 if (A.Instructions.size() != B.Instructions.size())
417 return false;
418 for (unsigned I = 0; I < A.Instructions.size(); ++I) {
419 auto OffA = GetOptionalAbsDifference(Asm, A.Instructions[I].Label, A.Start);
420 auto OffB = GetOptionalAbsDifference(Asm, B.Instructions[I].Label, B.Start);
421 if (!OffA || !OffB || *OffA != *OffB)
422 return false;
423 }
424 return true;
425}
426
427/// Emit V3 UNWIND_INFO for a single frame.
428static void EmitUnwindInfoV3(MCStreamer &Streamer, WinEH::FrameInfo *Info) {
429 // Should have been checked by our caller.
430 assert(!Info->Symbol && "UNWIND_INFO already has a symbol");
431
432 MCContext &Context = Streamer.getContext();
433 MCObjectStreamer *OS = static_cast<MCObjectStreamer *>(&Streamer);
434 const MCAssembler &Asm = OS->getAssembler();
435
436 MCSymbol *Label = Context.createTempSymbol();
437 Streamer.emitValueToAlignment(Align(4));
438 Streamer.emitLabel(Label);
439 Info->Symbol = Label;
440
441 // ===================================================================
442 // Phase 1: Data preparation — compute all metadata before emitting.
443 // ===================================================================
444
445 // --- Build prolog WOD pool (body-to-entry order) ---
447 for (auto It = Info->Instructions.rbegin(); It != Info->Instructions.rend();
448 ++It)
449 Win64EH::EncodeWOD(*It, WODPool);
450
451 // --- Build prolog IP offset label pairs (body-to-entry order) ---
453 unsigned PrologOpCount = Info->Instructions.size();
454 if (PrologOpCount > 31) {
456 "Too many prolog unwind codes for V3 encoding. Maximum "
457 "is 31. This function has " +
458 Twine(PrologOpCount));
459 }
460 for (auto It = Info->Instructions.rbegin(); It != Info->Instructions.rend();
461 ++It)
462 PrologIpLabels.push_back({It->Label, Info->Begin});
463
464 // --- Determine if UNW_FLAG_LARGE is needed for the prolog ---
465 // Conservative: if we KNOW a value exceeds 255 or can't measure, use LARGE.
466 // Reject evaluatable values that are negative or exceed the 16-bit unsigned
467 // range supported by LARGE, since those would be silently truncated.
468 bool NeedsLargeProlog = false;
469 if (Info->PrologEnd) {
470 auto MaybePrologSize =
471 GetOptionalAbsDifference(Asm, Info->PrologEnd, Info->Begin);
472 if (MaybePrologSize) {
473 if (*MaybePrologSize < 0)
474 reportFatalUsageError("Negative SizeOfProlog in V3 unwind info");
475 if (*MaybePrologSize > UINT16_MAX)
477 "SizeOfProlog exceeds 16-bit range for V3 unwind info");
478 NeedsLargeProlog = (*MaybePrologSize > 255);
479 } else {
480 NeedsLargeProlog = true; // Can't measure -> be conservative
481 }
482 }
483 for (auto &[InstLabel, BeginLabel] : PrologIpLabels) {
484 if (NeedsLargeProlog)
485 break;
486 auto MaybeOffset = GetOptionalAbsDifference(Asm, InstLabel, BeginLabel);
487 if (MaybeOffset) {
488 if (*MaybeOffset < 0)
489 reportFatalUsageError("Negative prolog IP offset in V3 unwind info");
490 if (*MaybeOffset > UINT16_MAX)
492 "Prolog IP offset exceeds 16-bit range for V3 unwind info");
493 NeedsLargeProlog = (*MaybeOffset > 255);
494 } else {
495 NeedsLargeProlog = true; // Can't measure -> be conservative
496 }
497 }
498
499 // --- Per-epilog data preparation ---
500 struct EpilogEmitInfo {
503 uint16_t FirstOp;
504 uint8_t NumberOfOps;
505 bool Inherited;
506 bool NeedsLarge; // EPILOG_INFO_LARGE needed for this epilog
507 };
508
510 for (const auto &[EpilogSym, Epilog] : Info->EpilogMap) {
511 if (Epilog.Instructions.empty())
512 continue;
513
514 EpilogEmitInfo EI;
515 EI.Epilog = &Epilog;
516 EI.NumberOfOps = Epilog.Instructions.size();
517 if (EI.NumberOfOps > 31)
519 "Too many epilog unwind codes for V3 encoding. Maximum "
520 "is 31. This epilog has " +
521 Twine(EI.NumberOfOps));
522 EI.Inherited = false;
523 EI.NeedsLarge = false;
524
525 // Determine if EPILOG_INFO_LARGE is needed.
526 // Check IpOffsetOfLastInstruction (EpilogEnd - EpilogStart).
527 // Reject negative or out-of-range evaluatable values.
528 auto MaybeLastInstOfs =
529 GetOptionalAbsDifference(Asm, Epilog.End, Epilog.Start);
530 if (MaybeLastInstOfs) {
531 if (*MaybeLastInstOfs < 0)
533 "Negative IpOffsetOfLastInstruction in V3 unwind info");
534 if (*MaybeLastInstOfs > UINT16_MAX)
536 "IpOffsetOfLastInstruction exceeds 16-bit range for "
537 "V3 unwind info");
538 EI.NeedsLarge = (*MaybeLastInstOfs > 255);
539 } else {
540 EI.NeedsLarge = true; // Can't measure -> be conservative
541 }
542
543 // Check each epilog IP offset.
544 for (const auto &EpiInst : Epilog.Instructions) {
545 if (EI.NeedsLarge)
546 break;
547 auto MaybeOffset =
548 GetOptionalAbsDifference(Asm, EpiInst.Label, Epilog.Start);
549 if (MaybeOffset) {
550 if (*MaybeOffset < 0)
551 reportFatalUsageError("Negative epilog IP offset in V3 unwind info");
552 if (*MaybeOffset > UINT16_MAX)
554 "Epilog IP offset exceeds 16-bit range for V3 unwind info");
555 EI.NeedsLarge = (*MaybeOffset > 255);
556 } else {
557 EI.NeedsLarge = true; // Can't measure -> be conservative
558 }
559 }
560
561 // Encode this epilog's WODs (forward order: body-to-terminator).
562 for (const auto &Inst : Epilog.Instructions)
563 Win64EH::EncodeWOD(Inst, EI.WODBytes);
564
565 // Pool sharing: try to re-use existing bytes in the pool rather than
566 // appending.
567 if (auto Offset = FindInPool(WODPool, EI.WODBytes)) {
568 EI.FirstOp = *Offset;
569 } else {
570 EI.FirstOp = WODPool.size();
571 WODPool.append(EI.WODBytes.begin(), EI.WODBytes.end());
572 }
573
574 EpilogInfos.push_back(std::move(EI));
575 }
576 if (EpilogInfos.size() > 7)
577 reportFatalUsageError("Too many epilogs for V3 encoding. Maximum is 7."
578 " This function has " +
579 Twine(EpilogInfos.size()));
580
581 // --- Inheritance decisions ---
582 // An epilog can use the inherited (3-byte) descriptor when FirstOp,
583 // NumberOfOps, NeedsLarge, and relative IP offsets all match the previous
584 // epilog.
585 for (unsigned I = 1; I < EpilogInfos.size(); ++I) {
586 auto &Prev = EpilogInfos[I - 1];
587 auto &Curr = EpilogInfos[I];
588 if (Curr.FirstOp == Prev.FirstOp && Curr.NumberOfOps == Prev.NumberOfOps &&
589 Curr.NeedsLarge == Prev.NeedsLarge &&
590 EpilogIpOffsetsMatch(*Curr.Epilog, *Prev.Epilog, OS->getAssembler()))
591 Curr.Inherited = true;
592 }
593
594 // --- Compute payload sizes ---
595 unsigned PrologIpEntrySize = NeedsLargeProlog ? 2 : 1;
596 unsigned EpilogDescBytes = 0;
597 for (const auto &EI : EpilogInfos) {
598 if (EI.Inherited) {
599 EpilogDescBytes += 3;
600 } else if (EI.NeedsLarge) {
601 // EPILOG_INFO_V3 (3) + EPILOG_INFO_LARGE_EX_V3 (4) + IP offsets (N*2)
602 EpilogDescBytes += 7 + EI.NumberOfOps * 2;
603 } else {
604 // EPILOG_INFO_V3 (3) + EPILOG_INFO_EX_V3 (3) + IP offsets (N*1)
605 EpilogDescBytes += 6 + EI.NumberOfOps;
606 }
607 }
608
609 unsigned PrologIpBytes = PrologOpCount * PrologIpEntrySize;
610 unsigned WODPoolBytes = WODPool.size();
611 // When UNW_FLAG_LARGE is set, the SizeOfPrologHighByte sits at the start
612 // of the payload (immediately after the 4-byte fixed header) and is
613 // counted in PayloadWords. See decodeUnwindInfoV3 / the V3 spec:
614 // handler_offset = ALIGN_UP(sizeof(UNWIND_INFO_V3) + PayloadWords * 2, 4)
615 unsigned LargeHeaderBytes = NeedsLargeProlog ? 1 : 0;
616 unsigned TotalPayloadBytes =
617 LargeHeaderBytes + PrologIpBytes + EpilogDescBytes + WODPoolBytes;
618 if (TotalPayloadBytes > 255 * 2) {
619 reportFatalUsageError("Too much unwind info for V3 encoding. Maximum is "
620 "510 bytes. This function has " +
621 Twine(TotalPayloadBytes));
622 }
623 uint8_t PayloadWords = (TotalPayloadBytes + 1) / 2;
624
625 // ===================================================================
626 // Phase 2: Emission — emit header, payload, and trailer.
627 // ===================================================================
628
629 // --- Emit header (4 bytes, or 5 when UNW_FLAG_LARGE) ---
630 uint8_t Flags = 0;
631 if (Info->ChainedParent)
632 Flags |= Win64EH::UNW_ChainInfo;
633 else {
634 if (Info->HandlesUnwind)
636 if (Info->HandlesExceptions)
638 }
639 if (NeedsLargeProlog)
640 Flags |= Win64EH::UNW_FlagLarge;
641
642 // Byte 0: (Flags << 3) | Version(3)
643 Streamer.emitInt8((Flags << 3) | 3);
644
645 // Byte 1: SizeOfProlog (low byte, or full 8-bit value when not LARGE)
646 if (Info->PrologEnd) {
647 if (NeedsLargeProlog) {
648 // Emit low byte as a fixup; we'll emit the high byte after Byte 3.
649 // Use a 2-byte value at a temp symbol and extract bytes, OR just emit
650 // the known value if evaluable.
651 auto MaybePrologSize =
652 GetOptionalAbsDifference(Asm, Info->PrologEnd, Info->Begin);
653 if (MaybePrologSize) {
654 Streamer.emitInt8(*MaybePrologSize & 0xFF);
655 } else {
656 // Emit as 1-byte fixup for the low byte.
657 EmitAbsDifference(Streamer, Info->PrologEnd, Info->Begin);
658 }
659 } else {
660 EmitAbsDifference(Streamer, Info->PrologEnd, Info->Begin);
661 }
662 } else {
663 Streamer.emitInt8(0);
664 }
665
666 // Byte 2: PayloadWords
667 Streamer.emitInt8(PayloadWords);
668
669 // Byte 3: (NumberOfEpilogs << 5) | NumberOfPrologOps
670 uint8_t NumberOfEpilogs = EpilogInfos.size();
671 Streamer.emitInt8((NumberOfEpilogs << 5) | (PrologOpCount & 0x1F));
672
673 // Byte 4 (LARGE only): SizeOfPrologHighByte
674 if (NeedsLargeProlog) {
675 if (Info->PrologEnd) {
676 auto MaybePrologSize =
677 GetOptionalAbsDifference(Asm, Info->PrologEnd, Info->Begin);
678 if (MaybePrologSize) {
679 Streamer.emitInt8((*MaybePrologSize >> 8) & 0xFF);
680 } else {
681 // Can't evaluate at this point — emit a fixup that shifts the
682 // difference right by 8 to extract the high byte.
683 const MCExpr *Diff = MCBinaryExpr::createSub(
684 MCSymbolRefExpr::create(Info->PrologEnd, Context),
685 MCSymbolRefExpr::create(Info->Begin, Context), Context);
686 const MCExpr *HighByte = MCBinaryExpr::createLShr(
687 Diff, MCConstantExpr::create(8, Context), Context);
688 Streamer.emitValue(HighByte, 1);
689 }
690 } else {
691 Streamer.emitInt8(0);
692 }
693 }
694
695 // --- Emit prolog IP offsets (8-bit or 16-bit) ---
696 for (auto &[InstLabel, BeginLabel] : PrologIpLabels) {
697 if (NeedsLargeProlog)
698 EmitAbsDifference16(Streamer, InstLabel, BeginLabel);
699 else
700 EmitAbsDifference(Streamer, InstLabel, BeginLabel);
701 }
702
703 // --- Emit epilog descriptors ---
704 const MCSymbol *PrevEpilogStart = nullptr;
705 for (const auto &EI : EpilogInfos) {
706 const auto &Epilog = *EI.Epilog;
707
708 // FlagsAndNumOps: bits [2:0] = flags, bits [7:3] = NumberOfOps.
709 // For inherited descriptors, NumberOfOps = 0.
710 uint8_t EpiFlags = 0;
711 if (EI.NeedsLarge && !EI.Inherited)
712 EpiFlags |= Win64EH::EPILOG_INFO_LARGE;
713 uint8_t EpiNumOps = EI.Inherited ? 0 : EI.NumberOfOps;
714 Streamer.emitInt8((EpiNumOps << 3) | EpiFlags);
715
716 // EpilogOffset: signed 16-bit.
717 // For the first epilog: byte offset from fragment start to epilog start.
718 // For subsequent epilogs: delta from the previous epilog's start position.
719 // Emit as a fixup since we may not know the exact distance yet.
720 {
721 const MCSymbol *Base = PrevEpilogStart ? PrevEpilogStart : Info->Begin;
722 const MCExpr *EpilogOffsetExpr = MCBinaryExpr::createSub(
723 MCSymbolRefExpr::create(Epilog.Start, Context),
724 MCSymbolRefExpr::create(Base, Context), Context);
725 // Validate the epilog offset fits in a signed 16-bit field if we can
726 // evaluate it now.
727 int64_t OffsetValue;
728 if (EpilogOffsetExpr->evaluateAsAbsolute(OffsetValue,
729 OS->getAssembler())) {
730 if (OffsetValue < INT16_MIN || OffsetValue > INT16_MAX)
732 "Epilog offset out of signed 16-bit range for V3 encoding");
733 }
734 OS->ensureHeadroom(2);
735 OS->addFixup(EpilogOffsetExpr, FK_Data_2);
736 OS->appendContents(2, 0);
737 }
738 PrevEpilogStart = Epilog.Start;
739
740 // Full descriptor fields (only for non-inherited epilogs).
741 if (!EI.Inherited) {
742 // FirstOp: byte offset into WOD pool (2 bytes LE).
743 Streamer.emitInt8(EI.FirstOp & 0xFF);
744 Streamer.emitInt8((EI.FirstOp >> 8) & 0xFF);
745
746 // IpOffsetOfLastInstruction: 8-bit or 16-bit depending on
747 // EPILOG_INFO_LARGE.
748 {
749 const MCExpr *LastInstOffsetExpr = MCBinaryExpr::createSub(
750 MCSymbolRefExpr::create(Epilog.End, Context),
751 MCSymbolRefExpr::create(Epilog.Start, Context), Context);
752 unsigned FixupSize = EI.NeedsLarge ? 2 : 1;
753 OS->ensureHeadroom(FixupSize);
754 OS->addFixup(LastInstOffsetExpr, EI.NeedsLarge ? FK_Data_2 : FK_Data_1);
755 OS->appendContents(FixupSize, 0);
756 }
757
758 // Epilog IP offsets (forward order: body-to-terminator).
759 for (const auto &EpiInst : Epilog.Instructions) {
760 if (EI.NeedsLarge)
761 EmitAbsDifference16(Streamer, EpiInst.Label, Epilog.Start);
762 else
763 EmitAbsDifference(Streamer, EpiInst.Label, Epilog.Start);
764 }
765 }
766 }
767
768 // --- Emit WOD pool ---
769 for (uint8_t B : WODPool)
770 Streamer.emitInt8(B);
771
772 // --- Pad to PayloadWords * 2 bytes ---
773 // PayloadWords = (TotalPayloadBytes + 1) / 2, so at most 1 byte of padding.
774 if (TotalPayloadBytes % 2 != 0)
775 Streamer.emitInt8(0);
776
777 // --- Pad to 4-byte boundary before handler/chain info ---
778 // Per the V3 spec, the handler RVA / chained RUNTIME_FUNCTION begins at
779 // handler_offset = ALIGN_UP(sizeof(UNWIND_INFO_V3) + PayloadWords * 2, 4)
780 // The unwind info structure itself is 4-byte aligned, so when PayloadWords
781 // is odd, the natural end of the payload sits at +2 mod 4 and requires 2
782 // additional zero bytes of padding before the handler/chain.
783 if (PayloadWords % 2 != 0)
784 Streamer.emitInt16(0);
785
786 // --- Emit handler/chained info (same position as V1/V2) ---
787 if (Flags & Win64EH::UNW_ChainInfo)
788 EmitRuntimeFunction(Streamer, Info->ChainedParent);
789 else if (Flags &
791 Streamer.emitValue(
792 MCSymbolRefExpr::create(Info->ExceptionHandler,
794 4);
795 else if (PayloadWords == 0) {
796 // Minimum size: pad to 8 bytes total.
797 Streamer.emitInt32(0);
798 }
799}
800
802 // If this UNWIND_INFO already has a symbol, it's already been emitted.
803 if (info->Symbol)
804 return;
805
806 // V3 has a completely different binary layout; dispatch to separate emitter.
807 if (info->Version == 3) {
808 EmitUnwindInfoV3(streamer, info);
809 return;
810 }
811
812 // UOP_Push2 is V3-only and cannot be encoded in V1/V2. Detect this early
813 // (before counting codes) so the error is reported cleanly. This is
814 // reachable from hand-written .s if `.seh_push2regs` is followed by a
815 // per-function `.seh_unwindversion 1` or `2` downgrade.
816 for (const auto &Inst : info->Instructions) {
817 if (Inst.Operation == Win64EH::UOP_Push2) {
818 streamer.getContext().reportError(
819 SMLoc(), "UOP_Push2 (PUSH2 with two registers) requires V3 unwind "
820 "info. Use `.seh_unwindversion 3`.");
821 // Mark the frame as emitted (with no UNWIND_INFO) and bail so we don't
822 // emit malformed bytes or hit a downstream assertion.
823 info->Symbol = streamer.getContext().createTempSymbol();
824 return;
825 }
826 }
827
828 MCContext &context = streamer.getContext();
829 MCObjectStreamer *OS = (MCObjectStreamer *)(&streamer);
830 MCSymbol *Label = context.createTempSymbol();
831
832 streamer.emitValueToAlignment(Align(4));
833 streamer.emitLabel(Label);
834 info->Symbol = Label;
835
836 uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
837 bool LastEpilogIsAtEnd = false;
838 bool AddPaddingEpilogCode = false;
839 uint8_t EpilogSize = 0;
840 bool EnableUnwindV2 = (info->Version >= 2) && !info->EpilogMap.empty();
841 if (EnableUnwindV2) {
842 auto &LastEpilog = info->EpilogMap.back().second;
843
844 // Calculate the size of the epilogs. Note that we +1 to the size so that
845 // the terminator instruction is also included in the epilog (the Windows
846 // unwinder does a simple range check versus the current instruction pointer
847 // so, although there are terminators that are large than 1 byte, the
848 // starting address of the terminator instruction will always be considered
849 // inside the epilog).
850 assert(
851 LastEpilog.UnwindV2Start &&
852 "If unwind v2 is enabled, epilog must have a unwind v2 start marker");
853 assert(LastEpilog.End && "Epilog must have an end");
854 auto MaybeSize = GetOptionalAbsDifference(
855 OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start);
856 if (!MaybeSize) {
857 context.reportError(LastEpilog.Loc,
858 "Failed to evaluate epilog size for Unwind v2 in " +
859 info->Function->getName());
860 return;
861 }
862 assert(*MaybeSize >= 0);
863 if (*MaybeSize >= (int64_t)UINT8_MAX) {
864 context.reportError(LastEpilog.Loc,
865 "Epilog size is too large for Unwind v2 in " +
866 info->Function->getName());
867 return;
868 }
869 EpilogSize = *MaybeSize + 1;
870
871 // If the last epilog is at the end of the function, we can use a special
872 // encoding for it. Because of our +1 trick for the size, this will only
873 // work where that final terminator instruction is 1 byte long.
874 // NOTE: At the point where the unwind info is emitted, the function may not
875 // have ended yet (e.g., if there is EH Handler Data), so assume that we
876 // aren't at the end (since we can't calculate it).
877 if (info->End) {
878 auto LastEpilogToFuncEnd = GetOptionalAbsDifference(
879 OS->getAssembler(), info->End, LastEpilog.UnwindV2Start);
880 LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize);
881 }
882
883 // If we have an odd number of epilog codes, we need to add a padding code.
884 size_t numEpilogCodes =
885 info->EpilogMap.size() + (LastEpilogIsAtEnd ? 0 : 1);
886 if ((numEpilogCodes % 2) != 0) {
887 AddPaddingEpilogCode = true;
888 numEpilogCodes++;
889 }
890
891 // Too many epilogs to handle.
892 if ((size_t)numCodes + numEpilogCodes > UINT8_MAX) {
893 context.reportError(info->FunctionLoc,
894 "Too many unwind codes with Unwind v2 enabled in " +
895 info->Function->getName());
896 return;
897 }
898
899 numCodes += numEpilogCodes;
900 }
901
902 // Upper 3 bits are the version number.
903 uint8_t flags = info->Version;
904 if (info->ChainedParent)
905 flags |= Win64EH::UNW_ChainInfo << 3;
906 else {
907 if (info->HandlesUnwind)
908 flags |= Win64EH::UNW_TerminateHandler << 3;
909 if (info->HandlesExceptions)
910 flags |= Win64EH::UNW_ExceptionHandler << 3;
911 }
912 streamer.emitInt8(flags);
913
914 if (info->PrologEnd)
915 EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
916 else
917 streamer.emitInt8(0);
918
919 streamer.emitInt8(numCodes);
920
921 uint8_t frame = 0;
922 if (info->LastFrameInst >= 0) {
923 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
925 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
926 }
927 streamer.emitInt8(frame);
928
929 // Emit the epilog instructions.
930 if (EnableUnwindV2) {
931 // Ensure the fixups and appended content apply to the same fragment.
932 // size byte + flags byte + 2 per epilog (for the distance).
933 OS->ensureHeadroom(2 + info->EpilogMap.size() * 2);
934
935 bool IsLast = true;
936 for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
937 if (IsLast) {
938 IsLast = false;
939 uint8_t Flags = LastEpilogIsAtEnd ? 0x01 : 0;
940 OS->emitInt8(EpilogSize);
941 OS->emitInt8((Flags << 4) | Win64EH::UOP_Epilog);
942
943 if (LastEpilogIsAtEnd)
944 continue;
945 }
946
947 // Each epilog is emitted as a fixup, since we can't measure the distance
948 // between the start of the epilog and the end of the function until
949 // layout has been completed.
950 auto *MCE = MCUnwindV2EpilogTargetExpr::create(*info, Epilog.second,
951 EpilogSize, context);
952 OS->addFixup(MCE, FK_Data_2);
953 OS->appendContents(2, 0);
954 }
955 }
956 if (AddPaddingEpilogCode)
957 streamer.emitInt16(Win64EH::UOP_Epilog << 8);
958
959 // Emit unwind instructions (in reverse order).
960 uint8_t numInst = info->Instructions.size();
961 for (uint8_t c = 0; c < numInst; ++c) {
962 WinEH::Instruction inst = info->Instructions.back();
963 info->Instructions.pop_back();
964 EmitUnwindCode(streamer, info->Begin, inst);
965 }
966
967 // For alignment purposes, the instruction array will always have an even
968 // number of entries, with the final entry potentially unused (in which case
969 // the array will be one longer than indicated by the count of unwind codes
970 // field).
971 if (numCodes & 1) {
972 streamer.emitInt16(0);
973 }
974
975 if (flags & (Win64EH::UNW_ChainInfo << 3))
976 EmitRuntimeFunction(streamer, info->ChainedParent);
977 else if (flags &
979 streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
981 context), 4);
982 else if (numCodes == 0) {
983 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
984 // a chained unwind info, if there is no handler, and if there are fewer
985 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
986 streamer.emitInt32(0);
987 }
988}
989
990bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl(
991 MCValue &Res, const MCAssembler *Asm) const {
992 // Calculate the offset to this epilog, and validate it's within the allowed
993 // range.
994 auto Offset = GetOptionalAbsDifference(*Asm, FrameInfo.End, UnwindV2Start);
995 if (!Offset) {
996 Asm->getContext().reportError(
997 Loc, "Failed to evaluate epilog offset for Unwind v2 in " +
998 FrameInfo.Function->getName());
999 return false;
1000 }
1001 assert(*Offset > 0);
1002 constexpr uint16_t MaxEpilogOffset = 0x0fff;
1003 if (*Offset > MaxEpilogOffset) {
1004 Asm->getContext().reportError(
1005 Loc, "Epilog offset is too large for Unwind v2 in " +
1006 FrameInfo.Function->getName());
1007 return false;
1008 }
1009
1010 // Validate that all epilogs are the same size.
1011 auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start);
1012 if (Size != (EpilogSize - 1)) {
1013 Asm->getContext().reportError(
1014 Loc, "Size of this epilog does not match size of last epilog in " +
1015 FrameInfo.Function->getName());
1016 return false;
1017 }
1018
1019 auto HighBits = *Offset >> 8;
1020 Res = MCValue::get((HighBits << 12) | (Win64EH::UOP_Epilog << 8) |
1021 (*Offset & 0xFF));
1022 return true;
1023}
1024
1026 // Emit the unwind info structs first.
1027 for (const auto &CFI : Streamer.getWinFrameInfos()) {
1028 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
1029 Streamer.switchSection(XData);
1030 ::EmitUnwindInfo(Streamer, CFI.get());
1031 }
1032
1033 // Now emit RUNTIME_FUNCTION entries.
1034 for (const auto &CFI : Streamer.getWinFrameInfos()) {
1035 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
1036 Streamer.switchSection(PData);
1037 EmitRuntimeFunction(Streamer, CFI.get());
1038 }
1039}
1040
1043 bool HandlerData) const {
1044 // Switch sections (the static function above is meant to be called from
1045 // here and from Emit().
1046 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
1047 Streamer.switchSection(XData);
1048
1049 ::EmitUnwindInfo(Streamer, info);
1050}
1051
1052static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
1053 const MCSymbol *RHS, int Div) {
1054 MCContext &Context = Streamer.getContext();
1055 const MCExpr *Expr =
1057 MCSymbolRefExpr::create(RHS, Context), Context);
1058 if (Div != 1)
1059 Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(Div, Context),
1060 Context);
1061 return Expr;
1062}
1063
1064static std::optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
1065 const MCSymbol *LHS,
1066 const MCSymbol *RHS) {
1067 MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
1069}
1070
1071static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
1072 const MCSymbol *RHS) {
1073 std::optional<int64_t> MaybeDiff =
1074 GetOptionalAbsDifference(Streamer, LHS, RHS);
1075 if (!MaybeDiff)
1076 report_fatal_error("Failed to evaluate function length in SEH unwind info");
1077 return *MaybeDiff;
1078}
1079
1082 const MCSymbol *Begin, const MCSymbol *End,
1083 StringRef Name, StringRef Type) {
1084 if (!End)
1085 return;
1086 std::optional<int64_t> MaybeDistance =
1087 GetOptionalAbsDifference(Streamer, End, Begin);
1088 if (!MaybeDistance)
1089 return;
1090 uint32_t Distance = (uint32_t)*MaybeDistance;
1091
1092 for (const auto &I : Insns) {
1093 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1094 default:
1095 break;
1101 // Can't reason about these opcodes and how they map to actual
1102 // instructions.
1103 return;
1104 }
1105 }
1106 // Exclude the end opcode which doesn't map to an instruction.
1107 uint32_t InstructionBytes = 4 * (Insns.size() - 1);
1108 if (Distance != InstructionBytes) {
1109 Streamer.getContext().reportError(
1110 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1111 Twine(Distance) +
1112 " bytes of instructions in range, but .seh directives "
1113 "corresponding to " +
1114 Twine(InstructionBytes) + " bytes\n");
1115 }
1116}
1117
1119 uint32_t Count = 0;
1120 for (const auto &I : Insns) {
1121 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1122 default:
1123 llvm_unreachable("Unsupported ARM64 unwind code");
1125 Count += 1;
1126 break;
1128 Count += 2;
1129 break;
1131 Count += 4;
1132 break;
1134 Count += 1;
1135 break;
1137 Count += 1;
1138 break;
1140 Count += 1;
1141 break;
1143 Count += 2;
1144 break;
1146 Count += 2;
1147 break;
1149 Count += 2;
1150 break;
1152 Count += 2;
1153 break;
1155 Count += 2;
1156 break;
1158 Count += 2;
1159 break;
1161 Count += 2;
1162 break;
1164 Count += 2;
1165 break;
1167 Count += 2;
1168 break;
1169 case Win64EH::UOP_SetFP:
1170 Count += 1;
1171 break;
1172 case Win64EH::UOP_AddFP:
1173 Count += 2;
1174 break;
1175 case Win64EH::UOP_Nop:
1176 Count += 1;
1177 break;
1178 case Win64EH::UOP_End:
1179 Count += 1;
1180 break;
1182 Count += 1;
1183 break;
1185 Count += 1;
1186 break;
1188 Count += 1;
1189 break;
1191 Count += 1;
1192 break;
1194 Count += 1;
1195 break;
1197 Count += 1;
1198 break;
1200 Count += 1;
1201 break;
1203 Count += 2;
1204 break;
1219 Count += 3;
1220 break;
1221 }
1222 }
1223 return Count;
1224}
1225
1226// Unwind opcode encodings and restrictions are documented at
1227// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
1228static void ARM64EmitUnwindCode(MCStreamer &streamer,
1229 const WinEH::Instruction &inst) {
1230 uint8_t b, reg;
1231 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1232 default:
1233 llvm_unreachable("Unsupported ARM64 unwind code");
1235 b = (inst.Offset >> 4) & 0x1F;
1236 streamer.emitInt8(b);
1237 break;
1239 uint16_t hw = (inst.Offset >> 4) & 0x7FF;
1240 b = 0xC0;
1241 b |= (hw >> 8);
1242 streamer.emitInt8(b);
1243 b = hw & 0xFF;
1244 streamer.emitInt8(b);
1245 break;
1246 }
1248 uint32_t w;
1249 b = 0xE0;
1250 streamer.emitInt8(b);
1251 w = inst.Offset >> 4;
1252 b = (w & 0x00FF0000) >> 16;
1253 streamer.emitInt8(b);
1254 b = (w & 0x0000FF00) >> 8;
1255 streamer.emitInt8(b);
1256 b = w & 0x000000FF;
1257 streamer.emitInt8(b);
1258 break;
1259 }
1260 case Win64EH::UOP_SetFP:
1261 b = 0xE1;
1262 streamer.emitInt8(b);
1263 break;
1264 case Win64EH::UOP_AddFP:
1265 b = 0xE2;
1266 streamer.emitInt8(b);
1267 b = (inst.Offset >> 3);
1268 streamer.emitInt8(b);
1269 break;
1270 case Win64EH::UOP_Nop:
1271 b = 0xE3;
1272 streamer.emitInt8(b);
1273 break;
1275 b = 0x20;
1276 b |= (inst.Offset >> 3) & 0x1F;
1277 streamer.emitInt8(b);
1278 break;
1280 b = 0x80;
1281 b |= ((inst.Offset >> 3) - 1) & 0x3F;
1282 streamer.emitInt8(b);
1283 break;
1285 b = 0x40;
1286 b |= (inst.Offset >> 3) & 0x3F;
1287 streamer.emitInt8(b);
1288 break;
1290 assert(inst.Register >= 19 && "Saved reg must be >= 19");
1291 reg = inst.Register - 19;
1292 b = 0xD0 | ((reg & 0xC) >> 2);
1293 streamer.emitInt8(b);
1294 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
1295 streamer.emitInt8(b);
1296 break;
1298 assert(inst.Register >= 19 && "Saved reg must be >= 19");
1299 reg = inst.Register - 19;
1300 b = 0xD4 | ((reg & 0x8) >> 3);
1301 streamer.emitInt8(b);
1302 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
1303 streamer.emitInt8(b);
1304 break;
1306 assert(inst.Register >= 19 && "Saved registers must be >= 19");
1307 reg = inst.Register - 19;
1308 b = 0xC8 | ((reg & 0xC) >> 2);
1309 streamer.emitInt8(b);
1310 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
1311 streamer.emitInt8(b);
1312 break;
1314 assert(inst.Register >= 19 && "Saved registers must be >= 19");
1315 reg = inst.Register - 19;
1316 b = 0xCC | ((reg & 0xC) >> 2);
1317 streamer.emitInt8(b);
1318 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
1319 streamer.emitInt8(b);
1320 break;
1322 assert(inst.Register >= 19 && "Saved reg must be >= 19");
1323 reg = inst.Register - 19;
1324 assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
1325 reg /= 2;
1326 b = 0xD6 | ((reg & 0x7) >> 2);
1327 streamer.emitInt8(b);
1328 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
1329 streamer.emitInt8(b);
1330 break;
1332 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
1333 reg = inst.Register - 8;
1334 b = 0xDC | ((reg & 0x4) >> 2);
1335 streamer.emitInt8(b);
1336 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
1337 streamer.emitInt8(b);
1338 break;
1340 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
1341 reg = inst.Register - 8;
1342 b = 0xDE;
1343 streamer.emitInt8(b);
1344 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
1345 streamer.emitInt8(b);
1346 break;
1348 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
1349 reg = inst.Register - 8;
1350 b = 0xD8 | ((reg & 0x4) >> 2);
1351 streamer.emitInt8(b);
1352 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
1353 streamer.emitInt8(b);
1354 break;
1356 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
1357 reg = inst.Register - 8;
1358 b = 0xDA | ((reg & 0x4) >> 2);
1359 streamer.emitInt8(b);
1360 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
1361 streamer.emitInt8(b);
1362 break;
1363 case Win64EH::UOP_End:
1364 b = 0xE4;
1365 streamer.emitInt8(b);
1366 break;
1368 b = 0xE6;
1369 streamer.emitInt8(b);
1370 break;
1372 b = 0xE8;
1373 streamer.emitInt8(b);
1374 break;
1376 b = 0xE9;
1377 streamer.emitInt8(b);
1378 break;
1380 b = 0xEA;
1381 streamer.emitInt8(b);
1382 break;
1384 b = 0xEB;
1385 streamer.emitInt8(b);
1386 break;
1388 b = 0xEC;
1389 streamer.emitInt8(b);
1390 break;
1392 b = 0xFC;
1393 streamer.emitInt8(b);
1394 break;
1407 // This assumes the opcodes are listed in the enum in a particular order.
1409 int Writeback = Op / 6;
1410 int Paired = Op % 2;
1411 int Mode = (Op / 2) % 3;
1412 int Offset = inst.Offset >> 3;
1413 if (Writeback || Paired || Mode == 2)
1414 Offset >>= 1;
1415 if (Writeback)
1416 --Offset;
1417 b = 0xE7;
1418 streamer.emitInt8(b);
1419 assert(inst.Register < 32);
1420 b = inst.Register | (Writeback << 5) | (Paired << 6);
1421 streamer.emitInt8(b);
1422 b = Offset | (Mode << 6);
1423 streamer.emitInt8(b);
1424 break;
1425 }
1426 case Win64EH::UOP_AllocZ: {
1427 b = 0xDF;
1428 streamer.emitInt8(b);
1429 b = inst.Offset;
1430 streamer.emitInt8(b);
1431 break;
1432 }
1433 case Win64EH::UOP_SaveZReg: {
1434 assert(inst.Register >= 8 && inst.Register <= 23);
1435 assert(inst.Offset < 256);
1436 b = 0xE7;
1437 streamer.emitInt8(b);
1438 reg = inst.Register - 8;
1439 b = ((inst.Offset & 0xC0) >> 1) | reg;
1440 streamer.emitInt8(b);
1441 b = 0xC0 | (inst.Offset & 0x3F);
1442 streamer.emitInt8(b);
1443 break;
1444 }
1445 case Win64EH::UOP_SavePReg: {
1446 assert(inst.Register >= 4 && inst.Register <= 15);
1447 assert(inst.Offset < 256);
1448 b = 0xE7;
1449 streamer.emitInt8(b);
1450 reg = inst.Register;
1451 b = ((inst.Offset & 0xC0) >> 1) | 0x10 | reg;
1452 streamer.emitInt8(b);
1453 b = 0xC0 | (inst.Offset & 0x3F);
1454 streamer.emitInt8(b);
1455 break;
1456 }
1457 }
1458}
1459
1460// Returns the epilog symbol of an epilog with the exact same unwind code
1461// sequence, if it exists. Otherwise, returns nullptr.
1462// EpilogInstrs - Unwind codes for the current epilog.
1463// Epilogs - Epilogs that potentialy match the current epilog.
1464static MCSymbol*
1465FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
1466 const std::vector<MCSymbol *>& Epilogs,
1467 const WinEH::FrameInfo *info) {
1468 for (auto *EpilogStart : Epilogs) {
1469 auto InstrsIter = info->EpilogMap.find(EpilogStart);
1470 assert(InstrsIter != info->EpilogMap.end() &&
1471 "Epilog not found in EpilogMap");
1472 const auto &Instrs = InstrsIter->second.Instructions;
1473
1474 if (Instrs.size() != EpilogInstrs.size())
1475 continue;
1476
1477 bool Match = true;
1478 for (unsigned i = 0; i < Instrs.size(); ++i)
1479 if (Instrs[i] != EpilogInstrs[i]) {
1480 Match = false;
1481 break;
1482 }
1483
1484 if (Match)
1485 return EpilogStart;
1486 }
1487 return nullptr;
1488}
1489
1490static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
1491 bool Reverse) {
1492 unsigned PrevOffset = -1;
1493 unsigned PrevRegister = -1;
1494
1495 // Iterate over instructions in a forward order (for prologues),
1496 // backwards for epilogues (i.e. always reverse compared to how the
1497 // opcodes are stored).
1498 for (WinEH::Instruction &Inst :
1499 llvm::reverse_conditionally(Instructions, Reverse)) {
1500 // Convert 2-byte opcodes into equivalent 1-byte ones.
1501 if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
1502 Inst.Operation = Win64EH::UOP_SaveFPLR;
1503 Inst.Register = -1;
1504 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
1505 Inst.Register == 29) {
1506 Inst.Operation = Win64EH::UOP_SaveFPLRX;
1507 Inst.Register = -1;
1508 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
1509 Inst.Register == 19 && Inst.Offset <= 248) {
1510 Inst.Operation = Win64EH::UOP_SaveR19R20X;
1511 Inst.Register = -1;
1512 } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
1513 Inst.Operation = Win64EH::UOP_SetFP;
1514 } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
1515 Inst.Register == PrevRegister + 2 &&
1516 Inst.Offset == PrevOffset + 16) {
1517 Inst.Operation = Win64EH::UOP_SaveNext;
1518 Inst.Register = -1;
1519 Inst.Offset = 0;
1520 // Intentionally not creating UOP_SaveNext for float register pairs,
1521 // as current versions of Windows (up to at least 20.04) is buggy
1522 // regarding SaveNext for float pairs.
1523 }
1524 // Update info about the previous instruction, for detecting if
1525 // the next one can be made a UOP_SaveNext
1526 if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
1527 PrevOffset = 0;
1528 PrevRegister = 19;
1529 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
1530 PrevOffset = 0;
1531 PrevRegister = Inst.Register;
1532 } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
1533 PrevOffset = Inst.Offset;
1534 PrevRegister = Inst.Register;
1535 } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
1536 PrevRegister += 2;
1537 PrevOffset += 16;
1538 } else {
1539 PrevRegister = -1;
1540 PrevOffset = -1;
1541 }
1542 }
1543}
1544
1545// Check if an epilog exists as a subset of the end of a prolog (backwards).
1546static int
1547getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1548 const std::vector<WinEH::Instruction> &Epilog) {
1549 // Can't find an epilog as a subset if it is longer than the prolog.
1550 if (Epilog.size() > Prolog.size())
1551 return -1;
1552
1553 // Check that the epilog actually is a perfect match for the end (backwrds)
1554 // of the prolog.
1555 for (int I = Epilog.size() - 1; I >= 0; I--) {
1556 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
1557 return -1;
1558 }
1559
1560 if (Epilog.size() == Prolog.size())
1561 return 0;
1562
1563 // If the epilog was a subset of the prolog, find its offset.
1565 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
1566}
1567
1570 int PrologCodeBytes) {
1571 // Can only pack if there's one single epilog
1572 if (Seg->Epilogs.size() != 1)
1573 return -1;
1574
1575 MCSymbol *Sym = Seg->Epilogs.begin()->first;
1576 const std::vector<WinEH::Instruction> &Epilog =
1577 info->EpilogMap[Sym].Instructions;
1578
1579 // Check that the epilog actually is at the very end of the function,
1580 // otherwise it can't be packed.
1581 uint32_t DistanceFromEnd =
1582 (uint32_t)(Seg->Offset + Seg->Length - Seg->Epilogs.begin()->second);
1583 if (DistanceFromEnd / 4 != Epilog.size())
1584 return -1;
1585
1586 int RetVal = -1;
1587 // Even if we don't end up sharing opcodes with the prolog, we can still
1588 // write the offset as a packed offset, if the single epilog is located at
1589 // the end of the function and the offset (pointing after the prolog) fits
1590 // as a packed offset.
1591 if (PrologCodeBytes <= 31 &&
1592 PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
1593 RetVal = PrologCodeBytes;
1594
1595 int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
1596 if (Offset < 0)
1597 return RetVal;
1598
1599 // Check that the offset and prolog size fits in the first word; it's
1600 // unclear whether the epilog count in the extension word can be taken
1601 // as packed epilog offset.
1602 if (Offset > 31 || PrologCodeBytes > 124)
1603 return RetVal;
1604
1605 // As we choose to express the epilog as part of the prolog, remove the
1606 // epilog from the map, so we don't try to emit its opcodes.
1607 info->EpilogMap.erase(Sym);
1608 return Offset;
1609}
1610
1612 int PackedEpilogOffset) {
1613 if (PackedEpilogOffset == 0) {
1614 // Fully symmetric prolog and epilog, should be ok for packed format.
1615 // For CR=3, the corresponding synthesized epilog actually lacks the
1616 // SetFP opcode, but unwinding should work just fine despite that
1617 // (if at the SetFP opcode, the unwinder considers it as part of the
1618 // function body and just unwinds the full prolog instead).
1619 } else if (PackedEpilogOffset == 1) {
1620 // One single case of differences between prolog and epilog is allowed:
1621 // The epilog can lack a single SetFP that is the last opcode in the
1622 // prolog, for the CR=3 case.
1623 if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
1624 return false;
1625 } else {
1626 // Too much difference between prolog and epilog.
1627 return false;
1628 }
1629 unsigned RegI = 0, RegF = 0;
1630 int Predecrement = 0;
1631 enum {
1632 Start,
1633 Start2,
1634 Start3,
1635 IntRegs,
1636 FloatRegs,
1637 InputArgs,
1638 StackAdjust,
1639 FrameRecord,
1640 End
1641 } Location = Start;
1642 bool StandaloneLR = false, FPLRPair = false;
1643 bool PAC = false;
1644 int StackOffset = 0;
1645 int Nops = 0;
1646 // Iterate over the prolog and check that all opcodes exactly match
1647 // the canonical order and form. A more lax check could verify that
1648 // all saved registers are in the expected locations, but not enforce
1649 // the order - that would work fine when unwinding from within
1650 // functions, but not be exactly right if unwinding happens within
1651 // prologs/epilogs.
1652 for (auto It = info->Instructions.begin(), EndIt = info->Instructions.end();
1653 It != EndIt; It++) {
1654 const WinEH::Instruction &Inst = *It;
1655 switch (Inst.Operation) {
1656 case Win64EH::UOP_End:
1657 if (Location != Start)
1658 return false;
1659 Location = Start2;
1660 break;
1662 if (Location != Start2)
1663 return false;
1664 PAC = true;
1665 Location = Start3;
1666 break;
1668 if (Location != Start2 && Location != Start3)
1669 return false;
1670 Predecrement = Inst.Offset;
1671 RegI = 2;
1672 Location = IntRegs;
1673 break;
1675 if (Location != Start2 && Location != Start3)
1676 return false;
1677 Predecrement = Inst.Offset;
1678 if (Inst.Register == 19)
1679 RegI += 1;
1680 else if (Inst.Register == 30)
1681 StandaloneLR = true;
1682 else
1683 return false;
1684 // Odd register; can't be any further int registers.
1685 Location = FloatRegs;
1686 break;
1688 // Can't have this in a canonical prologue. Either this has been
1689 // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
1690 // register pair.
1691 // It can't be canonicalized into SaveR19R20X if the offset is
1692 // larger than 248 bytes, but even with the maximum case with
1693 // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
1694 // fit into SaveR19R20X.
1695 // The unwinding opcodes can't describe the otherwise seemingly valid
1696 // case for RegI=1 CR=1, that would start with a
1697 // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
1698 // SaveLRPair.
1699 return false;
1701 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1702 Inst.Register != 19 + RegI)
1703 return false;
1704 RegI += 2;
1705 break;
1707 if (Location != IntRegs || Inst.Offset != 8 * RegI)
1708 return false;
1709 if (Inst.Register == 19 + RegI)
1710 RegI += 1;
1711 else if (Inst.Register == 30)
1712 StandaloneLR = true;
1713 else
1714 return false;
1715 // Odd register; can't be any further int registers.
1716 Location = FloatRegs;
1717 break;
1719 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1720 Inst.Register != 19 + RegI)
1721 return false;
1722 RegI += 1;
1723 StandaloneLR = true;
1724 Location = FloatRegs;
1725 break;
1727 // Packed unwind can't handle prologs that only save one single
1728 // float register.
1729 return false;
1731 if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
1732 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1733 return false;
1734 RegF += 1;
1735 Location = InputArgs;
1736 break;
1738 if ((Location != Start2 && Location != Start3) || Inst.Register != 8)
1739 return false;
1740 Predecrement = Inst.Offset;
1741 RegF = 2;
1742 Location = FloatRegs;
1743 break;
1745 if ((Location != IntRegs && Location != FloatRegs) ||
1746 Inst.Register != 8 + RegF ||
1747 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1748 return false;
1749 RegF += 2;
1750 Location = FloatRegs;
1751 break;
1753 if (Location == IntRegs)
1754 RegI += 2;
1755 else if (Location == FloatRegs)
1756 RegF += 2;
1757 else
1758 return false;
1759 break;
1760 case Win64EH::UOP_Nop:
1761 if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
1762 return false;
1763 Location = InputArgs;
1764 Nops++;
1765 break;
1768 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1769 Location != FloatRegs && Location != InputArgs &&
1770 Location != StackAdjust)
1771 return false;
1772 // Becuase there's no save_lrpair_x opcode, the case of CR=01,
1773 // RegI=1 is handled as a special case with a pair of instructions; an
1774 // alloc followed by a regular save_lrpair. So when encountering an
1775 // alloc here, check if this is the start of such an instruction pair.
1776 if (Location == Start2) { // Can't have this at Start3, after PACSignLR
1777 auto NextIt = It + 1;
1778 if (NextIt != EndIt) {
1779 const WinEH::Instruction &NextInst = *NextIt;
1780 if (NextInst.Operation == Win64EH::UOP_SaveLRPair &&
1781 NextInst.Offset == 0 && NextInst.Register == 19) {
1782 assert(Predecrement == 0);
1783 assert(RegI == 0);
1784 assert(!StandaloneLR);
1785 Predecrement = Inst.Offset;
1786 RegI = 1;
1787 StandaloneLR = true;
1788 Location = FloatRegs;
1789 It++; // Consume both the Alloc and the SaveLRPair
1790 continue;
1791 }
1792 }
1793 }
1794 // Can have either a single decrement, or a pair of decrements with
1795 // 4080 and another decrement.
1796 if (StackOffset == 0)
1797 StackOffset = Inst.Offset;
1798 else if (StackOffset != 4080)
1799 return false;
1800 else
1801 StackOffset += Inst.Offset;
1802 Location = StackAdjust;
1803 break;
1805 // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
1806 // should be followed by a FPLR instead.
1807 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1808 Location != FloatRegs && Location != InputArgs)
1809 return false;
1810 StackOffset = Inst.Offset;
1811 Location = FrameRecord;
1812 FPLRPair = true;
1813 break;
1815 // This can only follow after a StackAdjust
1816 if (Location != StackAdjust || Inst.Offset != 0)
1817 return false;
1818 Location = FrameRecord;
1819 FPLRPair = true;
1820 break;
1821 case Win64EH::UOP_SetFP:
1822 if (Location != FrameRecord)
1823 return false;
1824 Location = End;
1825 break;
1838 // These are never canonical; they don't show up with the usual Arm64
1839 // calling convention.
1840 return false;
1842 // Allocations this large can't be represented in packed unwind (and
1843 // usually don't fit the canonical form anyway because we need to use
1844 // __chkstk to allocate the stack space).
1845 return false;
1846 case Win64EH::UOP_AddFP:
1847 // "add x29, sp, #N" doesn't show up in the canonical pattern (except for
1848 // N=0, which is UOP_SetFP).
1849 return false;
1853 // Canonical prologues don't support spilling SVE registers.
1854 return false;
1860 // These are special opcodes that aren't normally generated.
1861 return false;
1862 default:
1863 report_fatal_error("Unknown Arm64 unwind opcode");
1864 }
1865 }
1866 if (RegI > 10 || RegF > 8)
1867 return false;
1868 if (StandaloneLR && FPLRPair)
1869 return false;
1870 if (FPLRPair && Location != End)
1871 return false;
1872 if (Nops != 0 && Nops != 4)
1873 return false;
1874 if (PAC && !FPLRPair)
1875 return false;
1876 int H = Nops == 4;
1877 // For packed unwind info with the H bit set, the prolog and epilog
1878 // actually shouldn't be symmetrical; the epilog shouldn't have any
1879 // nop instructions/opcodes while the prolog has them. We currently
1880 // require exactly symmetrical prologs/epilogs, which is wrong for this
1881 // case - therefore, don't emit packed unwind info for this case.
1882 // See https://github.com/llvm/llvm-project/issues/54879 for details.
1883 //
1884 // Additionally - older versions of Windows also deviated from the
1885 // documentation here; older versions of Windows (at least up until
1886 // 10.0.22000.2176) incorrectly did assume that the epilog has matching
1887 // nop instructions. This is fixed at least in version 10.0.26100.6899.
1888 // As long as we can't assume that the generated code always will run on
1889 // a new enough version, don't emit the packed format here, even if the
1890 // implementation would be fixed to match for the asymmetrical form
1891 // according to the documentation.
1892 if (H)
1893 return false;
1894 // Older versions of Windows (at least in 10.0.22000.2176) incorrectly
1895 // unwind packed unwind info with CR=01, RegI=1, RegF>0, see
1896 // https://github.com/llvm/llvm-project/issues/169588#issuecomment-3584907886.
1897 // This issue only exists in older versions; current versions
1898 // (10.0.26100.6899) do handle it correctly. As long as we can't be sure
1899 // that we won't run on older versions, avoid producing the packed form
1900 // here.
1901 if (StandaloneLR && RegI == 1 && RegF > 0)
1902 return false;
1903 int IntSZ = 8 * RegI;
1904 if (StandaloneLR)
1905 IntSZ += 8;
1906 int FpSZ = 8 * RegF; // RegF not yet decremented
1907 int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
1908 if (Predecrement != SavSZ)
1909 return false;
1910 if (FPLRPair && StackOffset < 16)
1911 return false;
1912 if (StackOffset % 16)
1913 return false;
1914 uint32_t FrameSize = (StackOffset + SavSZ) / 16;
1915 if (FrameSize > 0x1FF)
1916 return false;
1917 assert(RegF != 1 && "One single float reg not allowed");
1918 if (RegF > 0)
1919 RegF--; // Convert from actual number of registers, to value stored
1920 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
1921 int Flag = 0x01; // Function segments not supported yet
1922 int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0;
1923 info->PackedInfo |= Flag << 0;
1924 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1925 info->PackedInfo |= (RegF & 0x7) << 13;
1926 info->PackedInfo |= (RegI & 0xF) << 16;
1927 info->PackedInfo |= (H & 0x1) << 20;
1928 info->PackedInfo |= (CR & 0x3) << 21;
1929 info->PackedInfo |= (FrameSize & 0x1FF) << 23;
1930 return true;
1931}
1932
1935 uint32_t &TotalCodeBytes,
1936 MapVector<MCSymbol *, uint32_t> &EpilogInfo) {
1937
1938 std::vector<MCSymbol *> EpilogStarts;
1939 for (auto &I : Seg->Epilogs)
1940 EpilogStarts.push_back(I.first);
1941
1942 // Epilogs processed so far.
1943 std::vector<MCSymbol *> AddedEpilogs;
1944 for (auto *S : EpilogStarts) {
1945 MCSymbol *EpilogStart = S;
1946 auto &EpilogInstrs = info->EpilogMap[S].Instructions;
1947 uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
1948
1949 MCSymbol* MatchingEpilog =
1950 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
1951 int PrologOffset;
1952 if (MatchingEpilog) {
1953 assert(EpilogInfo.contains(MatchingEpilog) &&
1954 "Duplicate epilog not found");
1955 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
1956 // Clear the unwind codes in the EpilogMap, so that they don't get output
1957 // in ARM64EmitUnwindInfoForSegment().
1958 EpilogInstrs.clear();
1959 } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
1960 EpilogInstrs)) >= 0) {
1961 EpilogInfo[EpilogStart] = PrologOffset;
1962 // If the segment doesn't have a prolog, an end_c will be emitted before
1963 // prolog opcodes. So epilog start index in opcodes array is moved by 1.
1964 if (!Seg->HasProlog)
1965 EpilogInfo[EpilogStart] += 1;
1966 // Clear the unwind codes in the EpilogMap, so that they don't get output
1967 // in ARM64EmitUnwindInfoForSegment().
1968 EpilogInstrs.clear();
1969 } else {
1970 EpilogInfo[EpilogStart] = TotalCodeBytes;
1971 TotalCodeBytes += CodeBytes;
1972 AddedEpilogs.push_back(EpilogStart);
1973 }
1974 }
1975}
1976
1979 int64_t RawFuncLength) {
1980 if (info->PrologEnd)
1981 checkARM64Instructions(streamer, info->Instructions, info->Begin,
1982 info->PrologEnd, info->Function->getName(),
1983 "prologue");
1984 struct EpilogStartEnd {
1985 MCSymbol *Start;
1986 int64_t Offset;
1987 int64_t End;
1988 };
1989 // Record Start and End of each epilog.
1991 for (auto &I : info->EpilogMap) {
1992 MCSymbol *Start = I.first;
1993 auto &Instrs = I.second.Instructions;
1994 int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
1995 checkARM64Instructions(streamer, Instrs, Start, I.second.End,
1996 info->Function->getName(), "epilogue");
1997 assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&
1998 "Epilogs should be monotonically ordered");
1999 // Exclue the end opcode from Instrs.size() when calculating the end of the
2000 // epilog.
2001 Epilogs.push_back({Start, Offset, Offset + (int64_t)(Instrs.size() - 1) * 4});
2002 }
2003
2004 unsigned E = 0;
2005 int64_t SegLimit = 0xFFFFC;
2006 int64_t SegOffset = 0;
2007
2008 if (RawFuncLength > SegLimit) {
2009
2010 int64_t RemainingLength = RawFuncLength;
2011
2012 while (RemainingLength > SegLimit) {
2013 // Try divide the function into segments, requirements:
2014 // 1. Segment length <= 0xFFFFC;
2015 // 2. Each Prologue or Epilogue must be fully within a segment.
2016 int64_t SegLength = SegLimit;
2017 int64_t SegEnd = SegOffset + SegLength;
2018 // Keep record on symbols and offsets of epilogs in this segment.
2019 MapVector<MCSymbol *, int64_t> EpilogsInSegment;
2020
2021 while (E < Epilogs.size() && Epilogs[E].End < SegEnd) {
2022 // Epilogs within current segment.
2023 EpilogsInSegment[Epilogs[E].Start] = Epilogs[E].Offset;
2024 ++E;
2025 }
2026
2027 // At this point, we have:
2028 // 1. Put all epilogs in segments already. No action needed here; or
2029 // 2. Found an epilog that will cross segments boundry. We need to
2030 // move back current segment's end boundry, so the epilog is entirely
2031 // in the next segment; or
2032 // 3. Left at least one epilog that is entirely after this segment.
2033 // It'll be handled by the next iteration, or the last segment.
2034 if (E < Epilogs.size() && Epilogs[E].Offset <= SegEnd)
2035 // Move back current Segment's end boundry.
2036 SegLength = Epilogs[E].Offset - SegOffset;
2037
2038 auto Seg = WinEH::FrameInfo::Segment(
2039 SegOffset, SegLength, /* HasProlog */!SegOffset);
2040 Seg.Epilogs = std::move(EpilogsInSegment);
2041 info->Segments.push_back(Seg);
2042
2043 SegOffset += SegLength;
2044 RemainingLength -= SegLength;
2045 }
2046 }
2047
2048 // Add the last segment when RawFuncLength > 0xFFFFC,
2049 // or the only segment otherwise.
2050 auto LastSeg =
2051 WinEH::FrameInfo::Segment(SegOffset, RawFuncLength - SegOffset,
2052 /* HasProlog */!SegOffset);
2053 for (; E < Epilogs.size(); ++E)
2054 LastSeg.Epilogs[Epilogs[E].Start] = Epilogs[E].Offset;
2055 info->Segments.push_back(LastSeg);
2056}
2057
2061 bool TryPacked = true) {
2062 MCContext &context = streamer.getContext();
2063 MCSymbol *Label = context.createTempSymbol();
2064
2065 streamer.emitValueToAlignment(Align(4));
2066 streamer.emitLabel(Label);
2067 Seg.Symbol = Label;
2068 // Use the 1st segemnt's label as function's.
2069 if (Seg.Offset == 0)
2070 info->Symbol = Label;
2071
2072 bool HasProlog = Seg.HasProlog;
2073 bool HasEpilogs = (Seg.Epilogs.size() != 0);
2074
2075 uint32_t SegLength = (uint32_t)Seg.Length / 4;
2076 uint32_t PrologCodeBytes = info->PrologCodeBytes;
2077
2078 int PackedEpilogOffset = HasEpilogs ?
2079 checkARM64PackedEpilog(streamer, info, &Seg, PrologCodeBytes) : -1;
2080
2081 // TODO:
2082 // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
2083 // 2. Emit packed unwind info (.pdata only) for segments that have neithor
2084 // prolog nor epilog.
2085 if (info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
2086 uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
2087 !info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
2088 // Matching prolog/epilog and no exception handlers; check if the
2089 // prolog matches the patterns that can be described by the packed
2090 // format.
2091
2092 // info->Symbol was already set even if we didn't actually write any
2093 // unwind info there. Keep using that as indicator that this unwind
2094 // info has been generated already.
2095 if (tryARM64PackedUnwind(info, SegLength, PackedEpilogOffset))
2096 return;
2097 }
2098
2099 // If the prolog is not in this segment, we need to emit an end_c, which takes
2100 // 1 byte, before prolog unwind ops.
2101 if (!HasProlog) {
2102 PrologCodeBytes += 1;
2103 if (PackedEpilogOffset >= 0)
2104 PackedEpilogOffset += 1;
2105 // If a segment has neither prolog nor epilog, "With full .xdata record,
2106 // Epilog Count = 1. Epilog Start Index points to end_c."
2107 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
2108 // TODO: We can remove this if testing shows zero epilog scope is ok with
2109 // MS unwinder.
2110 if (!HasEpilogs)
2111 // Pack the fake epilog into phantom prolog.
2112 PackedEpilogOffset = 0;
2113 }
2114
2115 uint32_t TotalCodeBytes = PrologCodeBytes;
2116
2117 // Process epilogs.
2119 ARM64ProcessEpilogs(info, &Seg, TotalCodeBytes, EpilogInfo);
2120
2121 // Code Words, Epilog count, E, X, Vers, Function Length
2122 uint32_t row1 = 0x0;
2123 uint32_t CodeWords = TotalCodeBytes / 4;
2124 uint32_t CodeWordsMod = TotalCodeBytes % 4;
2125 if (CodeWordsMod)
2126 CodeWords++;
2127 uint32_t EpilogCount =
2128 PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.Epilogs.size();
2129 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
2130 if (!ExtensionWord) {
2131 row1 |= (EpilogCount & 0x1F) << 22;
2132 row1 |= (CodeWords & 0x1F) << 27;
2133 }
2134 if (info->HandlesExceptions) // X
2135 row1 |= 1 << 20;
2136 if (PackedEpilogOffset >= 0) // E
2137 row1 |= 1 << 21;
2138 row1 |= SegLength & 0x3FFFF;
2139 streamer.emitInt32(row1);
2140
2141 // Extended Code Words, Extended Epilog Count
2142 if (ExtensionWord) {
2143 // FIXME: We should be able to split unwind info into multiple sections.
2144 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2146 "SEH unwind data splitting is only implemented for large functions, "
2147 "cases of too many code words or too many epilogs will be done "
2148 "later");
2149 uint32_t row2 = 0x0;
2150 row2 |= (CodeWords & 0xFF) << 16;
2151 row2 |= (EpilogCount & 0xFFFF);
2152 streamer.emitInt32(row2);
2153 }
2154
2155 if (PackedEpilogOffset < 0) {
2156 // Epilog Start Index, Epilog Start Offset
2157 for (auto &I : EpilogInfo) {
2158 MCSymbol *EpilogStart = I.first;
2159 uint32_t EpilogIndex = I.second;
2160 // Epilog offset within the Segment.
2161 uint32_t EpilogOffset = (uint32_t)(Seg.Epilogs[EpilogStart] - Seg.Offset);
2162 if (EpilogOffset)
2163 EpilogOffset /= 4;
2164 uint32_t row3 = EpilogOffset;
2165 row3 |= (EpilogIndex & 0x3FF) << 22;
2166 streamer.emitInt32(row3);
2167 }
2168 }
2169
2170 // Note that even for segments that have no prolog, we still need to emit
2171 // prolog unwinding opcodes so that the unwinder knows how to unwind from
2172 // such a segment.
2173 // The end_c opcode at the start indicates to the unwinder that the actual
2174 // prolog is outside of the current segment, and the unwinder shouldn't try
2175 // to check for unwinding from a partial prolog.
2176 if (!HasProlog)
2177 // Emit an end_c.
2178 streamer.emitInt8((uint8_t)0xE5);
2179
2180 // Emit prolog unwind instructions (in reverse order).
2181 for (auto Inst : llvm::reverse(info->Instructions))
2182 ARM64EmitUnwindCode(streamer, Inst);
2183
2184 // Emit epilog unwind instructions
2185 for (auto &I : Seg.Epilogs) {
2186 auto &EpilogInstrs = info->EpilogMap[I.first].Instructions;
2187 for (const WinEH::Instruction &inst : EpilogInstrs)
2188 ARM64EmitUnwindCode(streamer, inst);
2189 }
2190
2191 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2192 assert(BytesMod >= 0);
2193 for (int i = 0; i < BytesMod; i++)
2194 streamer.emitInt8(0xE3);
2195
2196 if (info->HandlesExceptions)
2197 streamer.emitValue(
2198 MCSymbolRefExpr::create(info->ExceptionHandler,
2200 4);
2201}
2202
2203// Populate the .xdata section. The format of .xdata on ARM64 is documented at
2204// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
2206 bool TryPacked = true) {
2207 // If this UNWIND_INFO already has a symbol, it's already been emitted.
2208 if (info->Symbol)
2209 return;
2210 // If there's no unwind info here (not even a terminating UOP_End), the
2211 // unwind info is considered bogus and skipped. If this was done in
2212 // response to an explicit .seh_handlerdata, the associated trailing
2213 // handler data is left orphaned in the xdata section.
2214 if (info->empty()) {
2215 info->EmitAttempted = true;
2216 return;
2217 }
2218 if (info->EmitAttempted) {
2219 // If we tried to emit unwind info before (due to an explicit
2220 // .seh_handlerdata directive), but skipped it (because there was no
2221 // valid information to emit at the time), and it later got valid unwind
2222 // opcodes, we can't emit it here, because the trailing handler data
2223 // was already emitted elsewhere in the xdata section.
2224 streamer.getContext().reportError(
2225 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
2226 " skipped due to no unwind info at the time "
2227 "(.seh_handlerdata too early?), but the function later "
2228 "did get unwind info that can't be emitted");
2229 return;
2230 }
2231
2232 simplifyARM64Opcodes(info->Instructions, false);
2233 for (auto &I : info->EpilogMap)
2234 simplifyARM64Opcodes(I.second.Instructions, true);
2235
2236 int64_t RawFuncLength;
2237 if (!info->FuncletOrFuncEnd) {
2238 report_fatal_error("FuncletOrFuncEnd not set");
2239 } else {
2240 // FIXME: GetAbsDifference tries to compute the length of the function
2241 // immediately, before the whole file is emitted, but in general
2242 // that's impossible: the size in bytes of certain assembler directives
2243 // like .align and .fill is not known until the whole file is parsed and
2244 // relaxations are applied. Currently, GetAbsDifference fails with a fatal
2245 // error in that case. (We mostly don't hit this because inline assembly
2246 // specifying those directives is rare, and we don't normally try to
2247 // align loops on AArch64.)
2248 //
2249 // There are two potential approaches to delaying the computation. One,
2250 // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
2251 // as long as we have some conservative estimate we could use to prove
2252 // that we don't need to split the unwind data. Emitting the constant
2253 // is straightforward, but there's no existing code for estimating the
2254 // size of the function.
2255 //
2256 // The other approach would be to use a dedicated, relaxable fragment,
2257 // which could grow to accommodate splitting the unwind data if
2258 // necessary. This is more straightforward, since it automatically works
2259 // without any new infrastructure, and it's consistent with how we handle
2260 // relaxation in other contexts. But it would require some refactoring
2261 // to move parts of the pdata/xdata emission into the implementation of
2262 // a fragment. We could probably continue to encode the unwind codes
2263 // here, but we'd have to emit the pdata, the xdata header, and the
2264 // epilogue scopes later, since they depend on whether the we need to
2265 // split the unwind data.
2266 //
2267 // If this is fixed, remove code in AArch64ISelLowering.cpp that
2268 // disables loop alignment on Windows.
2269 RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
2270 info->Begin);
2271 }
2272
2273 ARM64FindSegmentsInFunction(streamer, info, RawFuncLength);
2274
2275 info->PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
2276 for (auto &S : info->Segments)
2277 ARM64EmitUnwindInfoForSegment(streamer, info, S, TryPacked);
2278
2279 // Clear prolog instructions after unwind info is emitted for all segments.
2280 info->Instructions.clear();
2281}
2282
2284 uint32_t Count = 0;
2285 for (const auto &I : Insns) {
2286 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
2287 default:
2288 llvm_unreachable("Unsupported ARM unwind code");
2290 Count += 1;
2291 break;
2293 Count += 3;
2294 break;
2296 Count += 4;
2297 break;
2299 Count += 2;
2300 break;
2302 Count += 3;
2303 break;
2305 Count += 4;
2306 break;
2308 Count += 2;
2309 break;
2311 Count += 1;
2312 break;
2314 Count += 1;
2315 break;
2317 Count += 1;
2318 break;
2320 Count += 1;
2321 break;
2323 Count += 2;
2324 break;
2326 Count += 2;
2327 break;
2329 Count += 2;
2330 break;
2332 Count += 2;
2333 break;
2334 case Win64EH::UOP_Nop:
2336 case Win64EH::UOP_End:
2339 Count += 1;
2340 break;
2341 case Win64EH::UOP_Custom: {
2342 int J;
2343 for (J = 3; J > 0; J--)
2344 if (I.Offset & (0xffu << (8 * J)))
2345 break;
2346 Count += J + 1;
2347 break;
2348 }
2349 }
2350 }
2351 return Count;
2352}
2353
2355 bool *HasCustom = nullptr) {
2356 uint32_t Count = 0;
2357 for (const auto &I : Insns) {
2358 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
2359 default:
2360 llvm_unreachable("Unsupported ARM unwind code");
2364 Count += 2;
2365 break;
2369 Count += 4;
2370 break;
2373 Count += 4;
2374 break;
2376 Count += 2;
2377 break;
2380 Count += 2;
2381 break;
2385 Count += 4;
2386 break;
2388 Count += 4;
2389 break;
2390 case Win64EH::UOP_Nop:
2392 Count += 2;
2393 break;
2396 Count += 4;
2397 break;
2398 case Win64EH::UOP_End:
2399 // This doesn't map to any instruction
2400 break;
2402 // We can't reason about what instructions this maps to; return a
2403 // phony number to make sure we don't accidentally do epilog packing.
2404 Count += 1000;
2405 if (HasCustom)
2406 *HasCustom = true;
2407 break;
2408 }
2409 }
2410 return Count;
2411}
2412
2413static void checkARMInstructions(MCStreamer &Streamer,
2415 const MCSymbol *Begin, const MCSymbol *End,
2416 StringRef Name, StringRef Type) {
2417 if (!End)
2418 return;
2419 std::optional<int64_t> MaybeDistance =
2420 GetOptionalAbsDifference(Streamer, End, Begin);
2421 if (!MaybeDistance)
2422 return;
2423 uint32_t Distance = (uint32_t)*MaybeDistance;
2424 bool HasCustom = false;
2425 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
2426 if (HasCustom)
2427 return;
2428 if (Distance != InstructionBytes) {
2429 Streamer.getContext().reportError(
2430 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
2431 Twine(Distance) +
2432 " bytes of instructions in range, but .seh directives "
2433 "corresponding to " +
2434 Twine(InstructionBytes) + " bytes\n");
2435 }
2436}
2437
2438static bool isARMTerminator(const WinEH::Instruction &inst) {
2439 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
2440 case Win64EH::UOP_End:
2443 return true;
2444 default:
2445 return false;
2446 }
2447}
2448
2449// Unwind opcode encodings and restrictions are documented at
2450// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
2451static void ARMEmitUnwindCode(MCStreamer &streamer,
2452 const WinEH::Instruction &inst) {
2453 uint32_t w, lr;
2454 int i;
2455 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
2456 default:
2457 llvm_unreachable("Unsupported ARM unwind code");
2459 assert((inst.Offset & 3) == 0);
2460 assert(inst.Offset / 4 <= 0x7f);
2461 streamer.emitInt8(inst.Offset / 4);
2462 break;
2464 assert((inst.Register & ~0x5fff) == 0);
2465 lr = (inst.Register >> 14) & 1;
2466 w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
2467 streamer.emitInt8((w >> 8) & 0xff);
2468 streamer.emitInt8((w >> 0) & 0xff);
2469 break;
2471 assert(inst.Register <= 0x0f);
2472 streamer.emitInt8(0xc0 | inst.Register);
2473 break;
2475 assert(inst.Register >= 4 && inst.Register <= 7);
2476 assert(inst.Offset <= 1);
2477 streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
2478 break;
2480 assert(inst.Register >= 8 && inst.Register <= 11);
2481 assert(inst.Offset <= 1);
2482 streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
2483 break;
2485 assert(inst.Register >= 8 && inst.Register <= 15);
2486 streamer.emitInt8(0xe0 | (inst.Register - 8));
2487 break;
2489 assert((inst.Offset & 3) == 0);
2490 assert(inst.Offset / 4 <= 0x3ff);
2491 w = 0xe800 | (inst.Offset / 4);
2492 streamer.emitInt8((w >> 8) & 0xff);
2493 streamer.emitInt8((w >> 0) & 0xff);
2494 break;
2496 assert((inst.Register & ~0x40ff) == 0);
2497 lr = (inst.Register >> 14) & 1;
2498 w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
2499 streamer.emitInt8((w >> 8) & 0xff);
2500 streamer.emitInt8((w >> 0) & 0xff);
2501 break;
2503 assert((inst.Offset & 3) == 0);
2504 assert(inst.Offset / 4 <= 0x0f);
2505 streamer.emitInt8(0xef);
2506 streamer.emitInt8(inst.Offset / 4);
2507 break;
2509 assert(inst.Register <= 15);
2510 assert(inst.Offset <= 15);
2511 assert(inst.Register <= inst.Offset);
2512 streamer.emitInt8(0xf5);
2513 streamer.emitInt8((inst.Register << 4) | inst.Offset);
2514 break;
2516 assert(inst.Register >= 16 && inst.Register <= 31);
2517 assert(inst.Offset >= 16 && inst.Offset <= 31);
2518 assert(inst.Register <= inst.Offset);
2519 streamer.emitInt8(0xf6);
2520 streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
2521 break;
2523 assert((inst.Offset & 3) == 0);
2524 assert(inst.Offset / 4 <= 0xffff);
2525 w = inst.Offset / 4;
2526 streamer.emitInt8(0xf7);
2527 streamer.emitInt8((w >> 8) & 0xff);
2528 streamer.emitInt8((w >> 0) & 0xff);
2529 break;
2531 assert((inst.Offset & 3) == 0);
2532 assert(inst.Offset / 4 <= 0xffffff);
2533 w = inst.Offset / 4;
2534 streamer.emitInt8(0xf8);
2535 streamer.emitInt8((w >> 16) & 0xff);
2536 streamer.emitInt8((w >> 8) & 0xff);
2537 streamer.emitInt8((w >> 0) & 0xff);
2538 break;
2540 assert((inst.Offset & 3) == 0);
2541 assert(inst.Offset / 4 <= 0xffff);
2542 w = inst.Offset / 4;
2543 streamer.emitInt8(0xf9);
2544 streamer.emitInt8((w >> 8) & 0xff);
2545 streamer.emitInt8((w >> 0) & 0xff);
2546 break;
2548 assert((inst.Offset & 3) == 0);
2549 assert(inst.Offset / 4 <= 0xffffff);
2550 w = inst.Offset / 4;
2551 streamer.emitInt8(0xfa);
2552 streamer.emitInt8((w >> 16) & 0xff);
2553 streamer.emitInt8((w >> 8) & 0xff);
2554 streamer.emitInt8((w >> 0) & 0xff);
2555 break;
2556 case Win64EH::UOP_Nop:
2557 streamer.emitInt8(0xfb);
2558 break;
2560 streamer.emitInt8(0xfc);
2561 break;
2563 streamer.emitInt8(0xfd);
2564 break;
2566 streamer.emitInt8(0xfe);
2567 break;
2568 case Win64EH::UOP_End:
2569 streamer.emitInt8(0xff);
2570 break;
2572 for (i = 3; i > 0; i--)
2573 if (inst.Offset & (0xffu << (8 * i)))
2574 break;
2575 for (; i >= 0; i--)
2576 streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
2577 break;
2578 }
2579}
2580
2581// Check if an epilog exists as a subset of the end of a prolog (backwards).
2582// An epilog may end with one out of three different end opcodes; if this
2583// is the first epilog that shares opcodes with the prolog, we can tolerate
2584// that this opcode differs (and the caller will update the prolog to use
2585// the same end opcode as the epilog). If another epilog already shares
2586// opcodes with the prolog, the ending opcode must be a strict match.
2587static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
2588 const std::vector<WinEH::Instruction> &Epilog,
2589 bool CanTweakProlog) {
2590 // Can't find an epilog as a subset if it is longer than the prolog.
2591 if (Epilog.size() > Prolog.size())
2592 return -1;
2593
2594 // Check that the epilog actually is a perfect match for the end (backwrds)
2595 // of the prolog.
2596 // If we can adjust the prolog afterwards, don't check that the end opcodes
2597 // match.
2598 int EndIdx = CanTweakProlog ? 1 : 0;
2599 for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
2600 // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
2601 // "push {r0-r3}".
2602 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
2603 return -1;
2604 }
2605
2606 if (CanTweakProlog) {
2607 // Check that both prolog and epilog end with an expected end opcode.
2608 if (Prolog.front().Operation != Win64EH::UOP_End)
2609 return -1;
2610 if (Epilog.back().Operation != Win64EH::UOP_End &&
2611 Epilog.back().Operation != Win64EH::UOP_EndNop &&
2612 Epilog.back().Operation != Win64EH::UOP_WideEndNop)
2613 return -1;
2614 }
2615
2616 // If the epilog was a subset of the prolog, find its offset.
2617 if (Epilog.size() == Prolog.size())
2618 return 0;
2620 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
2621}
2622
2624 int PrologCodeBytes) {
2625 // Can only pack if there's one single epilog
2626 if (info->EpilogMap.size() != 1)
2627 return -1;
2628
2629 const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
2630 // Can only pack if the epilog is unconditional
2631 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2632 return -1;
2633
2634 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2635 // Make sure we have at least the trailing end opcode
2636 if (info->Instructions.empty() || Epilog.empty())
2637 return -1;
2638
2639 // Check that the epilog actually is at the very end of the function,
2640 // otherwise it can't be packed.
2641 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2642 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2643 if (!MaybeDistance)
2644 return -1;
2645 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2646 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2647 if (DistanceFromEnd != InstructionBytes)
2648 return -1;
2649
2650 int RetVal = -1;
2651 // Even if we don't end up sharing opcodes with the prolog, we can still
2652 // write the offset as a packed offset, if the single epilog is located at
2653 // the end of the function and the offset (pointing after the prolog) fits
2654 // as a packed offset.
2655 if (PrologCodeBytes <= 31 &&
2656 PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
2657 RetVal = PrologCodeBytes;
2658
2659 int Offset =
2660 getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
2661 if (Offset < 0)
2662 return RetVal;
2663
2664 // Check that the offset and prolog size fits in the first word; it's
2665 // unclear whether the epilog count in the extension word can be taken
2666 // as packed epilog offset.
2667 if (Offset > 31 || PrologCodeBytes > 63)
2668 return RetVal;
2669
2670 // Replace the regular end opcode of the prolog with the one from the
2671 // epilog.
2672 info->Instructions.front() = Epilog.back();
2673
2674 // As we choose to express the epilog as part of the prolog, remove the
2675 // epilog from the map, so we don't try to emit its opcodes.
2676 info->EpilogMap.clear();
2677 return Offset;
2678}
2679
2680static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
2681 unsigned &Folded, int &IntRegs) {
2682 if (Mask & (1 << 14)) {
2683 HasLR = true;
2684 Mask &= ~(1 << 14);
2685 }
2686 if (Mask & (1 << 11)) {
2687 HasR11 = true;
2688 Mask &= ~(1 << 11);
2689 }
2690 Folded = 0;
2691 IntRegs = -1;
2692 if (!Mask)
2693 return true;
2694 int First = 0;
2695 // Shift right until we have the bits at the bottom
2696 while ((Mask & 1) == 0) {
2697 First++;
2698 Mask >>= 1;
2699 }
2700 if ((Mask & (Mask + 1)) != 0)
2701 return false; // Not a consecutive series of bits? Can't be packed.
2702 // Count the bits
2703 int N = 0;
2704 while (Mask & (1 << N))
2705 N++;
2706 if (First < 4) {
2707 if (First + N < 4)
2708 return false;
2709 Folded = 4 - First;
2710 N -= Folded;
2711 First = 4;
2712 }
2713 if (First > 4)
2714 return false; // Can't be packed
2715 if (N >= 1)
2716 IntRegs = N - 1;
2717 return true;
2718}
2719
2721 uint32_t FuncLength) {
2722 int Step = 0;
2723 bool Homing = false;
2724 bool HasR11 = false;
2725 bool HasChain = false;
2726 bool HasLR = false;
2727 int IntRegs = -1; // r4 - r(4+N)
2728 int FloatRegs = -1; // d8 - d(8+N)
2729 unsigned PF = 0; // Number of extra pushed registers
2730 unsigned StackAdjust = 0;
2731 // Iterate over the prolog and check that all opcodes exactly match
2732 // the canonical order and form.
2733 for (const WinEH::Instruction &Inst : info->Instructions) {
2734 switch (Inst.Operation) {
2735 default:
2736 llvm_unreachable("Unsupported ARM unwind code");
2744 // Can't be packed
2745 return false;
2747 // Can't be packed; we can't rely on restoring sp from r11 when
2748 // unwinding a packed prologue.
2749 return false;
2751 // Can't be present in a packed prologue
2752 return false;
2753
2754 case Win64EH::UOP_End:
2757 if (Step != 0)
2758 return false;
2759 Step = 1;
2760 break;
2761
2764 // push {r4-r11,lr}
2765 if (Step != 1 && Step != 2)
2766 return false;
2767 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2768 assert(Inst.Offset <= 1); // Lr
2769 IntRegs = Inst.Register - 4;
2770 if (Inst.Register == 11) {
2771 HasR11 = true;
2772 IntRegs--;
2773 }
2774 if (Inst.Offset)
2775 HasLR = true;
2776 Step = 3;
2777 break;
2778
2780 if (Step == 1 && Inst.Register == 0x0f) {
2781 // push {r0-r3}
2782 Homing = true;
2783 Step = 2;
2784 break;
2785 }
2786 [[fallthrough]];
2788 if (Step != 1 && Step != 2)
2789 return false;
2790 // push {r4-r9,r11,lr}
2791 // push {r11,lr}
2792 // push {r1-r5}
2793 if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
2794 return false;
2795 Step = 3;
2796 break;
2797
2798 case Win64EH::UOP_Nop:
2799 // mov r11, sp
2800 if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
2801 return false;
2802 HasChain = true;
2803 Step = 4;
2804 break;
2806 // add.w r11, sp, #xx
2807 if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
2808 return false;
2809 HasChain = true;
2810 Step = 4;
2811 break;
2812
2814 if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
2815 return false;
2816 assert(Inst.Register >= 8 && Inst.Register <= 15);
2817 if (Inst.Register == 15)
2818 return false; // Can't pack this case, R==7 means no IntRegs
2819 if (IntRegs >= 0)
2820 return false;
2821 FloatRegs = Inst.Register - 8;
2822 Step = 5;
2823 break;
2824
2827 if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
2828 return false;
2829 if (PF > 0) // Can't have both folded and explicit stack allocation
2830 return false;
2831 if (Inst.Offset / 4 >= 0x3f4)
2832 return false;
2833 StackAdjust = Inst.Offset / 4;
2834 Step = 6;
2835 break;
2836 }
2837 }
2838 if (HasR11 && !HasChain) {
2839 if (IntRegs + 4 == 10) {
2840 // r11 stored, but not chaining; can be packed if already saving r4-r10
2841 // and we can fit r11 into this range.
2842 IntRegs++;
2843 HasR11 = false;
2844 } else
2845 return false;
2846 }
2847 if (HasChain && !HasLR)
2848 return false;
2849
2850 // Packed uneind info can't express multiple epilogues.
2851 if (info->EpilogMap.size() > 1)
2852 return false;
2853
2854 unsigned EF = 0;
2855 int Ret = 0;
2856 if (info->EpilogMap.size() == 0) {
2857 Ret = 3; // No epilogue
2858 } else {
2859 // As the prologue and epilogue aren't exact mirrors of each other,
2860 // we have to check the epilogue too and see if it matches what we've
2861 // concluded from the prologue.
2862 const WinEH::FrameInfo::Epilog &EpilogInfo =
2863 info->EpilogMap.begin()->second;
2864 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2865 return false;
2866 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2867 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2868 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2869 if (!MaybeDistance)
2870 return false;
2871 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2872 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2873 if (DistanceFromEnd != InstructionBytes)
2874 return false;
2875
2876 bool GotStackAdjust = false;
2877 bool GotFloatRegs = false;
2878 bool GotIntRegs = false;
2879 bool GotHomingRestore = false;
2880 bool GotLRRestore = false;
2881 bool NeedsReturn = false;
2882 bool GotReturn = false;
2883
2884 Step = 6;
2885 for (const WinEH::Instruction &Inst : Epilog) {
2886 switch (Inst.Operation) {
2887 default:
2888 llvm_unreachable("Unsupported ARM unwind code");
2897 case Win64EH::UOP_Nop:
2899 // Can't be packed in an epilogue
2900 return false;
2901
2904 if (Inst.Offset / 4 >= 0x3f4)
2905 return false;
2906 if (Step == 6) {
2907 if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
2908 PF == 0 && Inst.Offset == 16) {
2909 GotHomingRestore = true;
2910 Step = 10;
2911 } else {
2912 if (StackAdjust > 0) {
2913 // Got stack adjust in prologue too; must match.
2914 if (StackAdjust != Inst.Offset / 4)
2915 return false;
2916 GotStackAdjust = true;
2917 } else if (PF == Inst.Offset / 4) {
2918 // Folded prologue, non-folded epilogue
2919 StackAdjust = Inst.Offset / 4;
2920 GotStackAdjust = true;
2921 } else {
2922 // StackAdjust == 0 in prologue, mismatch
2923 return false;
2924 }
2925 Step = 7;
2926 }
2927 } else if (Step == 7 || Step == 8 || Step == 9) {
2928 if (!Homing || Inst.Offset != 16)
2929 return false;
2930 GotHomingRestore = true;
2931 Step = 10;
2932 } else
2933 return false;
2934 break;
2935
2937 if (Step != 6 && Step != 7)
2938 return false;
2939 assert(Inst.Register >= 8 && Inst.Register <= 15);
2940 if (FloatRegs != (int)(Inst.Register - 8))
2941 return false;
2942 GotFloatRegs = true;
2943 Step = 8;
2944 break;
2945
2948 // push {r4-r11,lr}
2949 if (Step != 6 && Step != 7 && Step != 8)
2950 return false;
2951 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2952 assert(Inst.Offset <= 1); // Lr
2953 if (Homing && HasLR) {
2954 // If homing and LR is backed up, we can either restore LR here
2955 // and return with Ret == 1 or 2, or return with SaveLR below
2956 if (Inst.Offset) {
2957 GotLRRestore = true;
2958 NeedsReturn = true;
2959 } else {
2960 // Expecting a separate SaveLR below
2961 }
2962 } else {
2963 if (HasLR != (Inst.Offset == 1))
2964 return false;
2965 }
2966 GotLRRestore = Inst.Offset == 1;
2967 if (IntRegs < 0) // This opcode must include r4
2968 return false;
2969 int Expected = IntRegs;
2970 if (HasChain) {
2971 // Can't express r11 here unless IntRegs describe r4-r10
2972 if (IntRegs != 6)
2973 return false;
2974 Expected++;
2975 }
2976 if (Expected != (int)(Inst.Register - 4))
2977 return false;
2978 GotIntRegs = true;
2979 Step = 9;
2980 break;
2981 }
2982
2985 if (Step != 6 && Step != 7 && Step != 8)
2986 return false;
2987 // push {r4-r9,r11,lr}
2988 // push {r11,lr}
2989 // push {r1-r5}
2990 bool CurHasLR = false, CurHasR11 = false;
2991 int Regs;
2992 if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
2993 return false;
2994 if (EF > 0) {
2995 if (EF != PF && EF != StackAdjust)
2996 return false;
2997 }
2998 if (Homing && HasLR) {
2999 // If homing and LR is backed up, we can either restore LR here
3000 // and return with Ret == 1 or 2, or return with SaveLR below
3001 if (CurHasLR) {
3002 GotLRRestore = true;
3003 NeedsReturn = true;
3004 } else {
3005 // Expecting a separate SaveLR below
3006 }
3007 } else {
3008 if (CurHasLR != HasLR)
3009 return false;
3010 GotLRRestore = CurHasLR;
3011 }
3012 int Expected = IntRegs;
3013 if (HasChain) {
3014 // If we have chaining, the mask must have included r11.
3015 if (!CurHasR11)
3016 return false;
3017 } else if (Expected == 7) {
3018 // If we don't have chaining, the mask could still include r11,
3019 // expressed as part of IntRegs Instead.
3020 Expected--;
3021 if (!CurHasR11)
3022 return false;
3023 } else {
3024 // Neither HasChain nor r11 included in IntRegs, must not have r11
3025 // here either.
3026 if (CurHasR11)
3027 return false;
3028 }
3029 if (Expected != Regs)
3030 return false;
3031 GotIntRegs = true;
3032 Step = 9;
3033 break;
3034 }
3035
3037 if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
3038 return false;
3039 if (!Homing || Inst.Offset != 20 || GotLRRestore)
3040 return false;
3041 GotLRRestore = true;
3042 GotHomingRestore = true;
3043 Step = 10;
3044 break;
3045
3048 GotReturn = true;
3049 Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
3050 [[fallthrough]];
3051 case Win64EH::UOP_End:
3052 if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
3053 return false;
3054 Step = 11;
3055 break;
3056 }
3057 }
3058
3059 if (Step != 11)
3060 return false;
3061 if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
3062 return false;
3063 if (FloatRegs >= 0 && !GotFloatRegs)
3064 return false;
3065 if (IntRegs >= 0 && !GotIntRegs)
3066 return false;
3067 if (Homing && !GotHomingRestore)
3068 return false;
3069 if (HasLR && !GotLRRestore)
3070 return false;
3071 if (NeedsReturn && !GotReturn)
3072 return false;
3073 }
3074
3075 assert(PF == 0 || EF == 0 ||
3076 StackAdjust == 0); // Can't have adjust in all three
3077 if (PF > 0 || EF > 0) {
3078 StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
3079 assert(StackAdjust <= 3);
3080 StackAdjust |= 0x3f0;
3081 if (PF > 0)
3082 StackAdjust |= 1 << 2;
3083 if (EF > 0)
3084 StackAdjust |= 1 << 3;
3085 }
3086
3087 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
3088 int Flag = info->Fragment ? 0x02 : 0x01;
3089 int H = Homing ? 1 : 0;
3090 int L = HasLR ? 1 : 0;
3091 int C = HasChain ? 1 : 0;
3092 assert(IntRegs < 0 || FloatRegs < 0);
3093 unsigned Reg, R;
3094 if (IntRegs >= 0) {
3095 Reg = IntRegs;
3096 assert(Reg <= 7);
3097 R = 0;
3098 } else if (FloatRegs >= 0) {
3099 Reg = FloatRegs;
3100 assert(Reg < 7);
3101 R = 1;
3102 } else {
3103 // No int or float regs stored (except possibly R11,LR)
3104 Reg = 7;
3105 R = 1;
3106 }
3107 info->PackedInfo |= Flag << 0;
3108 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
3109 info->PackedInfo |= (Ret & 0x3) << 13;
3110 info->PackedInfo |= H << 15;
3111 info->PackedInfo |= Reg << 16;
3112 info->PackedInfo |= R << 19;
3113 info->PackedInfo |= L << 20;
3114 info->PackedInfo |= C << 21;
3115 assert(StackAdjust <= 0x3ff);
3116 info->PackedInfo |= StackAdjust << 22;
3117 return true;
3118}
3119
3120// Populate the .xdata section. The format of .xdata on ARM is documented at
3121// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
3123 bool TryPacked = true) {
3124 // If this UNWIND_INFO already has a symbol, it's already been emitted.
3125 if (info->Symbol)
3126 return;
3127 // If there's no unwind info here (not even a terminating UOP_End), the
3128 // unwind info is considered bogus and skipped. If this was done in
3129 // response to an explicit .seh_handlerdata, the associated trailing
3130 // handler data is left orphaned in the xdata section.
3131 if (info->empty()) {
3132 info->EmitAttempted = true;
3133 return;
3134 }
3135 if (info->EmitAttempted) {
3136 // If we tried to emit unwind info before (due to an explicit
3137 // .seh_handlerdata directive), but skipped it (because there was no
3138 // valid information to emit at the time), and it later got valid unwind
3139 // opcodes, we can't emit it here, because the trailing handler data
3140 // was already emitted elsewhere in the xdata section.
3141 streamer.getContext().reportError(
3142 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
3143 " skipped due to no unwind info at the time "
3144 "(.seh_handlerdata too early?), but the function later "
3145 "did get unwind info that can't be emitted");
3146 return;
3147 }
3148
3149 MCContext &context = streamer.getContext();
3150 MCSymbol *Label = context.createTempSymbol();
3151
3152 streamer.emitValueToAlignment(Align(4));
3153 streamer.emitLabel(Label);
3154 info->Symbol = Label;
3155
3156 if (!info->PrologEnd)
3157 streamer.getContext().reportError(SMLoc(), "Prologue in " +
3158 info->Function->getName() +
3159 " not correctly terminated");
3160
3161 if (info->PrologEnd && !info->Fragment)
3162 checkARMInstructions(streamer, info->Instructions, info->Begin,
3163 info->PrologEnd, info->Function->getName(),
3164 "prologue");
3165 for (auto &I : info->EpilogMap) {
3166 MCSymbol *EpilogStart = I.first;
3167 auto &Epilog = I.second;
3168 checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
3169 info->Function->getName(), "epilogue");
3170 if (Epilog.Instructions.empty() ||
3171 !isARMTerminator(Epilog.Instructions.back()))
3172 streamer.getContext().reportError(
3173 SMLoc(), "Epilogue in " + info->Function->getName() +
3174 " not correctly terminated");
3175 }
3176
3177 std::optional<int64_t> RawFuncLength;
3178 const MCExpr *FuncLengthExpr = nullptr;
3179 if (!info->FuncletOrFuncEnd) {
3180 report_fatal_error("FuncletOrFuncEnd not set");
3181 } else {
3182 // As the size of many thumb2 instructions isn't known until later,
3183 // we can't always rely on being able to calculate the absolute
3184 // length of the function here. If we can't calculate it, defer it
3185 // to a relocation.
3186 //
3187 // In such a case, we won't know if the function is too long so that
3188 // the unwind info would need to be split (but this isn't implemented
3189 // anyway).
3190 RawFuncLength =
3191 GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
3192 if (!RawFuncLength)
3193 FuncLengthExpr =
3194 GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
3195 }
3196 uint32_t FuncLength = 0;
3197 if (RawFuncLength)
3198 FuncLength = (uint32_t)*RawFuncLength / 2;
3199 if (FuncLength > 0x3FFFF)
3200 report_fatal_error("SEH unwind data splitting not yet implemented");
3201 uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
3202 uint32_t TotalCodeBytes = PrologCodeBytes;
3203
3204 if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
3205 TryPacked) {
3206 // No exception handlers; check if the prolog and epilog matches the
3207 // patterns that can be described by the packed format. If we don't
3208 // know the exact function length yet, we can't do this.
3209
3210 // info->Symbol was already set even if we didn't actually write any
3211 // unwind info there. Keep using that as indicator that this unwind
3212 // info has been generated already.
3213
3214 if (tryARMPackedUnwind(streamer, info, FuncLength))
3215 return;
3216 }
3217
3218 int PackedEpilogOffset =
3219 checkARMPackedEpilog(streamer, info, PrologCodeBytes);
3220
3221 // Process epilogs.
3223 // Epilogs processed so far.
3224 std::vector<MCSymbol *> AddedEpilogs;
3225
3226 bool CanTweakProlog = true;
3227 for (auto &I : info->EpilogMap) {
3228 MCSymbol *EpilogStart = I.first;
3229 auto &EpilogInstrs = I.second.Instructions;
3230 uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
3231
3232 MCSymbol *MatchingEpilog =
3233 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
3234 int PrologOffset;
3235 if (MatchingEpilog) {
3236 assert(EpilogInfo.contains(MatchingEpilog) &&
3237 "Duplicate epilog not found");
3238 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
3239 // Clear the unwind codes in the EpilogMap, so that they don't get output
3240 // in the logic below.
3241 EpilogInstrs.clear();
3242 } else if ((PrologOffset = getARMOffsetInProlog(
3243 info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
3244 if (CanTweakProlog) {
3245 // Replace the regular end opcode of the prolog with the one from the
3246 // epilog.
3247 info->Instructions.front() = EpilogInstrs.back();
3248 // Later epilogs need a strict match for the end opcode.
3249 CanTweakProlog = false;
3250 }
3251 EpilogInfo[EpilogStart] = PrologOffset;
3252 // Clear the unwind codes in the EpilogMap, so that they don't get output
3253 // in the logic below.
3254 EpilogInstrs.clear();
3255 } else {
3256 EpilogInfo[EpilogStart] = TotalCodeBytes;
3257 TotalCodeBytes += CodeBytes;
3258 AddedEpilogs.push_back(EpilogStart);
3259 }
3260 }
3261
3262 // Code Words, Epilog count, F, E, X, Vers, Function Length
3263 uint32_t row1 = 0x0;
3264 uint32_t CodeWords = TotalCodeBytes / 4;
3265 uint32_t CodeWordsMod = TotalCodeBytes % 4;
3266 if (CodeWordsMod)
3267 CodeWords++;
3268 uint32_t EpilogCount =
3269 PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
3270 bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
3271 if (!ExtensionWord) {
3272 row1 |= (EpilogCount & 0x1F) << 23;
3273 row1 |= (CodeWords & 0x0F) << 28;
3274 }
3275 if (info->HandlesExceptions) // X
3276 row1 |= 1 << 20;
3277 if (PackedEpilogOffset >= 0) // E
3278 row1 |= 1 << 21;
3279 if (info->Fragment) // F
3280 row1 |= 1 << 22;
3281 row1 |= FuncLength & 0x3FFFF;
3282 if (RawFuncLength)
3283 streamer.emitInt32(row1);
3284 else
3285 streamer.emitValue(
3286 MCBinaryExpr::createOr(FuncLengthExpr,
3287 MCConstantExpr::create(row1, context), context),
3288 4);
3289
3290 // Extended Code Words, Extended Epilog Count
3291 if (ExtensionWord) {
3292 // FIXME: We should be able to split unwind info into multiple sections.
3293 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
3294 report_fatal_error("SEH unwind data splitting not yet implemented");
3295 uint32_t row2 = 0x0;
3296 row2 |= (CodeWords & 0xFF) << 16;
3297 row2 |= (EpilogCount & 0xFFFF);
3298 streamer.emitInt32(row2);
3299 }
3300
3301 if (PackedEpilogOffset < 0) {
3302 // Epilog Start Index, Epilog Start Offset
3303 for (auto &I : EpilogInfo) {
3304 MCSymbol *EpilogStart = I.first;
3305 uint32_t EpilogIndex = I.second;
3306
3307 std::optional<int64_t> MaybeEpilogOffset =
3308 GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
3309 const MCExpr *OffsetExpr = nullptr;
3310 uint32_t EpilogOffset = 0;
3311 if (MaybeEpilogOffset)
3312 EpilogOffset = *MaybeEpilogOffset / 2;
3313 else
3314 OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
3315
3316 assert(info->EpilogMap.contains(EpilogStart));
3317 unsigned Condition = info->EpilogMap[EpilogStart].Condition;
3318 assert(Condition <= 0xf);
3319
3320 uint32_t row3 = EpilogOffset;
3321 row3 |= Condition << 20;
3322 row3 |= (EpilogIndex & 0x3FF) << 24;
3323 if (MaybeEpilogOffset)
3324 streamer.emitInt32(row3);
3325 else
3326 streamer.emitValue(
3328 OffsetExpr, MCConstantExpr::create(row3, context), context),
3329 4);
3330 }
3331 }
3332
3333 // Emit prolog unwind instructions (in reverse order).
3334 uint8_t numInst = info->Instructions.size();
3335 for (uint8_t c = 0; c < numInst; ++c) {
3336 WinEH::Instruction inst = info->Instructions.back();
3337 info->Instructions.pop_back();
3338 ARMEmitUnwindCode(streamer, inst);
3339 }
3340
3341 // Emit epilog unwind instructions
3342 for (auto &I : info->EpilogMap) {
3343 auto &EpilogInstrs = I.second.Instructions;
3344 for (const WinEH::Instruction &inst : EpilogInstrs)
3345 ARMEmitUnwindCode(streamer, inst);
3346 }
3347
3348 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
3349 assert(BytesMod >= 0);
3350 for (int i = 0; i < BytesMod; i++)
3351 streamer.emitInt8(0xFB);
3352
3353 if (info->HandlesExceptions)
3354 streamer.emitValue(
3355 MCSymbolRefExpr::create(info->ExceptionHandler,
3357 4);
3358}
3359
3361 const WinEH::FrameInfo *info) {
3362 MCContext &context = streamer.getContext();
3363
3364 streamer.emitValueToAlignment(Align(4));
3365 for (const auto &S : info->Segments) {
3366 EmitSymbolRefWithOfs(streamer, info->Begin, S.Offset);
3367 if (info->PackedInfo)
3368 streamer.emitInt32(info->PackedInfo);
3369 else
3370 streamer.emitValue(
3372 context),
3373 4);
3374 }
3375}
3376
3377
3379 const WinEH::FrameInfo *info) {
3380 MCContext &context = streamer.getContext();
3381
3382 streamer.emitValueToAlignment(Align(4));
3383 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
3384 if (info->PackedInfo)
3385 streamer.emitInt32(info->PackedInfo);
3386 else
3387 streamer.emitValue(
3389 context),
3390 4);
3391}
3392
3394 // Emit the unwind info structs first.
3395 for (const auto &CFI : Streamer.getWinFrameInfos()) {
3396 WinEH::FrameInfo *Info = CFI.get();
3397 if (Info->empty())
3398 continue;
3399 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
3400 Streamer.switchSection(XData);
3401 ARM64EmitUnwindInfo(Streamer, Info);
3402 }
3403
3404 // Now emit RUNTIME_FUNCTION entries.
3405 for (const auto &CFI : Streamer.getWinFrameInfos()) {
3406 WinEH::FrameInfo *Info = CFI.get();
3407 // ARM64EmitUnwindInfo above clears the info struct, so we can't check
3408 // empty here. But if a Symbol is set, we should create the corresponding
3409 // pdata entry.
3410 if (!Info->Symbol)
3411 continue;
3412 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
3413 Streamer.switchSection(PData);
3414 ARM64EmitRuntimeFunction(Streamer, Info);
3415 }
3416}
3417
3420 bool HandlerData) const {
3421 // Called if there's an .seh_handlerdata directive before the end of the
3422 // function. This forces writing the xdata record already here - and
3423 // in this case, the function isn't actually ended already, but the xdata
3424 // record needs to know the function length. In these cases, if the funclet
3425 // end hasn't been marked yet, the xdata function length won't cover the
3426 // whole function, only up to this point.
3427 if (!info->FuncletOrFuncEnd) {
3428 Streamer.switchSection(info->TextSection);
3429 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
3430 }
3431 // Switch sections (the static function above is meant to be called from
3432 // here and from Emit().
3433 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
3434 Streamer.switchSection(XData);
3435 ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
3436}
3437
3439 // Emit the unwind info structs first.
3440 for (const auto &CFI : Streamer.getWinFrameInfos()) {
3441 WinEH::FrameInfo *Info = CFI.get();
3442 if (Info->empty())
3443 continue;
3444 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
3445 Streamer.switchSection(XData);
3446 ARMEmitUnwindInfo(Streamer, Info);
3447 }
3448
3449 // Now emit RUNTIME_FUNCTION entries.
3450 for (const auto &CFI : Streamer.getWinFrameInfos()) {
3451 WinEH::FrameInfo *Info = CFI.get();
3452 // ARMEmitUnwindInfo above clears the info struct, so we can't check
3453 // empty here. But if a Symbol is set, we should create the corresponding
3454 // pdata entry.
3455 if (!Info->Symbol)
3456 continue;
3457 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
3458 Streamer.switchSection(PData);
3459 ARMEmitRuntimeFunction(Streamer, Info);
3460 }
3461}
3462
3465 bool HandlerData) const {
3466 // Called if there's an .seh_handlerdata directive before the end of the
3467 // function. This forces writing the xdata record already here - and
3468 // in this case, the function isn't actually ended already, but the xdata
3469 // record needs to know the function length. In these cases, if the funclet
3470 // end hasn't been marked yet, the xdata function length won't cover the
3471 // whole function, only up to this point.
3472 if (!info->FuncletOrFuncEnd) {
3473 Streamer.switchSection(info->TextSection);
3474 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
3475 }
3476 // Switch sections (the static function above is meant to be called from
3477 // here and from Emit().
3478 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
3479 Streamer.switchSection(XData);
3480 ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
3481}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
@ Scaled
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
lazy value info
static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, int PrologCodeBytes)
static void ARM64EmitUnwindInfoForSegment(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment &Seg, bool TryPacked=true)
static uint32_t ARMCountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
static uint32_t ARM64CountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
static void checkARMInstructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
static bool isARMTerminator(const WinEH::Instruction &inst)
static void ARM64EmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
static void simplifyARM64Opcodes(std::vector< WinEH::Instruction > &Instructions, bool Reverse)
static void ARMEmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
static bool EpilogIpOffsetsMatch(const WinEH::FrameInfo::Epilog &A, const WinEH::FrameInfo::Epilog &B, const MCAssembler &Asm)
Compare the relative IP offset arrays of two epilogs.
static std::optional< int64_t > GetOptionalAbsDifference(const MCAssembler &Assembler, const MCSymbol *LHS, const MCSymbol *RHS)
static int getARM64OffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog)
static void ARMEmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength, int PackedEpilogOffset)
static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info)
static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, WinEH::Instruction &inst)
static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
static int getARMOffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog, bool CanTweakProlog)
static void ARM64EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static void EmitSymbolRefWithOfs(MCStreamer &streamer, const MCSymbol *Base, int64_t Offset)
static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11, unsigned &Folded, int &IntRegs)
static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, int PrologCodeBytes)
static void EmitAbsDifference16(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
Emit a 16-bit (2-byte LE) label difference.
static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
static void ARM64FindSegmentsInFunction(MCStreamer &streamer, WinEH::FrameInfo *info, int64_t RawFuncLength)
static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info, uint32_t FuncLength)
static void EmitUnwindInfoV3(MCStreamer &Streamer, WinEH::FrameInfo *Info)
Emit V3 UNWIND_INFO for a single frame.
static MCSymbol * FindMatchingEpilog(const std::vector< WinEH::Instruction > &EpilogInstrs, const std::vector< MCSymbol * > &Epilogs, const WinEH::FrameInfo *info)
static void EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static void checkARM64Instructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
static const MCExpr * GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS, int Div)
static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
static uint32_t ARMCountOfInstructionBytes(ArrayRef< WinEH::Instruction > Insns, bool *HasCustom=nullptr)
static void ARM64ProcessEpilogs(WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, uint32_t &TotalCodeBytes, MapVector< MCSymbol *, uint32_t > &EpilogInfo)
static std::optional< uint16_t > FindInPool(ArrayRef< uint8_t > Haystack, ArrayRef< uint8_t > Needle)
Try to find Needle as a contiguous subsequence within Haystack.
static uint8_t CountOfUnwindCodes(std::vector< WinEH::Instruction > &Insns)
Definition MCWin64EH.cpp:73
#define I(x, y, z)
Definition MD5.cpp:57
#define H(x, y, z)
Definition MD5.cpp:56
Register Reg
static void printImpl(const MCAsmInfo &MAI, raw_ostream &OS, const MCSpecifierExpr &Expr)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static const MCPhysReg IntRegs[32]
Value * RHS
Value * LHS
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator end() const
Definition ArrayRef.h:130
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
Tagged union holding either a T or a Error.
Definition Error.h:485
MCContext & getContext() const
static const MCBinaryExpr * createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:423
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:343
static const MCBinaryExpr * createOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:408
static const MCBinaryExpr * createDiv(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:353
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition MCExpr.h:428
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Context object for machine code objects.
Definition MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
Streaming object file generation interface.
MCAssembler & getAssembler()
void appendContents(ArrayRef< char > Contents)
void addFixup(const MCExpr *Value, MCFixupKind Kind)
void ensureHeadroom(size_t Headroom)
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:573
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual MCSymbol * emitCFILabel()
When emitting an object file, create and emit a real label.
MCSection * getAssociatedPDataSection(const MCSection *TextSec)
Get the .pdata section used for the given section.
MCContext & getContext() const
Definition MCStreamer.h:326
MCSection * getAssociatedXDataSection(const MCSection *TextSec)
Get the .xdata section used for the given section.
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
virtual void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
void emitInt16(uint64_t Value)
Definition MCStreamer.h:759
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
void emitInt32(uint64_t Value)
Definition MCStreamer.h:760
ArrayRef< std::unique_ptr< WinEH::FrameInfo > > getWinFrameInfos() const
Definition MCStreamer.h:359
void emitInt8(uint64_t Value)
Definition MCStreamer.h:758
Represent a reference to a symbol from inside an expression.
Definition MCExpr.h:190
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
MCFragment * getFragment() const
Definition MCSymbol.h:345
static MCValue get(const MCSymbol *SymA, const MCSymbol *SymB=nullptr, int64_t Val=0, uint32_t Specifier=0)
Definition MCValue.h:56
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
Represents a location in source code.
Definition SMLoc.h:22
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:30
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ EPILOG_INFO_LARGE
When set, the extended descriptor uses EPILOG_INFO_LARGE_EX_V3 (16-bit IpOffsetOfLastInstruction) and...
Definition Win64EH.h:261
@ UNW_TerminateHandler
UNW_TerminateHandler - Specifies that this function has a termination handler.
Definition Win64EH.h:151
@ UNW_FlagLarge
UNW_FlagLarge - V3 only.
Definition Win64EH.h:158
@ UNW_ExceptionHandler
UNW_ExceptionHandler - Specifies that this function has an exception handler.
Definition Win64EH.h:148
@ UNW_ChainInfo
UNW_ChainInfo - Specifies that this UnwindInfo structure is chained to another one.
Definition Win64EH.h:154
UnwindOpcodes
UnwindOpcodes - Enumeration whose values specify a single operation in the prolog of a function.
Definition Win64EH.h:30
@ UOP_SaveAnyRegDPX
Definition Win64EH.h:79
@ UOP_SaveRegsR4R7LR
Definition Win64EH.h:102
@ UOP_ClearUnwoundToCall
Definition Win64EH.h:68
@ UOP_SaveNonVolBig
Definition Win64EH.h:39
@ UOP_WideAllocMedium
Definition Win64EH.h:96
@ UOP_SaveAnyRegDX
Definition Win64EH.h:78
@ UOP_SaveFRegD0D15
Definition Win64EH.h:107
@ UOP_SaveAnyRegQP
Definition Win64EH.h:75
@ UOP_SaveAnyRegD
Definition Win64EH.h:72
@ UOP_WideSaveRegsR4R11LR
Definition Win64EH.h:103
@ UOP_SaveAnyRegIPX
Definition Win64EH.h:77
@ UOP_WideAllocHuge
Definition Win64EH.h:98
@ UOP_SaveAnyRegQX
Definition Win64EH.h:80
@ UOP_SaveAnyRegIX
Definition Win64EH.h:76
@ UOP_SaveXMM128Big
Definition Win64EH.h:43
@ UOP_SaveAnyRegQ
Definition Win64EH.h:74
@ UOP_SaveAnyRegDP
Definition Win64EH.h:73
@ UOP_SaveFRegD8D15
Definition Win64EH.h:104
@ UOP_PushMachFrame
Definition Win64EH.h:44
@ UOP_SaveR19R20X
Definition Win64EH.h:48
@ UOP_SaveAnyRegQPX
Definition Win64EH.h:81
@ UOP_WideAllocLarge
Definition Win64EH.h:97
@ UOP_WideSaveRegMask
Definition Win64EH.h:100
@ UOP_AllocMedium
Definition Win64EH.h:47
@ UOP_SaveAnyRegIP
Definition Win64EH.h:71
@ UOP_SaveFRegD16D31
Definition Win64EH.h:108
@ UOP_SaveAnyRegI
Definition Win64EH.h:70
@ WOD_SAVE_XMM128_FAR
Definition Win64EH.h:251
@ WOD_PUSH_CANONICAL_FRAME
Definition Win64EH.h:245
@ WOD_PUSH_CONSECUTIVE_2
Definition Win64EH.h:249
@ WOD_SAVE_NONVOL_FAR
Definition Win64EH.h:247
void EncodeWOD(const WinEH::Instruction &Inst, SmallVectorImpl< uint8_t > &Out)
Encode a single WinEH::Instruction as V3 WOD bytes.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:558
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
auto reverse_conditionally(ContainerTy &&C, bool ShouldReverse)
Return a range that conditionally reverses C.
Definition STLExtras.h:1422
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
@ FK_Data_1
A one-byte fixup.
Definition MCFixup.h:34
@ FK_Data_2
A two-byte fixup.
Definition MCFixup.h:35
DWARFExpression::Operation Op
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
MapVector< MCSymbol *, int64_t > Epilogs
Definition MCWinEH.h:86
const MCSymbol * Function
Definition MCWinEH.h:51
const MCSymbol * End
Definition MCWinEH.h:48
const MCSymbol * Label
Definition MCWinEH.h:24