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"
19
20namespace llvm {
21class MCSection;
22}
23
24using namespace llvm;
25
26namespace {
27/// MCExpr that represents the epilog unwind code in an unwind table.
28class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr {
29 const WinEH::FrameInfo &FrameInfo;
30 const MCSymbol *UnwindV2Start;
31 const MCSymbol *EpilogEnd;
32 uint8_t EpilogSize;
33 SMLoc Loc;
34
35 MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo &FrameInfo,
36 const WinEH::FrameInfo::Epilog &Epilog,
37 uint8_t EpilogSize_)
38 : FrameInfo(FrameInfo), UnwindV2Start(Epilog.UnwindV2Start),
39 EpilogEnd(Epilog.End), EpilogSize(EpilogSize_), Loc(Epilog.Loc) {
40 assert(UnwindV2Start && "Epilog must have a start");
41 assert(EpilogEnd && "Epilog must have an end");
42 }
43
44public:
45 static MCUnwindV2EpilogTargetExpr *
46 create(const WinEH::FrameInfo &FrameInfo,
47 const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_,
48 MCContext &Ctx) {
49 return new (Ctx) MCUnwindV2EpilogTargetExpr(FrameInfo, Epilog, EpilogSize_);
50 }
51
52 void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
53 OS << ":epilog:";
54 UnwindV2Start->print(OS, MAI);
55 }
56
57 bool evaluateAsRelocatableImpl(MCValue &Res,
58 const MCAssembler *Asm) const override;
59
60 void visitUsedExpr(MCStreamer &Streamer) const override {
61 // Contains no sub-expressions.
62 }
63
64 MCFragment *findAssociatedFragment() const override {
65 return UnwindV2Start->getFragment();
66 }
67};
68} // namespace
69
70// NOTE: All relocations generated here are 4-byte image-relative.
71
72static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
73 uint8_t Count = 0;
74 for (const auto &I : Insns) {
75 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
76 default:
77 llvm_unreachable("Unsupported unwind code");
82 Count += 1;
83 break;
86 Count += 2;
87 break;
90 Count += 3;
91 break;
93 Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
94 break;
95 }
96 }
97 return Count;
98}
99
100static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
101 const MCSymbol *RHS) {
102 MCContext &Context = Streamer.getContext();
103 const MCExpr *Diff =
105 MCSymbolRefExpr::create(RHS, Context), Context);
106 Streamer.emitValue(Diff, 1);
107}
108
109static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
110 WinEH::Instruction &inst) {
111 uint8_t b2;
112 uint16_t w;
113 b2 = (inst.Operation & 0x0F);
114 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
115 default:
116 llvm_unreachable("Unsupported unwind code");
118 EmitAbsDifference(streamer, inst.Label, begin);
119 b2 |= (inst.Register & 0x0F) << 4;
120 streamer.emitInt8(b2);
121 break;
123 EmitAbsDifference(streamer, inst.Label, begin);
124 if (inst.Offset > 512 * 1024 - 8) {
125 b2 |= 0x10;
126 streamer.emitInt8(b2);
127 w = inst.Offset & 0xFFF8;
128 streamer.emitInt16(w);
129 w = inst.Offset >> 16;
130 } else {
131 streamer.emitInt8(b2);
132 w = inst.Offset >> 3;
133 }
134 streamer.emitInt16(w);
135 break;
137 b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
138 EmitAbsDifference(streamer, inst.Label, begin);
139 streamer.emitInt8(b2);
140 break;
142 EmitAbsDifference(streamer, inst.Label, begin);
143 streamer.emitInt8(b2);
144 break;
147 b2 |= (inst.Register & 0x0F) << 4;
148 EmitAbsDifference(streamer, inst.Label, begin);
149 streamer.emitInt8(b2);
150 w = inst.Offset >> 3;
152 w >>= 1;
153 streamer.emitInt16(w);
154 break;
157 b2 |= (inst.Register & 0x0F) << 4;
158 EmitAbsDifference(streamer, inst.Label, begin);
159 streamer.emitInt8(b2);
161 w = inst.Offset & 0xFFF0;
162 else
163 w = inst.Offset & 0xFFF8;
164 streamer.emitInt16(w);
165 w = inst.Offset >> 16;
166 streamer.emitInt16(w);
167 break;
169 if (inst.Offset == 1)
170 b2 |= 0x10;
171 EmitAbsDifference(streamer, inst.Label, begin);
172 streamer.emitInt8(b2);
173 break;
174 }
175}
176
177static void EmitSymbolRefWithOfs(MCStreamer &streamer,
178 const MCSymbol *Base,
179 int64_t Offset) {
180 MCContext &Context = streamer.getContext();
181 const MCConstantExpr *OffExpr = MCConstantExpr::create(Offset, Context);
182 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
184 Context);
185 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, OffExpr, Context), 4);
186}
187
188static void EmitSymbolRefWithOfs(MCStreamer &streamer,
189 const MCSymbol *Base,
190 const MCSymbol *Other) {
191 MCContext &Context = streamer.getContext();
192 const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
193 const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
194 const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
195 const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
197 Context);
198 streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
199}
200
201static void EmitRuntimeFunction(MCStreamer &streamer,
202 const WinEH::FrameInfo *info) {
203 MCContext &context = streamer.getContext();
204
205 streamer.emitValueToAlignment(Align(4));
206 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
207 EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
208 streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
210 context), 4);
211}
212
213static std::optional<int64_t>
215 const MCSymbol *RHS) {
216 MCContext &Context = Assembler.getContext();
217 const MCExpr *Diff =
219 MCSymbolRefExpr::create(RHS, Context), Context);
220 // It should normally be possible to calculate the length of a function
221 // at this point, but it might not be possible in the presence of certain
222 // unusual constructs, like an inline asm with an alignment directive.
223 int64_t value;
224 if (!Diff->evaluateAsAbsolute(value, Assembler))
225 return std::nullopt;
226 return value;
227}
228
230 // If this UNWIND_INFO already has a symbol, it's already been emitted.
231 if (info->Symbol)
232 return;
233
234 MCContext &context = streamer.getContext();
235 MCObjectStreamer *OS = (MCObjectStreamer *)(&streamer);
236 MCSymbol *Label = context.createTempSymbol();
237
238 streamer.emitValueToAlignment(Align(4));
239 streamer.emitLabel(Label);
240 info->Symbol = Label;
241
242 uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
243 bool LastEpilogIsAtEnd = false;
244 bool AddPaddingEpilogCode = false;
245 uint8_t EpilogSize = 0;
246 bool EnableUnwindV2 = (info->Version >= 2) && !info->EpilogMap.empty();
247 if (EnableUnwindV2) {
248 auto &LastEpilog = info->EpilogMap.back().second;
249
250 // Calculate the size of the epilogs. Note that we +1 to the size so that
251 // the terminator instruction is also included in the epilog (the Windows
252 // unwinder does a simple range check versus the current instruction pointer
253 // so, although there are terminators that are large than 1 byte, the
254 // starting address of the terminator instruction will always be considered
255 // inside the epilog).
256 assert(
257 LastEpilog.UnwindV2Start &&
258 "If unwind v2 is enabled, epilog must have a unwind v2 start marker");
259 assert(LastEpilog.End && "Epilog must have an end");
260 auto MaybeSize = GetOptionalAbsDifference(
261 OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start);
262 if (!MaybeSize) {
263 context.reportError(LastEpilog.Loc,
264 "Failed to evaluate epilog size for Unwind v2 in " +
265 info->Function->getName());
266 return;
267 }
268 assert(*MaybeSize >= 0);
269 if (*MaybeSize >= (int64_t)UINT8_MAX) {
270 context.reportError(LastEpilog.Loc,
271 "Epilog size is too large for Unwind v2 in " +
272 info->Function->getName());
273 return;
274 }
275 EpilogSize = *MaybeSize + 1;
276
277 // If the last epilog is at the end of the function, we can use a special
278 // encoding for it. Because of our +1 trick for the size, this will only
279 // work where that final terminator instruction is 1 byte long.
280 // NOTE: At the point where the unwind info is emitted, the function may not
281 // have ended yet (e.g., if there is EH Handler Data), so assume that we
282 // aren't at the end (since we can't calculate it).
283 if (info->End) {
284 auto LastEpilogToFuncEnd = GetOptionalAbsDifference(
285 OS->getAssembler(), info->End, LastEpilog.UnwindV2Start);
286 LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize);
287 }
288
289 // If we have an odd number of epilog codes, we need to add a padding code.
290 size_t numEpilogCodes =
291 info->EpilogMap.size() + (LastEpilogIsAtEnd ? 0 : 1);
292 if ((numEpilogCodes % 2) != 0) {
293 AddPaddingEpilogCode = true;
294 numEpilogCodes++;
295 }
296
297 // Too many epilogs to handle.
298 if ((size_t)numCodes + numEpilogCodes > UINT8_MAX) {
299 context.reportError(info->FunctionLoc,
300 "Too many unwind codes with Unwind v2 enabled in " +
301 info->Function->getName());
302 return;
303 }
304
305 numCodes += numEpilogCodes;
306 }
307
308 // Upper 3 bits are the version number.
309 uint8_t flags = info->Version;
310 if (info->ChainedParent)
311 flags |= Win64EH::UNW_ChainInfo << 3;
312 else {
313 if (info->HandlesUnwind)
314 flags |= Win64EH::UNW_TerminateHandler << 3;
315 if (info->HandlesExceptions)
316 flags |= Win64EH::UNW_ExceptionHandler << 3;
317 }
318 streamer.emitInt8(flags);
319
320 if (info->PrologEnd)
321 EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
322 else
323 streamer.emitInt8(0);
324
325 streamer.emitInt8(numCodes);
326
327 uint8_t frame = 0;
328 if (info->LastFrameInst >= 0) {
329 WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
331 frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
332 }
333 streamer.emitInt8(frame);
334
335 // Emit the epilog instructions.
336 if (EnableUnwindV2) {
337 // Ensure the fixups and appended content apply to the same fragment.
338 OS->ensureHeadroom(info->EpilogMap.size() * 2);
339
340 bool IsLast = true;
341 for (const auto &Epilog : llvm::reverse(info->EpilogMap)) {
342 if (IsLast) {
343 IsLast = false;
344 uint8_t Flags = LastEpilogIsAtEnd ? 0x01 : 0;
345 OS->emitInt8(EpilogSize);
346 OS->emitInt8((Flags << 4) | Win64EH::UOP_Epilog);
347
348 if (LastEpilogIsAtEnd)
349 continue;
350 }
351
352 // Each epilog is emitted as a fixup, since we can't measure the distance
353 // between the start of the epilog and the end of the function until
354 // layout has been completed.
355 auto *MCE = MCUnwindV2EpilogTargetExpr::create(*info, Epilog.second,
356 EpilogSize, context);
357 OS->addFixup(MCE, FK_Data_2);
358 OS->appendContents(2, 0);
359 }
360 }
361 if (AddPaddingEpilogCode)
362 streamer.emitInt16(Win64EH::UOP_Epilog << 8);
363
364 // Emit unwind instructions (in reverse order).
365 uint8_t numInst = info->Instructions.size();
366 for (uint8_t c = 0; c < numInst; ++c) {
367 WinEH::Instruction inst = info->Instructions.back();
368 info->Instructions.pop_back();
369 EmitUnwindCode(streamer, info->Begin, inst);
370 }
371
372 // For alignment purposes, the instruction array will always have an even
373 // number of entries, with the final entry potentially unused (in which case
374 // the array will be one longer than indicated by the count of unwind codes
375 // field).
376 if (numCodes & 1) {
377 streamer.emitInt16(0);
378 }
379
380 if (flags & (Win64EH::UNW_ChainInfo << 3))
381 EmitRuntimeFunction(streamer, info->ChainedParent);
382 else if (flags &
384 streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
386 context), 4);
387 else if (numCodes == 0) {
388 // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
389 // a chained unwind info, if there is no handler, and if there are fewer
390 // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
391 streamer.emitInt32(0);
392 }
393}
394
395bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl(
396 MCValue &Res, const MCAssembler *Asm) const {
397 // Calculate the offset to this epilog, and validate it's within the allowed
398 // range.
399 auto Offset = GetOptionalAbsDifference(*Asm, FrameInfo.End, UnwindV2Start);
400 if (!Offset) {
401 Asm->getContext().reportError(
402 Loc, "Failed to evaluate epilog offset for Unwind v2 in " +
403 FrameInfo.Function->getName());
404 return false;
405 }
406 assert(*Offset > 0);
407 constexpr uint16_t MaxEpilogOffset = 0x0fff;
408 if (*Offset > MaxEpilogOffset) {
409 Asm->getContext().reportError(
410 Loc, "Epilog offset is too large for Unwind v2 in " +
411 FrameInfo.Function->getName());
412 return false;
413 }
414
415 // Validate that all epilogs are the same size.
416 auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start);
417 if (Size != (EpilogSize - 1)) {
418 Asm->getContext().reportError(
419 Loc, "Size of this epilog does not match size of last epilog in " +
420 FrameInfo.Function->getName());
421 return false;
422 }
423
424 auto HighBits = *Offset >> 8;
425 Res = MCValue::get((HighBits << 12) | (Win64EH::UOP_Epilog << 8) |
426 (*Offset & 0xFF));
427 return true;
428}
429
431 // Emit the unwind info structs first.
432 for (const auto &CFI : Streamer.getWinFrameInfos()) {
433 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
434 Streamer.switchSection(XData);
435 ::EmitUnwindInfo(Streamer, CFI.get());
436 }
437
438 // Now emit RUNTIME_FUNCTION entries.
439 for (const auto &CFI : Streamer.getWinFrameInfos()) {
440 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
441 Streamer.switchSection(PData);
442 EmitRuntimeFunction(Streamer, CFI.get());
443 }
444}
445
448 bool HandlerData) const {
449 // Switch sections (the static function above is meant to be called from
450 // here and from Emit().
451 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
452 Streamer.switchSection(XData);
453
454 ::EmitUnwindInfo(Streamer, info);
455}
456
457static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
458 const MCSymbol *RHS, int Div) {
459 MCContext &Context = Streamer.getContext();
460 const MCExpr *Expr =
462 MCSymbolRefExpr::create(RHS, Context), Context);
463 if (Div != 1)
464 Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(Div, Context),
465 Context);
466 return Expr;
467}
468
469static std::optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
470 const MCSymbol *LHS,
471 const MCSymbol *RHS) {
472 MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
474}
475
476static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
477 const MCSymbol *RHS) {
478 std::optional<int64_t> MaybeDiff =
479 GetOptionalAbsDifference(Streamer, LHS, RHS);
480 if (!MaybeDiff)
481 report_fatal_error("Failed to evaluate function length in SEH unwind info");
482 return *MaybeDiff;
483}
484
485static void checkARM64Instructions(MCStreamer &Streamer,
487 const MCSymbol *Begin, const MCSymbol *End,
488 StringRef Name, StringRef Type) {
489 if (!End)
490 return;
491 std::optional<int64_t> MaybeDistance =
492 GetOptionalAbsDifference(Streamer, End, Begin);
493 if (!MaybeDistance)
494 return;
495 uint32_t Distance = (uint32_t)*MaybeDistance;
496
497 for (const auto &I : Insns) {
498 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
499 default:
500 break;
506 // Can't reason about these opcodes and how they map to actual
507 // instructions.
508 return;
509 }
510 }
511 // Exclude the end opcode which doesn't map to an instruction.
512 uint32_t InstructionBytes = 4 * (Insns.size() - 1);
513 if (Distance != InstructionBytes) {
514 Streamer.getContext().reportError(
515 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
516 Twine(Distance) +
517 " bytes of instructions in range, but .seh directives "
518 "corresponding to " +
519 Twine(InstructionBytes) + " bytes\n");
520 }
521}
522
524 uint32_t Count = 0;
525 for (const auto &I : Insns) {
526 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
527 default:
528 llvm_unreachable("Unsupported ARM64 unwind code");
530 Count += 1;
531 break;
533 Count += 2;
534 break;
536 Count += 4;
537 break;
539 Count += 1;
540 break;
542 Count += 1;
543 break;
545 Count += 1;
546 break;
548 Count += 2;
549 break;
551 Count += 2;
552 break;
554 Count += 2;
555 break;
557 Count += 2;
558 break;
560 Count += 2;
561 break;
563 Count += 2;
564 break;
566 Count += 2;
567 break;
569 Count += 2;
570 break;
572 Count += 2;
573 break;
575 Count += 1;
576 break;
578 Count += 2;
579 break;
580 case Win64EH::UOP_Nop:
581 Count += 1;
582 break;
583 case Win64EH::UOP_End:
584 Count += 1;
585 break;
587 Count += 1;
588 break;
590 Count += 1;
591 break;
593 Count += 1;
594 break;
596 Count += 1;
597 break;
599 Count += 1;
600 break;
602 Count += 1;
603 break;
605 Count += 1;
606 break;
608 Count += 2;
609 break;
624 Count += 3;
625 break;
626 }
627 }
628 return Count;
629}
630
631// Unwind opcode encodings and restrictions are documented at
632// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
633static void ARM64EmitUnwindCode(MCStreamer &streamer,
634 const WinEH::Instruction &inst) {
635 uint8_t b, reg;
636 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
637 default:
638 llvm_unreachable("Unsupported ARM64 unwind code");
640 b = (inst.Offset >> 4) & 0x1F;
641 streamer.emitInt8(b);
642 break;
644 uint16_t hw = (inst.Offset >> 4) & 0x7FF;
645 b = 0xC0;
646 b |= (hw >> 8);
647 streamer.emitInt8(b);
648 b = hw & 0xFF;
649 streamer.emitInt8(b);
650 break;
651 }
653 uint32_t w;
654 b = 0xE0;
655 streamer.emitInt8(b);
656 w = inst.Offset >> 4;
657 b = (w & 0x00FF0000) >> 16;
658 streamer.emitInt8(b);
659 b = (w & 0x0000FF00) >> 8;
660 streamer.emitInt8(b);
661 b = w & 0x000000FF;
662 streamer.emitInt8(b);
663 break;
664 }
666 b = 0xE1;
667 streamer.emitInt8(b);
668 break;
670 b = 0xE2;
671 streamer.emitInt8(b);
672 b = (inst.Offset >> 3);
673 streamer.emitInt8(b);
674 break;
675 case Win64EH::UOP_Nop:
676 b = 0xE3;
677 streamer.emitInt8(b);
678 break;
680 b = 0x20;
681 b |= (inst.Offset >> 3) & 0x1F;
682 streamer.emitInt8(b);
683 break;
685 b = 0x80;
686 b |= ((inst.Offset >> 3) - 1) & 0x3F;
687 streamer.emitInt8(b);
688 break;
690 b = 0x40;
691 b |= (inst.Offset >> 3) & 0x3F;
692 streamer.emitInt8(b);
693 break;
695 assert(inst.Register >= 19 && "Saved reg must be >= 19");
696 reg = inst.Register - 19;
697 b = 0xD0 | ((reg & 0xC) >> 2);
698 streamer.emitInt8(b);
699 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
700 streamer.emitInt8(b);
701 break;
703 assert(inst.Register >= 19 && "Saved reg must be >= 19");
704 reg = inst.Register - 19;
705 b = 0xD4 | ((reg & 0x8) >> 3);
706 streamer.emitInt8(b);
707 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
708 streamer.emitInt8(b);
709 break;
711 assert(inst.Register >= 19 && "Saved registers must be >= 19");
712 reg = inst.Register - 19;
713 b = 0xC8 | ((reg & 0xC) >> 2);
714 streamer.emitInt8(b);
715 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
716 streamer.emitInt8(b);
717 break;
719 assert(inst.Register >= 19 && "Saved registers must be >= 19");
720 reg = inst.Register - 19;
721 b = 0xCC | ((reg & 0xC) >> 2);
722 streamer.emitInt8(b);
723 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
724 streamer.emitInt8(b);
725 break;
727 assert(inst.Register >= 19 && "Saved reg must be >= 19");
728 reg = inst.Register - 19;
729 assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
730 reg /= 2;
731 b = 0xD6 | ((reg & 0x7) >> 2);
732 streamer.emitInt8(b);
733 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
734 streamer.emitInt8(b);
735 break;
737 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
738 reg = inst.Register - 8;
739 b = 0xDC | ((reg & 0x4) >> 2);
740 streamer.emitInt8(b);
741 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
742 streamer.emitInt8(b);
743 break;
745 assert(inst.Register >= 8 && "Saved dreg must be >= 8");
746 reg = inst.Register - 8;
747 b = 0xDE;
748 streamer.emitInt8(b);
749 b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
750 streamer.emitInt8(b);
751 break;
753 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
754 reg = inst.Register - 8;
755 b = 0xD8 | ((reg & 0x4) >> 2);
756 streamer.emitInt8(b);
757 b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
758 streamer.emitInt8(b);
759 break;
761 assert(inst.Register >= 8 && "Saved dregs must be >= 8");
762 reg = inst.Register - 8;
763 b = 0xDA | ((reg & 0x4) >> 2);
764 streamer.emitInt8(b);
765 b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
766 streamer.emitInt8(b);
767 break;
768 case Win64EH::UOP_End:
769 b = 0xE4;
770 streamer.emitInt8(b);
771 break;
773 b = 0xE6;
774 streamer.emitInt8(b);
775 break;
777 b = 0xE8;
778 streamer.emitInt8(b);
779 break;
781 b = 0xE9;
782 streamer.emitInt8(b);
783 break;
785 b = 0xEA;
786 streamer.emitInt8(b);
787 break;
789 b = 0xEB;
790 streamer.emitInt8(b);
791 break;
793 b = 0xEC;
794 streamer.emitInt8(b);
795 break;
797 b = 0xFC;
798 streamer.emitInt8(b);
799 break;
812 // This assumes the opcodes are listed in the enum in a particular order.
814 int Writeback = Op / 6;
815 int Paired = Op % 2;
816 int Mode = (Op / 2) % 3;
817 int Offset = inst.Offset >> 3;
818 if (Writeback || Paired || Mode == 2)
819 Offset >>= 1;
820 if (Writeback)
821 --Offset;
822 b = 0xE7;
823 streamer.emitInt8(b);
824 assert(inst.Register < 32);
825 b = inst.Register | (Writeback << 5) | (Paired << 6);
826 streamer.emitInt8(b);
827 b = Offset | (Mode << 6);
828 streamer.emitInt8(b);
829 break;
830 }
831 case Win64EH::UOP_AllocZ: {
832 b = 0xDF;
833 streamer.emitInt8(b);
834 b = inst.Offset;
835 streamer.emitInt8(b);
836 break;
837 }
839 assert(inst.Register >= 8 && inst.Register <= 23);
840 assert(inst.Offset < 256);
841 b = 0xE7;
842 streamer.emitInt8(b);
843 reg = inst.Register - 8;
844 b = ((inst.Offset & 0xC0) >> 1) | reg;
845 streamer.emitInt8(b);
846 b = 0xC0 | (inst.Offset & 0x3F);
847 streamer.emitInt8(b);
848 break;
849 }
851 assert(inst.Register >= 4 && inst.Register <= 15);
852 assert(inst.Offset < 256);
853 b = 0xE7;
854 streamer.emitInt8(b);
855 reg = inst.Register;
856 b = ((inst.Offset & 0xC0) >> 1) | 0x10 | reg;
857 streamer.emitInt8(b);
858 b = 0xC0 | (inst.Offset & 0x3F);
859 streamer.emitInt8(b);
860 break;
861 }
862 }
863}
864
865// Returns the epilog symbol of an epilog with the exact same unwind code
866// sequence, if it exists. Otherwise, returns nullptr.
867// EpilogInstrs - Unwind codes for the current epilog.
868// Epilogs - Epilogs that potentialy match the current epilog.
869static MCSymbol*
870FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
871 const std::vector<MCSymbol *>& Epilogs,
872 const WinEH::FrameInfo *info) {
873 for (auto *EpilogStart : Epilogs) {
874 auto InstrsIter = info->EpilogMap.find(EpilogStart);
875 assert(InstrsIter != info->EpilogMap.end() &&
876 "Epilog not found in EpilogMap");
877 const auto &Instrs = InstrsIter->second.Instructions;
878
879 if (Instrs.size() != EpilogInstrs.size())
880 continue;
881
882 bool Match = true;
883 for (unsigned i = 0; i < Instrs.size(); ++i)
884 if (Instrs[i] != EpilogInstrs[i]) {
885 Match = false;
886 break;
887 }
888
889 if (Match)
890 return EpilogStart;
891 }
892 return nullptr;
893}
894
895static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
896 bool Reverse) {
897 unsigned PrevOffset = -1;
898 unsigned PrevRegister = -1;
899
900 // Iterate over instructions in a forward order (for prologues),
901 // backwards for epilogues (i.e. always reverse compared to how the
902 // opcodes are stored).
903 for (WinEH::Instruction &Inst :
904 llvm::reverse_conditionally(Instructions, Reverse)) {
905 // Convert 2-byte opcodes into equivalent 1-byte ones.
906 if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
907 Inst.Operation = Win64EH::UOP_SaveFPLR;
908 Inst.Register = -1;
909 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
910 Inst.Register == 29) {
911 Inst.Operation = Win64EH::UOP_SaveFPLRX;
912 Inst.Register = -1;
913 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
914 Inst.Register == 19 && Inst.Offset <= 248) {
915 Inst.Operation = Win64EH::UOP_SaveR19R20X;
916 Inst.Register = -1;
917 } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
918 Inst.Operation = Win64EH::UOP_SetFP;
919 } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
920 Inst.Register == PrevRegister + 2 &&
921 Inst.Offset == PrevOffset + 16) {
922 Inst.Operation = Win64EH::UOP_SaveNext;
923 Inst.Register = -1;
924 Inst.Offset = 0;
925 // Intentionally not creating UOP_SaveNext for float register pairs,
926 // as current versions of Windows (up to at least 20.04) is buggy
927 // regarding SaveNext for float pairs.
928 }
929 // Update info about the previous instruction, for detecting if
930 // the next one can be made a UOP_SaveNext
931 if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
932 PrevOffset = 0;
933 PrevRegister = 19;
934 } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
935 PrevOffset = 0;
936 PrevRegister = Inst.Register;
937 } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
938 PrevOffset = Inst.Offset;
939 PrevRegister = Inst.Register;
940 } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
941 PrevRegister += 2;
942 PrevOffset += 16;
943 } else {
944 PrevRegister = -1;
945 PrevOffset = -1;
946 }
947 }
948}
949
950// Check if an epilog exists as a subset of the end of a prolog (backwards).
951static int
952getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
953 const std::vector<WinEH::Instruction> &Epilog) {
954 // Can't find an epilog as a subset if it is longer than the prolog.
955 if (Epilog.size() > Prolog.size())
956 return -1;
957
958 // Check that the epilog actually is a perfect match for the end (backwrds)
959 // of the prolog.
960 for (int I = Epilog.size() - 1; I >= 0; I--) {
961 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
962 return -1;
963 }
964
965 if (Epilog.size() == Prolog.size())
966 return 0;
967
968 // If the epilog was a subset of the prolog, find its offset.
970 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
971}
972
975 int PrologCodeBytes) {
976 // Can only pack if there's one single epilog
977 if (Seg->Epilogs.size() != 1)
978 return -1;
979
980 MCSymbol *Sym = Seg->Epilogs.begin()->first;
981 const std::vector<WinEH::Instruction> &Epilog =
982 info->EpilogMap[Sym].Instructions;
983
984 // Check that the epilog actually is at the very end of the function,
985 // otherwise it can't be packed.
986 uint32_t DistanceFromEnd =
987 (uint32_t)(Seg->Offset + Seg->Length - Seg->Epilogs.begin()->second);
988 if (DistanceFromEnd / 4 != Epilog.size())
989 return -1;
990
991 int RetVal = -1;
992 // Even if we don't end up sharing opcodes with the prolog, we can still
993 // write the offset as a packed offset, if the single epilog is located at
994 // the end of the function and the offset (pointing after the prolog) fits
995 // as a packed offset.
996 if (PrologCodeBytes <= 31 &&
997 PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
998 RetVal = PrologCodeBytes;
999
1000 int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
1001 if (Offset < 0)
1002 return RetVal;
1003
1004 // Check that the offset and prolog size fits in the first word; it's
1005 // unclear whether the epilog count in the extension word can be taken
1006 // as packed epilog offset.
1007 if (Offset > 31 || PrologCodeBytes > 124)
1008 return RetVal;
1009
1010 // As we choose to express the epilog as part of the prolog, remove the
1011 // epilog from the map, so we don't try to emit its opcodes.
1012 info->EpilogMap.erase(Sym);
1013 return Offset;
1014}
1015
1017 int PackedEpilogOffset) {
1018 if (PackedEpilogOffset == 0) {
1019 // Fully symmetric prolog and epilog, should be ok for packed format.
1020 // For CR=3, the corresponding synthesized epilog actually lacks the
1021 // SetFP opcode, but unwinding should work just fine despite that
1022 // (if at the SetFP opcode, the unwinder considers it as part of the
1023 // function body and just unwinds the full prolog instead).
1024 } else if (PackedEpilogOffset == 1) {
1025 // One single case of differences between prolog and epilog is allowed:
1026 // The epilog can lack a single SetFP that is the last opcode in the
1027 // prolog, for the CR=3 case.
1028 if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
1029 return false;
1030 } else {
1031 // Too much difference between prolog and epilog.
1032 return false;
1033 }
1034 unsigned RegI = 0, RegF = 0;
1035 int Predecrement = 0;
1036 enum {
1037 Start,
1038 Start2,
1039 Start3,
1040 IntRegs,
1041 FloatRegs,
1042 InputArgs,
1043 StackAdjust,
1044 FrameRecord,
1045 End
1046 } Location = Start;
1047 bool StandaloneLR = false, FPLRPair = false;
1048 bool PAC = false;
1049 int StackOffset = 0;
1050 int Nops = 0;
1051 // Iterate over the prolog and check that all opcodes exactly match
1052 // the canonical order and form. A more lax check could verify that
1053 // all saved registers are in the expected locations, but not enforce
1054 // the order - that would work fine when unwinding from within
1055 // functions, but not be exactly right if unwinding happens within
1056 // prologs/epilogs.
1057 for (auto It = info->Instructions.begin(), EndIt = info->Instructions.end();
1058 It != EndIt; It++) {
1059 const WinEH::Instruction &Inst = *It;
1060 switch (Inst.Operation) {
1061 case Win64EH::UOP_End:
1062 if (Location != Start)
1063 return false;
1064 Location = Start2;
1065 break;
1067 if (Location != Start2)
1068 return false;
1069 PAC = true;
1070 Location = Start3;
1071 break;
1073 if (Location != Start2 && Location != Start3)
1074 return false;
1075 Predecrement = Inst.Offset;
1076 RegI = 2;
1077 Location = IntRegs;
1078 break;
1080 if (Location != Start2 && Location != Start3)
1081 return false;
1082 Predecrement = Inst.Offset;
1083 if (Inst.Register == 19)
1084 RegI += 1;
1085 else if (Inst.Register == 30)
1086 StandaloneLR = true;
1087 else
1088 return false;
1089 // Odd register; can't be any further int registers.
1090 Location = FloatRegs;
1091 break;
1093 // Can't have this in a canonical prologue. Either this has been
1094 // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
1095 // register pair.
1096 // It can't be canonicalized into SaveR19R20X if the offset is
1097 // larger than 248 bytes, but even with the maximum case with
1098 // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
1099 // fit into SaveR19R20X.
1100 // The unwinding opcodes can't describe the otherwise seemingly valid
1101 // case for RegI=1 CR=1, that would start with a
1102 // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
1103 // SaveLRPair.
1104 return false;
1106 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1107 Inst.Register != 19 + RegI)
1108 return false;
1109 RegI += 2;
1110 break;
1112 if (Location != IntRegs || Inst.Offset != 8 * RegI)
1113 return false;
1114 if (Inst.Register == 19 + RegI)
1115 RegI += 1;
1116 else if (Inst.Register == 30)
1117 StandaloneLR = true;
1118 else
1119 return false;
1120 // Odd register; can't be any further int registers.
1121 Location = FloatRegs;
1122 break;
1124 if (Location != IntRegs || Inst.Offset != 8 * RegI ||
1125 Inst.Register != 19 + RegI)
1126 return false;
1127 RegI += 1;
1128 StandaloneLR = true;
1129 Location = FloatRegs;
1130 break;
1132 // Packed unwind can't handle prologs that only save one single
1133 // float register.
1134 return false;
1136 if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
1137 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1138 return false;
1139 RegF += 1;
1140 Location = InputArgs;
1141 break;
1143 if ((Location != Start2 && Location != Start3) || Inst.Register != 8)
1144 return false;
1145 Predecrement = Inst.Offset;
1146 RegF = 2;
1147 Location = FloatRegs;
1148 break;
1150 if ((Location != IntRegs && Location != FloatRegs) ||
1151 Inst.Register != 8 + RegF ||
1152 Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1153 return false;
1154 RegF += 2;
1155 Location = FloatRegs;
1156 break;
1158 if (Location == IntRegs)
1159 RegI += 2;
1160 else if (Location == FloatRegs)
1161 RegF += 2;
1162 else
1163 return false;
1164 break;
1165 case Win64EH::UOP_Nop:
1166 if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
1167 return false;
1168 Location = InputArgs;
1169 Nops++;
1170 break;
1173 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1174 Location != FloatRegs && Location != InputArgs &&
1175 Location != StackAdjust)
1176 return false;
1177 // Becuase there's no save_lrpair_x opcode, the case of CR=01,
1178 // RegI=1 is handled as a special case with a pair of instructions; an
1179 // alloc followed by a regular save_lrpair. So when encountering an
1180 // alloc here, check if this is the start of such an instruction pair.
1181 if (Location == Start2) { // Can't have this at Start3, after PACSignLR
1182 auto NextIt = It + 1;
1183 if (NextIt != EndIt) {
1184 const WinEH::Instruction &NextInst = *NextIt;
1185 if (NextInst.Operation == Win64EH::UOP_SaveLRPair &&
1186 NextInst.Offset == 0 && NextInst.Register == 19) {
1187 assert(Predecrement == 0);
1188 assert(RegI == 0);
1189 assert(!StandaloneLR);
1190 Predecrement = Inst.Offset;
1191 RegI = 1;
1192 StandaloneLR = true;
1193 Location = FloatRegs;
1194 It++; // Consume both the Alloc and the SaveLRPair
1195 continue;
1196 }
1197 }
1198 }
1199 // Can have either a single decrement, or a pair of decrements with
1200 // 4080 and another decrement.
1201 if (StackOffset == 0)
1202 StackOffset = Inst.Offset;
1203 else if (StackOffset != 4080)
1204 return false;
1205 else
1206 StackOffset += Inst.Offset;
1207 Location = StackAdjust;
1208 break;
1210 // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
1211 // should be followed by a FPLR instead.
1212 if (Location != Start2 && Location != Start3 && Location != IntRegs &&
1213 Location != FloatRegs && Location != InputArgs)
1214 return false;
1215 StackOffset = Inst.Offset;
1216 Location = FrameRecord;
1217 FPLRPair = true;
1218 break;
1220 // This can only follow after a StackAdjust
1221 if (Location != StackAdjust || Inst.Offset != 0)
1222 return false;
1223 Location = FrameRecord;
1224 FPLRPair = true;
1225 break;
1226 case Win64EH::UOP_SetFP:
1227 if (Location != FrameRecord)
1228 return false;
1229 Location = End;
1230 break;
1243 // These are never canonical; they don't show up with the usual Arm64
1244 // calling convention.
1245 return false;
1247 // Allocations this large can't be represented in packed unwind (and
1248 // usually don't fit the canonical form anyway because we need to use
1249 // __chkstk to allocate the stack space).
1250 return false;
1251 case Win64EH::UOP_AddFP:
1252 // "add x29, sp, #N" doesn't show up in the canonical pattern (except for
1253 // N=0, which is UOP_SetFP).
1254 return false;
1258 // Canonical prologues don't support spilling SVE registers.
1259 return false;
1265 // These are special opcodes that aren't normally generated.
1266 return false;
1267 default:
1268 report_fatal_error("Unknown Arm64 unwind opcode");
1269 }
1270 }
1271 if (RegI > 10 || RegF > 8)
1272 return false;
1273 if (StandaloneLR && FPLRPair)
1274 return false;
1275 if (FPLRPair && Location != End)
1276 return false;
1277 if (Nops != 0 && Nops != 4)
1278 return false;
1279 if (PAC && !FPLRPair)
1280 return false;
1281 int H = Nops == 4;
1282 // For packed unwind info with the H bit set, the prolog and epilog
1283 // actually shouldn't be symmetrical; the epilog shouldn't have any
1284 // nop instructions/opcodes while the prolog has them. We currently
1285 // require exactly symmetrical prologs/epilogs, which is wrong for this
1286 // case - therefore, don't emit packed unwind info for this case.
1287 // See https://github.com/llvm/llvm-project/issues/54879 for details.
1288 //
1289 // Additionally - older versions of Windows also deviated from the
1290 // documentation here; older versions of Windows (at least up until
1291 // 10.0.22000.2176) incorrectly did assume that the epilog has matching
1292 // nop instructions. This is fixed at least in version 10.0.26100.6899.
1293 // As long as we can't assume that the generated code always will run on
1294 // a new enough version, don't emit the packed format here, even if the
1295 // implementation would be fixed to match for the asymmetrical form
1296 // according to the documentation.
1297 if (H)
1298 return false;
1299 // Older versions of Windows (at least in 10.0.22000.2176) incorrectly
1300 // unwind packed unwind info with CR=01, RegI=1, RegF>0, see
1301 // https://github.com/llvm/llvm-project/issues/169588#issuecomment-3584907886.
1302 // This issue only exists in older versions; current versions
1303 // (10.0.26100.6899) do handle it correctly. As long as we can't be sure
1304 // that we won't run on older versions, avoid producing the packed form
1305 // here.
1306 if (StandaloneLR && RegI == 1 && RegF > 0)
1307 return false;
1308 int IntSZ = 8 * RegI;
1309 if (StandaloneLR)
1310 IntSZ += 8;
1311 int FpSZ = 8 * RegF; // RegF not yet decremented
1312 int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
1313 if (Predecrement != SavSZ)
1314 return false;
1315 if (FPLRPair && StackOffset < 16)
1316 return false;
1317 if (StackOffset % 16)
1318 return false;
1319 uint32_t FrameSize = (StackOffset + SavSZ) / 16;
1320 if (FrameSize > 0x1FF)
1321 return false;
1322 assert(RegF != 1 && "One single float reg not allowed");
1323 if (RegF > 0)
1324 RegF--; // Convert from actual number of registers, to value stored
1325 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
1326 int Flag = 0x01; // Function segments not supported yet
1327 int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0;
1328 info->PackedInfo |= Flag << 0;
1329 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1330 info->PackedInfo |= (RegF & 0x7) << 13;
1331 info->PackedInfo |= (RegI & 0xF) << 16;
1332 info->PackedInfo |= (H & 0x1) << 20;
1333 info->PackedInfo |= (CR & 0x3) << 21;
1334 info->PackedInfo |= (FrameSize & 0x1FF) << 23;
1335 return true;
1336}
1337
1340 uint32_t &TotalCodeBytes,
1341 MapVector<MCSymbol *, uint32_t> &EpilogInfo) {
1342
1343 std::vector<MCSymbol *> EpilogStarts;
1344 for (auto &I : Seg->Epilogs)
1345 EpilogStarts.push_back(I.first);
1346
1347 // Epilogs processed so far.
1348 std::vector<MCSymbol *> AddedEpilogs;
1349 for (auto *S : EpilogStarts) {
1350 MCSymbol *EpilogStart = S;
1351 auto &EpilogInstrs = info->EpilogMap[S].Instructions;
1352 uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
1353
1354 MCSymbol* MatchingEpilog =
1355 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
1356 int PrologOffset;
1357 if (MatchingEpilog) {
1358 assert(EpilogInfo.contains(MatchingEpilog) &&
1359 "Duplicate epilog not found");
1360 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
1361 // Clear the unwind codes in the EpilogMap, so that they don't get output
1362 // in ARM64EmitUnwindInfoForSegment().
1363 EpilogInstrs.clear();
1364 } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
1365 EpilogInstrs)) >= 0) {
1366 EpilogInfo[EpilogStart] = PrologOffset;
1367 // If the segment doesn't have a prolog, an end_c will be emitted before
1368 // prolog opcodes. So epilog start index in opcodes array is moved by 1.
1369 if (!Seg->HasProlog)
1370 EpilogInfo[EpilogStart] += 1;
1371 // Clear the unwind codes in the EpilogMap, so that they don't get output
1372 // in ARM64EmitUnwindInfoForSegment().
1373 EpilogInstrs.clear();
1374 } else {
1375 EpilogInfo[EpilogStart] = TotalCodeBytes;
1376 TotalCodeBytes += CodeBytes;
1377 AddedEpilogs.push_back(EpilogStart);
1378 }
1379 }
1380}
1381
1384 int64_t RawFuncLength) {
1385 if (info->PrologEnd)
1386 checkARM64Instructions(streamer, info->Instructions, info->Begin,
1387 info->PrologEnd, info->Function->getName(),
1388 "prologue");
1389 struct EpilogStartEnd {
1390 MCSymbol *Start;
1391 int64_t Offset;
1392 int64_t End;
1393 };
1394 // Record Start and End of each epilog.
1396 for (auto &I : info->EpilogMap) {
1397 MCSymbol *Start = I.first;
1398 auto &Instrs = I.second.Instructions;
1399 int64_t Offset = GetAbsDifference(streamer, Start, info->Begin);
1400 checkARM64Instructions(streamer, Instrs, Start, I.second.End,
1401 info->Function->getName(), "epilogue");
1402 assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) &&
1403 "Epilogs should be monotonically ordered");
1404 // Exclue the end opcode from Instrs.size() when calculating the end of the
1405 // epilog.
1406 Epilogs.push_back({Start, Offset, Offset + (int64_t)(Instrs.size() - 1) * 4});
1407 }
1408
1409 unsigned E = 0;
1410 int64_t SegLimit = 0xFFFFC;
1411 int64_t SegOffset = 0;
1412
1413 if (RawFuncLength > SegLimit) {
1414
1415 int64_t RemainingLength = RawFuncLength;
1416
1417 while (RemainingLength > SegLimit) {
1418 // Try divide the function into segments, requirements:
1419 // 1. Segment length <= 0xFFFFC;
1420 // 2. Each Prologue or Epilogue must be fully within a segment.
1421 int64_t SegLength = SegLimit;
1422 int64_t SegEnd = SegOffset + SegLength;
1423 // Keep record on symbols and offsets of epilogs in this segment.
1424 MapVector<MCSymbol *, int64_t> EpilogsInSegment;
1425
1426 while (E < Epilogs.size() && Epilogs[E].End < SegEnd) {
1427 // Epilogs within current segment.
1428 EpilogsInSegment[Epilogs[E].Start] = Epilogs[E].Offset;
1429 ++E;
1430 }
1431
1432 // At this point, we have:
1433 // 1. Put all epilogs in segments already. No action needed here; or
1434 // 2. Found an epilog that will cross segments boundry. We need to
1435 // move back current segment's end boundry, so the epilog is entirely
1436 // in the next segment; or
1437 // 3. Left at least one epilog that is entirely after this segment.
1438 // It'll be handled by the next iteration, or the last segment.
1439 if (E < Epilogs.size() && Epilogs[E].Offset <= SegEnd)
1440 // Move back current Segment's end boundry.
1441 SegLength = Epilogs[E].Offset - SegOffset;
1442
1443 auto Seg = WinEH::FrameInfo::Segment(
1444 SegOffset, SegLength, /* HasProlog */!SegOffset);
1445 Seg.Epilogs = std::move(EpilogsInSegment);
1446 info->Segments.push_back(Seg);
1447
1448 SegOffset += SegLength;
1449 RemainingLength -= SegLength;
1450 }
1451 }
1452
1453 // Add the last segment when RawFuncLength > 0xFFFFC,
1454 // or the only segment otherwise.
1455 auto LastSeg =
1456 WinEH::FrameInfo::Segment(SegOffset, RawFuncLength - SegOffset,
1457 /* HasProlog */!SegOffset);
1458 for (; E < Epilogs.size(); ++E)
1459 LastSeg.Epilogs[Epilogs[E].Start] = Epilogs[E].Offset;
1460 info->Segments.push_back(LastSeg);
1461}
1462
1466 bool TryPacked = true) {
1467 MCContext &context = streamer.getContext();
1468 MCSymbol *Label = context.createTempSymbol();
1469
1470 streamer.emitValueToAlignment(Align(4));
1471 streamer.emitLabel(Label);
1472 Seg.Symbol = Label;
1473 // Use the 1st segemnt's label as function's.
1474 if (Seg.Offset == 0)
1475 info->Symbol = Label;
1476
1477 bool HasProlog = Seg.HasProlog;
1478 bool HasEpilogs = (Seg.Epilogs.size() != 0);
1479
1480 uint32_t SegLength = (uint32_t)Seg.Length / 4;
1481 uint32_t PrologCodeBytes = info->PrologCodeBytes;
1482
1483 int PackedEpilogOffset = HasEpilogs ?
1484 checkARM64PackedEpilog(streamer, info, &Seg, PrologCodeBytes) : -1;
1485
1486 // TODO:
1487 // 1. Enable packed unwind info (.pdata only) for multi-segment functions.
1488 // 2. Emit packed unwind info (.pdata only) for segments that have neithor
1489 // prolog nor epilog.
1490 if (info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
1491 uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1492 !info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
1493 // Matching prolog/epilog and no exception handlers; check if the
1494 // prolog matches the patterns that can be described by the packed
1495 // format.
1496
1497 // info->Symbol was already set even if we didn't actually write any
1498 // unwind info there. Keep using that as indicator that this unwind
1499 // info has been generated already.
1500 if (tryARM64PackedUnwind(info, SegLength, PackedEpilogOffset))
1501 return;
1502 }
1503
1504 // If the prolog is not in this segment, we need to emit an end_c, which takes
1505 // 1 byte, before prolog unwind ops.
1506 if (!HasProlog) {
1507 PrologCodeBytes += 1;
1508 if (PackedEpilogOffset >= 0)
1509 PackedEpilogOffset += 1;
1510 // If a segment has neither prolog nor epilog, "With full .xdata record,
1511 // Epilog Count = 1. Epilog Start Index points to end_c."
1512 // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling#function-fragments
1513 // TODO: We can remove this if testing shows zero epilog scope is ok with
1514 // MS unwinder.
1515 if (!HasEpilogs)
1516 // Pack the fake epilog into phantom prolog.
1517 PackedEpilogOffset = 0;
1518 }
1519
1520 uint32_t TotalCodeBytes = PrologCodeBytes;
1521
1522 // Process epilogs.
1524 ARM64ProcessEpilogs(info, &Seg, TotalCodeBytes, EpilogInfo);
1525
1526 // Code Words, Epilog count, E, X, Vers, Function Length
1527 uint32_t row1 = 0x0;
1528 uint32_t CodeWords = TotalCodeBytes / 4;
1529 uint32_t CodeWordsMod = TotalCodeBytes % 4;
1530 if (CodeWordsMod)
1531 CodeWords++;
1532 uint32_t EpilogCount =
1533 PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.Epilogs.size();
1534 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
1535 if (!ExtensionWord) {
1536 row1 |= (EpilogCount & 0x1F) << 22;
1537 row1 |= (CodeWords & 0x1F) << 27;
1538 }
1539 if (info->HandlesExceptions) // X
1540 row1 |= 1 << 20;
1541 if (PackedEpilogOffset >= 0) // E
1542 row1 |= 1 << 21;
1543 row1 |= SegLength & 0x3FFFF;
1544 streamer.emitInt32(row1);
1545
1546 // Extended Code Words, Extended Epilog Count
1547 if (ExtensionWord) {
1548 // FIXME: We should be able to split unwind info into multiple sections.
1549 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
1551 "SEH unwind data splitting is only implemented for large functions, "
1552 "cases of too many code words or too many epilogs will be done "
1553 "later");
1554 uint32_t row2 = 0x0;
1555 row2 |= (CodeWords & 0xFF) << 16;
1556 row2 |= (EpilogCount & 0xFFFF);
1557 streamer.emitInt32(row2);
1558 }
1559
1560 if (PackedEpilogOffset < 0) {
1561 // Epilog Start Index, Epilog Start Offset
1562 for (auto &I : EpilogInfo) {
1563 MCSymbol *EpilogStart = I.first;
1564 uint32_t EpilogIndex = I.second;
1565 // Epilog offset within the Segment.
1566 uint32_t EpilogOffset = (uint32_t)(Seg.Epilogs[EpilogStart] - Seg.Offset);
1567 if (EpilogOffset)
1568 EpilogOffset /= 4;
1569 uint32_t row3 = EpilogOffset;
1570 row3 |= (EpilogIndex & 0x3FF) << 22;
1571 streamer.emitInt32(row3);
1572 }
1573 }
1574
1575 // Note that even for segments that have no prolog, we still need to emit
1576 // prolog unwinding opcodes so that the unwinder knows how to unwind from
1577 // such a segment.
1578 // The end_c opcode at the start indicates to the unwinder that the actual
1579 // prolog is outside of the current segment, and the unwinder shouldn't try
1580 // to check for unwinding from a partial prolog.
1581 if (!HasProlog)
1582 // Emit an end_c.
1583 streamer.emitInt8((uint8_t)0xE5);
1584
1585 // Emit prolog unwind instructions (in reverse order).
1586 for (auto Inst : llvm::reverse(info->Instructions))
1587 ARM64EmitUnwindCode(streamer, Inst);
1588
1589 // Emit epilog unwind instructions
1590 for (auto &I : Seg.Epilogs) {
1591 auto &EpilogInstrs = info->EpilogMap[I.first].Instructions;
1592 for (const WinEH::Instruction &inst : EpilogInstrs)
1593 ARM64EmitUnwindCode(streamer, inst);
1594 }
1595
1596 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
1597 assert(BytesMod >= 0);
1598 for (int i = 0; i < BytesMod; i++)
1599 streamer.emitInt8(0xE3);
1600
1601 if (info->HandlesExceptions)
1602 streamer.emitValue(
1603 MCSymbolRefExpr::create(info->ExceptionHandler,
1605 4);
1606}
1607
1608// Populate the .xdata section. The format of .xdata on ARM64 is documented at
1609// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
1611 bool TryPacked = true) {
1612 // If this UNWIND_INFO already has a symbol, it's already been emitted.
1613 if (info->Symbol)
1614 return;
1615 // If there's no unwind info here (not even a terminating UOP_End), the
1616 // unwind info is considered bogus and skipped. If this was done in
1617 // response to an explicit .seh_handlerdata, the associated trailing
1618 // handler data is left orphaned in the xdata section.
1619 if (info->empty()) {
1620 info->EmitAttempted = true;
1621 return;
1622 }
1623 if (info->EmitAttempted) {
1624 // If we tried to emit unwind info before (due to an explicit
1625 // .seh_handlerdata directive), but skipped it (because there was no
1626 // valid information to emit at the time), and it later got valid unwind
1627 // opcodes, we can't emit it here, because the trailing handler data
1628 // was already emitted elsewhere in the xdata section.
1629 streamer.getContext().reportError(
1630 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
1631 " skipped due to no unwind info at the time "
1632 "(.seh_handlerdata too early?), but the function later "
1633 "did get unwind info that can't be emitted");
1634 return;
1635 }
1636
1637 simplifyARM64Opcodes(info->Instructions, false);
1638 for (auto &I : info->EpilogMap)
1639 simplifyARM64Opcodes(I.second.Instructions, true);
1640
1641 int64_t RawFuncLength;
1642 if (!info->FuncletOrFuncEnd) {
1643 report_fatal_error("FuncletOrFuncEnd not set");
1644 } else {
1645 // FIXME: GetAbsDifference tries to compute the length of the function
1646 // immediately, before the whole file is emitted, but in general
1647 // that's impossible: the size in bytes of certain assembler directives
1648 // like .align and .fill is not known until the whole file is parsed and
1649 // relaxations are applied. Currently, GetAbsDifference fails with a fatal
1650 // error in that case. (We mostly don't hit this because inline assembly
1651 // specifying those directives is rare, and we don't normally try to
1652 // align loops on AArch64.)
1653 //
1654 // There are two potential approaches to delaying the computation. One,
1655 // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
1656 // as long as we have some conservative estimate we could use to prove
1657 // that we don't need to split the unwind data. Emitting the constant
1658 // is straightforward, but there's no existing code for estimating the
1659 // size of the function.
1660 //
1661 // The other approach would be to use a dedicated, relaxable fragment,
1662 // which could grow to accommodate splitting the unwind data if
1663 // necessary. This is more straightforward, since it automatically works
1664 // without any new infrastructure, and it's consistent with how we handle
1665 // relaxation in other contexts. But it would require some refactoring
1666 // to move parts of the pdata/xdata emission into the implementation of
1667 // a fragment. We could probably continue to encode the unwind codes
1668 // here, but we'd have to emit the pdata, the xdata header, and the
1669 // epilogue scopes later, since they depend on whether the we need to
1670 // split the unwind data.
1671 //
1672 // If this is fixed, remove code in AArch64ISelLowering.cpp that
1673 // disables loop alignment on Windows.
1674 RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
1675 info->Begin);
1676 }
1677
1678 ARM64FindSegmentsInFunction(streamer, info, RawFuncLength);
1679
1680 info->PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
1681 for (auto &S : info->Segments)
1682 ARM64EmitUnwindInfoForSegment(streamer, info, S, TryPacked);
1683
1684 // Clear prolog instructions after unwind info is emitted for all segments.
1685 info->Instructions.clear();
1686}
1687
1689 uint32_t Count = 0;
1690 for (const auto &I : Insns) {
1691 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1692 default:
1693 llvm_unreachable("Unsupported ARM unwind code");
1695 Count += 1;
1696 break;
1698 Count += 3;
1699 break;
1701 Count += 4;
1702 break;
1704 Count += 2;
1705 break;
1707 Count += 3;
1708 break;
1710 Count += 4;
1711 break;
1713 Count += 2;
1714 break;
1716 Count += 1;
1717 break;
1719 Count += 1;
1720 break;
1722 Count += 1;
1723 break;
1725 Count += 1;
1726 break;
1728 Count += 2;
1729 break;
1731 Count += 2;
1732 break;
1734 Count += 2;
1735 break;
1737 Count += 2;
1738 break;
1739 case Win64EH::UOP_Nop:
1741 case Win64EH::UOP_End:
1744 Count += 1;
1745 break;
1746 case Win64EH::UOP_Custom: {
1747 int J;
1748 for (J = 3; J > 0; J--)
1749 if (I.Offset & (0xffu << (8 * J)))
1750 break;
1751 Count += J + 1;
1752 break;
1753 }
1754 }
1755 }
1756 return Count;
1757}
1758
1760 bool *HasCustom = nullptr) {
1761 uint32_t Count = 0;
1762 for (const auto &I : Insns) {
1763 switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1764 default:
1765 llvm_unreachable("Unsupported ARM unwind code");
1769 Count += 2;
1770 break;
1774 Count += 4;
1775 break;
1778 Count += 4;
1779 break;
1781 Count += 2;
1782 break;
1785 Count += 2;
1786 break;
1790 Count += 4;
1791 break;
1793 Count += 4;
1794 break;
1795 case Win64EH::UOP_Nop:
1797 Count += 2;
1798 break;
1801 Count += 4;
1802 break;
1803 case Win64EH::UOP_End:
1804 // This doesn't map to any instruction
1805 break;
1807 // We can't reason about what instructions this maps to; return a
1808 // phony number to make sure we don't accidentally do epilog packing.
1809 Count += 1000;
1810 if (HasCustom)
1811 *HasCustom = true;
1812 break;
1813 }
1814 }
1815 return Count;
1816}
1817
1818static void checkARMInstructions(MCStreamer &Streamer,
1820 const MCSymbol *Begin, const MCSymbol *End,
1821 StringRef Name, StringRef Type) {
1822 if (!End)
1823 return;
1824 std::optional<int64_t> MaybeDistance =
1825 GetOptionalAbsDifference(Streamer, End, Begin);
1826 if (!MaybeDistance)
1827 return;
1828 uint32_t Distance = (uint32_t)*MaybeDistance;
1829 bool HasCustom = false;
1830 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
1831 if (HasCustom)
1832 return;
1833 if (Distance != InstructionBytes) {
1834 Streamer.getContext().reportError(
1835 SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1836 Twine(Distance) +
1837 " bytes of instructions in range, but .seh directives "
1838 "corresponding to " +
1839 Twine(InstructionBytes) + " bytes\n");
1840 }
1841}
1842
1843static bool isARMTerminator(const WinEH::Instruction &inst) {
1844 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1845 case Win64EH::UOP_End:
1848 return true;
1849 default:
1850 return false;
1851 }
1852}
1853
1854// Unwind opcode encodings and restrictions are documented at
1855// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1856static void ARMEmitUnwindCode(MCStreamer &streamer,
1857 const WinEH::Instruction &inst) {
1858 uint32_t w, lr;
1859 int i;
1860 switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1861 default:
1862 llvm_unreachable("Unsupported ARM unwind code");
1864 assert((inst.Offset & 3) == 0);
1865 assert(inst.Offset / 4 <= 0x7f);
1866 streamer.emitInt8(inst.Offset / 4);
1867 break;
1869 assert((inst.Register & ~0x5fff) == 0);
1870 lr = (inst.Register >> 14) & 1;
1871 w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
1872 streamer.emitInt8((w >> 8) & 0xff);
1873 streamer.emitInt8((w >> 0) & 0xff);
1874 break;
1876 assert(inst.Register <= 0x0f);
1877 streamer.emitInt8(0xc0 | inst.Register);
1878 break;
1880 assert(inst.Register >= 4 && inst.Register <= 7);
1881 assert(inst.Offset <= 1);
1882 streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
1883 break;
1885 assert(inst.Register >= 8 && inst.Register <= 11);
1886 assert(inst.Offset <= 1);
1887 streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
1888 break;
1890 assert(inst.Register >= 8 && inst.Register <= 15);
1891 streamer.emitInt8(0xe0 | (inst.Register - 8));
1892 break;
1894 assert((inst.Offset & 3) == 0);
1895 assert(inst.Offset / 4 <= 0x3ff);
1896 w = 0xe800 | (inst.Offset / 4);
1897 streamer.emitInt8((w >> 8) & 0xff);
1898 streamer.emitInt8((w >> 0) & 0xff);
1899 break;
1901 assert((inst.Register & ~0x40ff) == 0);
1902 lr = (inst.Register >> 14) & 1;
1903 w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
1904 streamer.emitInt8((w >> 8) & 0xff);
1905 streamer.emitInt8((w >> 0) & 0xff);
1906 break;
1908 assert((inst.Offset & 3) == 0);
1909 assert(inst.Offset / 4 <= 0x0f);
1910 streamer.emitInt8(0xef);
1911 streamer.emitInt8(inst.Offset / 4);
1912 break;
1914 assert(inst.Register <= 15);
1915 assert(inst.Offset <= 15);
1916 assert(inst.Register <= inst.Offset);
1917 streamer.emitInt8(0xf5);
1918 streamer.emitInt8((inst.Register << 4) | inst.Offset);
1919 break;
1921 assert(inst.Register >= 16 && inst.Register <= 31);
1922 assert(inst.Offset >= 16 && inst.Offset <= 31);
1923 assert(inst.Register <= inst.Offset);
1924 streamer.emitInt8(0xf6);
1925 streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
1926 break;
1928 assert((inst.Offset & 3) == 0);
1929 assert(inst.Offset / 4 <= 0xffff);
1930 w = inst.Offset / 4;
1931 streamer.emitInt8(0xf7);
1932 streamer.emitInt8((w >> 8) & 0xff);
1933 streamer.emitInt8((w >> 0) & 0xff);
1934 break;
1936 assert((inst.Offset & 3) == 0);
1937 assert(inst.Offset / 4 <= 0xffffff);
1938 w = inst.Offset / 4;
1939 streamer.emitInt8(0xf8);
1940 streamer.emitInt8((w >> 16) & 0xff);
1941 streamer.emitInt8((w >> 8) & 0xff);
1942 streamer.emitInt8((w >> 0) & 0xff);
1943 break;
1945 assert((inst.Offset & 3) == 0);
1946 assert(inst.Offset / 4 <= 0xffff);
1947 w = inst.Offset / 4;
1948 streamer.emitInt8(0xf9);
1949 streamer.emitInt8((w >> 8) & 0xff);
1950 streamer.emitInt8((w >> 0) & 0xff);
1951 break;
1953 assert((inst.Offset & 3) == 0);
1954 assert(inst.Offset / 4 <= 0xffffff);
1955 w = inst.Offset / 4;
1956 streamer.emitInt8(0xfa);
1957 streamer.emitInt8((w >> 16) & 0xff);
1958 streamer.emitInt8((w >> 8) & 0xff);
1959 streamer.emitInt8((w >> 0) & 0xff);
1960 break;
1961 case Win64EH::UOP_Nop:
1962 streamer.emitInt8(0xfb);
1963 break;
1965 streamer.emitInt8(0xfc);
1966 break;
1968 streamer.emitInt8(0xfd);
1969 break;
1971 streamer.emitInt8(0xfe);
1972 break;
1973 case Win64EH::UOP_End:
1974 streamer.emitInt8(0xff);
1975 break;
1977 for (i = 3; i > 0; i--)
1978 if (inst.Offset & (0xffu << (8 * i)))
1979 break;
1980 for (; i >= 0; i--)
1981 streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
1982 break;
1983 }
1984}
1985
1986// Check if an epilog exists as a subset of the end of a prolog (backwards).
1987// An epilog may end with one out of three different end opcodes; if this
1988// is the first epilog that shares opcodes with the prolog, we can tolerate
1989// that this opcode differs (and the caller will update the prolog to use
1990// the same end opcode as the epilog). If another epilog already shares
1991// opcodes with the prolog, the ending opcode must be a strict match.
1992static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1993 const std::vector<WinEH::Instruction> &Epilog,
1994 bool CanTweakProlog) {
1995 // Can't find an epilog as a subset if it is longer than the prolog.
1996 if (Epilog.size() > Prolog.size())
1997 return -1;
1998
1999 // Check that the epilog actually is a perfect match for the end (backwrds)
2000 // of the prolog.
2001 // If we can adjust the prolog afterwards, don't check that the end opcodes
2002 // match.
2003 int EndIdx = CanTweakProlog ? 1 : 0;
2004 for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
2005 // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
2006 // "push {r0-r3}".
2007 if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
2008 return -1;
2009 }
2010
2011 if (CanTweakProlog) {
2012 // Check that both prolog and epilog end with an expected end opcode.
2013 if (Prolog.front().Operation != Win64EH::UOP_End)
2014 return -1;
2015 if (Epilog.back().Operation != Win64EH::UOP_End &&
2016 Epilog.back().Operation != Win64EH::UOP_EndNop &&
2017 Epilog.back().Operation != Win64EH::UOP_WideEndNop)
2018 return -1;
2019 }
2020
2021 // If the epilog was a subset of the prolog, find its offset.
2022 if (Epilog.size() == Prolog.size())
2023 return 0;
2025 &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
2026}
2027
2029 int PrologCodeBytes) {
2030 // Can only pack if there's one single epilog
2031 if (info->EpilogMap.size() != 1)
2032 return -1;
2033
2034 const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
2035 // Can only pack if the epilog is unconditional
2036 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2037 return -1;
2038
2039 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2040 // Make sure we have at least the trailing end opcode
2041 if (info->Instructions.empty() || Epilog.empty())
2042 return -1;
2043
2044 // Check that the epilog actually is at the very end of the function,
2045 // otherwise it can't be packed.
2046 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2047 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2048 if (!MaybeDistance)
2049 return -1;
2050 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2051 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2052 if (DistanceFromEnd != InstructionBytes)
2053 return -1;
2054
2055 int RetVal = -1;
2056 // Even if we don't end up sharing opcodes with the prolog, we can still
2057 // write the offset as a packed offset, if the single epilog is located at
2058 // the end of the function and the offset (pointing after the prolog) fits
2059 // as a packed offset.
2060 if (PrologCodeBytes <= 31 &&
2061 PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
2062 RetVal = PrologCodeBytes;
2063
2064 int Offset =
2065 getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
2066 if (Offset < 0)
2067 return RetVal;
2068
2069 // Check that the offset and prolog size fits in the first word; it's
2070 // unclear whether the epilog count in the extension word can be taken
2071 // as packed epilog offset.
2072 if (Offset > 31 || PrologCodeBytes > 63)
2073 return RetVal;
2074
2075 // Replace the regular end opcode of the prolog with the one from the
2076 // epilog.
2077 info->Instructions.front() = Epilog.back();
2078
2079 // As we choose to express the epilog as part of the prolog, remove the
2080 // epilog from the map, so we don't try to emit its opcodes.
2081 info->EpilogMap.clear();
2082 return Offset;
2083}
2084
2085static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
2086 unsigned &Folded, int &IntRegs) {
2087 if (Mask & (1 << 14)) {
2088 HasLR = true;
2089 Mask &= ~(1 << 14);
2090 }
2091 if (Mask & (1 << 11)) {
2092 HasR11 = true;
2093 Mask &= ~(1 << 11);
2094 }
2095 Folded = 0;
2096 IntRegs = -1;
2097 if (!Mask)
2098 return true;
2099 int First = 0;
2100 // Shift right until we have the bits at the bottom
2101 while ((Mask & 1) == 0) {
2102 First++;
2103 Mask >>= 1;
2104 }
2105 if ((Mask & (Mask + 1)) != 0)
2106 return false; // Not a consecutive series of bits? Can't be packed.
2107 // Count the bits
2108 int N = 0;
2109 while (Mask & (1 << N))
2110 N++;
2111 if (First < 4) {
2112 if (First + N < 4)
2113 return false;
2114 Folded = 4 - First;
2115 N -= Folded;
2116 First = 4;
2117 }
2118 if (First > 4)
2119 return false; // Can't be packed
2120 if (N >= 1)
2121 IntRegs = N - 1;
2122 return true;
2123}
2124
2126 uint32_t FuncLength) {
2127 int Step = 0;
2128 bool Homing = false;
2129 bool HasR11 = false;
2130 bool HasChain = false;
2131 bool HasLR = false;
2132 int IntRegs = -1; // r4 - r(4+N)
2133 int FloatRegs = -1; // d8 - d(8+N)
2134 unsigned PF = 0; // Number of extra pushed registers
2135 unsigned StackAdjust = 0;
2136 // Iterate over the prolog and check that all opcodes exactly match
2137 // the canonical order and form.
2138 for (const WinEH::Instruction &Inst : info->Instructions) {
2139 switch (Inst.Operation) {
2140 default:
2141 llvm_unreachable("Unsupported ARM unwind code");
2149 // Can't be packed
2150 return false;
2152 // Can't be packed; we can't rely on restoring sp from r11 when
2153 // unwinding a packed prologue.
2154 return false;
2156 // Can't be present in a packed prologue
2157 return false;
2158
2159 case Win64EH::UOP_End:
2162 if (Step != 0)
2163 return false;
2164 Step = 1;
2165 break;
2166
2169 // push {r4-r11,lr}
2170 if (Step != 1 && Step != 2)
2171 return false;
2172 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2173 assert(Inst.Offset <= 1); // Lr
2174 IntRegs = Inst.Register - 4;
2175 if (Inst.Register == 11) {
2176 HasR11 = true;
2177 IntRegs--;
2178 }
2179 if (Inst.Offset)
2180 HasLR = true;
2181 Step = 3;
2182 break;
2183
2185 if (Step == 1 && Inst.Register == 0x0f) {
2186 // push {r0-r3}
2187 Homing = true;
2188 Step = 2;
2189 break;
2190 }
2191 [[fallthrough]];
2193 if (Step != 1 && Step != 2)
2194 return false;
2195 // push {r4-r9,r11,lr}
2196 // push {r11,lr}
2197 // push {r1-r5}
2198 if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
2199 return false;
2200 Step = 3;
2201 break;
2202
2203 case Win64EH::UOP_Nop:
2204 // mov r11, sp
2205 if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
2206 return false;
2207 HasChain = true;
2208 Step = 4;
2209 break;
2211 // add.w r11, sp, #xx
2212 if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
2213 return false;
2214 HasChain = true;
2215 Step = 4;
2216 break;
2217
2219 if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
2220 return false;
2221 assert(Inst.Register >= 8 && Inst.Register <= 15);
2222 if (Inst.Register == 15)
2223 return false; // Can't pack this case, R==7 means no IntRegs
2224 if (IntRegs >= 0)
2225 return false;
2226 FloatRegs = Inst.Register - 8;
2227 Step = 5;
2228 break;
2229
2232 if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
2233 return false;
2234 if (PF > 0) // Can't have both folded and explicit stack allocation
2235 return false;
2236 if (Inst.Offset / 4 >= 0x3f4)
2237 return false;
2238 StackAdjust = Inst.Offset / 4;
2239 Step = 6;
2240 break;
2241 }
2242 }
2243 if (HasR11 && !HasChain) {
2244 if (IntRegs + 4 == 10) {
2245 // r11 stored, but not chaining; can be packed if already saving r4-r10
2246 // and we can fit r11 into this range.
2247 IntRegs++;
2248 HasR11 = false;
2249 } else
2250 return false;
2251 }
2252 if (HasChain && !HasLR)
2253 return false;
2254
2255 // Packed uneind info can't express multiple epilogues.
2256 if (info->EpilogMap.size() > 1)
2257 return false;
2258
2259 unsigned EF = 0;
2260 int Ret = 0;
2261 if (info->EpilogMap.size() == 0) {
2262 Ret = 3; // No epilogue
2263 } else {
2264 // As the prologue and epilogue aren't exact mirrors of each other,
2265 // we have to check the epilogue too and see if it matches what we've
2266 // concluded from the prologue.
2267 const WinEH::FrameInfo::Epilog &EpilogInfo =
2268 info->EpilogMap.begin()->second;
2269 if (EpilogInfo.Condition != 0xe) // ARMCC::AL
2270 return false;
2271 const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
2272 std::optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
2273 streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
2274 if (!MaybeDistance)
2275 return false;
2276 uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
2277 uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
2278 if (DistanceFromEnd != InstructionBytes)
2279 return false;
2280
2281 bool GotStackAdjust = false;
2282 bool GotFloatRegs = false;
2283 bool GotIntRegs = false;
2284 bool GotHomingRestore = false;
2285 bool GotLRRestore = false;
2286 bool NeedsReturn = false;
2287 bool GotReturn = false;
2288
2289 Step = 6;
2290 for (const WinEH::Instruction &Inst : Epilog) {
2291 switch (Inst.Operation) {
2292 default:
2293 llvm_unreachable("Unsupported ARM unwind code");
2302 case Win64EH::UOP_Nop:
2304 // Can't be packed in an epilogue
2305 return false;
2306
2309 if (Inst.Offset / 4 >= 0x3f4)
2310 return false;
2311 if (Step == 6) {
2312 if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
2313 PF == 0 && Inst.Offset == 16) {
2314 GotHomingRestore = true;
2315 Step = 10;
2316 } else {
2317 if (StackAdjust > 0) {
2318 // Got stack adjust in prologue too; must match.
2319 if (StackAdjust != Inst.Offset / 4)
2320 return false;
2321 GotStackAdjust = true;
2322 } else if (PF == Inst.Offset / 4) {
2323 // Folded prologue, non-folded epilogue
2324 StackAdjust = Inst.Offset / 4;
2325 GotStackAdjust = true;
2326 } else {
2327 // StackAdjust == 0 in prologue, mismatch
2328 return false;
2329 }
2330 Step = 7;
2331 }
2332 } else if (Step == 7 || Step == 8 || Step == 9) {
2333 if (!Homing || Inst.Offset != 16)
2334 return false;
2335 GotHomingRestore = true;
2336 Step = 10;
2337 } else
2338 return false;
2339 break;
2340
2342 if (Step != 6 && Step != 7)
2343 return false;
2344 assert(Inst.Register >= 8 && Inst.Register <= 15);
2345 if (FloatRegs != (int)(Inst.Register - 8))
2346 return false;
2347 GotFloatRegs = true;
2348 Step = 8;
2349 break;
2350
2353 // push {r4-r11,lr}
2354 if (Step != 6 && Step != 7 && Step != 8)
2355 return false;
2356 assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
2357 assert(Inst.Offset <= 1); // Lr
2358 if (Homing && HasLR) {
2359 // If homing and LR is backed up, we can either restore LR here
2360 // and return with Ret == 1 or 2, or return with SaveLR below
2361 if (Inst.Offset) {
2362 GotLRRestore = true;
2363 NeedsReturn = true;
2364 } else {
2365 // Expecting a separate SaveLR below
2366 }
2367 } else {
2368 if (HasLR != (Inst.Offset == 1))
2369 return false;
2370 }
2371 GotLRRestore = Inst.Offset == 1;
2372 if (IntRegs < 0) // This opcode must include r4
2373 return false;
2374 int Expected = IntRegs;
2375 if (HasChain) {
2376 // Can't express r11 here unless IntRegs describe r4-r10
2377 if (IntRegs != 6)
2378 return false;
2379 Expected++;
2380 }
2381 if (Expected != (int)(Inst.Register - 4))
2382 return false;
2383 GotIntRegs = true;
2384 Step = 9;
2385 break;
2386 }
2387
2390 if (Step != 6 && Step != 7 && Step != 8)
2391 return false;
2392 // push {r4-r9,r11,lr}
2393 // push {r11,lr}
2394 // push {r1-r5}
2395 bool CurHasLR = false, CurHasR11 = false;
2396 int Regs;
2397 if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
2398 return false;
2399 if (EF > 0) {
2400 if (EF != PF && EF != StackAdjust)
2401 return false;
2402 }
2403 if (Homing && HasLR) {
2404 // If homing and LR is backed up, we can either restore LR here
2405 // and return with Ret == 1 or 2, or return with SaveLR below
2406 if (CurHasLR) {
2407 GotLRRestore = true;
2408 NeedsReturn = true;
2409 } else {
2410 // Expecting a separate SaveLR below
2411 }
2412 } else {
2413 if (CurHasLR != HasLR)
2414 return false;
2415 GotLRRestore = CurHasLR;
2416 }
2417 int Expected = IntRegs;
2418 if (HasChain) {
2419 // If we have chaining, the mask must have included r11.
2420 if (!CurHasR11)
2421 return false;
2422 } else if (Expected == 7) {
2423 // If we don't have chaining, the mask could still include r11,
2424 // expressed as part of IntRegs Instead.
2425 Expected--;
2426 if (!CurHasR11)
2427 return false;
2428 } else {
2429 // Neither HasChain nor r11 included in IntRegs, must not have r11
2430 // here either.
2431 if (CurHasR11)
2432 return false;
2433 }
2434 if (Expected != Regs)
2435 return false;
2436 GotIntRegs = true;
2437 Step = 9;
2438 break;
2439 }
2440
2442 if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
2443 return false;
2444 if (!Homing || Inst.Offset != 20 || GotLRRestore)
2445 return false;
2446 GotLRRestore = true;
2447 GotHomingRestore = true;
2448 Step = 10;
2449 break;
2450
2453 GotReturn = true;
2454 Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
2455 [[fallthrough]];
2456 case Win64EH::UOP_End:
2457 if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
2458 return false;
2459 Step = 11;
2460 break;
2461 }
2462 }
2463
2464 if (Step != 11)
2465 return false;
2466 if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
2467 return false;
2468 if (FloatRegs >= 0 && !GotFloatRegs)
2469 return false;
2470 if (IntRegs >= 0 && !GotIntRegs)
2471 return false;
2472 if (Homing && !GotHomingRestore)
2473 return false;
2474 if (HasLR && !GotLRRestore)
2475 return false;
2476 if (NeedsReturn && !GotReturn)
2477 return false;
2478 }
2479
2480 assert(PF == 0 || EF == 0 ||
2481 StackAdjust == 0); // Can't have adjust in all three
2482 if (PF > 0 || EF > 0) {
2483 StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
2484 assert(StackAdjust <= 3);
2485 StackAdjust |= 0x3f0;
2486 if (PF > 0)
2487 StackAdjust |= 1 << 2;
2488 if (EF > 0)
2489 StackAdjust |= 1 << 3;
2490 }
2491
2492 assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
2493 int Flag = info->Fragment ? 0x02 : 0x01;
2494 int H = Homing ? 1 : 0;
2495 int L = HasLR ? 1 : 0;
2496 int C = HasChain ? 1 : 0;
2497 assert(IntRegs < 0 || FloatRegs < 0);
2498 unsigned Reg, R;
2499 if (IntRegs >= 0) {
2500 Reg = IntRegs;
2501 assert(Reg <= 7);
2502 R = 0;
2503 } else if (FloatRegs >= 0) {
2504 Reg = FloatRegs;
2505 assert(Reg < 7);
2506 R = 1;
2507 } else {
2508 // No int or float regs stored (except possibly R11,LR)
2509 Reg = 7;
2510 R = 1;
2511 }
2512 info->PackedInfo |= Flag << 0;
2513 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
2514 info->PackedInfo |= (Ret & 0x3) << 13;
2515 info->PackedInfo |= H << 15;
2516 info->PackedInfo |= Reg << 16;
2517 info->PackedInfo |= R << 19;
2518 info->PackedInfo |= L << 20;
2519 info->PackedInfo |= C << 21;
2520 assert(StackAdjust <= 0x3ff);
2521 info->PackedInfo |= StackAdjust << 22;
2522 return true;
2523}
2524
2525// Populate the .xdata section. The format of .xdata on ARM is documented at
2526// https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
2528 bool TryPacked = true) {
2529 // If this UNWIND_INFO already has a symbol, it's already been emitted.
2530 if (info->Symbol)
2531 return;
2532 // If there's no unwind info here (not even a terminating UOP_End), the
2533 // unwind info is considered bogus and skipped. If this was done in
2534 // response to an explicit .seh_handlerdata, the associated trailing
2535 // handler data is left orphaned in the xdata section.
2536 if (info->empty()) {
2537 info->EmitAttempted = true;
2538 return;
2539 }
2540 if (info->EmitAttempted) {
2541 // If we tried to emit unwind info before (due to an explicit
2542 // .seh_handlerdata directive), but skipped it (because there was no
2543 // valid information to emit at the time), and it later got valid unwind
2544 // opcodes, we can't emit it here, because the trailing handler data
2545 // was already emitted elsewhere in the xdata section.
2546 streamer.getContext().reportError(
2547 SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
2548 " skipped due to no unwind info at the time "
2549 "(.seh_handlerdata too early?), but the function later "
2550 "did get unwind info that can't be emitted");
2551 return;
2552 }
2553
2554 MCContext &context = streamer.getContext();
2555 MCSymbol *Label = context.createTempSymbol();
2556
2557 streamer.emitValueToAlignment(Align(4));
2558 streamer.emitLabel(Label);
2559 info->Symbol = Label;
2560
2561 if (!info->PrologEnd)
2562 streamer.getContext().reportError(SMLoc(), "Prologue in " +
2563 info->Function->getName() +
2564 " not correctly terminated");
2565
2566 if (info->PrologEnd && !info->Fragment)
2567 checkARMInstructions(streamer, info->Instructions, info->Begin,
2568 info->PrologEnd, info->Function->getName(),
2569 "prologue");
2570 for (auto &I : info->EpilogMap) {
2571 MCSymbol *EpilogStart = I.first;
2572 auto &Epilog = I.second;
2573 checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
2574 info->Function->getName(), "epilogue");
2575 if (Epilog.Instructions.empty() ||
2576 !isARMTerminator(Epilog.Instructions.back()))
2577 streamer.getContext().reportError(
2578 SMLoc(), "Epilogue in " + info->Function->getName() +
2579 " not correctly terminated");
2580 }
2581
2582 std::optional<int64_t> RawFuncLength;
2583 const MCExpr *FuncLengthExpr = nullptr;
2584 if (!info->FuncletOrFuncEnd) {
2585 report_fatal_error("FuncletOrFuncEnd not set");
2586 } else {
2587 // As the size of many thumb2 instructions isn't known until later,
2588 // we can't always rely on being able to calculate the absolute
2589 // length of the function here. If we can't calculate it, defer it
2590 // to a relocation.
2591 //
2592 // In such a case, we won't know if the function is too long so that
2593 // the unwind info would need to be split (but this isn't implemented
2594 // anyway).
2595 RawFuncLength =
2596 GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
2597 if (!RawFuncLength)
2598 FuncLengthExpr =
2599 GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
2600 }
2601 uint32_t FuncLength = 0;
2602 if (RawFuncLength)
2603 FuncLength = (uint32_t)*RawFuncLength / 2;
2604 if (FuncLength > 0x3FFFF)
2605 report_fatal_error("SEH unwind data splitting not yet implemented");
2606 uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
2607 uint32_t TotalCodeBytes = PrologCodeBytes;
2608
2609 if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2610 TryPacked) {
2611 // No exception handlers; check if the prolog and epilog matches the
2612 // patterns that can be described by the packed format. If we don't
2613 // know the exact function length yet, we can't do this.
2614
2615 // info->Symbol was already set even if we didn't actually write any
2616 // unwind info there. Keep using that as indicator that this unwind
2617 // info has been generated already.
2618
2619 if (tryARMPackedUnwind(streamer, info, FuncLength))
2620 return;
2621 }
2622
2623 int PackedEpilogOffset =
2624 checkARMPackedEpilog(streamer, info, PrologCodeBytes);
2625
2626 // Process epilogs.
2628 // Epilogs processed so far.
2629 std::vector<MCSymbol *> AddedEpilogs;
2630
2631 bool CanTweakProlog = true;
2632 for (auto &I : info->EpilogMap) {
2633 MCSymbol *EpilogStart = I.first;
2634 auto &EpilogInstrs = I.second.Instructions;
2635 uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
2636
2637 MCSymbol *MatchingEpilog =
2638 FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
2639 int PrologOffset;
2640 if (MatchingEpilog) {
2641 assert(EpilogInfo.contains(MatchingEpilog) &&
2642 "Duplicate epilog not found");
2643 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2644 // Clear the unwind codes in the EpilogMap, so that they don't get output
2645 // in the logic below.
2646 EpilogInstrs.clear();
2647 } else if ((PrologOffset = getARMOffsetInProlog(
2648 info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2649 if (CanTweakProlog) {
2650 // Replace the regular end opcode of the prolog with the one from the
2651 // epilog.
2652 info->Instructions.front() = EpilogInstrs.back();
2653 // Later epilogs need a strict match for the end opcode.
2654 CanTweakProlog = false;
2655 }
2656 EpilogInfo[EpilogStart] = PrologOffset;
2657 // Clear the unwind codes in the EpilogMap, so that they don't get output
2658 // in the logic below.
2659 EpilogInstrs.clear();
2660 } else {
2661 EpilogInfo[EpilogStart] = TotalCodeBytes;
2662 TotalCodeBytes += CodeBytes;
2663 AddedEpilogs.push_back(EpilogStart);
2664 }
2665 }
2666
2667 // Code Words, Epilog count, F, E, X, Vers, Function Length
2668 uint32_t row1 = 0x0;
2669 uint32_t CodeWords = TotalCodeBytes / 4;
2670 uint32_t CodeWordsMod = TotalCodeBytes % 4;
2671 if (CodeWordsMod)
2672 CodeWords++;
2673 uint32_t EpilogCount =
2674 PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
2675 bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2676 if (!ExtensionWord) {
2677 row1 |= (EpilogCount & 0x1F) << 23;
2678 row1 |= (CodeWords & 0x0F) << 28;
2679 }
2680 if (info->HandlesExceptions) // X
2681 row1 |= 1 << 20;
2682 if (PackedEpilogOffset >= 0) // E
2683 row1 |= 1 << 21;
2684 if (info->Fragment) // F
2685 row1 |= 1 << 22;
2686 row1 |= FuncLength & 0x3FFFF;
2687 if (RawFuncLength)
2688 streamer.emitInt32(row1);
2689 else
2690 streamer.emitValue(
2691 MCBinaryExpr::createOr(FuncLengthExpr,
2692 MCConstantExpr::create(row1, context), context),
2693 4);
2694
2695 // Extended Code Words, Extended Epilog Count
2696 if (ExtensionWord) {
2697 // FIXME: We should be able to split unwind info into multiple sections.
2698 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2699 report_fatal_error("SEH unwind data splitting not yet implemented");
2700 uint32_t row2 = 0x0;
2701 row2 |= (CodeWords & 0xFF) << 16;
2702 row2 |= (EpilogCount & 0xFFFF);
2703 streamer.emitInt32(row2);
2704 }
2705
2706 if (PackedEpilogOffset < 0) {
2707 // Epilog Start Index, Epilog Start Offset
2708 for (auto &I : EpilogInfo) {
2709 MCSymbol *EpilogStart = I.first;
2710 uint32_t EpilogIndex = I.second;
2711
2712 std::optional<int64_t> MaybeEpilogOffset =
2713 GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
2714 const MCExpr *OffsetExpr = nullptr;
2715 uint32_t EpilogOffset = 0;
2716 if (MaybeEpilogOffset)
2717 EpilogOffset = *MaybeEpilogOffset / 2;
2718 else
2719 OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
2720
2721 assert(info->EpilogMap.contains(EpilogStart));
2722 unsigned Condition = info->EpilogMap[EpilogStart].Condition;
2723 assert(Condition <= 0xf);
2724
2725 uint32_t row3 = EpilogOffset;
2726 row3 |= Condition << 20;
2727 row3 |= (EpilogIndex & 0x3FF) << 24;
2728 if (MaybeEpilogOffset)
2729 streamer.emitInt32(row3);
2730 else
2731 streamer.emitValue(
2733 OffsetExpr, MCConstantExpr::create(row3, context), context),
2734 4);
2735 }
2736 }
2737
2738 // Emit prolog unwind instructions (in reverse order).
2739 uint8_t numInst = info->Instructions.size();
2740 for (uint8_t c = 0; c < numInst; ++c) {
2741 WinEH::Instruction inst = info->Instructions.back();
2742 info->Instructions.pop_back();
2743 ARMEmitUnwindCode(streamer, inst);
2744 }
2745
2746 // Emit epilog unwind instructions
2747 for (auto &I : info->EpilogMap) {
2748 auto &EpilogInstrs = I.second.Instructions;
2749 for (const WinEH::Instruction &inst : EpilogInstrs)
2750 ARMEmitUnwindCode(streamer, inst);
2751 }
2752
2753 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2754 assert(BytesMod >= 0);
2755 for (int i = 0; i < BytesMod; i++)
2756 streamer.emitInt8(0xFB);
2757
2758 if (info->HandlesExceptions)
2759 streamer.emitValue(
2760 MCSymbolRefExpr::create(info->ExceptionHandler,
2762 4);
2763}
2764
2766 const WinEH::FrameInfo *info) {
2767 MCContext &context = streamer.getContext();
2768
2769 streamer.emitValueToAlignment(Align(4));
2770 for (const auto &S : info->Segments) {
2771 EmitSymbolRefWithOfs(streamer, info->Begin, S.Offset);
2772 if (info->PackedInfo)
2773 streamer.emitInt32(info->PackedInfo);
2774 else
2775 streamer.emitValue(
2777 context),
2778 4);
2779 }
2780}
2781
2782
2784 const WinEH::FrameInfo *info) {
2785 MCContext &context = streamer.getContext();
2786
2787 streamer.emitValueToAlignment(Align(4));
2788 EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
2789 if (info->PackedInfo)
2790 streamer.emitInt32(info->PackedInfo);
2791 else
2792 streamer.emitValue(
2794 context),
2795 4);
2796}
2797
2799 // Emit the unwind info structs first.
2800 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2801 WinEH::FrameInfo *Info = CFI.get();
2802 if (Info->empty())
2803 continue;
2804 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2805 Streamer.switchSection(XData);
2806 ARM64EmitUnwindInfo(Streamer, Info);
2807 }
2808
2809 // Now emit RUNTIME_FUNCTION entries.
2810 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2811 WinEH::FrameInfo *Info = CFI.get();
2812 // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2813 // empty here. But if a Symbol is set, we should create the corresponding
2814 // pdata entry.
2815 if (!Info->Symbol)
2816 continue;
2817 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2818 Streamer.switchSection(PData);
2819 ARM64EmitRuntimeFunction(Streamer, Info);
2820 }
2821}
2822
2825 bool HandlerData) const {
2826 // Called if there's an .seh_handlerdata directive before the end of the
2827 // function. This forces writing the xdata record already here - and
2828 // in this case, the function isn't actually ended already, but the xdata
2829 // record needs to know the function length. In these cases, if the funclet
2830 // end hasn't been marked yet, the xdata function length won't cover the
2831 // whole function, only up to this point.
2832 if (!info->FuncletOrFuncEnd) {
2833 Streamer.switchSection(info->TextSection);
2834 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2835 }
2836 // Switch sections (the static function above is meant to be called from
2837 // here and from Emit().
2838 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2839 Streamer.switchSection(XData);
2840 ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2841}
2842
2844 // Emit the unwind info structs first.
2845 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2846 WinEH::FrameInfo *Info = CFI.get();
2847 if (Info->empty())
2848 continue;
2849 MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2850 Streamer.switchSection(XData);
2851 ARMEmitUnwindInfo(Streamer, Info);
2852 }
2853
2854 // Now emit RUNTIME_FUNCTION entries.
2855 for (const auto &CFI : Streamer.getWinFrameInfos()) {
2856 WinEH::FrameInfo *Info = CFI.get();
2857 // ARMEmitUnwindInfo above clears the info struct, so we can't check
2858 // empty here. But if a Symbol is set, we should create the corresponding
2859 // pdata entry.
2860 if (!Info->Symbol)
2861 continue;
2862 MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2863 Streamer.switchSection(PData);
2864 ARMEmitRuntimeFunction(Streamer, Info);
2865 }
2866}
2867
2870 bool HandlerData) const {
2871 // Called if there's an .seh_handlerdata directive before the end of the
2872 // function. This forces writing the xdata record already here - and
2873 // in this case, the function isn't actually ended already, but the xdata
2874 // record needs to know the function length. In these cases, if the funclet
2875 // end hasn't been marked yet, the xdata function length won't cover the
2876 // whole function, only up to this point.
2877 if (!info->FuncletOrFuncEnd) {
2878 Streamer.switchSection(info->TextSection);
2879 info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2880 }
2881 // Switch sections (the static function above is meant to be called from
2882 // here and from Emit().
2883 MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2884 Streamer.switchSection(XData);
2885 ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2886}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-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 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 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 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 uint8_t CountOfUnwindCodes(std::vector< WinEH::Instruction > &Insns)
Definition MCWin64EH.cpp:72
#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
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
size - Get the array size.
Definition ArrayRef.h:142
Tagged union holding either a T or a Error.
Definition Error.h:485
MCContext & getContext() const
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:517
Streaming machine code generation interface.
Definition MCStreamer.h:220
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:314
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:749
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:750
ArrayRef< std::unique_ptr< WinEH::FrameInfo > > getWinFrameInfos() const
Definition MCStreamer.h:347
void emitInt8(uint64_t Value)
Definition MCStreamer.h:748
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:346
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:36
bool contains(const KeyT &Key) const
Definition MapVector.h:146
ValueT lookup(const KeyT &Key) const
Definition MapVector.h:108
Represents a location in source code.
Definition SMLoc.h:22
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
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
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:45
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
@ UNW_TerminateHandler
UNW_TerminateHandler - Specifies that this function has a termination handler.
Definition Win64EH.h:143
@ UNW_ExceptionHandler
UNW_ExceptionHandler - Specifies that this function has an exception handler.
Definition Win64EH.h:140
@ UNW_ChainInfo
UNW_ChainInfo - Specifies that this UnwindInfo structure is chained to another one.
Definition Win64EH.h:146
UnwindOpcodes
UnwindOpcodes - Enumeration whose values specify a single operation in the prolog of a function.
Definition Win64EH.h:26
@ UOP_SaveAnyRegDPX
Definition Win64EH.h:75
@ UOP_SaveRegsR4R7LR
Definition Win64EH.h:98
@ UOP_ClearUnwoundToCall
Definition Win64EH.h:64
@ UOP_SaveNonVolBig
Definition Win64EH.h:35
@ UOP_WideAllocMedium
Definition Win64EH.h:92
@ UOP_SaveAnyRegDX
Definition Win64EH.h:74
@ UOP_SaveFRegD0D15
Definition Win64EH.h:103
@ UOP_SaveAnyRegQP
Definition Win64EH.h:71
@ UOP_SaveAnyRegD
Definition Win64EH.h:68
@ UOP_WideSaveRegsR4R11LR
Definition Win64EH.h:99
@ UOP_SaveAnyRegIPX
Definition Win64EH.h:73
@ UOP_WideAllocHuge
Definition Win64EH.h:94
@ UOP_SaveAnyRegQX
Definition Win64EH.h:76
@ UOP_SaveAnyRegIX
Definition Win64EH.h:72
@ UOP_SaveXMM128Big
Definition Win64EH.h:39
@ UOP_SaveAnyRegQ
Definition Win64EH.h:70
@ UOP_SaveAnyRegDP
Definition Win64EH.h:69
@ UOP_SaveFRegD8D15
Definition Win64EH.h:100
@ UOP_PushMachFrame
Definition Win64EH.h:40
@ UOP_SaveR19R20X
Definition Win64EH.h:44
@ UOP_SaveAnyRegQPX
Definition Win64EH.h:77
@ UOP_WideAllocLarge
Definition Win64EH.h:93
@ UOP_WideSaveRegMask
Definition Win64EH.h:96
@ UOP_AllocMedium
Definition Win64EH.h:43
@ UOP_SaveAnyRegIP
Definition Win64EH.h:67
@ UOP_SaveFRegD16D31
Definition Win64EH.h:104
@ UOP_SaveAnyRegI
Definition Win64EH.h:66
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
@ Offset
Definition DWP.cpp:532
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
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:1421
@ Other
Any other memory.
Definition ModRef.h:68
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
@ FK_Data_2
A two-byte fixup.
Definition MCFixup.h:35
DWARFExpression::Operation Op
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
std::vector< Instruction > Instructions
Definition MCWinEH.h:65
MapVector< MCSymbol *, int64_t > Epilogs
Definition MCWinEH.h:81
const MCSymbol * Function
Definition MCWinEH.h:46
const MCSymbol * End
Definition MCWinEH.h:43
const MCSymbol * Label
Definition MCWinEH.h:24