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