xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCWin64EH.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/MC/MCWin64EH.h"
10*81ad6265SDimitry Andric #include "llvm/ADT/Optional.h"
110b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
120b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
170b57cec5SDimitry Andric #include "llvm/Support/Win64EH.h"
18*81ad6265SDimitry Andric namespace llvm {
19*81ad6265SDimitry Andric class MCSection;
20*81ad6265SDimitry Andric }
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric // NOTE: All relocations generated here are 4-byte image-relative.
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
270b57cec5SDimitry Andric   uint8_t Count = 0;
280b57cec5SDimitry Andric   for (const auto &I : Insns) {
290b57cec5SDimitry Andric     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
300b57cec5SDimitry Andric     default:
310b57cec5SDimitry Andric       llvm_unreachable("Unsupported unwind code");
320b57cec5SDimitry Andric     case Win64EH::UOP_PushNonVol:
330b57cec5SDimitry Andric     case Win64EH::UOP_AllocSmall:
340b57cec5SDimitry Andric     case Win64EH::UOP_SetFPReg:
350b57cec5SDimitry Andric     case Win64EH::UOP_PushMachFrame:
360b57cec5SDimitry Andric       Count += 1;
370b57cec5SDimitry Andric       break;
380b57cec5SDimitry Andric     case Win64EH::UOP_SaveNonVol:
390b57cec5SDimitry Andric     case Win64EH::UOP_SaveXMM128:
400b57cec5SDimitry Andric       Count += 2;
410b57cec5SDimitry Andric       break;
420b57cec5SDimitry Andric     case Win64EH::UOP_SaveNonVolBig:
430b57cec5SDimitry Andric     case Win64EH::UOP_SaveXMM128Big:
440b57cec5SDimitry Andric       Count += 3;
450b57cec5SDimitry Andric       break;
460b57cec5SDimitry Andric     case Win64EH::UOP_AllocLarge:
470b57cec5SDimitry Andric       Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
480b57cec5SDimitry Andric       break;
490b57cec5SDimitry Andric     }
500b57cec5SDimitry Andric   }
510b57cec5SDimitry Andric   return Count;
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
550b57cec5SDimitry Andric                               const MCSymbol *RHS) {
560b57cec5SDimitry Andric   MCContext &Context = Streamer.getContext();
570b57cec5SDimitry Andric   const MCExpr *Diff =
580b57cec5SDimitry Andric       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
590b57cec5SDimitry Andric                               MCSymbolRefExpr::create(RHS, Context), Context);
605ffd83dbSDimitry Andric   Streamer.emitValue(Diff, 1);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
640b57cec5SDimitry Andric                            WinEH::Instruction &inst) {
650b57cec5SDimitry Andric   uint8_t b2;
660b57cec5SDimitry Andric   uint16_t w;
670b57cec5SDimitry Andric   b2 = (inst.Operation & 0x0F);
680b57cec5SDimitry Andric   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
690b57cec5SDimitry Andric   default:
700b57cec5SDimitry Andric     llvm_unreachable("Unsupported unwind code");
710b57cec5SDimitry Andric   case Win64EH::UOP_PushNonVol:
720b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
730b57cec5SDimitry Andric     b2 |= (inst.Register & 0x0F) << 4;
745ffd83dbSDimitry Andric     streamer.emitInt8(b2);
750b57cec5SDimitry Andric     break;
760b57cec5SDimitry Andric   case Win64EH::UOP_AllocLarge:
770b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
780b57cec5SDimitry Andric     if (inst.Offset > 512 * 1024 - 8) {
790b57cec5SDimitry Andric       b2 |= 0x10;
805ffd83dbSDimitry Andric       streamer.emitInt8(b2);
810b57cec5SDimitry Andric       w = inst.Offset & 0xFFF8;
825ffd83dbSDimitry Andric       streamer.emitInt16(w);
830b57cec5SDimitry Andric       w = inst.Offset >> 16;
840b57cec5SDimitry Andric     } else {
855ffd83dbSDimitry Andric       streamer.emitInt8(b2);
860b57cec5SDimitry Andric       w = inst.Offset >> 3;
870b57cec5SDimitry Andric     }
885ffd83dbSDimitry Andric     streamer.emitInt16(w);
890b57cec5SDimitry Andric     break;
900b57cec5SDimitry Andric   case Win64EH::UOP_AllocSmall:
910b57cec5SDimitry Andric     b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
920b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
935ffd83dbSDimitry Andric     streamer.emitInt8(b2);
940b57cec5SDimitry Andric     break;
950b57cec5SDimitry Andric   case Win64EH::UOP_SetFPReg:
960b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
975ffd83dbSDimitry Andric     streamer.emitInt8(b2);
980b57cec5SDimitry Andric     break;
990b57cec5SDimitry Andric   case Win64EH::UOP_SaveNonVol:
1000b57cec5SDimitry Andric   case Win64EH::UOP_SaveXMM128:
1010b57cec5SDimitry Andric     b2 |= (inst.Register & 0x0F) << 4;
1020b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
1035ffd83dbSDimitry Andric     streamer.emitInt8(b2);
1040b57cec5SDimitry Andric     w = inst.Offset >> 3;
1050b57cec5SDimitry Andric     if (inst.Operation == Win64EH::UOP_SaveXMM128)
1060b57cec5SDimitry Andric       w >>= 1;
1075ffd83dbSDimitry Andric     streamer.emitInt16(w);
1080b57cec5SDimitry Andric     break;
1090b57cec5SDimitry Andric   case Win64EH::UOP_SaveNonVolBig:
1100b57cec5SDimitry Andric   case Win64EH::UOP_SaveXMM128Big:
1110b57cec5SDimitry Andric     b2 |= (inst.Register & 0x0F) << 4;
1120b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
1135ffd83dbSDimitry Andric     streamer.emitInt8(b2);
1140b57cec5SDimitry Andric     if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
1150b57cec5SDimitry Andric       w = inst.Offset & 0xFFF0;
1160b57cec5SDimitry Andric     else
1170b57cec5SDimitry Andric       w = inst.Offset & 0xFFF8;
1185ffd83dbSDimitry Andric     streamer.emitInt16(w);
1190b57cec5SDimitry Andric     w = inst.Offset >> 16;
1205ffd83dbSDimitry Andric     streamer.emitInt16(w);
1210b57cec5SDimitry Andric     break;
1220b57cec5SDimitry Andric   case Win64EH::UOP_PushMachFrame:
1230b57cec5SDimitry Andric     if (inst.Offset == 1)
1240b57cec5SDimitry Andric       b2 |= 0x10;
1250b57cec5SDimitry Andric     EmitAbsDifference(streamer, inst.Label, begin);
1265ffd83dbSDimitry Andric     streamer.emitInt8(b2);
1270b57cec5SDimitry Andric     break;
1280b57cec5SDimitry Andric   }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric static void EmitSymbolRefWithOfs(MCStreamer &streamer,
1320b57cec5SDimitry Andric                                  const MCSymbol *Base,
1330b57cec5SDimitry Andric                                  const MCSymbol *Other) {
1340b57cec5SDimitry Andric   MCContext &Context = streamer.getContext();
1350b57cec5SDimitry Andric   const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
1360b57cec5SDimitry Andric   const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
1370b57cec5SDimitry Andric   const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
1380b57cec5SDimitry Andric   const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
1390b57cec5SDimitry Andric                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
1400b57cec5SDimitry Andric                                               Context);
1415ffd83dbSDimitry Andric   streamer.emitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric static void EmitRuntimeFunction(MCStreamer &streamer,
1450b57cec5SDimitry Andric                                 const WinEH::FrameInfo *info) {
1460b57cec5SDimitry Andric   MCContext &context = streamer.getContext();
1470b57cec5SDimitry Andric 
1485ffd83dbSDimitry Andric   streamer.emitValueToAlignment(4);
149349cc55cSDimitry Andric   EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
150349cc55cSDimitry Andric   EmitSymbolRefWithOfs(streamer, info->Begin, info->End);
1515ffd83dbSDimitry Andric   streamer.emitValue(MCSymbolRefExpr::create(info->Symbol,
1520b57cec5SDimitry Andric                                              MCSymbolRefExpr::VK_COFF_IMGREL32,
1530b57cec5SDimitry Andric                                              context), 4);
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
1570b57cec5SDimitry Andric   // If this UNWIND_INFO already has a symbol, it's already been emitted.
1580b57cec5SDimitry Andric   if (info->Symbol)
1590b57cec5SDimitry Andric     return;
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   MCContext &context = streamer.getContext();
1620b57cec5SDimitry Andric   MCSymbol *Label = context.createTempSymbol();
1630b57cec5SDimitry Andric 
1645ffd83dbSDimitry Andric   streamer.emitValueToAlignment(4);
1655ffd83dbSDimitry Andric   streamer.emitLabel(Label);
1660b57cec5SDimitry Andric   info->Symbol = Label;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   // Upper 3 bits are the version number (currently 1).
1690b57cec5SDimitry Andric   uint8_t flags = 0x01;
1700b57cec5SDimitry Andric   if (info->ChainedParent)
1710b57cec5SDimitry Andric     flags |= Win64EH::UNW_ChainInfo << 3;
1720b57cec5SDimitry Andric   else {
1730b57cec5SDimitry Andric     if (info->HandlesUnwind)
1740b57cec5SDimitry Andric       flags |= Win64EH::UNW_TerminateHandler << 3;
1750b57cec5SDimitry Andric     if (info->HandlesExceptions)
1760b57cec5SDimitry Andric       flags |= Win64EH::UNW_ExceptionHandler << 3;
1770b57cec5SDimitry Andric   }
1785ffd83dbSDimitry Andric   streamer.emitInt8(flags);
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   if (info->PrologEnd)
1810b57cec5SDimitry Andric     EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
1820b57cec5SDimitry Andric   else
1835ffd83dbSDimitry Andric     streamer.emitInt8(0);
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
1865ffd83dbSDimitry Andric   streamer.emitInt8(numCodes);
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   uint8_t frame = 0;
1890b57cec5SDimitry Andric   if (info->LastFrameInst >= 0) {
1900b57cec5SDimitry Andric     WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
1910b57cec5SDimitry Andric     assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
1920b57cec5SDimitry Andric     frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
1930b57cec5SDimitry Andric   }
1945ffd83dbSDimitry Andric   streamer.emitInt8(frame);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   // Emit unwind instructions (in reverse order).
1970b57cec5SDimitry Andric   uint8_t numInst = info->Instructions.size();
1980b57cec5SDimitry Andric   for (uint8_t c = 0; c < numInst; ++c) {
1990b57cec5SDimitry Andric     WinEH::Instruction inst = info->Instructions.back();
2000b57cec5SDimitry Andric     info->Instructions.pop_back();
2010b57cec5SDimitry Andric     EmitUnwindCode(streamer, info->Begin, inst);
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   // For alignment purposes, the instruction array will always have an even
2050b57cec5SDimitry Andric   // number of entries, with the final entry potentially unused (in which case
2060b57cec5SDimitry Andric   // the array will be one longer than indicated by the count of unwind codes
2070b57cec5SDimitry Andric   // field).
2080b57cec5SDimitry Andric   if (numCodes & 1) {
2095ffd83dbSDimitry Andric     streamer.emitInt16(0);
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   if (flags & (Win64EH::UNW_ChainInfo << 3))
2130b57cec5SDimitry Andric     EmitRuntimeFunction(streamer, info->ChainedParent);
2140b57cec5SDimitry Andric   else if (flags &
2150b57cec5SDimitry Andric            ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
2165ffd83dbSDimitry Andric     streamer.emitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
2170b57cec5SDimitry Andric                                               MCSymbolRefExpr::VK_COFF_IMGREL32,
2180b57cec5SDimitry Andric                                               context), 4);
2190b57cec5SDimitry Andric   else if (numCodes == 0) {
2200b57cec5SDimitry Andric     // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
2210b57cec5SDimitry Andric     // a chained unwind info, if there is no handler, and if there are fewer
2220b57cec5SDimitry Andric     // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
2235ffd83dbSDimitry Andric     streamer.emitInt32(0);
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const {
2280b57cec5SDimitry Andric   // Emit the unwind info structs first.
2290b57cec5SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2300b57cec5SDimitry Andric     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
231*81ad6265SDimitry Andric     Streamer.switchSection(XData);
2320b57cec5SDimitry Andric     ::EmitUnwindInfo(Streamer, CFI.get());
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   // Now emit RUNTIME_FUNCTION entries.
2360b57cec5SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2370b57cec5SDimitry Andric     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
238*81ad6265SDimitry Andric     Streamer.switchSection(PData);
2390b57cec5SDimitry Andric     EmitRuntimeFunction(Streamer, CFI.get());
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
243e8d8bef9SDimitry Andric void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
244e8d8bef9SDimitry Andric                                                   WinEH::FrameInfo *info,
245e8d8bef9SDimitry Andric                                                   bool HandlerData) const {
2460b57cec5SDimitry Andric   // Switch sections (the static function above is meant to be called from
2470b57cec5SDimitry Andric   // here and from Emit().
2480b57cec5SDimitry Andric   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
249*81ad6265SDimitry Andric   Streamer.switchSection(XData);
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   ::EmitUnwindInfo(Streamer, info);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
254*81ad6265SDimitry Andric static const MCExpr *GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS,
255*81ad6265SDimitry Andric                                    const MCSymbol *RHS, int Div) {
256*81ad6265SDimitry Andric   MCContext &Context = Streamer.getContext();
257*81ad6265SDimitry Andric   const MCExpr *Expr =
258*81ad6265SDimitry Andric       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
259*81ad6265SDimitry Andric                               MCSymbolRefExpr::create(RHS, Context), Context);
260*81ad6265SDimitry Andric   if (Div != 1)
261*81ad6265SDimitry Andric     Expr = MCBinaryExpr::createDiv(Expr, MCConstantExpr::create(Div, Context),
262*81ad6265SDimitry Andric                                    Context);
263*81ad6265SDimitry Andric   return Expr;
264*81ad6265SDimitry Andric }
265*81ad6265SDimitry Andric 
266*81ad6265SDimitry Andric static Optional<int64_t> GetOptionalAbsDifference(MCStreamer &Streamer,
267*81ad6265SDimitry Andric                                                   const MCSymbol *LHS,
2680b57cec5SDimitry Andric                                                   const MCSymbol *RHS) {
2690b57cec5SDimitry Andric   MCContext &Context = Streamer.getContext();
2700b57cec5SDimitry Andric   const MCExpr *Diff =
2710b57cec5SDimitry Andric       MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
2720b57cec5SDimitry Andric                               MCSymbolRefExpr::create(RHS, Context), Context);
2730b57cec5SDimitry Andric   MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
2740b57cec5SDimitry Andric   // It should normally be possible to calculate the length of a function
2750b57cec5SDimitry Andric   // at this point, but it might not be possible in the presence of certain
2760b57cec5SDimitry Andric   // unusual constructs, like an inline asm with an alignment directive.
2770b57cec5SDimitry Andric   int64_t value;
2780b57cec5SDimitry Andric   if (!Diff->evaluateAsAbsolute(value, OS->getAssembler()))
279*81ad6265SDimitry Andric     return None;
2800b57cec5SDimitry Andric   return value;
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
283*81ad6265SDimitry Andric static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
284*81ad6265SDimitry Andric                                 const MCSymbol *RHS) {
285*81ad6265SDimitry Andric   Optional<int64_t> MaybeDiff = GetOptionalAbsDifference(Streamer, LHS, RHS);
286*81ad6265SDimitry Andric   if (!MaybeDiff)
287*81ad6265SDimitry Andric     report_fatal_error("Failed to evaluate function length in SEH unwind info");
288*81ad6265SDimitry Andric   return *MaybeDiff;
289*81ad6265SDimitry Andric }
290*81ad6265SDimitry Andric 
291e8d8bef9SDimitry Andric static uint32_t ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
2920b57cec5SDimitry Andric   uint32_t Count = 0;
2930b57cec5SDimitry Andric   for (const auto &I : Insns) {
2940b57cec5SDimitry Andric     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
2950b57cec5SDimitry Andric     default:
2960b57cec5SDimitry Andric       llvm_unreachable("Unsupported ARM64 unwind code");
2970b57cec5SDimitry Andric     case Win64EH::UOP_AllocSmall:
2980b57cec5SDimitry Andric       Count += 1;
2990b57cec5SDimitry Andric       break;
3000b57cec5SDimitry Andric     case Win64EH::UOP_AllocMedium:
3010b57cec5SDimitry Andric       Count += 2;
3020b57cec5SDimitry Andric       break;
3030b57cec5SDimitry Andric     case Win64EH::UOP_AllocLarge:
3040b57cec5SDimitry Andric       Count += 4;
3050b57cec5SDimitry Andric       break;
306e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveR19R20X:
307e8d8bef9SDimitry Andric       Count += 1;
308e8d8bef9SDimitry Andric       break;
3090b57cec5SDimitry Andric     case Win64EH::UOP_SaveFPLRX:
3100b57cec5SDimitry Andric       Count += 1;
3110b57cec5SDimitry Andric       break;
3120b57cec5SDimitry Andric     case Win64EH::UOP_SaveFPLR:
3130b57cec5SDimitry Andric       Count += 1;
3140b57cec5SDimitry Andric       break;
3150b57cec5SDimitry Andric     case Win64EH::UOP_SaveReg:
3160b57cec5SDimitry Andric       Count += 2;
3170b57cec5SDimitry Andric       break;
3180b57cec5SDimitry Andric     case Win64EH::UOP_SaveRegP:
3190b57cec5SDimitry Andric       Count += 2;
3200b57cec5SDimitry Andric       break;
3210b57cec5SDimitry Andric     case Win64EH::UOP_SaveRegPX:
3220b57cec5SDimitry Andric       Count += 2;
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric     case Win64EH::UOP_SaveRegX:
3250b57cec5SDimitry Andric       Count += 2;
3260b57cec5SDimitry Andric       break;
327e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveLRPair:
328e8d8bef9SDimitry Andric       Count += 2;
329e8d8bef9SDimitry Andric       break;
3300b57cec5SDimitry Andric     case Win64EH::UOP_SaveFReg:
3310b57cec5SDimitry Andric       Count += 2;
3320b57cec5SDimitry Andric       break;
3330b57cec5SDimitry Andric     case Win64EH::UOP_SaveFRegP:
3340b57cec5SDimitry Andric       Count += 2;
3350b57cec5SDimitry Andric       break;
3360b57cec5SDimitry Andric     case Win64EH::UOP_SaveFRegX:
3370b57cec5SDimitry Andric       Count += 2;
3380b57cec5SDimitry Andric       break;
3390b57cec5SDimitry Andric     case Win64EH::UOP_SaveFRegPX:
3400b57cec5SDimitry Andric       Count += 2;
3410b57cec5SDimitry Andric       break;
3420b57cec5SDimitry Andric     case Win64EH::UOP_SetFP:
3430b57cec5SDimitry Andric       Count += 1;
3440b57cec5SDimitry Andric       break;
3450b57cec5SDimitry Andric     case Win64EH::UOP_AddFP:
3460b57cec5SDimitry Andric       Count += 2;
3470b57cec5SDimitry Andric       break;
3480b57cec5SDimitry Andric     case Win64EH::UOP_Nop:
3490b57cec5SDimitry Andric       Count += 1;
3500b57cec5SDimitry Andric       break;
3510b57cec5SDimitry Andric     case Win64EH::UOP_End:
3520b57cec5SDimitry Andric       Count += 1;
3530b57cec5SDimitry Andric       break;
354e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveNext:
355e8d8bef9SDimitry Andric       Count += 1;
356e8d8bef9SDimitry Andric       break;
357e8d8bef9SDimitry Andric     case Win64EH::UOP_TrapFrame:
358e8d8bef9SDimitry Andric       Count += 1;
359e8d8bef9SDimitry Andric       break;
360e8d8bef9SDimitry Andric     case Win64EH::UOP_PushMachFrame:
361e8d8bef9SDimitry Andric       Count += 1;
362e8d8bef9SDimitry Andric       break;
363e8d8bef9SDimitry Andric     case Win64EH::UOP_Context:
364e8d8bef9SDimitry Andric       Count += 1;
365e8d8bef9SDimitry Andric       break;
366e8d8bef9SDimitry Andric     case Win64EH::UOP_ClearUnwoundToCall:
367e8d8bef9SDimitry Andric       Count += 1;
368e8d8bef9SDimitry Andric       break;
3690b57cec5SDimitry Andric     }
3700b57cec5SDimitry Andric   }
3710b57cec5SDimitry Andric   return Count;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric // Unwind opcode encodings and restrictions are documented at
3750b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
376*81ad6265SDimitry Andric static void ARM64EmitUnwindCode(MCStreamer &streamer,
3770eae32dcSDimitry Andric                                 const WinEH::Instruction &inst) {
3780b57cec5SDimitry Andric   uint8_t b, reg;
3790b57cec5SDimitry Andric   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
3800b57cec5SDimitry Andric   default:
3810b57cec5SDimitry Andric     llvm_unreachable("Unsupported ARM64 unwind code");
3820b57cec5SDimitry Andric   case Win64EH::UOP_AllocSmall:
3830b57cec5SDimitry Andric     b = (inst.Offset >> 4) & 0x1F;
3845ffd83dbSDimitry Andric     streamer.emitInt8(b);
3850b57cec5SDimitry Andric     break;
3860b57cec5SDimitry Andric   case Win64EH::UOP_AllocMedium: {
3870b57cec5SDimitry Andric     uint16_t hw = (inst.Offset >> 4) & 0x7FF;
3880b57cec5SDimitry Andric     b = 0xC0;
3890b57cec5SDimitry Andric     b |= (hw >> 8);
3905ffd83dbSDimitry Andric     streamer.emitInt8(b);
3910b57cec5SDimitry Andric     b = hw & 0xFF;
3925ffd83dbSDimitry Andric     streamer.emitInt8(b);
3930b57cec5SDimitry Andric     break;
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric   case Win64EH::UOP_AllocLarge: {
3960b57cec5SDimitry Andric     uint32_t w;
3970b57cec5SDimitry Andric     b = 0xE0;
3985ffd83dbSDimitry Andric     streamer.emitInt8(b);
3990b57cec5SDimitry Andric     w = inst.Offset >> 4;
4000b57cec5SDimitry Andric     b = (w & 0x00FF0000) >> 16;
4015ffd83dbSDimitry Andric     streamer.emitInt8(b);
4020b57cec5SDimitry Andric     b = (w & 0x0000FF00) >> 8;
4035ffd83dbSDimitry Andric     streamer.emitInt8(b);
4040b57cec5SDimitry Andric     b = w & 0x000000FF;
4055ffd83dbSDimitry Andric     streamer.emitInt8(b);
4060b57cec5SDimitry Andric     break;
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric   case Win64EH::UOP_SetFP:
4090b57cec5SDimitry Andric     b = 0xE1;
4105ffd83dbSDimitry Andric     streamer.emitInt8(b);
4110b57cec5SDimitry Andric     break;
4120b57cec5SDimitry Andric   case Win64EH::UOP_AddFP:
4130b57cec5SDimitry Andric     b = 0xE2;
4145ffd83dbSDimitry Andric     streamer.emitInt8(b);
4150b57cec5SDimitry Andric     b = (inst.Offset >> 3);
4165ffd83dbSDimitry Andric     streamer.emitInt8(b);
4170b57cec5SDimitry Andric     break;
4180b57cec5SDimitry Andric   case Win64EH::UOP_Nop:
4190b57cec5SDimitry Andric     b = 0xE3;
4205ffd83dbSDimitry Andric     streamer.emitInt8(b);
4210b57cec5SDimitry Andric     break;
422e8d8bef9SDimitry Andric   case Win64EH::UOP_SaveR19R20X:
423e8d8bef9SDimitry Andric     b = 0x20;
424e8d8bef9SDimitry Andric     b |= (inst.Offset >> 3) & 0x1F;
425e8d8bef9SDimitry Andric     streamer.emitInt8(b);
426e8d8bef9SDimitry Andric     break;
4270b57cec5SDimitry Andric   case Win64EH::UOP_SaveFPLRX:
4280b57cec5SDimitry Andric     b = 0x80;
4290b57cec5SDimitry Andric     b |= ((inst.Offset - 1) >> 3) & 0x3F;
4305ffd83dbSDimitry Andric     streamer.emitInt8(b);
4310b57cec5SDimitry Andric     break;
4320b57cec5SDimitry Andric   case Win64EH::UOP_SaveFPLR:
4330b57cec5SDimitry Andric     b = 0x40;
4340b57cec5SDimitry Andric     b |= (inst.Offset >> 3) & 0x3F;
4355ffd83dbSDimitry Andric     streamer.emitInt8(b);
4360b57cec5SDimitry Andric     break;
4370b57cec5SDimitry Andric   case Win64EH::UOP_SaveReg:
4380b57cec5SDimitry Andric     assert(inst.Register >= 19 && "Saved reg must be >= 19");
4390b57cec5SDimitry Andric     reg = inst.Register - 19;
4400b57cec5SDimitry Andric     b = 0xD0 | ((reg & 0xC) >> 2);
4415ffd83dbSDimitry Andric     streamer.emitInt8(b);
4420b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
4435ffd83dbSDimitry Andric     streamer.emitInt8(b);
4440b57cec5SDimitry Andric     break;
4450b57cec5SDimitry Andric   case Win64EH::UOP_SaveRegX:
4460b57cec5SDimitry Andric     assert(inst.Register >= 19 && "Saved reg must be >= 19");
4470b57cec5SDimitry Andric     reg = inst.Register - 19;
4480b57cec5SDimitry Andric     b = 0xD4 | ((reg & 0x8) >> 3);
4495ffd83dbSDimitry Andric     streamer.emitInt8(b);
4500b57cec5SDimitry Andric     b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
4515ffd83dbSDimitry Andric     streamer.emitInt8(b);
4520b57cec5SDimitry Andric     break;
4530b57cec5SDimitry Andric   case Win64EH::UOP_SaveRegP:
4540b57cec5SDimitry Andric     assert(inst.Register >= 19 && "Saved registers must be >= 19");
4550b57cec5SDimitry Andric     reg = inst.Register - 19;
4560b57cec5SDimitry Andric     b = 0xC8 | ((reg & 0xC) >> 2);
4575ffd83dbSDimitry Andric     streamer.emitInt8(b);
4580b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
4595ffd83dbSDimitry Andric     streamer.emitInt8(b);
4600b57cec5SDimitry Andric     break;
4610b57cec5SDimitry Andric   case Win64EH::UOP_SaveRegPX:
4620b57cec5SDimitry Andric     assert(inst.Register >= 19 && "Saved registers must be >= 19");
4630b57cec5SDimitry Andric     reg = inst.Register - 19;
4640b57cec5SDimitry Andric     b = 0xCC | ((reg & 0xC) >> 2);
4655ffd83dbSDimitry Andric     streamer.emitInt8(b);
4660b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
4675ffd83dbSDimitry Andric     streamer.emitInt8(b);
4680b57cec5SDimitry Andric     break;
469e8d8bef9SDimitry Andric   case Win64EH::UOP_SaveLRPair:
470e8d8bef9SDimitry Andric     assert(inst.Register >= 19 && "Saved reg must be >= 19");
471e8d8bef9SDimitry Andric     reg = inst.Register - 19;
472e8d8bef9SDimitry Andric     assert((reg % 2) == 0 && "Saved reg must be 19+2*X");
473e8d8bef9SDimitry Andric     reg /= 2;
474e8d8bef9SDimitry Andric     b = 0xD6 | ((reg & 0x7) >> 2);
475e8d8bef9SDimitry Andric     streamer.emitInt8(b);
476e8d8bef9SDimitry Andric     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
477e8d8bef9SDimitry Andric     streamer.emitInt8(b);
478e8d8bef9SDimitry Andric     break;
4790b57cec5SDimitry Andric   case Win64EH::UOP_SaveFReg:
4800b57cec5SDimitry Andric     assert(inst.Register >= 8 && "Saved dreg must be >= 8");
4810b57cec5SDimitry Andric     reg = inst.Register - 8;
4820b57cec5SDimitry Andric     b = 0xDC | ((reg & 0x4) >> 2);
4835ffd83dbSDimitry Andric     streamer.emitInt8(b);
4840b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
4855ffd83dbSDimitry Andric     streamer.emitInt8(b);
4860b57cec5SDimitry Andric     break;
4870b57cec5SDimitry Andric   case Win64EH::UOP_SaveFRegX:
4880b57cec5SDimitry Andric     assert(inst.Register >= 8 && "Saved dreg must be >= 8");
4890b57cec5SDimitry Andric     reg = inst.Register - 8;
4900b57cec5SDimitry Andric     b = 0xDE;
4915ffd83dbSDimitry Andric     streamer.emitInt8(b);
4920b57cec5SDimitry Andric     b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
4935ffd83dbSDimitry Andric     streamer.emitInt8(b);
4940b57cec5SDimitry Andric     break;
4950b57cec5SDimitry Andric   case Win64EH::UOP_SaveFRegP:
4960b57cec5SDimitry Andric     assert(inst.Register >= 8 && "Saved dregs must be >= 8");
4970b57cec5SDimitry Andric     reg = inst.Register - 8;
4980b57cec5SDimitry Andric     b = 0xD8 | ((reg & 0x4) >> 2);
4995ffd83dbSDimitry Andric     streamer.emitInt8(b);
5000b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
5015ffd83dbSDimitry Andric     streamer.emitInt8(b);
5020b57cec5SDimitry Andric     break;
5030b57cec5SDimitry Andric   case Win64EH::UOP_SaveFRegPX:
5040b57cec5SDimitry Andric     assert(inst.Register >= 8 && "Saved dregs must be >= 8");
5050b57cec5SDimitry Andric     reg = inst.Register - 8;
5060b57cec5SDimitry Andric     b = 0xDA | ((reg & 0x4) >> 2);
5075ffd83dbSDimitry Andric     streamer.emitInt8(b);
5080b57cec5SDimitry Andric     b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
5095ffd83dbSDimitry Andric     streamer.emitInt8(b);
5100b57cec5SDimitry Andric     break;
5110b57cec5SDimitry Andric   case Win64EH::UOP_End:
5120b57cec5SDimitry Andric     b = 0xE4;
5135ffd83dbSDimitry Andric     streamer.emitInt8(b);
5140b57cec5SDimitry Andric     break;
515e8d8bef9SDimitry Andric   case Win64EH::UOP_SaveNext:
516e8d8bef9SDimitry Andric     b = 0xE6;
517e8d8bef9SDimitry Andric     streamer.emitInt8(b);
518e8d8bef9SDimitry Andric     break;
519e8d8bef9SDimitry Andric   case Win64EH::UOP_TrapFrame:
520e8d8bef9SDimitry Andric     b = 0xE8;
521e8d8bef9SDimitry Andric     streamer.emitInt8(b);
522e8d8bef9SDimitry Andric     break;
523e8d8bef9SDimitry Andric   case Win64EH::UOP_PushMachFrame:
524e8d8bef9SDimitry Andric     b = 0xE9;
525e8d8bef9SDimitry Andric     streamer.emitInt8(b);
526e8d8bef9SDimitry Andric     break;
527e8d8bef9SDimitry Andric   case Win64EH::UOP_Context:
528e8d8bef9SDimitry Andric     b = 0xEA;
529e8d8bef9SDimitry Andric     streamer.emitInt8(b);
530e8d8bef9SDimitry Andric     break;
531e8d8bef9SDimitry Andric   case Win64EH::UOP_ClearUnwoundToCall:
532e8d8bef9SDimitry Andric     b = 0xEC;
533e8d8bef9SDimitry Andric     streamer.emitInt8(b);
534e8d8bef9SDimitry Andric     break;
5350b57cec5SDimitry Andric   }
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric // Returns the epilog symbol of an epilog with the exact same unwind code
539*81ad6265SDimitry Andric // sequence, if it exists.  Otherwise, returns nullptr.
5400b57cec5SDimitry Andric // EpilogInstrs - Unwind codes for the current epilog.
5410b57cec5SDimitry Andric // Epilogs - Epilogs that potentialy match the current epilog.
5420b57cec5SDimitry Andric static MCSymbol*
5430b57cec5SDimitry Andric FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
5440b57cec5SDimitry Andric                    const std::vector<MCSymbol *>& Epilogs,
5450b57cec5SDimitry Andric                    const WinEH::FrameInfo *info) {
5460b57cec5SDimitry Andric   for (auto *EpilogStart : Epilogs) {
5470b57cec5SDimitry Andric     auto InstrsIter = info->EpilogMap.find(EpilogStart);
5480b57cec5SDimitry Andric     assert(InstrsIter != info->EpilogMap.end() &&
5490b57cec5SDimitry Andric            "Epilog not found in EpilogMap");
550*81ad6265SDimitry Andric     const auto &Instrs = InstrsIter->second.Instructions;
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric     if (Instrs.size() != EpilogInstrs.size())
5530b57cec5SDimitry Andric       continue;
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric     bool Match = true;
5560b57cec5SDimitry Andric     for (unsigned i = 0; i < Instrs.size(); ++i)
557*81ad6265SDimitry Andric       if (Instrs[i] != EpilogInstrs[i]) {
5580b57cec5SDimitry Andric         Match = false;
5590b57cec5SDimitry Andric         break;
5600b57cec5SDimitry Andric       }
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric     if (Match)
5630b57cec5SDimitry Andric       return EpilogStart;
5640b57cec5SDimitry Andric   }
5650b57cec5SDimitry Andric   return nullptr;
5660b57cec5SDimitry Andric }
5670b57cec5SDimitry Andric 
568*81ad6265SDimitry Andric static void simplifyARM64Opcodes(std::vector<WinEH::Instruction> &Instructions,
569e8d8bef9SDimitry Andric                                  bool Reverse) {
570e8d8bef9SDimitry Andric   unsigned PrevOffset = -1;
571e8d8bef9SDimitry Andric   unsigned PrevRegister = -1;
572e8d8bef9SDimitry Andric 
573e8d8bef9SDimitry Andric   auto VisitInstruction = [&](WinEH::Instruction &Inst) {
574e8d8bef9SDimitry Andric     // Convert 2-byte opcodes into equivalent 1-byte ones.
575e8d8bef9SDimitry Andric     if (Inst.Operation == Win64EH::UOP_SaveRegP && Inst.Register == 29) {
576e8d8bef9SDimitry Andric       Inst.Operation = Win64EH::UOP_SaveFPLR;
577e8d8bef9SDimitry Andric       Inst.Register = -1;
578e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
579e8d8bef9SDimitry Andric                Inst.Register == 29) {
580e8d8bef9SDimitry Andric       Inst.Operation = Win64EH::UOP_SaveFPLRX;
581e8d8bef9SDimitry Andric       Inst.Register = -1;
582e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX &&
583e8d8bef9SDimitry Andric                Inst.Register == 19 && Inst.Offset <= 248) {
584e8d8bef9SDimitry Andric       Inst.Operation = Win64EH::UOP_SaveR19R20X;
585e8d8bef9SDimitry Andric       Inst.Register = -1;
586e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_AddFP && Inst.Offset == 0) {
587e8d8bef9SDimitry Andric       Inst.Operation = Win64EH::UOP_SetFP;
588e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveRegP &&
589e8d8bef9SDimitry Andric                Inst.Register == PrevRegister + 2 &&
590e8d8bef9SDimitry Andric                Inst.Offset == PrevOffset + 16) {
591e8d8bef9SDimitry Andric       Inst.Operation = Win64EH::UOP_SaveNext;
592e8d8bef9SDimitry Andric       Inst.Register = -1;
593e8d8bef9SDimitry Andric       Inst.Offset = 0;
594e8d8bef9SDimitry Andric       // Intentionally not creating UOP_SaveNext for float register pairs,
595e8d8bef9SDimitry Andric       // as current versions of Windows (up to at least 20.04) is buggy
596e8d8bef9SDimitry Andric       // regarding SaveNext for float pairs.
597e8d8bef9SDimitry Andric     }
598e8d8bef9SDimitry Andric     // Update info about the previous instruction, for detecting if
599e8d8bef9SDimitry Andric     // the next one can be made a UOP_SaveNext
600e8d8bef9SDimitry Andric     if (Inst.Operation == Win64EH::UOP_SaveR19R20X) {
601e8d8bef9SDimitry Andric       PrevOffset = 0;
602e8d8bef9SDimitry Andric       PrevRegister = 19;
603e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveRegPX) {
604e8d8bef9SDimitry Andric       PrevOffset = 0;
605e8d8bef9SDimitry Andric       PrevRegister = Inst.Register;
606e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveRegP) {
607e8d8bef9SDimitry Andric       PrevOffset = Inst.Offset;
608e8d8bef9SDimitry Andric       PrevRegister = Inst.Register;
609e8d8bef9SDimitry Andric     } else if (Inst.Operation == Win64EH::UOP_SaveNext) {
610e8d8bef9SDimitry Andric       PrevRegister += 2;
611e8d8bef9SDimitry Andric       PrevOffset += 16;
612e8d8bef9SDimitry Andric     } else {
613e8d8bef9SDimitry Andric       PrevRegister = -1;
614e8d8bef9SDimitry Andric       PrevOffset = -1;
615e8d8bef9SDimitry Andric     }
616e8d8bef9SDimitry Andric   };
617e8d8bef9SDimitry Andric 
618e8d8bef9SDimitry Andric   // Iterate over instructions in a forward order (for prologues),
619e8d8bef9SDimitry Andric   // backwards for epilogues (i.e. always reverse compared to how the
620e8d8bef9SDimitry Andric   // opcodes are stored).
621e8d8bef9SDimitry Andric   if (Reverse) {
622e8d8bef9SDimitry Andric     for (auto It = Instructions.rbegin(); It != Instructions.rend(); It++)
623e8d8bef9SDimitry Andric       VisitInstruction(*It);
624e8d8bef9SDimitry Andric   } else {
625e8d8bef9SDimitry Andric     for (WinEH::Instruction &Inst : Instructions)
626e8d8bef9SDimitry Andric       VisitInstruction(Inst);
627e8d8bef9SDimitry Andric   }
628e8d8bef9SDimitry Andric }
629e8d8bef9SDimitry Andric 
630*81ad6265SDimitry Andric // Check if an epilog exists as a subset of the end of a prolog (backwards).
631*81ad6265SDimitry Andric static int
632*81ad6265SDimitry Andric getARM64OffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
633*81ad6265SDimitry Andric                        const std::vector<WinEH::Instruction> &Epilog) {
634*81ad6265SDimitry Andric   // Can't find an epilog as a subset if it is longer than the prolog.
635*81ad6265SDimitry Andric   if (Epilog.size() > Prolog.size())
636*81ad6265SDimitry Andric     return -1;
637*81ad6265SDimitry Andric 
638*81ad6265SDimitry Andric   // Check that the epilog actually is a perfect match for the end (backwrds)
639*81ad6265SDimitry Andric   // of the prolog.
640*81ad6265SDimitry Andric   for (int I = Epilog.size() - 1; I >= 0; I--) {
641*81ad6265SDimitry Andric     if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
642*81ad6265SDimitry Andric       return -1;
643*81ad6265SDimitry Andric   }
644*81ad6265SDimitry Andric 
645*81ad6265SDimitry Andric   // If the epilog was a subset of the prolog, find its offset.
646*81ad6265SDimitry Andric   if (Epilog.size() == Prolog.size())
647*81ad6265SDimitry Andric     return 0;
648*81ad6265SDimitry Andric   return ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
649*81ad6265SDimitry Andric       &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
650*81ad6265SDimitry Andric }
651*81ad6265SDimitry Andric 
652*81ad6265SDimitry Andric static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
653e8d8bef9SDimitry Andric                                   int PrologCodeBytes) {
654e8d8bef9SDimitry Andric   // Can only pack if there's one single epilog
655e8d8bef9SDimitry Andric   if (info->EpilogMap.size() != 1)
656e8d8bef9SDimitry Andric     return -1;
657e8d8bef9SDimitry Andric 
658e8d8bef9SDimitry Andric   const std::vector<WinEH::Instruction> &Epilog =
659*81ad6265SDimitry Andric       info->EpilogMap.begin()->second.Instructions;
660e8d8bef9SDimitry Andric 
661e8d8bef9SDimitry Andric   // Check that the epilog actually is at the very end of the function,
662e8d8bef9SDimitry Andric   // otherwise it can't be packed.
663e8d8bef9SDimitry Andric   uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference(
664e8d8bef9SDimitry Andric       streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
665e8d8bef9SDimitry Andric   if (DistanceFromEnd / 4 != Epilog.size())
666e8d8bef9SDimitry Andric     return -1;
667e8d8bef9SDimitry Andric 
668*81ad6265SDimitry Andric   int RetVal = -1;
669*81ad6265SDimitry Andric   // Even if we don't end up sharing opcodes with the prolog, we can still
670*81ad6265SDimitry Andric   // write the offset as a packed offset, if the single epilog is located at
671*81ad6265SDimitry Andric   // the end of the function and the offset (pointing after the prolog) fits
672*81ad6265SDimitry Andric   // as a packed offset.
673*81ad6265SDimitry Andric   if (PrologCodeBytes <= 31 &&
674*81ad6265SDimitry Andric       PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
675*81ad6265SDimitry Andric     RetVal = PrologCodeBytes;
676*81ad6265SDimitry Andric 
677*81ad6265SDimitry Andric   int Offset = getARM64OffsetInProlog(info->Instructions, Epilog);
678*81ad6265SDimitry Andric   if (Offset < 0)
679*81ad6265SDimitry Andric     return RetVal;
680e8d8bef9SDimitry Andric 
681e8d8bef9SDimitry Andric   // Check that the offset and prolog size fits in the first word; it's
682e8d8bef9SDimitry Andric   // unclear whether the epilog count in the extension word can be taken
683e8d8bef9SDimitry Andric   // as packed epilog offset.
684e8d8bef9SDimitry Andric   if (Offset > 31 || PrologCodeBytes > 124)
685*81ad6265SDimitry Andric     return RetVal;
686e8d8bef9SDimitry Andric 
687*81ad6265SDimitry Andric   // As we choose to express the epilog as part of the prolog, remove the
688*81ad6265SDimitry Andric   // epilog from the map, so we don't try to emit its opcodes.
689e8d8bef9SDimitry Andric   info->EpilogMap.clear();
690e8d8bef9SDimitry Andric   return Offset;
691e8d8bef9SDimitry Andric }
692e8d8bef9SDimitry Andric 
693*81ad6265SDimitry Andric static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength,
694e8d8bef9SDimitry Andric                                  int PackedEpilogOffset) {
695e8d8bef9SDimitry Andric   if (PackedEpilogOffset == 0) {
696e8d8bef9SDimitry Andric     // Fully symmetric prolog and epilog, should be ok for packed format.
697e8d8bef9SDimitry Andric     // For CR=3, the corresponding synthesized epilog actually lacks the
698e8d8bef9SDimitry Andric     // SetFP opcode, but unwinding should work just fine despite that
699e8d8bef9SDimitry Andric     // (if at the SetFP opcode, the unwinder considers it as part of the
700e8d8bef9SDimitry Andric     // function body and just unwinds the full prolog instead).
701e8d8bef9SDimitry Andric   } else if (PackedEpilogOffset == 1) {
702e8d8bef9SDimitry Andric     // One single case of differences between prolog and epilog is allowed:
703e8d8bef9SDimitry Andric     // The epilog can lack a single SetFP that is the last opcode in the
704e8d8bef9SDimitry Andric     // prolog, for the CR=3 case.
705e8d8bef9SDimitry Andric     if (info->Instructions.back().Operation != Win64EH::UOP_SetFP)
706e8d8bef9SDimitry Andric       return false;
707e8d8bef9SDimitry Andric   } else {
708e8d8bef9SDimitry Andric     // Too much difference between prolog and epilog.
709e8d8bef9SDimitry Andric     return false;
710e8d8bef9SDimitry Andric   }
711e8d8bef9SDimitry Andric   unsigned RegI = 0, RegF = 0;
712e8d8bef9SDimitry Andric   int Predecrement = 0;
713e8d8bef9SDimitry Andric   enum {
714e8d8bef9SDimitry Andric     Start,
715e8d8bef9SDimitry Andric     Start2,
716e8d8bef9SDimitry Andric     IntRegs,
717e8d8bef9SDimitry Andric     FloatRegs,
718e8d8bef9SDimitry Andric     InputArgs,
719e8d8bef9SDimitry Andric     StackAdjust,
720e8d8bef9SDimitry Andric     FrameRecord,
721e8d8bef9SDimitry Andric     End
722e8d8bef9SDimitry Andric   } Location = Start;
723e8d8bef9SDimitry Andric   bool StandaloneLR = false, FPLRPair = false;
724e8d8bef9SDimitry Andric   int StackOffset = 0;
725e8d8bef9SDimitry Andric   int Nops = 0;
726e8d8bef9SDimitry Andric   // Iterate over the prolog and check that all opcodes exactly match
727e8d8bef9SDimitry Andric   // the canonical order and form. A more lax check could verify that
728e8d8bef9SDimitry Andric   // all saved registers are in the expected locations, but not enforce
729e8d8bef9SDimitry Andric   // the order - that would work fine when unwinding from within
730e8d8bef9SDimitry Andric   // functions, but not be exactly right if unwinding happens within
731e8d8bef9SDimitry Andric   // prologs/epilogs.
732e8d8bef9SDimitry Andric   for (const WinEH::Instruction &Inst : info->Instructions) {
733e8d8bef9SDimitry Andric     switch (Inst.Operation) {
734e8d8bef9SDimitry Andric     case Win64EH::UOP_End:
735e8d8bef9SDimitry Andric       if (Location != Start)
736e8d8bef9SDimitry Andric         return false;
737e8d8bef9SDimitry Andric       Location = Start2;
738e8d8bef9SDimitry Andric       break;
739e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveR19R20X:
740e8d8bef9SDimitry Andric       if (Location != Start2)
741e8d8bef9SDimitry Andric         return false;
742e8d8bef9SDimitry Andric       Predecrement = Inst.Offset;
743e8d8bef9SDimitry Andric       RegI = 2;
744e8d8bef9SDimitry Andric       Location = IntRegs;
745e8d8bef9SDimitry Andric       break;
746e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveRegX:
747e8d8bef9SDimitry Andric       if (Location != Start2)
748e8d8bef9SDimitry Andric         return false;
749e8d8bef9SDimitry Andric       Predecrement = Inst.Offset;
750e8d8bef9SDimitry Andric       if (Inst.Register == 19)
751e8d8bef9SDimitry Andric         RegI += 1;
752e8d8bef9SDimitry Andric       else if (Inst.Register == 30)
753e8d8bef9SDimitry Andric         StandaloneLR = true;
754e8d8bef9SDimitry Andric       else
755e8d8bef9SDimitry Andric         return false;
756e8d8bef9SDimitry Andric       // Odd register; can't be any further int registers.
757e8d8bef9SDimitry Andric       Location = FloatRegs;
758e8d8bef9SDimitry Andric       break;
759e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveRegPX:
760e8d8bef9SDimitry Andric       // Can't have this in a canonical prologue. Either this has been
761e8d8bef9SDimitry Andric       // canonicalized into SaveR19R20X or SaveFPLRX, or it's an unsupported
762e8d8bef9SDimitry Andric       // register pair.
763e8d8bef9SDimitry Andric       // It can't be canonicalized into SaveR19R20X if the offset is
764e8d8bef9SDimitry Andric       // larger than 248 bytes, but even with the maximum case with
765e8d8bef9SDimitry Andric       // RegI=10/RegF=8/CR=1/H=1, we end up with SavSZ = 216, which should
766e8d8bef9SDimitry Andric       // fit into SaveR19R20X.
767e8d8bef9SDimitry Andric       // The unwinding opcodes can't describe the otherwise seemingly valid
768e8d8bef9SDimitry Andric       // case for RegI=1 CR=1, that would start with a
769e8d8bef9SDimitry Andric       // "stp x19, lr, [sp, #-...]!" as that fits neither SaveRegPX nor
770e8d8bef9SDimitry Andric       // SaveLRPair.
771e8d8bef9SDimitry Andric       return false;
772e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveRegP:
773e8d8bef9SDimitry Andric       if (Location != IntRegs || Inst.Offset != 8 * RegI ||
774e8d8bef9SDimitry Andric           Inst.Register != 19 + RegI)
775e8d8bef9SDimitry Andric         return false;
776e8d8bef9SDimitry Andric       RegI += 2;
777e8d8bef9SDimitry Andric       break;
778e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveReg:
779e8d8bef9SDimitry Andric       if (Location != IntRegs || Inst.Offset != 8 * RegI)
780e8d8bef9SDimitry Andric         return false;
781e8d8bef9SDimitry Andric       if (Inst.Register == 19 + RegI)
782e8d8bef9SDimitry Andric         RegI += 1;
783e8d8bef9SDimitry Andric       else if (Inst.Register == 30)
784e8d8bef9SDimitry Andric         StandaloneLR = true;
785e8d8bef9SDimitry Andric       else
786e8d8bef9SDimitry Andric         return false;
787e8d8bef9SDimitry Andric       // Odd register; can't be any further int registers.
788e8d8bef9SDimitry Andric       Location = FloatRegs;
789e8d8bef9SDimitry Andric       break;
790e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveLRPair:
791e8d8bef9SDimitry Andric       if (Location != IntRegs || Inst.Offset != 8 * RegI ||
792e8d8bef9SDimitry Andric           Inst.Register != 19 + RegI)
793e8d8bef9SDimitry Andric         return false;
794e8d8bef9SDimitry Andric       RegI += 1;
795e8d8bef9SDimitry Andric       StandaloneLR = true;
796e8d8bef9SDimitry Andric       Location = FloatRegs;
797e8d8bef9SDimitry Andric       break;
798e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFRegX:
799e8d8bef9SDimitry Andric       // Packed unwind can't handle prologs that only save one single
800e8d8bef9SDimitry Andric       // float register.
801e8d8bef9SDimitry Andric       return false;
802e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFReg:
803e8d8bef9SDimitry Andric       if (Location != FloatRegs || RegF == 0 || Inst.Register != 8 + RegF ||
804e8d8bef9SDimitry Andric           Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
805e8d8bef9SDimitry Andric         return false;
806e8d8bef9SDimitry Andric       RegF += 1;
807e8d8bef9SDimitry Andric       Location = InputArgs;
808e8d8bef9SDimitry Andric       break;
809e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFRegPX:
810e8d8bef9SDimitry Andric       if (Location != Start2 || Inst.Register != 8)
811e8d8bef9SDimitry Andric         return false;
812e8d8bef9SDimitry Andric       Predecrement = Inst.Offset;
813e8d8bef9SDimitry Andric       RegF = 2;
814e8d8bef9SDimitry Andric       Location = FloatRegs;
815e8d8bef9SDimitry Andric       break;
816e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFRegP:
817e8d8bef9SDimitry Andric       if ((Location != IntRegs && Location != FloatRegs) ||
818e8d8bef9SDimitry Andric           Inst.Register != 8 + RegF ||
819e8d8bef9SDimitry Andric           Inst.Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
820e8d8bef9SDimitry Andric         return false;
821e8d8bef9SDimitry Andric       RegF += 2;
822e8d8bef9SDimitry Andric       Location = FloatRegs;
823e8d8bef9SDimitry Andric       break;
824e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveNext:
825e8d8bef9SDimitry Andric       if (Location == IntRegs)
826e8d8bef9SDimitry Andric         RegI += 2;
827e8d8bef9SDimitry Andric       else if (Location == FloatRegs)
828e8d8bef9SDimitry Andric         RegF += 2;
829e8d8bef9SDimitry Andric       else
830e8d8bef9SDimitry Andric         return false;
831e8d8bef9SDimitry Andric       break;
832e8d8bef9SDimitry Andric     case Win64EH::UOP_Nop:
833e8d8bef9SDimitry Andric       if (Location != IntRegs && Location != FloatRegs && Location != InputArgs)
834e8d8bef9SDimitry Andric         return false;
835e8d8bef9SDimitry Andric       Location = InputArgs;
836e8d8bef9SDimitry Andric       Nops++;
837e8d8bef9SDimitry Andric       break;
838e8d8bef9SDimitry Andric     case Win64EH::UOP_AllocSmall:
839e8d8bef9SDimitry Andric     case Win64EH::UOP_AllocMedium:
840e8d8bef9SDimitry Andric       if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
841e8d8bef9SDimitry Andric           Location != InputArgs && Location != StackAdjust)
842e8d8bef9SDimitry Andric         return false;
843e8d8bef9SDimitry Andric       // Can have either a single decrement, or a pair of decrements with
844e8d8bef9SDimitry Andric       // 4080 and another decrement.
845e8d8bef9SDimitry Andric       if (StackOffset == 0)
846e8d8bef9SDimitry Andric         StackOffset = Inst.Offset;
847e8d8bef9SDimitry Andric       else if (StackOffset != 4080)
848e8d8bef9SDimitry Andric         return false;
849e8d8bef9SDimitry Andric       else
850e8d8bef9SDimitry Andric         StackOffset += Inst.Offset;
851e8d8bef9SDimitry Andric       Location = StackAdjust;
852e8d8bef9SDimitry Andric       break;
853e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFPLRX:
854e8d8bef9SDimitry Andric       // Not allowing FPLRX after StackAdjust; if a StackAdjust is used, it
855e8d8bef9SDimitry Andric       // should be followed by a FPLR instead.
856e8d8bef9SDimitry Andric       if (Location != Start2 && Location != IntRegs && Location != FloatRegs &&
857e8d8bef9SDimitry Andric           Location != InputArgs)
858e8d8bef9SDimitry Andric         return false;
859e8d8bef9SDimitry Andric       StackOffset = Inst.Offset;
860e8d8bef9SDimitry Andric       Location = FrameRecord;
861e8d8bef9SDimitry Andric       FPLRPair = true;
862e8d8bef9SDimitry Andric       break;
863e8d8bef9SDimitry Andric     case Win64EH::UOP_SaveFPLR:
864e8d8bef9SDimitry Andric       // This can only follow after a StackAdjust
865e8d8bef9SDimitry Andric       if (Location != StackAdjust || Inst.Offset != 0)
866e8d8bef9SDimitry Andric         return false;
867e8d8bef9SDimitry Andric       Location = FrameRecord;
868e8d8bef9SDimitry Andric       FPLRPair = true;
869e8d8bef9SDimitry Andric       break;
870e8d8bef9SDimitry Andric     case Win64EH::UOP_SetFP:
871e8d8bef9SDimitry Andric       if (Location != FrameRecord)
872e8d8bef9SDimitry Andric         return false;
873e8d8bef9SDimitry Andric       Location = End;
874e8d8bef9SDimitry Andric       break;
875e8d8bef9SDimitry Andric     }
876e8d8bef9SDimitry Andric   }
877e8d8bef9SDimitry Andric   if (RegI > 10 || RegF > 8)
878e8d8bef9SDimitry Andric     return false;
879e8d8bef9SDimitry Andric   if (StandaloneLR && FPLRPair)
880e8d8bef9SDimitry Andric     return false;
881e8d8bef9SDimitry Andric   if (FPLRPair && Location != End)
882e8d8bef9SDimitry Andric     return false;
883e8d8bef9SDimitry Andric   if (Nops != 0 && Nops != 4)
884e8d8bef9SDimitry Andric     return false;
885e8d8bef9SDimitry Andric   int H = Nops == 4;
886*81ad6265SDimitry Andric   // There's an inconsistency regarding packed unwind info with homed
887*81ad6265SDimitry Andric   // parameters; according to the documentation, the epilog shouldn't have
888*81ad6265SDimitry Andric   // the same corresponding nops (and thus, to set the H bit, we should
889*81ad6265SDimitry Andric   // require an epilog which isn't exactly symmetrical - we shouldn't accept
890*81ad6265SDimitry Andric   // an exact mirrored epilog for those cases), but in practice,
891*81ad6265SDimitry Andric   // RtlVirtualUnwind behaves as if it does expect the epilogue to contain
892*81ad6265SDimitry Andric   // the same nops. See https://github.com/llvm/llvm-project/issues/54879.
893*81ad6265SDimitry Andric   // To play it safe, don't produce packed unwind info with homed parameters.
894*81ad6265SDimitry Andric   if (H)
895*81ad6265SDimitry Andric     return false;
896e8d8bef9SDimitry Andric   int IntSZ = 8 * RegI;
897e8d8bef9SDimitry Andric   if (StandaloneLR)
898e8d8bef9SDimitry Andric     IntSZ += 8;
899e8d8bef9SDimitry Andric   int FpSZ = 8 * RegF; // RegF not yet decremented
900e8d8bef9SDimitry Andric   int SavSZ = (IntSZ + FpSZ + 8 * 8 * H + 0xF) & ~0xF;
901e8d8bef9SDimitry Andric   if (Predecrement != SavSZ)
902e8d8bef9SDimitry Andric     return false;
903e8d8bef9SDimitry Andric   if (FPLRPair && StackOffset < 16)
904e8d8bef9SDimitry Andric     return false;
905e8d8bef9SDimitry Andric   if (StackOffset % 16)
906e8d8bef9SDimitry Andric     return false;
907e8d8bef9SDimitry Andric   uint32_t FrameSize = (StackOffset + SavSZ) / 16;
908e8d8bef9SDimitry Andric   if (FrameSize > 0x1FF)
909e8d8bef9SDimitry Andric     return false;
910e8d8bef9SDimitry Andric   assert(RegF != 1 && "One single float reg not allowed");
911e8d8bef9SDimitry Andric   if (RegF > 0)
912e8d8bef9SDimitry Andric     RegF--; // Convert from actual number of registers, to value stored
913e8d8bef9SDimitry Andric   assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
914e8d8bef9SDimitry Andric   int Flag = 0x01; // Function segments not supported yet
915e8d8bef9SDimitry Andric   int CR = FPLRPair ? 3 : StandaloneLR ? 1 : 0;
916e8d8bef9SDimitry Andric   info->PackedInfo |= Flag << 0;
917e8d8bef9SDimitry Andric   info->PackedInfo |= (FuncLength & 0x7FF) << 2;
918e8d8bef9SDimitry Andric   info->PackedInfo |= (RegF & 0x7) << 13;
919e8d8bef9SDimitry Andric   info->PackedInfo |= (RegI & 0xF) << 16;
920e8d8bef9SDimitry Andric   info->PackedInfo |= (H & 0x1) << 20;
921e8d8bef9SDimitry Andric   info->PackedInfo |= (CR & 0x3) << 21;
922e8d8bef9SDimitry Andric   info->PackedInfo |= (FrameSize & 0x1FF) << 23;
923e8d8bef9SDimitry Andric   return true;
924e8d8bef9SDimitry Andric }
925e8d8bef9SDimitry Andric 
9260b57cec5SDimitry Andric // Populate the .xdata section.  The format of .xdata on ARM64 is documented at
9270b57cec5SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
928e8d8bef9SDimitry Andric static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
929e8d8bef9SDimitry Andric                                 bool TryPacked = true) {
9300b57cec5SDimitry Andric   // If this UNWIND_INFO already has a symbol, it's already been emitted.
9310b57cec5SDimitry Andric   if (info->Symbol)
9320b57cec5SDimitry Andric     return;
933e8d8bef9SDimitry Andric   // If there's no unwind info here (not even a terminating UOP_End), the
934e8d8bef9SDimitry Andric   // unwind info is considered bogus and skipped. If this was done in
935e8d8bef9SDimitry Andric   // response to an explicit .seh_handlerdata, the associated trailing
936e8d8bef9SDimitry Andric   // handler data is left orphaned in the xdata section.
937e8d8bef9SDimitry Andric   if (info->empty()) {
938e8d8bef9SDimitry Andric     info->EmitAttempted = true;
939e8d8bef9SDimitry Andric     return;
940e8d8bef9SDimitry Andric   }
941e8d8bef9SDimitry Andric   if (info->EmitAttempted) {
942e8d8bef9SDimitry Andric     // If we tried to emit unwind info before (due to an explicit
943e8d8bef9SDimitry Andric     // .seh_handlerdata directive), but skipped it (because there was no
944e8d8bef9SDimitry Andric     // valid information to emit at the time), and it later got valid unwind
945e8d8bef9SDimitry Andric     // opcodes, we can't emit it here, because the trailing handler data
946e8d8bef9SDimitry Andric     // was already emitted elsewhere in the xdata section.
947e8d8bef9SDimitry Andric     streamer.getContext().reportError(
948e8d8bef9SDimitry Andric         SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
949e8d8bef9SDimitry Andric                      " skipped due to no unwind info at the time "
950e8d8bef9SDimitry Andric                      "(.seh_handlerdata too early?), but the function later "
951e8d8bef9SDimitry Andric                      "did get unwind info that can't be emitted");
952e8d8bef9SDimitry Andric     return;
953e8d8bef9SDimitry Andric   }
954e8d8bef9SDimitry Andric 
955*81ad6265SDimitry Andric   simplifyARM64Opcodes(info->Instructions, false);
956e8d8bef9SDimitry Andric   for (auto &I : info->EpilogMap)
957*81ad6265SDimitry Andric     simplifyARM64Opcodes(I.second.Instructions, true);
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric   MCContext &context = streamer.getContext();
9600b57cec5SDimitry Andric   MCSymbol *Label = context.createTempSymbol();
9610b57cec5SDimitry Andric 
9625ffd83dbSDimitry Andric   streamer.emitValueToAlignment(4);
9635ffd83dbSDimitry Andric   streamer.emitLabel(Label);
9640b57cec5SDimitry Andric   info->Symbol = Label;
9650b57cec5SDimitry Andric 
9660b57cec5SDimitry Andric   int64_t RawFuncLength;
9670b57cec5SDimitry Andric   if (!info->FuncletOrFuncEnd) {
968e8d8bef9SDimitry Andric     report_fatal_error("FuncletOrFuncEnd not set");
9690b57cec5SDimitry Andric   } else {
9700b57cec5SDimitry Andric     // FIXME: GetAbsDifference tries to compute the length of the function
9710b57cec5SDimitry Andric     // immediately, before the whole file is emitted, but in general
9720b57cec5SDimitry Andric     // that's impossible: the size in bytes of certain assembler directives
9730b57cec5SDimitry Andric     // like .align and .fill is not known until the whole file is parsed and
9740b57cec5SDimitry Andric     // relaxations are applied. Currently, GetAbsDifference fails with a fatal
9750b57cec5SDimitry Andric     // error in that case. (We mostly don't hit this because inline assembly
9760b57cec5SDimitry Andric     // specifying those directives is rare, and we don't normally try to
9770b57cec5SDimitry Andric     // align loops on AArch64.)
9780b57cec5SDimitry Andric     //
9790b57cec5SDimitry Andric     // There are two potential approaches to delaying the computation. One,
9800b57cec5SDimitry Andric     // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
9810b57cec5SDimitry Andric     // as long as we have some conservative estimate we could use to prove
9820b57cec5SDimitry Andric     // that we don't need to split the unwind data. Emitting the constant
9830b57cec5SDimitry Andric     // is straightforward, but there's no existing code for estimating the
9840b57cec5SDimitry Andric     // size of the function.
9850b57cec5SDimitry Andric     //
9860b57cec5SDimitry Andric     // The other approach would be to use a dedicated, relaxable fragment,
9870b57cec5SDimitry Andric     // which could grow to accommodate splitting the unwind data if
9880b57cec5SDimitry Andric     // necessary. This is more straightforward, since it automatically works
9890b57cec5SDimitry Andric     // without any new infrastructure, and it's consistent with how we handle
9900b57cec5SDimitry Andric     // relaxation in other contexts.  But it would require some refactoring
9910b57cec5SDimitry Andric     // to move parts of the pdata/xdata emission into the implementation of
9920b57cec5SDimitry Andric     // a fragment. We could probably continue to encode the unwind codes
9930b57cec5SDimitry Andric     // here, but we'd have to emit the pdata, the xdata header, and the
9940b57cec5SDimitry Andric     // epilogue scopes later, since they depend on whether the we need to
9950b57cec5SDimitry Andric     // split the unwind data.
9960b57cec5SDimitry Andric     RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
9970b57cec5SDimitry Andric                                      info->Begin);
9980b57cec5SDimitry Andric   }
9990b57cec5SDimitry Andric   if (RawFuncLength > 0xFFFFF)
10000b57cec5SDimitry Andric     report_fatal_error("SEH unwind data splitting not yet implemented");
10010b57cec5SDimitry Andric   uint32_t FuncLength = (uint32_t)RawFuncLength / 4;
10020b57cec5SDimitry Andric   uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
10030b57cec5SDimitry Andric   uint32_t TotalCodeBytes = PrologCodeBytes;
10040b57cec5SDimitry Andric 
1005*81ad6265SDimitry Andric   int PackedEpilogOffset =
1006*81ad6265SDimitry Andric       checkARM64PackedEpilog(streamer, info, PrologCodeBytes);
1007e8d8bef9SDimitry Andric 
1008*81ad6265SDimitry Andric   if (PackedEpilogOffset >= 0 &&
1009*81ad6265SDimitry Andric       uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1010*81ad6265SDimitry Andric       !info->HandlesExceptions && FuncLength <= 0x7ff && TryPacked) {
1011e8d8bef9SDimitry Andric     // Matching prolog/epilog and no exception handlers; check if the
1012e8d8bef9SDimitry Andric     // prolog matches the patterns that can be described by the packed
1013e8d8bef9SDimitry Andric     // format.
1014e8d8bef9SDimitry Andric 
1015e8d8bef9SDimitry Andric     // info->Symbol was already set even if we didn't actually write any
1016e8d8bef9SDimitry Andric     // unwind info there. Keep using that as indicator that this unwind
1017e8d8bef9SDimitry Andric     // info has been generated already.
1018e8d8bef9SDimitry Andric 
1019*81ad6265SDimitry Andric     if (tryARM64PackedUnwind(info, FuncLength, PackedEpilogOffset))
1020e8d8bef9SDimitry Andric       return;
1021e8d8bef9SDimitry Andric   }
1022e8d8bef9SDimitry Andric 
10230b57cec5SDimitry Andric   // Process epilogs.
10240b57cec5SDimitry Andric   MapVector<MCSymbol *, uint32_t> EpilogInfo;
10250b57cec5SDimitry Andric   // Epilogs processed so far.
10260b57cec5SDimitry Andric   std::vector<MCSymbol *> AddedEpilogs;
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric   for (auto &I : info->EpilogMap) {
10290b57cec5SDimitry Andric     MCSymbol *EpilogStart = I.first;
1030*81ad6265SDimitry Andric     auto &EpilogInstrs = I.second.Instructions;
10310b57cec5SDimitry Andric     uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric     MCSymbol* MatchingEpilog =
10340b57cec5SDimitry Andric       FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
1035*81ad6265SDimitry Andric     int PrologOffset;
10360b57cec5SDimitry Andric     if (MatchingEpilog) {
10370b57cec5SDimitry Andric       assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&
10380b57cec5SDimitry Andric              "Duplicate epilog not found");
10390b57cec5SDimitry Andric       EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
10400b57cec5SDimitry Andric       // Clear the unwind codes in the EpilogMap, so that they don't get output
10410b57cec5SDimitry Andric       // in the logic below.
10420b57cec5SDimitry Andric       EpilogInstrs.clear();
1043*81ad6265SDimitry Andric     } else if ((PrologOffset = getARM64OffsetInProlog(info->Instructions,
1044*81ad6265SDimitry Andric                                                       EpilogInstrs)) >= 0) {
1045*81ad6265SDimitry Andric       EpilogInfo[EpilogStart] = PrologOffset;
1046*81ad6265SDimitry Andric       // Clear the unwind codes in the EpilogMap, so that they don't get output
1047*81ad6265SDimitry Andric       // in the logic below.
1048*81ad6265SDimitry Andric       EpilogInstrs.clear();
10490b57cec5SDimitry Andric     } else {
10500b57cec5SDimitry Andric       EpilogInfo[EpilogStart] = TotalCodeBytes;
10510b57cec5SDimitry Andric       TotalCodeBytes += CodeBytes;
10520b57cec5SDimitry Andric       AddedEpilogs.push_back(EpilogStart);
10530b57cec5SDimitry Andric     }
10540b57cec5SDimitry Andric   }
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric   // Code Words, Epilog count, E, X, Vers, Function Length
10570b57cec5SDimitry Andric   uint32_t row1 = 0x0;
10580b57cec5SDimitry Andric   uint32_t CodeWords = TotalCodeBytes / 4;
10590b57cec5SDimitry Andric   uint32_t CodeWordsMod = TotalCodeBytes % 4;
10600b57cec5SDimitry Andric   if (CodeWordsMod)
10610b57cec5SDimitry Andric     CodeWords++;
1062e8d8bef9SDimitry Andric   uint32_t EpilogCount =
1063e8d8bef9SDimitry Andric       PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
10640b57cec5SDimitry Andric   bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
10650b57cec5SDimitry Andric   if (!ExtensionWord) {
10660b57cec5SDimitry Andric     row1 |= (EpilogCount & 0x1F) << 22;
10670b57cec5SDimitry Andric     row1 |= (CodeWords & 0x1F) << 27;
10680b57cec5SDimitry Andric   }
10690b57cec5SDimitry Andric   if (info->HandlesExceptions) // X
10700b57cec5SDimitry Andric     row1 |= 1 << 20;
1071e8d8bef9SDimitry Andric   if (PackedEpilogOffset >= 0) // E
1072e8d8bef9SDimitry Andric     row1 |= 1 << 21;
10730b57cec5SDimitry Andric   row1 |= FuncLength & 0x3FFFF;
10745ffd83dbSDimitry Andric   streamer.emitInt32(row1);
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric   // Extended Code Words, Extended Epilog Count
10770b57cec5SDimitry Andric   if (ExtensionWord) {
10780b57cec5SDimitry Andric     // FIXME: We should be able to split unwind info into multiple sections.
10790b57cec5SDimitry Andric     if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
10800b57cec5SDimitry Andric       report_fatal_error("SEH unwind data splitting not yet implemented");
10810b57cec5SDimitry Andric     uint32_t row2 = 0x0;
10820b57cec5SDimitry Andric     row2 |= (CodeWords & 0xFF) << 16;
10830b57cec5SDimitry Andric     row2 |= (EpilogCount & 0xFFFF);
10845ffd83dbSDimitry Andric     streamer.emitInt32(row2);
10850b57cec5SDimitry Andric   }
10860b57cec5SDimitry Andric 
1087*81ad6265SDimitry Andric   if (PackedEpilogOffset < 0) {
10880b57cec5SDimitry Andric     // Epilog Start Index, Epilog Start Offset
10890b57cec5SDimitry Andric     for (auto &I : EpilogInfo) {
10900b57cec5SDimitry Andric       MCSymbol *EpilogStart = I.first;
10910b57cec5SDimitry Andric       uint32_t EpilogIndex = I.second;
10920b57cec5SDimitry Andric       uint32_t EpilogOffset =
10930b57cec5SDimitry Andric           (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
10940b57cec5SDimitry Andric       if (EpilogOffset)
10950b57cec5SDimitry Andric         EpilogOffset /= 4;
10960b57cec5SDimitry Andric       uint32_t row3 = EpilogOffset;
10970b57cec5SDimitry Andric       row3 |= (EpilogIndex & 0x3FF) << 22;
10985ffd83dbSDimitry Andric       streamer.emitInt32(row3);
10990b57cec5SDimitry Andric     }
1100*81ad6265SDimitry Andric   }
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric   // Emit prolog unwind instructions (in reverse order).
11030b57cec5SDimitry Andric   uint8_t numInst = info->Instructions.size();
11040b57cec5SDimitry Andric   for (uint8_t c = 0; c < numInst; ++c) {
11050b57cec5SDimitry Andric     WinEH::Instruction inst = info->Instructions.back();
11060b57cec5SDimitry Andric     info->Instructions.pop_back();
1107*81ad6265SDimitry Andric     ARM64EmitUnwindCode(streamer, inst);
11080b57cec5SDimitry Andric   }
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric   // Emit epilog unwind instructions
11110b57cec5SDimitry Andric   for (auto &I : info->EpilogMap) {
1112*81ad6265SDimitry Andric     auto &EpilogInstrs = I.second.Instructions;
11130eae32dcSDimitry Andric     for (const WinEH::Instruction &inst : EpilogInstrs)
1114*81ad6265SDimitry Andric       ARM64EmitUnwindCode(streamer, inst);
11150b57cec5SDimitry Andric   }
11160b57cec5SDimitry Andric 
11170b57cec5SDimitry Andric   int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
11180b57cec5SDimitry Andric   assert(BytesMod >= 0);
11190b57cec5SDimitry Andric   for (int i = 0; i < BytesMod; i++)
11205ffd83dbSDimitry Andric     streamer.emitInt8(0xE3);
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric   if (info->HandlesExceptions)
11235ffd83dbSDimitry Andric     streamer.emitValue(
11240b57cec5SDimitry Andric         MCSymbolRefExpr::create(info->ExceptionHandler,
11250b57cec5SDimitry Andric                                 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
11260b57cec5SDimitry Andric         4);
11270b57cec5SDimitry Andric }
11280b57cec5SDimitry Andric 
1129*81ad6265SDimitry Andric static uint32_t ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction> Insns) {
1130*81ad6265SDimitry Andric   uint32_t Count = 0;
1131*81ad6265SDimitry Andric   for (const auto &I : Insns) {
1132*81ad6265SDimitry Andric     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1133*81ad6265SDimitry Andric     default:
1134*81ad6265SDimitry Andric       llvm_unreachable("Unsupported ARM unwind code");
1135*81ad6265SDimitry Andric     case Win64EH::UOP_AllocSmall:
1136*81ad6265SDimitry Andric       Count += 1;
1137*81ad6265SDimitry Andric       break;
1138*81ad6265SDimitry Andric     case Win64EH::UOP_AllocLarge:
1139*81ad6265SDimitry Andric       Count += 3;
1140*81ad6265SDimitry Andric       break;
1141*81ad6265SDimitry Andric     case Win64EH::UOP_AllocHuge:
1142*81ad6265SDimitry Andric       Count += 4;
1143*81ad6265SDimitry Andric       break;
1144*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocMedium:
1145*81ad6265SDimitry Andric       Count += 2;
1146*81ad6265SDimitry Andric       break;
1147*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocLarge:
1148*81ad6265SDimitry Andric       Count += 3;
1149*81ad6265SDimitry Andric       break;
1150*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocHuge:
1151*81ad6265SDimitry Andric       Count += 4;
1152*81ad6265SDimitry Andric       break;
1153*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegMask:
1154*81ad6265SDimitry Andric       Count += 2;
1155*81ad6265SDimitry Andric       break;
1156*81ad6265SDimitry Andric     case Win64EH::UOP_SaveSP:
1157*81ad6265SDimitry Andric       Count += 1;
1158*81ad6265SDimitry Andric       break;
1159*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegsR4R7LR:
1160*81ad6265SDimitry Andric       Count += 1;
1161*81ad6265SDimitry Andric       break;
1162*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegsR4R11LR:
1163*81ad6265SDimitry Andric       Count += 1;
1164*81ad6265SDimitry Andric       break;
1165*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD8D15:
1166*81ad6265SDimitry Andric       Count += 1;
1167*81ad6265SDimitry Andric       break;
1168*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegMask:
1169*81ad6265SDimitry Andric       Count += 2;
1170*81ad6265SDimitry Andric       break;
1171*81ad6265SDimitry Andric     case Win64EH::UOP_SaveLR:
1172*81ad6265SDimitry Andric       Count += 2;
1173*81ad6265SDimitry Andric       break;
1174*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD0D15:
1175*81ad6265SDimitry Andric       Count += 2;
1176*81ad6265SDimitry Andric       break;
1177*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD16D31:
1178*81ad6265SDimitry Andric       Count += 2;
1179*81ad6265SDimitry Andric       break;
1180*81ad6265SDimitry Andric     case Win64EH::UOP_Nop:
1181*81ad6265SDimitry Andric     case Win64EH::UOP_WideNop:
1182*81ad6265SDimitry Andric     case Win64EH::UOP_End:
1183*81ad6265SDimitry Andric     case Win64EH::UOP_EndNop:
1184*81ad6265SDimitry Andric     case Win64EH::UOP_WideEndNop:
1185*81ad6265SDimitry Andric       Count += 1;
1186*81ad6265SDimitry Andric       break;
1187*81ad6265SDimitry Andric     case Win64EH::UOP_Custom: {
1188*81ad6265SDimitry Andric       int J;
1189*81ad6265SDimitry Andric       for (J = 3; J > 0; J--)
1190*81ad6265SDimitry Andric         if (I.Offset & (0xffu << (8 * J)))
1191*81ad6265SDimitry Andric           break;
1192*81ad6265SDimitry Andric       Count += J + 1;
1193*81ad6265SDimitry Andric       break;
1194*81ad6265SDimitry Andric     }
1195*81ad6265SDimitry Andric     }
1196*81ad6265SDimitry Andric   }
1197*81ad6265SDimitry Andric   return Count;
1198*81ad6265SDimitry Andric }
1199*81ad6265SDimitry Andric 
1200*81ad6265SDimitry Andric static uint32_t ARMCountOfInstructionBytes(ArrayRef<WinEH::Instruction> Insns,
1201*81ad6265SDimitry Andric                                            bool *HasCustom = nullptr) {
1202*81ad6265SDimitry Andric   uint32_t Count = 0;
1203*81ad6265SDimitry Andric   for (const auto &I : Insns) {
1204*81ad6265SDimitry Andric     switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
1205*81ad6265SDimitry Andric     default:
1206*81ad6265SDimitry Andric       llvm_unreachable("Unsupported ARM unwind code");
1207*81ad6265SDimitry Andric     case Win64EH::UOP_AllocSmall:
1208*81ad6265SDimitry Andric     case Win64EH::UOP_AllocLarge:
1209*81ad6265SDimitry Andric     case Win64EH::UOP_AllocHuge:
1210*81ad6265SDimitry Andric       Count += 2;
1211*81ad6265SDimitry Andric       break;
1212*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocMedium:
1213*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocLarge:
1214*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocHuge:
1215*81ad6265SDimitry Andric       Count += 4;
1216*81ad6265SDimitry Andric       break;
1217*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegMask:
1218*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegsR4R11LR:
1219*81ad6265SDimitry Andric       Count += 4;
1220*81ad6265SDimitry Andric       break;
1221*81ad6265SDimitry Andric     case Win64EH::UOP_SaveSP:
1222*81ad6265SDimitry Andric       Count += 2;
1223*81ad6265SDimitry Andric       break;
1224*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegMask:
1225*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegsR4R7LR:
1226*81ad6265SDimitry Andric       Count += 2;
1227*81ad6265SDimitry Andric       break;
1228*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD8D15:
1229*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD0D15:
1230*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD16D31:
1231*81ad6265SDimitry Andric       Count += 4;
1232*81ad6265SDimitry Andric       break;
1233*81ad6265SDimitry Andric     case Win64EH::UOP_SaveLR:
1234*81ad6265SDimitry Andric       Count += 4;
1235*81ad6265SDimitry Andric       break;
1236*81ad6265SDimitry Andric     case Win64EH::UOP_Nop:
1237*81ad6265SDimitry Andric     case Win64EH::UOP_EndNop:
1238*81ad6265SDimitry Andric       Count += 2;
1239*81ad6265SDimitry Andric       break;
1240*81ad6265SDimitry Andric     case Win64EH::UOP_WideNop:
1241*81ad6265SDimitry Andric     case Win64EH::UOP_WideEndNop:
1242*81ad6265SDimitry Andric       Count += 4;
1243*81ad6265SDimitry Andric       break;
1244*81ad6265SDimitry Andric     case Win64EH::UOP_End:
1245*81ad6265SDimitry Andric       // This doesn't map to any instruction
1246*81ad6265SDimitry Andric       break;
1247*81ad6265SDimitry Andric     case Win64EH::UOP_Custom:
1248*81ad6265SDimitry Andric       // We can't reason about what instructions this maps to; return a
1249*81ad6265SDimitry Andric       // phony number to make sure we don't accidentally do epilog packing.
1250*81ad6265SDimitry Andric       Count += 1000;
1251*81ad6265SDimitry Andric       if (HasCustom)
1252*81ad6265SDimitry Andric         *HasCustom = true;
1253*81ad6265SDimitry Andric       break;
1254*81ad6265SDimitry Andric     }
1255*81ad6265SDimitry Andric   }
1256*81ad6265SDimitry Andric   return Count;
1257*81ad6265SDimitry Andric }
1258*81ad6265SDimitry Andric 
1259*81ad6265SDimitry Andric static void checkARMInstructions(MCStreamer &Streamer,
1260*81ad6265SDimitry Andric                                  ArrayRef<WinEH::Instruction> Insns,
1261*81ad6265SDimitry Andric                                  const MCSymbol *Begin, const MCSymbol *End,
1262*81ad6265SDimitry Andric                                  StringRef Name, StringRef Type) {
1263*81ad6265SDimitry Andric   if (!End)
1264*81ad6265SDimitry Andric     return;
1265*81ad6265SDimitry Andric   Optional<int64_t> MaybeDistance =
1266*81ad6265SDimitry Andric       GetOptionalAbsDifference(Streamer, End, Begin);
1267*81ad6265SDimitry Andric   if (!MaybeDistance)
1268*81ad6265SDimitry Andric     return;
1269*81ad6265SDimitry Andric   uint32_t Distance = (uint32_t)*MaybeDistance;
1270*81ad6265SDimitry Andric   bool HasCustom = false;
1271*81ad6265SDimitry Andric   uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom);
1272*81ad6265SDimitry Andric   if (HasCustom)
1273*81ad6265SDimitry Andric     return;
1274*81ad6265SDimitry Andric   if (Distance != InstructionBytes) {
1275*81ad6265SDimitry Andric     Streamer.getContext().reportError(
1276*81ad6265SDimitry Andric         SMLoc(), "Incorrect size for " + Name + " " + Type + ": " +
1277*81ad6265SDimitry Andric                      Twine(Distance) +
1278*81ad6265SDimitry Andric                      " bytes of instructions in range, but .seh directives "
1279*81ad6265SDimitry Andric                      "corresponding to " +
1280*81ad6265SDimitry Andric                      Twine(InstructionBytes) + " bytes\n");
1281*81ad6265SDimitry Andric   }
1282*81ad6265SDimitry Andric }
1283*81ad6265SDimitry Andric 
1284*81ad6265SDimitry Andric static bool isARMTerminator(const WinEH::Instruction &inst) {
1285*81ad6265SDimitry Andric   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1286*81ad6265SDimitry Andric   case Win64EH::UOP_End:
1287*81ad6265SDimitry Andric   case Win64EH::UOP_EndNop:
1288*81ad6265SDimitry Andric   case Win64EH::UOP_WideEndNop:
1289*81ad6265SDimitry Andric     return true;
1290*81ad6265SDimitry Andric   default:
1291*81ad6265SDimitry Andric     return false;
1292*81ad6265SDimitry Andric   }
1293*81ad6265SDimitry Andric }
1294*81ad6265SDimitry Andric 
1295*81ad6265SDimitry Andric // Unwind opcode encodings and restrictions are documented at
1296*81ad6265SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1297*81ad6265SDimitry Andric static void ARMEmitUnwindCode(MCStreamer &streamer,
1298*81ad6265SDimitry Andric                               const WinEH::Instruction &inst) {
1299*81ad6265SDimitry Andric   uint32_t w, lr;
1300*81ad6265SDimitry Andric   int i;
1301*81ad6265SDimitry Andric   switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
1302*81ad6265SDimitry Andric   default:
1303*81ad6265SDimitry Andric     llvm_unreachable("Unsupported ARM unwind code");
1304*81ad6265SDimitry Andric   case Win64EH::UOP_AllocSmall:
1305*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1306*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0x7f);
1307*81ad6265SDimitry Andric     streamer.emitInt8(inst.Offset / 4);
1308*81ad6265SDimitry Andric     break;
1309*81ad6265SDimitry Andric   case Win64EH::UOP_WideSaveRegMask:
1310*81ad6265SDimitry Andric     assert((inst.Register & ~0x5fff) == 0);
1311*81ad6265SDimitry Andric     lr = (inst.Register >> 14) & 1;
1312*81ad6265SDimitry Andric     w = 0x8000 | (inst.Register & 0x1fff) | (lr << 13);
1313*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1314*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1315*81ad6265SDimitry Andric     break;
1316*81ad6265SDimitry Andric   case Win64EH::UOP_SaveSP:
1317*81ad6265SDimitry Andric     assert(inst.Register <= 0x0f);
1318*81ad6265SDimitry Andric     streamer.emitInt8(0xc0 | inst.Register);
1319*81ad6265SDimitry Andric     break;
1320*81ad6265SDimitry Andric   case Win64EH::UOP_SaveRegsR4R7LR:
1321*81ad6265SDimitry Andric     assert(inst.Register >= 4 && inst.Register <= 7);
1322*81ad6265SDimitry Andric     assert(inst.Offset <= 1);
1323*81ad6265SDimitry Andric     streamer.emitInt8(0xd0 | (inst.Register - 4) | (inst.Offset << 2));
1324*81ad6265SDimitry Andric     break;
1325*81ad6265SDimitry Andric   case Win64EH::UOP_WideSaveRegsR4R11LR:
1326*81ad6265SDimitry Andric     assert(inst.Register >= 8 && inst.Register <= 11);
1327*81ad6265SDimitry Andric     assert(inst.Offset <= 1);
1328*81ad6265SDimitry Andric     streamer.emitInt8(0xd8 | (inst.Register - 8) | (inst.Offset << 2));
1329*81ad6265SDimitry Andric     break;
1330*81ad6265SDimitry Andric   case Win64EH::UOP_SaveFRegD8D15:
1331*81ad6265SDimitry Andric     assert(inst.Register >= 8 && inst.Register <= 15);
1332*81ad6265SDimitry Andric     streamer.emitInt8(0xe0 | (inst.Register - 8));
1333*81ad6265SDimitry Andric     break;
1334*81ad6265SDimitry Andric   case Win64EH::UOP_WideAllocMedium:
1335*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1336*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0x3ff);
1337*81ad6265SDimitry Andric     w = 0xe800 | (inst.Offset / 4);
1338*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1339*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1340*81ad6265SDimitry Andric     break;
1341*81ad6265SDimitry Andric   case Win64EH::UOP_SaveRegMask:
1342*81ad6265SDimitry Andric     assert((inst.Register & ~0x40ff) == 0);
1343*81ad6265SDimitry Andric     lr = (inst.Register >> 14) & 1;
1344*81ad6265SDimitry Andric     w = 0xec00 | (inst.Register & 0x0ff) | (lr << 8);
1345*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1346*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1347*81ad6265SDimitry Andric     break;
1348*81ad6265SDimitry Andric   case Win64EH::UOP_SaveLR:
1349*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1350*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0x0f);
1351*81ad6265SDimitry Andric     streamer.emitInt8(0xef);
1352*81ad6265SDimitry Andric     streamer.emitInt8(inst.Offset / 4);
1353*81ad6265SDimitry Andric     break;
1354*81ad6265SDimitry Andric   case Win64EH::UOP_SaveFRegD0D15:
1355*81ad6265SDimitry Andric     assert(inst.Register <= 15);
1356*81ad6265SDimitry Andric     assert(inst.Offset <= 15);
1357*81ad6265SDimitry Andric     assert(inst.Register <= inst.Offset);
1358*81ad6265SDimitry Andric     streamer.emitInt8(0xf5);
1359*81ad6265SDimitry Andric     streamer.emitInt8((inst.Register << 4) | inst.Offset);
1360*81ad6265SDimitry Andric     break;
1361*81ad6265SDimitry Andric   case Win64EH::UOP_SaveFRegD16D31:
1362*81ad6265SDimitry Andric     assert(inst.Register >= 16 && inst.Register <= 31);
1363*81ad6265SDimitry Andric     assert(inst.Offset >= 16 && inst.Offset <= 31);
1364*81ad6265SDimitry Andric     assert(inst.Register <= inst.Offset);
1365*81ad6265SDimitry Andric     streamer.emitInt8(0xf6);
1366*81ad6265SDimitry Andric     streamer.emitInt8(((inst.Register - 16) << 4) | (inst.Offset - 16));
1367*81ad6265SDimitry Andric     break;
1368*81ad6265SDimitry Andric   case Win64EH::UOP_AllocLarge:
1369*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1370*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0xffff);
1371*81ad6265SDimitry Andric     w = inst.Offset / 4;
1372*81ad6265SDimitry Andric     streamer.emitInt8(0xf7);
1373*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1374*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1375*81ad6265SDimitry Andric     break;
1376*81ad6265SDimitry Andric   case Win64EH::UOP_AllocHuge:
1377*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1378*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0xffffff);
1379*81ad6265SDimitry Andric     w = inst.Offset / 4;
1380*81ad6265SDimitry Andric     streamer.emitInt8(0xf8);
1381*81ad6265SDimitry Andric     streamer.emitInt8((w >> 16) & 0xff);
1382*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1383*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1384*81ad6265SDimitry Andric     break;
1385*81ad6265SDimitry Andric   case Win64EH::UOP_WideAllocLarge:
1386*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1387*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0xffff);
1388*81ad6265SDimitry Andric     w = inst.Offset / 4;
1389*81ad6265SDimitry Andric     streamer.emitInt8(0xf9);
1390*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1391*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1392*81ad6265SDimitry Andric     break;
1393*81ad6265SDimitry Andric   case Win64EH::UOP_WideAllocHuge:
1394*81ad6265SDimitry Andric     assert((inst.Offset & 3) == 0);
1395*81ad6265SDimitry Andric     assert(inst.Offset / 4 <= 0xffffff);
1396*81ad6265SDimitry Andric     w = inst.Offset / 4;
1397*81ad6265SDimitry Andric     streamer.emitInt8(0xfa);
1398*81ad6265SDimitry Andric     streamer.emitInt8((w >> 16) & 0xff);
1399*81ad6265SDimitry Andric     streamer.emitInt8((w >> 8) & 0xff);
1400*81ad6265SDimitry Andric     streamer.emitInt8((w >> 0) & 0xff);
1401*81ad6265SDimitry Andric     break;
1402*81ad6265SDimitry Andric   case Win64EH::UOP_Nop:
1403*81ad6265SDimitry Andric     streamer.emitInt8(0xfb);
1404*81ad6265SDimitry Andric     break;
1405*81ad6265SDimitry Andric   case Win64EH::UOP_WideNop:
1406*81ad6265SDimitry Andric     streamer.emitInt8(0xfc);
1407*81ad6265SDimitry Andric     break;
1408*81ad6265SDimitry Andric   case Win64EH::UOP_EndNop:
1409*81ad6265SDimitry Andric     streamer.emitInt8(0xfd);
1410*81ad6265SDimitry Andric     break;
1411*81ad6265SDimitry Andric   case Win64EH::UOP_WideEndNop:
1412*81ad6265SDimitry Andric     streamer.emitInt8(0xfe);
1413*81ad6265SDimitry Andric     break;
1414*81ad6265SDimitry Andric   case Win64EH::UOP_End:
1415*81ad6265SDimitry Andric     streamer.emitInt8(0xff);
1416*81ad6265SDimitry Andric     break;
1417*81ad6265SDimitry Andric   case Win64EH::UOP_Custom:
1418*81ad6265SDimitry Andric     for (i = 3; i > 0; i--)
1419*81ad6265SDimitry Andric       if (inst.Offset & (0xffu << (8 * i)))
1420*81ad6265SDimitry Andric         break;
1421*81ad6265SDimitry Andric     for (; i >= 0; i--)
1422*81ad6265SDimitry Andric       streamer.emitInt8((inst.Offset >> (8 * i)) & 0xff);
1423*81ad6265SDimitry Andric     break;
1424*81ad6265SDimitry Andric   }
1425*81ad6265SDimitry Andric }
1426*81ad6265SDimitry Andric 
1427*81ad6265SDimitry Andric // Check if an epilog exists as a subset of the end of a prolog (backwards).
1428*81ad6265SDimitry Andric // An epilog may end with one out of three different end opcodes; if this
1429*81ad6265SDimitry Andric // is the first epilog that shares opcodes with the prolog, we can tolerate
1430*81ad6265SDimitry Andric // that this opcode differs (and the caller will update the prolog to use
1431*81ad6265SDimitry Andric // the same end opcode as the epilog). If another epilog already shares
1432*81ad6265SDimitry Andric // opcodes with the prolog, the ending opcode must be a strict match.
1433*81ad6265SDimitry Andric static int getARMOffsetInProlog(const std::vector<WinEH::Instruction> &Prolog,
1434*81ad6265SDimitry Andric                                 const std::vector<WinEH::Instruction> &Epilog,
1435*81ad6265SDimitry Andric                                 bool CanTweakProlog) {
1436*81ad6265SDimitry Andric   // Can't find an epilog as a subset if it is longer than the prolog.
1437*81ad6265SDimitry Andric   if (Epilog.size() > Prolog.size())
1438*81ad6265SDimitry Andric     return -1;
1439*81ad6265SDimitry Andric 
1440*81ad6265SDimitry Andric   // Check that the epilog actually is a perfect match for the end (backwrds)
1441*81ad6265SDimitry Andric   // of the prolog.
1442*81ad6265SDimitry Andric   // If we can adjust the prolog afterwards, don't check that the end opcodes
1443*81ad6265SDimitry Andric   // match.
1444*81ad6265SDimitry Andric   int EndIdx = CanTweakProlog ? 1 : 0;
1445*81ad6265SDimitry Andric   for (int I = Epilog.size() - 1; I >= EndIdx; I--) {
1446*81ad6265SDimitry Andric     // TODO: Could also allow minor mismatches, e.g. "add sp, #16" vs
1447*81ad6265SDimitry Andric     // "push {r0-r3}".
1448*81ad6265SDimitry Andric     if (Prolog[I] != Epilog[Epilog.size() - 1 - I])
1449*81ad6265SDimitry Andric       return -1;
1450*81ad6265SDimitry Andric   }
1451*81ad6265SDimitry Andric 
1452*81ad6265SDimitry Andric   if (CanTweakProlog) {
1453*81ad6265SDimitry Andric     // Check that both prolog and epilog end with an expected end opcode.
1454*81ad6265SDimitry Andric     if (Prolog.front().Operation != Win64EH::UOP_End)
1455*81ad6265SDimitry Andric       return -1;
1456*81ad6265SDimitry Andric     if (Epilog.back().Operation != Win64EH::UOP_End &&
1457*81ad6265SDimitry Andric         Epilog.back().Operation != Win64EH::UOP_EndNop &&
1458*81ad6265SDimitry Andric         Epilog.back().Operation != Win64EH::UOP_WideEndNop)
1459*81ad6265SDimitry Andric       return -1;
1460*81ad6265SDimitry Andric   }
1461*81ad6265SDimitry Andric 
1462*81ad6265SDimitry Andric   // If the epilog was a subset of the prolog, find its offset.
1463*81ad6265SDimitry Andric   if (Epilog.size() == Prolog.size())
1464*81ad6265SDimitry Andric     return 0;
1465*81ad6265SDimitry Andric   return ARMCountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
1466*81ad6265SDimitry Andric       &Prolog[Epilog.size()], Prolog.size() - Epilog.size()));
1467*81ad6265SDimitry Andric }
1468*81ad6265SDimitry Andric 
1469*81ad6265SDimitry Andric static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
1470*81ad6265SDimitry Andric                                 int PrologCodeBytes) {
1471*81ad6265SDimitry Andric   // Can only pack if there's one single epilog
1472*81ad6265SDimitry Andric   if (info->EpilogMap.size() != 1)
1473*81ad6265SDimitry Andric     return -1;
1474*81ad6265SDimitry Andric 
1475*81ad6265SDimitry Andric   const WinEH::FrameInfo::Epilog &EpilogInfo = info->EpilogMap.begin()->second;
1476*81ad6265SDimitry Andric   // Can only pack if the epilog is unconditional
1477*81ad6265SDimitry Andric   if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1478*81ad6265SDimitry Andric     return -1;
1479*81ad6265SDimitry Andric 
1480*81ad6265SDimitry Andric   const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1481*81ad6265SDimitry Andric   // Make sure we have at least the trailing end opcode
1482*81ad6265SDimitry Andric   if (info->Instructions.empty() || Epilog.empty())
1483*81ad6265SDimitry Andric     return -1;
1484*81ad6265SDimitry Andric 
1485*81ad6265SDimitry Andric   // Check that the epilog actually is at the very end of the function,
1486*81ad6265SDimitry Andric   // otherwise it can't be packed.
1487*81ad6265SDimitry Andric   Optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
1488*81ad6265SDimitry Andric       streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
1489*81ad6265SDimitry Andric   if (!MaybeDistance)
1490*81ad6265SDimitry Andric     return -1;
1491*81ad6265SDimitry Andric   uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
1492*81ad6265SDimitry Andric   uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
1493*81ad6265SDimitry Andric   if (DistanceFromEnd != InstructionBytes)
1494*81ad6265SDimitry Andric     return -1;
1495*81ad6265SDimitry Andric 
1496*81ad6265SDimitry Andric   int RetVal = -1;
1497*81ad6265SDimitry Andric   // Even if we don't end up sharing opcodes with the prolog, we can still
1498*81ad6265SDimitry Andric   // write the offset as a packed offset, if the single epilog is located at
1499*81ad6265SDimitry Andric   // the end of the function and the offset (pointing after the prolog) fits
1500*81ad6265SDimitry Andric   // as a packed offset.
1501*81ad6265SDimitry Andric   if (PrologCodeBytes <= 31 &&
1502*81ad6265SDimitry Andric       PrologCodeBytes + ARMCountOfUnwindCodes(Epilog) <= 63)
1503*81ad6265SDimitry Andric     RetVal = PrologCodeBytes;
1504*81ad6265SDimitry Andric 
1505*81ad6265SDimitry Andric   int Offset =
1506*81ad6265SDimitry Andric       getARMOffsetInProlog(info->Instructions, Epilog, /*CanTweakProlog=*/true);
1507*81ad6265SDimitry Andric   if (Offset < 0)
1508*81ad6265SDimitry Andric     return RetVal;
1509*81ad6265SDimitry Andric 
1510*81ad6265SDimitry Andric   // Check that the offset and prolog size fits in the first word; it's
1511*81ad6265SDimitry Andric   // unclear whether the epilog count in the extension word can be taken
1512*81ad6265SDimitry Andric   // as packed epilog offset.
1513*81ad6265SDimitry Andric   if (Offset > 31 || PrologCodeBytes > 63)
1514*81ad6265SDimitry Andric     return RetVal;
1515*81ad6265SDimitry Andric 
1516*81ad6265SDimitry Andric   // Replace the regular end opcode of the prolog with the one from the
1517*81ad6265SDimitry Andric   // epilog.
1518*81ad6265SDimitry Andric   info->Instructions.front() = Epilog.back();
1519*81ad6265SDimitry Andric 
1520*81ad6265SDimitry Andric   // As we choose to express the epilog as part of the prolog, remove the
1521*81ad6265SDimitry Andric   // epilog from the map, so we don't try to emit its opcodes.
1522*81ad6265SDimitry Andric   info->EpilogMap.clear();
1523*81ad6265SDimitry Andric   return Offset;
1524*81ad6265SDimitry Andric }
1525*81ad6265SDimitry Andric 
1526*81ad6265SDimitry Andric static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11,
1527*81ad6265SDimitry Andric                          unsigned &Folded, int &IntRegs) {
1528*81ad6265SDimitry Andric   if (Mask & (1 << 14)) {
1529*81ad6265SDimitry Andric     HasLR = true;
1530*81ad6265SDimitry Andric     Mask &= ~(1 << 14);
1531*81ad6265SDimitry Andric   }
1532*81ad6265SDimitry Andric   if (Mask & (1 << 11)) {
1533*81ad6265SDimitry Andric     HasR11 = true;
1534*81ad6265SDimitry Andric     Mask &= ~(1 << 11);
1535*81ad6265SDimitry Andric   }
1536*81ad6265SDimitry Andric   Folded = 0;
1537*81ad6265SDimitry Andric   IntRegs = -1;
1538*81ad6265SDimitry Andric   if (!Mask)
1539*81ad6265SDimitry Andric     return true;
1540*81ad6265SDimitry Andric   int First = 0;
1541*81ad6265SDimitry Andric   // Shift right until we have the bits at the bottom
1542*81ad6265SDimitry Andric   while ((Mask & 1) == 0) {
1543*81ad6265SDimitry Andric     First++;
1544*81ad6265SDimitry Andric     Mask >>= 1;
1545*81ad6265SDimitry Andric   }
1546*81ad6265SDimitry Andric   if ((Mask & (Mask + 1)) != 0)
1547*81ad6265SDimitry Andric     return false; // Not a consecutive series of bits? Can't be packed.
1548*81ad6265SDimitry Andric   // Count the bits
1549*81ad6265SDimitry Andric   int N = 0;
1550*81ad6265SDimitry Andric   while (Mask & (1 << N))
1551*81ad6265SDimitry Andric     N++;
1552*81ad6265SDimitry Andric   if (First < 4) {
1553*81ad6265SDimitry Andric     if (First + N < 4)
1554*81ad6265SDimitry Andric       return false;
1555*81ad6265SDimitry Andric     Folded = 4 - First;
1556*81ad6265SDimitry Andric     N -= Folded;
1557*81ad6265SDimitry Andric     First = 4;
1558*81ad6265SDimitry Andric   }
1559*81ad6265SDimitry Andric   if (First > 4)
1560*81ad6265SDimitry Andric     return false; // Can't be packed
1561*81ad6265SDimitry Andric   if (N >= 1)
1562*81ad6265SDimitry Andric     IntRegs = N - 1;
1563*81ad6265SDimitry Andric   return true;
1564*81ad6265SDimitry Andric }
1565*81ad6265SDimitry Andric 
1566*81ad6265SDimitry Andric static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info,
1567*81ad6265SDimitry Andric                                uint32_t FuncLength) {
1568*81ad6265SDimitry Andric   int Step = 0;
1569*81ad6265SDimitry Andric   bool Homing = false;
1570*81ad6265SDimitry Andric   bool HasR11 = false;
1571*81ad6265SDimitry Andric   bool HasChain = false;
1572*81ad6265SDimitry Andric   bool HasLR = false;
1573*81ad6265SDimitry Andric   int IntRegs = -1;   // r4 - r(4+N)
1574*81ad6265SDimitry Andric   int FloatRegs = -1; // d8 - d(8+N)
1575*81ad6265SDimitry Andric   unsigned PF = 0;    // Number of extra pushed registers
1576*81ad6265SDimitry Andric   unsigned StackAdjust = 0;
1577*81ad6265SDimitry Andric   // Iterate over the prolog and check that all opcodes exactly match
1578*81ad6265SDimitry Andric   // the canonical order and form.
1579*81ad6265SDimitry Andric   for (const WinEH::Instruction &Inst : info->Instructions) {
1580*81ad6265SDimitry Andric     switch (Inst.Operation) {
1581*81ad6265SDimitry Andric     default:
1582*81ad6265SDimitry Andric       llvm_unreachable("Unsupported ARM unwind code");
1583*81ad6265SDimitry Andric     case Win64EH::UOP_Custom:
1584*81ad6265SDimitry Andric     case Win64EH::UOP_AllocLarge:
1585*81ad6265SDimitry Andric     case Win64EH::UOP_AllocHuge:
1586*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocLarge:
1587*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocHuge:
1588*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD0D15:
1589*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD16D31:
1590*81ad6265SDimitry Andric       // Can't be packed
1591*81ad6265SDimitry Andric       return false;
1592*81ad6265SDimitry Andric     case Win64EH::UOP_SaveSP:
1593*81ad6265SDimitry Andric       // Can't be packed; we can't rely on restoring sp from r11 when
1594*81ad6265SDimitry Andric       // unwinding a packed prologue.
1595*81ad6265SDimitry Andric       return false;
1596*81ad6265SDimitry Andric     case Win64EH::UOP_SaveLR:
1597*81ad6265SDimitry Andric       // Can't be present in a packed prologue
1598*81ad6265SDimitry Andric       return false;
1599*81ad6265SDimitry Andric 
1600*81ad6265SDimitry Andric     case Win64EH::UOP_End:
1601*81ad6265SDimitry Andric     case Win64EH::UOP_EndNop:
1602*81ad6265SDimitry Andric     case Win64EH::UOP_WideEndNop:
1603*81ad6265SDimitry Andric       if (Step != 0)
1604*81ad6265SDimitry Andric         return false;
1605*81ad6265SDimitry Andric       Step = 1;
1606*81ad6265SDimitry Andric       break;
1607*81ad6265SDimitry Andric 
1608*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegsR4R7LR:
1609*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegsR4R11LR:
1610*81ad6265SDimitry Andric       // push {r4-r11,lr}
1611*81ad6265SDimitry Andric       if (Step != 1 && Step != 2)
1612*81ad6265SDimitry Andric         return false;
1613*81ad6265SDimitry Andric       assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
1614*81ad6265SDimitry Andric       assert(Inst.Offset <= 1);                          // Lr
1615*81ad6265SDimitry Andric       IntRegs = Inst.Register - 4;
1616*81ad6265SDimitry Andric       if (Inst.Register == 11) {
1617*81ad6265SDimitry Andric         HasR11 = true;
1618*81ad6265SDimitry Andric         IntRegs--;
1619*81ad6265SDimitry Andric       }
1620*81ad6265SDimitry Andric       if (Inst.Offset)
1621*81ad6265SDimitry Andric         HasLR = true;
1622*81ad6265SDimitry Andric       Step = 3;
1623*81ad6265SDimitry Andric       break;
1624*81ad6265SDimitry Andric 
1625*81ad6265SDimitry Andric     case Win64EH::UOP_SaveRegMask:
1626*81ad6265SDimitry Andric       if (Step == 1 && Inst.Register == 0x0f) {
1627*81ad6265SDimitry Andric         // push {r0-r3}
1628*81ad6265SDimitry Andric         Homing = true;
1629*81ad6265SDimitry Andric         Step = 2;
1630*81ad6265SDimitry Andric         break;
1631*81ad6265SDimitry Andric       }
1632*81ad6265SDimitry Andric       LLVM_FALLTHROUGH;
1633*81ad6265SDimitry Andric     case Win64EH::UOP_WideSaveRegMask:
1634*81ad6265SDimitry Andric       if (Step != 1 && Step != 2)
1635*81ad6265SDimitry Andric         return false;
1636*81ad6265SDimitry Andric       // push {r4-r9,r11,lr}
1637*81ad6265SDimitry Andric       // push {r11,lr}
1638*81ad6265SDimitry Andric       // push {r1-r5}
1639*81ad6265SDimitry Andric       if (!parseRegMask(Inst.Register, HasLR, HasR11, PF, IntRegs))
1640*81ad6265SDimitry Andric         return false;
1641*81ad6265SDimitry Andric       Step = 3;
1642*81ad6265SDimitry Andric       break;
1643*81ad6265SDimitry Andric 
1644*81ad6265SDimitry Andric     case Win64EH::UOP_Nop:
1645*81ad6265SDimitry Andric       // mov r11, sp
1646*81ad6265SDimitry Andric       if (Step != 3 || !HasR11 || IntRegs >= 0 || PF > 0)
1647*81ad6265SDimitry Andric         return false;
1648*81ad6265SDimitry Andric       HasChain = true;
1649*81ad6265SDimitry Andric       Step = 4;
1650*81ad6265SDimitry Andric       break;
1651*81ad6265SDimitry Andric     case Win64EH::UOP_WideNop:
1652*81ad6265SDimitry Andric       // add.w r11, sp, #xx
1653*81ad6265SDimitry Andric       if (Step != 3 || !HasR11 || (IntRegs < 0 && PF == 0))
1654*81ad6265SDimitry Andric         return false;
1655*81ad6265SDimitry Andric       HasChain = true;
1656*81ad6265SDimitry Andric       Step = 4;
1657*81ad6265SDimitry Andric       break;
1658*81ad6265SDimitry Andric 
1659*81ad6265SDimitry Andric     case Win64EH::UOP_SaveFRegD8D15:
1660*81ad6265SDimitry Andric       if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
1661*81ad6265SDimitry Andric         return false;
1662*81ad6265SDimitry Andric       assert(Inst.Register >= 8 && Inst.Register <= 15);
1663*81ad6265SDimitry Andric       if (Inst.Register == 15)
1664*81ad6265SDimitry Andric         return false; // Can't pack this case, R==7 means no IntRegs
1665*81ad6265SDimitry Andric       if (IntRegs >= 0)
1666*81ad6265SDimitry Andric         return false;
1667*81ad6265SDimitry Andric       FloatRegs = Inst.Register - 8;
1668*81ad6265SDimitry Andric       Step = 5;
1669*81ad6265SDimitry Andric       break;
1670*81ad6265SDimitry Andric 
1671*81ad6265SDimitry Andric     case Win64EH::UOP_AllocSmall:
1672*81ad6265SDimitry Andric     case Win64EH::UOP_WideAllocMedium:
1673*81ad6265SDimitry Andric       if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
1674*81ad6265SDimitry Andric         return false;
1675*81ad6265SDimitry Andric       if (PF > 0) // Can't have both folded and explicit stack allocation
1676*81ad6265SDimitry Andric         return false;
1677*81ad6265SDimitry Andric       if (Inst.Offset / 4 >= 0x3f4)
1678*81ad6265SDimitry Andric         return false;
1679*81ad6265SDimitry Andric       StackAdjust = Inst.Offset / 4;
1680*81ad6265SDimitry Andric       Step = 6;
1681*81ad6265SDimitry Andric       break;
1682*81ad6265SDimitry Andric     }
1683*81ad6265SDimitry Andric   }
1684*81ad6265SDimitry Andric   if (HasR11 && !HasChain) {
1685*81ad6265SDimitry Andric     if (IntRegs + 4 == 10) {
1686*81ad6265SDimitry Andric       // r11 stored, but not chaining; can be packed if already saving r4-r10
1687*81ad6265SDimitry Andric       // and we can fit r11 into this range.
1688*81ad6265SDimitry Andric       IntRegs++;
1689*81ad6265SDimitry Andric       HasR11 = false;
1690*81ad6265SDimitry Andric     } else
1691*81ad6265SDimitry Andric       return false;
1692*81ad6265SDimitry Andric   }
1693*81ad6265SDimitry Andric   if (HasChain && !HasLR)
1694*81ad6265SDimitry Andric     return false;
1695*81ad6265SDimitry Andric 
1696*81ad6265SDimitry Andric   // Packed uneind info can't express multiple epilogues.
1697*81ad6265SDimitry Andric   if (info->EpilogMap.size() > 1)
1698*81ad6265SDimitry Andric     return false;
1699*81ad6265SDimitry Andric 
1700*81ad6265SDimitry Andric   unsigned EF = 0;
1701*81ad6265SDimitry Andric   int Ret = 0;
1702*81ad6265SDimitry Andric   if (info->EpilogMap.size() == 0) {
1703*81ad6265SDimitry Andric     Ret = 3; // No epilogue
1704*81ad6265SDimitry Andric   } else {
1705*81ad6265SDimitry Andric     // As the prologue and epilogue aren't exact mirrors of each other,
1706*81ad6265SDimitry Andric     // we have to check the epilogue too and see if it matches what we've
1707*81ad6265SDimitry Andric     // concluded from the prologue.
1708*81ad6265SDimitry Andric     const WinEH::FrameInfo::Epilog &EpilogInfo =
1709*81ad6265SDimitry Andric         info->EpilogMap.begin()->second;
1710*81ad6265SDimitry Andric     if (EpilogInfo.Condition != 0xe) // ARMCC::AL
1711*81ad6265SDimitry Andric       return false;
1712*81ad6265SDimitry Andric     const std::vector<WinEH::Instruction> &Epilog = EpilogInfo.Instructions;
1713*81ad6265SDimitry Andric     Optional<int64_t> MaybeDistance = GetOptionalAbsDifference(
1714*81ad6265SDimitry Andric         streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
1715*81ad6265SDimitry Andric     if (!MaybeDistance)
1716*81ad6265SDimitry Andric       return false;
1717*81ad6265SDimitry Andric     uint32_t DistanceFromEnd = (uint32_t)*MaybeDistance;
1718*81ad6265SDimitry Andric     uint32_t InstructionBytes = ARMCountOfInstructionBytes(Epilog);
1719*81ad6265SDimitry Andric     if (DistanceFromEnd != InstructionBytes)
1720*81ad6265SDimitry Andric       return false;
1721*81ad6265SDimitry Andric 
1722*81ad6265SDimitry Andric     bool GotStackAdjust = false;
1723*81ad6265SDimitry Andric     bool GotFloatRegs = false;
1724*81ad6265SDimitry Andric     bool GotIntRegs = false;
1725*81ad6265SDimitry Andric     bool GotHomingRestore = false;
1726*81ad6265SDimitry Andric     bool GotLRRestore = false;
1727*81ad6265SDimitry Andric     bool NeedsReturn = false;
1728*81ad6265SDimitry Andric     bool GotReturn = false;
1729*81ad6265SDimitry Andric 
1730*81ad6265SDimitry Andric     Step = 6;
1731*81ad6265SDimitry Andric     for (const WinEH::Instruction &Inst : Epilog) {
1732*81ad6265SDimitry Andric       switch (Inst.Operation) {
1733*81ad6265SDimitry Andric       default:
1734*81ad6265SDimitry Andric         llvm_unreachable("Unsupported ARM unwind code");
1735*81ad6265SDimitry Andric       case Win64EH::UOP_Custom:
1736*81ad6265SDimitry Andric       case Win64EH::UOP_AllocLarge:
1737*81ad6265SDimitry Andric       case Win64EH::UOP_AllocHuge:
1738*81ad6265SDimitry Andric       case Win64EH::UOP_WideAllocLarge:
1739*81ad6265SDimitry Andric       case Win64EH::UOP_WideAllocHuge:
1740*81ad6265SDimitry Andric       case Win64EH::UOP_SaveFRegD0D15:
1741*81ad6265SDimitry Andric       case Win64EH::UOP_SaveFRegD16D31:
1742*81ad6265SDimitry Andric       case Win64EH::UOP_SaveSP:
1743*81ad6265SDimitry Andric       case Win64EH::UOP_Nop:
1744*81ad6265SDimitry Andric       case Win64EH::UOP_WideNop:
1745*81ad6265SDimitry Andric         // Can't be packed in an epilogue
1746*81ad6265SDimitry Andric         return false;
1747*81ad6265SDimitry Andric 
1748*81ad6265SDimitry Andric       case Win64EH::UOP_AllocSmall:
1749*81ad6265SDimitry Andric       case Win64EH::UOP_WideAllocMedium:
1750*81ad6265SDimitry Andric         if (Inst.Offset / 4 >= 0x3f4)
1751*81ad6265SDimitry Andric           return false;
1752*81ad6265SDimitry Andric         if (Step == 6) {
1753*81ad6265SDimitry Andric           if (Homing && FloatRegs < 0 && IntRegs < 0 && StackAdjust == 0 &&
1754*81ad6265SDimitry Andric               PF == 0 && Inst.Offset == 16) {
1755*81ad6265SDimitry Andric             GotHomingRestore = true;
1756*81ad6265SDimitry Andric             Step = 10;
1757*81ad6265SDimitry Andric           } else {
1758*81ad6265SDimitry Andric             if (StackAdjust > 0) {
1759*81ad6265SDimitry Andric               // Got stack adjust in prologue too; must match.
1760*81ad6265SDimitry Andric               if (StackAdjust != Inst.Offset / 4)
1761*81ad6265SDimitry Andric                 return false;
1762*81ad6265SDimitry Andric               GotStackAdjust = true;
1763*81ad6265SDimitry Andric             } else if (PF == Inst.Offset / 4) {
1764*81ad6265SDimitry Andric               // Folded prologue, non-folded epilogue
1765*81ad6265SDimitry Andric               StackAdjust = Inst.Offset / 4;
1766*81ad6265SDimitry Andric               GotStackAdjust = true;
1767*81ad6265SDimitry Andric             } else {
1768*81ad6265SDimitry Andric               // StackAdjust == 0 in prologue, mismatch
1769*81ad6265SDimitry Andric               return false;
1770*81ad6265SDimitry Andric             }
1771*81ad6265SDimitry Andric             Step = 7;
1772*81ad6265SDimitry Andric           }
1773*81ad6265SDimitry Andric         } else if (Step == 7 || Step == 8 || Step == 9) {
1774*81ad6265SDimitry Andric           if (!Homing || Inst.Offset != 16)
1775*81ad6265SDimitry Andric             return false;
1776*81ad6265SDimitry Andric           GotHomingRestore = true;
1777*81ad6265SDimitry Andric           Step = 10;
1778*81ad6265SDimitry Andric         } else
1779*81ad6265SDimitry Andric           return false;
1780*81ad6265SDimitry Andric         break;
1781*81ad6265SDimitry Andric 
1782*81ad6265SDimitry Andric       case Win64EH::UOP_SaveFRegD8D15:
1783*81ad6265SDimitry Andric         if (Step != 6 && Step != 7)
1784*81ad6265SDimitry Andric           return false;
1785*81ad6265SDimitry Andric         assert(Inst.Register >= 8 && Inst.Register <= 15);
1786*81ad6265SDimitry Andric         if (FloatRegs != (int)(Inst.Register - 8))
1787*81ad6265SDimitry Andric           return false;
1788*81ad6265SDimitry Andric         GotFloatRegs = true;
1789*81ad6265SDimitry Andric         Step = 8;
1790*81ad6265SDimitry Andric         break;
1791*81ad6265SDimitry Andric 
1792*81ad6265SDimitry Andric       case Win64EH::UOP_SaveRegsR4R7LR:
1793*81ad6265SDimitry Andric       case Win64EH::UOP_WideSaveRegsR4R11LR: {
1794*81ad6265SDimitry Andric         // push {r4-r11,lr}
1795*81ad6265SDimitry Andric         if (Step != 6 && Step != 7 && Step != 8)
1796*81ad6265SDimitry Andric           return false;
1797*81ad6265SDimitry Andric         assert(Inst.Register >= 4 && Inst.Register <= 11); // r4-rX
1798*81ad6265SDimitry Andric         assert(Inst.Offset <= 1);                          // Lr
1799*81ad6265SDimitry Andric         if (Homing && HasLR) {
1800*81ad6265SDimitry Andric           // If homing and LR is backed up, we can either restore LR here
1801*81ad6265SDimitry Andric           // and return with Ret == 1 or 2, or return with SaveLR below
1802*81ad6265SDimitry Andric           if (Inst.Offset) {
1803*81ad6265SDimitry Andric             GotLRRestore = true;
1804*81ad6265SDimitry Andric             NeedsReturn = true;
1805*81ad6265SDimitry Andric           } else {
1806*81ad6265SDimitry Andric             // Expecting a separate SaveLR below
1807*81ad6265SDimitry Andric           }
1808*81ad6265SDimitry Andric         } else {
1809*81ad6265SDimitry Andric           if (HasLR != (Inst.Offset == 1))
1810*81ad6265SDimitry Andric             return false;
1811*81ad6265SDimitry Andric         }
1812*81ad6265SDimitry Andric         GotLRRestore = Inst.Offset == 1;
1813*81ad6265SDimitry Andric         if (IntRegs < 0) // This opcode must include r4
1814*81ad6265SDimitry Andric           return false;
1815*81ad6265SDimitry Andric         int Expected = IntRegs;
1816*81ad6265SDimitry Andric         if (HasChain) {
1817*81ad6265SDimitry Andric           // Can't express r11 here unless IntRegs describe r4-r10
1818*81ad6265SDimitry Andric           if (IntRegs != 6)
1819*81ad6265SDimitry Andric             return false;
1820*81ad6265SDimitry Andric           Expected++;
1821*81ad6265SDimitry Andric         }
1822*81ad6265SDimitry Andric         if (Expected != (int)(Inst.Register - 4))
1823*81ad6265SDimitry Andric           return false;
1824*81ad6265SDimitry Andric         GotIntRegs = true;
1825*81ad6265SDimitry Andric         Step = 9;
1826*81ad6265SDimitry Andric         break;
1827*81ad6265SDimitry Andric       }
1828*81ad6265SDimitry Andric 
1829*81ad6265SDimitry Andric       case Win64EH::UOP_SaveRegMask:
1830*81ad6265SDimitry Andric       case Win64EH::UOP_WideSaveRegMask: {
1831*81ad6265SDimitry Andric         if (Step != 6 && Step != 7 && Step != 8)
1832*81ad6265SDimitry Andric           return false;
1833*81ad6265SDimitry Andric         // push {r4-r9,r11,lr}
1834*81ad6265SDimitry Andric         // push {r11,lr}
1835*81ad6265SDimitry Andric         // push {r1-r5}
1836*81ad6265SDimitry Andric         bool CurHasLR = false, CurHasR11 = false;
1837*81ad6265SDimitry Andric         int Regs;
1838*81ad6265SDimitry Andric         if (!parseRegMask(Inst.Register, CurHasLR, CurHasR11, EF, Regs))
1839*81ad6265SDimitry Andric           return false;
1840*81ad6265SDimitry Andric         if (EF > 0) {
1841*81ad6265SDimitry Andric           if (EF != PF && EF != StackAdjust)
1842*81ad6265SDimitry Andric             return false;
1843*81ad6265SDimitry Andric         }
1844*81ad6265SDimitry Andric         if (Homing && HasLR) {
1845*81ad6265SDimitry Andric           // If homing and LR is backed up, we can either restore LR here
1846*81ad6265SDimitry Andric           // and return with Ret == 1 or 2, or return with SaveLR below
1847*81ad6265SDimitry Andric           if (CurHasLR) {
1848*81ad6265SDimitry Andric             GotLRRestore = true;
1849*81ad6265SDimitry Andric             NeedsReturn = true;
1850*81ad6265SDimitry Andric           } else {
1851*81ad6265SDimitry Andric             // Expecting a separate SaveLR below
1852*81ad6265SDimitry Andric           }
1853*81ad6265SDimitry Andric         } else {
1854*81ad6265SDimitry Andric           if (CurHasLR != HasLR)
1855*81ad6265SDimitry Andric             return false;
1856*81ad6265SDimitry Andric           GotLRRestore = CurHasLR;
1857*81ad6265SDimitry Andric         }
1858*81ad6265SDimitry Andric         int Expected = IntRegs;
1859*81ad6265SDimitry Andric         if (HasChain) {
1860*81ad6265SDimitry Andric           // If we have chaining, the mask must have included r11.
1861*81ad6265SDimitry Andric           if (!CurHasR11)
1862*81ad6265SDimitry Andric             return false;
1863*81ad6265SDimitry Andric         } else if (Expected == 7) {
1864*81ad6265SDimitry Andric           // If we don't have chaining, the mask could still include r11,
1865*81ad6265SDimitry Andric           // expressed as part of IntRegs Instead.
1866*81ad6265SDimitry Andric           Expected--;
1867*81ad6265SDimitry Andric           if (!CurHasR11)
1868*81ad6265SDimitry Andric             return false;
1869*81ad6265SDimitry Andric         } else {
1870*81ad6265SDimitry Andric           // Neither HasChain nor r11 included in IntRegs, must not have r11
1871*81ad6265SDimitry Andric           // here either.
1872*81ad6265SDimitry Andric           if (CurHasR11)
1873*81ad6265SDimitry Andric             return false;
1874*81ad6265SDimitry Andric         }
1875*81ad6265SDimitry Andric         if (Expected != Regs)
1876*81ad6265SDimitry Andric           return false;
1877*81ad6265SDimitry Andric         GotIntRegs = true;
1878*81ad6265SDimitry Andric         Step = 9;
1879*81ad6265SDimitry Andric         break;
1880*81ad6265SDimitry Andric       }
1881*81ad6265SDimitry Andric 
1882*81ad6265SDimitry Andric       case Win64EH::UOP_SaveLR:
1883*81ad6265SDimitry Andric         if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
1884*81ad6265SDimitry Andric           return false;
1885*81ad6265SDimitry Andric         if (!Homing || Inst.Offset != 20 || GotLRRestore)
1886*81ad6265SDimitry Andric           return false;
1887*81ad6265SDimitry Andric         GotLRRestore = true;
1888*81ad6265SDimitry Andric         GotHomingRestore = true;
1889*81ad6265SDimitry Andric         Step = 10;
1890*81ad6265SDimitry Andric         break;
1891*81ad6265SDimitry Andric 
1892*81ad6265SDimitry Andric       case Win64EH::UOP_EndNop:
1893*81ad6265SDimitry Andric       case Win64EH::UOP_WideEndNop:
1894*81ad6265SDimitry Andric         GotReturn = true;
1895*81ad6265SDimitry Andric         Ret = (Inst.Operation == Win64EH::UOP_EndNop) ? 1 : 2;
1896*81ad6265SDimitry Andric         LLVM_FALLTHROUGH;
1897*81ad6265SDimitry Andric       case Win64EH::UOP_End:
1898*81ad6265SDimitry Andric         if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
1899*81ad6265SDimitry Andric           return false;
1900*81ad6265SDimitry Andric         Step = 11;
1901*81ad6265SDimitry Andric         break;
1902*81ad6265SDimitry Andric       }
1903*81ad6265SDimitry Andric     }
1904*81ad6265SDimitry Andric 
1905*81ad6265SDimitry Andric     if (Step != 11)
1906*81ad6265SDimitry Andric       return false;
1907*81ad6265SDimitry Andric     if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
1908*81ad6265SDimitry Andric       return false;
1909*81ad6265SDimitry Andric     if (FloatRegs >= 0 && !GotFloatRegs)
1910*81ad6265SDimitry Andric       return false;
1911*81ad6265SDimitry Andric     if (IntRegs >= 0 && !GotIntRegs)
1912*81ad6265SDimitry Andric       return false;
1913*81ad6265SDimitry Andric     if (Homing && !GotHomingRestore)
1914*81ad6265SDimitry Andric       return false;
1915*81ad6265SDimitry Andric     if (HasLR && !GotLRRestore)
1916*81ad6265SDimitry Andric       return false;
1917*81ad6265SDimitry Andric     if (NeedsReturn && !GotReturn)
1918*81ad6265SDimitry Andric       return false;
1919*81ad6265SDimitry Andric   }
1920*81ad6265SDimitry Andric 
1921*81ad6265SDimitry Andric   assert(PF == 0 || EF == 0 ||
1922*81ad6265SDimitry Andric          StackAdjust == 0); // Can't have adjust in all three
1923*81ad6265SDimitry Andric   if (PF > 0 || EF > 0) {
1924*81ad6265SDimitry Andric     StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
1925*81ad6265SDimitry Andric     assert(StackAdjust <= 3);
1926*81ad6265SDimitry Andric     StackAdjust |= 0x3f0;
1927*81ad6265SDimitry Andric     if (PF > 0)
1928*81ad6265SDimitry Andric       StackAdjust |= 1 << 2;
1929*81ad6265SDimitry Andric     if (EF > 0)
1930*81ad6265SDimitry Andric       StackAdjust |= 1 << 3;
1931*81ad6265SDimitry Andric   }
1932*81ad6265SDimitry Andric 
1933*81ad6265SDimitry Andric   assert(FuncLength <= 0x7FF && "FuncLength should have been checked earlier");
1934*81ad6265SDimitry Andric   int Flag = info->Fragment ? 0x02 : 0x01;
1935*81ad6265SDimitry Andric   int H = Homing ? 1 : 0;
1936*81ad6265SDimitry Andric   int L = HasLR ? 1 : 0;
1937*81ad6265SDimitry Andric   int C = HasChain ? 1 : 0;
1938*81ad6265SDimitry Andric   assert(IntRegs < 0 || FloatRegs < 0);
1939*81ad6265SDimitry Andric   unsigned Reg, R;
1940*81ad6265SDimitry Andric   if (IntRegs >= 0) {
1941*81ad6265SDimitry Andric     Reg = IntRegs;
1942*81ad6265SDimitry Andric     assert(Reg <= 7);
1943*81ad6265SDimitry Andric     R = 0;
1944*81ad6265SDimitry Andric   } else if (FloatRegs >= 0) {
1945*81ad6265SDimitry Andric     Reg = FloatRegs;
1946*81ad6265SDimitry Andric     assert(Reg < 7);
1947*81ad6265SDimitry Andric     R = 1;
1948*81ad6265SDimitry Andric   } else {
1949*81ad6265SDimitry Andric     // No int or float regs stored (except possibly R11,LR)
1950*81ad6265SDimitry Andric     Reg = 7;
1951*81ad6265SDimitry Andric     R = 1;
1952*81ad6265SDimitry Andric   }
1953*81ad6265SDimitry Andric   info->PackedInfo |= Flag << 0;
1954*81ad6265SDimitry Andric   info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1955*81ad6265SDimitry Andric   info->PackedInfo |= (Ret & 0x3) << 13;
1956*81ad6265SDimitry Andric   info->PackedInfo |= H << 15;
1957*81ad6265SDimitry Andric   info->PackedInfo |= Reg << 16;
1958*81ad6265SDimitry Andric   info->PackedInfo |= R << 19;
1959*81ad6265SDimitry Andric   info->PackedInfo |= L << 20;
1960*81ad6265SDimitry Andric   info->PackedInfo |= C << 21;
1961*81ad6265SDimitry Andric   assert(StackAdjust <= 0x3ff);
1962*81ad6265SDimitry Andric   info->PackedInfo |= StackAdjust << 22;
1963*81ad6265SDimitry Andric   return true;
1964*81ad6265SDimitry Andric }
1965*81ad6265SDimitry Andric 
1966*81ad6265SDimitry Andric // Populate the .xdata section.  The format of .xdata on ARM is documented at
1967*81ad6265SDimitry Andric // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
1968*81ad6265SDimitry Andric static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
1969*81ad6265SDimitry Andric                               bool TryPacked = true) {
1970*81ad6265SDimitry Andric   // If this UNWIND_INFO already has a symbol, it's already been emitted.
1971*81ad6265SDimitry Andric   if (info->Symbol)
1972*81ad6265SDimitry Andric     return;
1973*81ad6265SDimitry Andric   // If there's no unwind info here (not even a terminating UOP_End), the
1974*81ad6265SDimitry Andric   // unwind info is considered bogus and skipped. If this was done in
1975*81ad6265SDimitry Andric   // response to an explicit .seh_handlerdata, the associated trailing
1976*81ad6265SDimitry Andric   // handler data is left orphaned in the xdata section.
1977*81ad6265SDimitry Andric   if (info->empty()) {
1978*81ad6265SDimitry Andric     info->EmitAttempted = true;
1979*81ad6265SDimitry Andric     return;
1980*81ad6265SDimitry Andric   }
1981*81ad6265SDimitry Andric   if (info->EmitAttempted) {
1982*81ad6265SDimitry Andric     // If we tried to emit unwind info before (due to an explicit
1983*81ad6265SDimitry Andric     // .seh_handlerdata directive), but skipped it (because there was no
1984*81ad6265SDimitry Andric     // valid information to emit at the time), and it later got valid unwind
1985*81ad6265SDimitry Andric     // opcodes, we can't emit it here, because the trailing handler data
1986*81ad6265SDimitry Andric     // was already emitted elsewhere in the xdata section.
1987*81ad6265SDimitry Andric     streamer.getContext().reportError(
1988*81ad6265SDimitry Andric         SMLoc(), "Earlier .seh_handlerdata for " + info->Function->getName() +
1989*81ad6265SDimitry Andric                      " skipped due to no unwind info at the time "
1990*81ad6265SDimitry Andric                      "(.seh_handlerdata too early?), but the function later "
1991*81ad6265SDimitry Andric                      "did get unwind info that can't be emitted");
1992*81ad6265SDimitry Andric     return;
1993*81ad6265SDimitry Andric   }
1994*81ad6265SDimitry Andric 
1995*81ad6265SDimitry Andric   MCContext &context = streamer.getContext();
1996*81ad6265SDimitry Andric   MCSymbol *Label = context.createTempSymbol();
1997*81ad6265SDimitry Andric 
1998*81ad6265SDimitry Andric   streamer.emitValueToAlignment(4);
1999*81ad6265SDimitry Andric   streamer.emitLabel(Label);
2000*81ad6265SDimitry Andric   info->Symbol = Label;
2001*81ad6265SDimitry Andric 
2002*81ad6265SDimitry Andric   if (!info->PrologEnd)
2003*81ad6265SDimitry Andric     streamer.getContext().reportError(SMLoc(), "Prologue in " +
2004*81ad6265SDimitry Andric                                                    info->Function->getName() +
2005*81ad6265SDimitry Andric                                                    " not correctly terminated");
2006*81ad6265SDimitry Andric 
2007*81ad6265SDimitry Andric   if (info->PrologEnd && !info->Fragment)
2008*81ad6265SDimitry Andric     checkARMInstructions(streamer, info->Instructions, info->Begin,
2009*81ad6265SDimitry Andric                          info->PrologEnd, info->Function->getName(),
2010*81ad6265SDimitry Andric                          "prologue");
2011*81ad6265SDimitry Andric   for (auto &I : info->EpilogMap) {
2012*81ad6265SDimitry Andric     MCSymbol *EpilogStart = I.first;
2013*81ad6265SDimitry Andric     auto &Epilog = I.second;
2014*81ad6265SDimitry Andric     checkARMInstructions(streamer, Epilog.Instructions, EpilogStart, Epilog.End,
2015*81ad6265SDimitry Andric                          info->Function->getName(), "epilogue");
2016*81ad6265SDimitry Andric     if (Epilog.Instructions.empty() ||
2017*81ad6265SDimitry Andric         !isARMTerminator(Epilog.Instructions.back()))
2018*81ad6265SDimitry Andric       streamer.getContext().reportError(
2019*81ad6265SDimitry Andric           SMLoc(), "Epilogue in " + info->Function->getName() +
2020*81ad6265SDimitry Andric                        " not correctly terminated");
2021*81ad6265SDimitry Andric   }
2022*81ad6265SDimitry Andric 
2023*81ad6265SDimitry Andric   Optional<int64_t> RawFuncLength;
2024*81ad6265SDimitry Andric   const MCExpr *FuncLengthExpr = nullptr;
2025*81ad6265SDimitry Andric   if (!info->FuncletOrFuncEnd) {
2026*81ad6265SDimitry Andric     report_fatal_error("FuncletOrFuncEnd not set");
2027*81ad6265SDimitry Andric   } else {
2028*81ad6265SDimitry Andric     // As the size of many thumb2 instructions isn't known until later,
2029*81ad6265SDimitry Andric     // we can't always rely on being able to calculate the absolute
2030*81ad6265SDimitry Andric     // length of the function here. If we can't calculate it, defer it
2031*81ad6265SDimitry Andric     // to a relocation.
2032*81ad6265SDimitry Andric     //
2033*81ad6265SDimitry Andric     // In such a case, we won't know if the function is too long so that
2034*81ad6265SDimitry Andric     // the unwind info would need to be split (but this isn't implemented
2035*81ad6265SDimitry Andric     // anyway).
2036*81ad6265SDimitry Andric     RawFuncLength =
2037*81ad6265SDimitry Andric         GetOptionalAbsDifference(streamer, info->FuncletOrFuncEnd, info->Begin);
2038*81ad6265SDimitry Andric     if (!RawFuncLength)
2039*81ad6265SDimitry Andric       FuncLengthExpr =
2040*81ad6265SDimitry Andric           GetSubDivExpr(streamer, info->FuncletOrFuncEnd, info->Begin, 2);
2041*81ad6265SDimitry Andric   }
2042*81ad6265SDimitry Andric   uint32_t FuncLength = 0;
2043*81ad6265SDimitry Andric   if (RawFuncLength)
2044*81ad6265SDimitry Andric     FuncLength = (uint32_t)*RawFuncLength / 2;
2045*81ad6265SDimitry Andric   if (FuncLength > 0x3FFFF)
2046*81ad6265SDimitry Andric     report_fatal_error("SEH unwind data splitting not yet implemented");
2047*81ad6265SDimitry Andric   uint32_t PrologCodeBytes = ARMCountOfUnwindCodes(info->Instructions);
2048*81ad6265SDimitry Andric   uint32_t TotalCodeBytes = PrologCodeBytes;
2049*81ad6265SDimitry Andric 
2050*81ad6265SDimitry Andric   if (!info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2051*81ad6265SDimitry Andric       TryPacked) {
2052*81ad6265SDimitry Andric     // No exception handlers; check if the prolog and epilog matches the
2053*81ad6265SDimitry Andric     // patterns that can be described by the packed format. If we don't
2054*81ad6265SDimitry Andric     // know the exact function length yet, we can't do this.
2055*81ad6265SDimitry Andric 
2056*81ad6265SDimitry Andric     // info->Symbol was already set even if we didn't actually write any
2057*81ad6265SDimitry Andric     // unwind info there. Keep using that as indicator that this unwind
2058*81ad6265SDimitry Andric     // info has been generated already.
2059*81ad6265SDimitry Andric 
2060*81ad6265SDimitry Andric     if (tryARMPackedUnwind(streamer, info, FuncLength))
2061*81ad6265SDimitry Andric       return;
2062*81ad6265SDimitry Andric   }
2063*81ad6265SDimitry Andric 
2064*81ad6265SDimitry Andric   int PackedEpilogOffset =
2065*81ad6265SDimitry Andric       checkARMPackedEpilog(streamer, info, PrologCodeBytes);
2066*81ad6265SDimitry Andric 
2067*81ad6265SDimitry Andric   // Process epilogs.
2068*81ad6265SDimitry Andric   MapVector<MCSymbol *, uint32_t> EpilogInfo;
2069*81ad6265SDimitry Andric   // Epilogs processed so far.
2070*81ad6265SDimitry Andric   std::vector<MCSymbol *> AddedEpilogs;
2071*81ad6265SDimitry Andric 
2072*81ad6265SDimitry Andric   bool CanTweakProlog = true;
2073*81ad6265SDimitry Andric   for (auto &I : info->EpilogMap) {
2074*81ad6265SDimitry Andric     MCSymbol *EpilogStart = I.first;
2075*81ad6265SDimitry Andric     auto &EpilogInstrs = I.second.Instructions;
2076*81ad6265SDimitry Andric     uint32_t CodeBytes = ARMCountOfUnwindCodes(EpilogInstrs);
2077*81ad6265SDimitry Andric 
2078*81ad6265SDimitry Andric     MCSymbol *MatchingEpilog =
2079*81ad6265SDimitry Andric         FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
2080*81ad6265SDimitry Andric     int PrologOffset;
2081*81ad6265SDimitry Andric     if (MatchingEpilog) {
2082*81ad6265SDimitry Andric       assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&
2083*81ad6265SDimitry Andric              "Duplicate epilog not found");
2084*81ad6265SDimitry Andric       EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2085*81ad6265SDimitry Andric       // Clear the unwind codes in the EpilogMap, so that they don't get output
2086*81ad6265SDimitry Andric       // in the logic below.
2087*81ad6265SDimitry Andric       EpilogInstrs.clear();
2088*81ad6265SDimitry Andric     } else if ((PrologOffset = getARMOffsetInProlog(
2089*81ad6265SDimitry Andric                     info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2090*81ad6265SDimitry Andric       if (CanTweakProlog) {
2091*81ad6265SDimitry Andric         // Replace the regular end opcode of the prolog with the one from the
2092*81ad6265SDimitry Andric         // epilog.
2093*81ad6265SDimitry Andric         info->Instructions.front() = EpilogInstrs.back();
2094*81ad6265SDimitry Andric         // Later epilogs need a strict match for the end opcode.
2095*81ad6265SDimitry Andric         CanTweakProlog = false;
2096*81ad6265SDimitry Andric       }
2097*81ad6265SDimitry Andric       EpilogInfo[EpilogStart] = PrologOffset;
2098*81ad6265SDimitry Andric       // Clear the unwind codes in the EpilogMap, so that they don't get output
2099*81ad6265SDimitry Andric       // in the logic below.
2100*81ad6265SDimitry Andric       EpilogInstrs.clear();
2101*81ad6265SDimitry Andric     } else {
2102*81ad6265SDimitry Andric       EpilogInfo[EpilogStart] = TotalCodeBytes;
2103*81ad6265SDimitry Andric       TotalCodeBytes += CodeBytes;
2104*81ad6265SDimitry Andric       AddedEpilogs.push_back(EpilogStart);
2105*81ad6265SDimitry Andric     }
2106*81ad6265SDimitry Andric   }
2107*81ad6265SDimitry Andric 
2108*81ad6265SDimitry Andric   // Code Words, Epilog count, F, E, X, Vers, Function Length
2109*81ad6265SDimitry Andric   uint32_t row1 = 0x0;
2110*81ad6265SDimitry Andric   uint32_t CodeWords = TotalCodeBytes / 4;
2111*81ad6265SDimitry Andric   uint32_t CodeWordsMod = TotalCodeBytes % 4;
2112*81ad6265SDimitry Andric   if (CodeWordsMod)
2113*81ad6265SDimitry Andric     CodeWords++;
2114*81ad6265SDimitry Andric   uint32_t EpilogCount =
2115*81ad6265SDimitry Andric       PackedEpilogOffset >= 0 ? PackedEpilogOffset : info->EpilogMap.size();
2116*81ad6265SDimitry Andric   bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2117*81ad6265SDimitry Andric   if (!ExtensionWord) {
2118*81ad6265SDimitry Andric     row1 |= (EpilogCount & 0x1F) << 23;
2119*81ad6265SDimitry Andric     row1 |= (CodeWords & 0x0F) << 28;
2120*81ad6265SDimitry Andric   }
2121*81ad6265SDimitry Andric   if (info->HandlesExceptions) // X
2122*81ad6265SDimitry Andric     row1 |= 1 << 20;
2123*81ad6265SDimitry Andric   if (PackedEpilogOffset >= 0) // E
2124*81ad6265SDimitry Andric     row1 |= 1 << 21;
2125*81ad6265SDimitry Andric   if (info->Fragment) // F
2126*81ad6265SDimitry Andric     row1 |= 1 << 22;
2127*81ad6265SDimitry Andric   row1 |= FuncLength & 0x3FFFF;
2128*81ad6265SDimitry Andric   if (RawFuncLength)
2129*81ad6265SDimitry Andric     streamer.emitInt32(row1);
2130*81ad6265SDimitry Andric   else
2131*81ad6265SDimitry Andric     streamer.emitValue(
2132*81ad6265SDimitry Andric         MCBinaryExpr::createOr(FuncLengthExpr,
2133*81ad6265SDimitry Andric                                MCConstantExpr::create(row1, context), context),
2134*81ad6265SDimitry Andric         4);
2135*81ad6265SDimitry Andric 
2136*81ad6265SDimitry Andric   // Extended Code Words, Extended Epilog Count
2137*81ad6265SDimitry Andric   if (ExtensionWord) {
2138*81ad6265SDimitry Andric     // FIXME: We should be able to split unwind info into multiple sections.
2139*81ad6265SDimitry Andric     if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2140*81ad6265SDimitry Andric       report_fatal_error("SEH unwind data splitting not yet implemented");
2141*81ad6265SDimitry Andric     uint32_t row2 = 0x0;
2142*81ad6265SDimitry Andric     row2 |= (CodeWords & 0xFF) << 16;
2143*81ad6265SDimitry Andric     row2 |= (EpilogCount & 0xFFFF);
2144*81ad6265SDimitry Andric     streamer.emitInt32(row2);
2145*81ad6265SDimitry Andric   }
2146*81ad6265SDimitry Andric 
2147*81ad6265SDimitry Andric   if (PackedEpilogOffset < 0) {
2148*81ad6265SDimitry Andric     // Epilog Start Index, Epilog Start Offset
2149*81ad6265SDimitry Andric     for (auto &I : EpilogInfo) {
2150*81ad6265SDimitry Andric       MCSymbol *EpilogStart = I.first;
2151*81ad6265SDimitry Andric       uint32_t EpilogIndex = I.second;
2152*81ad6265SDimitry Andric 
2153*81ad6265SDimitry Andric       Optional<int64_t> MaybeEpilogOffset =
2154*81ad6265SDimitry Andric           GetOptionalAbsDifference(streamer, EpilogStart, info->Begin);
2155*81ad6265SDimitry Andric       const MCExpr *OffsetExpr = nullptr;
2156*81ad6265SDimitry Andric       uint32_t EpilogOffset = 0;
2157*81ad6265SDimitry Andric       if (MaybeEpilogOffset)
2158*81ad6265SDimitry Andric         EpilogOffset = *MaybeEpilogOffset / 2;
2159*81ad6265SDimitry Andric       else
2160*81ad6265SDimitry Andric         OffsetExpr = GetSubDivExpr(streamer, EpilogStart, info->Begin, 2);
2161*81ad6265SDimitry Andric 
2162*81ad6265SDimitry Andric       assert(info->EpilogMap.find(EpilogStart) != info->EpilogMap.end());
2163*81ad6265SDimitry Andric       unsigned Condition = info->EpilogMap[EpilogStart].Condition;
2164*81ad6265SDimitry Andric       assert(Condition <= 0xf);
2165*81ad6265SDimitry Andric 
2166*81ad6265SDimitry Andric       uint32_t row3 = EpilogOffset;
2167*81ad6265SDimitry Andric       row3 |= Condition << 20;
2168*81ad6265SDimitry Andric       row3 |= (EpilogIndex & 0x3FF) << 24;
2169*81ad6265SDimitry Andric       if (MaybeEpilogOffset)
2170*81ad6265SDimitry Andric         streamer.emitInt32(row3);
2171*81ad6265SDimitry Andric       else
2172*81ad6265SDimitry Andric         streamer.emitValue(
2173*81ad6265SDimitry Andric             MCBinaryExpr::createOr(
2174*81ad6265SDimitry Andric                 OffsetExpr, MCConstantExpr::create(row3, context), context),
2175*81ad6265SDimitry Andric             4);
2176*81ad6265SDimitry Andric     }
2177*81ad6265SDimitry Andric   }
2178*81ad6265SDimitry Andric 
2179*81ad6265SDimitry Andric   // Emit prolog unwind instructions (in reverse order).
2180*81ad6265SDimitry Andric   uint8_t numInst = info->Instructions.size();
2181*81ad6265SDimitry Andric   for (uint8_t c = 0; c < numInst; ++c) {
2182*81ad6265SDimitry Andric     WinEH::Instruction inst = info->Instructions.back();
2183*81ad6265SDimitry Andric     info->Instructions.pop_back();
2184*81ad6265SDimitry Andric     ARMEmitUnwindCode(streamer, inst);
2185*81ad6265SDimitry Andric   }
2186*81ad6265SDimitry Andric 
2187*81ad6265SDimitry Andric   // Emit epilog unwind instructions
2188*81ad6265SDimitry Andric   for (auto &I : info->EpilogMap) {
2189*81ad6265SDimitry Andric     auto &EpilogInstrs = I.second.Instructions;
2190*81ad6265SDimitry Andric     for (uint32_t i = 0; i < EpilogInstrs.size(); i++) {
2191*81ad6265SDimitry Andric       WinEH::Instruction inst = EpilogInstrs[i];
2192*81ad6265SDimitry Andric       ARMEmitUnwindCode(streamer, inst);
2193*81ad6265SDimitry Andric     }
2194*81ad6265SDimitry Andric   }
2195*81ad6265SDimitry Andric 
2196*81ad6265SDimitry Andric   int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2197*81ad6265SDimitry Andric   assert(BytesMod >= 0);
2198*81ad6265SDimitry Andric   for (int i = 0; i < BytesMod; i++)
2199*81ad6265SDimitry Andric     streamer.emitInt8(0xFB);
2200*81ad6265SDimitry Andric 
2201*81ad6265SDimitry Andric   if (info->HandlesExceptions)
2202*81ad6265SDimitry Andric     streamer.emitValue(
2203*81ad6265SDimitry Andric         MCSymbolRefExpr::create(info->ExceptionHandler,
2204*81ad6265SDimitry Andric                                 MCSymbolRefExpr::VK_COFF_IMGREL32, context),
2205*81ad6265SDimitry Andric         4);
2206*81ad6265SDimitry Andric }
2207*81ad6265SDimitry Andric 
2208*81ad6265SDimitry Andric static void ARMEmitRuntimeFunction(MCStreamer &streamer,
22090b57cec5SDimitry Andric                                    const WinEH::FrameInfo *info) {
22100b57cec5SDimitry Andric   MCContext &context = streamer.getContext();
22110b57cec5SDimitry Andric 
22125ffd83dbSDimitry Andric   streamer.emitValueToAlignment(4);
2213349cc55cSDimitry Andric   EmitSymbolRefWithOfs(streamer, info->Begin, info->Begin);
2214e8d8bef9SDimitry Andric   if (info->PackedInfo)
2215e8d8bef9SDimitry Andric     streamer.emitInt32(info->PackedInfo);
2216e8d8bef9SDimitry Andric   else
2217e8d8bef9SDimitry Andric     streamer.emitValue(
2218e8d8bef9SDimitry Andric         MCSymbolRefExpr::create(info->Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32,
22190b57cec5SDimitry Andric                                 context),
22200b57cec5SDimitry Andric         4);
22210b57cec5SDimitry Andric }
22220b57cec5SDimitry Andric 
22230b57cec5SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
22240b57cec5SDimitry Andric   // Emit the unwind info structs first.
22250b57cec5SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2226e8d8bef9SDimitry Andric     WinEH::FrameInfo *Info = CFI.get();
2227e8d8bef9SDimitry Andric     if (Info->empty())
2228e8d8bef9SDimitry Andric       continue;
22290b57cec5SDimitry Andric     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2230*81ad6265SDimitry Andric     Streamer.switchSection(XData);
2231e8d8bef9SDimitry Andric     ARM64EmitUnwindInfo(Streamer, Info);
22320b57cec5SDimitry Andric   }
22330b57cec5SDimitry Andric 
22340b57cec5SDimitry Andric   // Now emit RUNTIME_FUNCTION entries.
22350b57cec5SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2236e8d8bef9SDimitry Andric     WinEH::FrameInfo *Info = CFI.get();
2237e8d8bef9SDimitry Andric     // ARM64EmitUnwindInfo above clears the info struct, so we can't check
2238e8d8bef9SDimitry Andric     // empty here. But if a Symbol is set, we should create the corresponding
2239e8d8bef9SDimitry Andric     // pdata entry.
2240e8d8bef9SDimitry Andric     if (!Info->Symbol)
2241e8d8bef9SDimitry Andric       continue;
22420b57cec5SDimitry Andric     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2243*81ad6265SDimitry Andric     Streamer.switchSection(PData);
2244*81ad6265SDimitry Andric     ARMEmitRuntimeFunction(Streamer, Info);
22450b57cec5SDimitry Andric   }
22460b57cec5SDimitry Andric }
22470b57cec5SDimitry Andric 
2248e8d8bef9SDimitry Andric void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2249e8d8bef9SDimitry Andric                                                        WinEH::FrameInfo *info,
2250e8d8bef9SDimitry Andric                                                        bool HandlerData) const {
2251e8d8bef9SDimitry Andric   // Called if there's an .seh_handlerdata directive before the end of the
2252e8d8bef9SDimitry Andric   // function. This forces writing the xdata record already here - and
2253e8d8bef9SDimitry Andric   // in this case, the function isn't actually ended already, but the xdata
2254e8d8bef9SDimitry Andric   // record needs to know the function length. In these cases, if the funclet
2255e8d8bef9SDimitry Andric   // end hasn't been marked yet, the xdata function length won't cover the
2256e8d8bef9SDimitry Andric   // whole function, only up to this point.
2257e8d8bef9SDimitry Andric   if (!info->FuncletOrFuncEnd) {
2258*81ad6265SDimitry Andric     Streamer.switchSection(info->TextSection);
2259e8d8bef9SDimitry Andric     info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2260e8d8bef9SDimitry Andric   }
22610b57cec5SDimitry Andric   // Switch sections (the static function above is meant to be called from
22620b57cec5SDimitry Andric   // here and from Emit().
22630b57cec5SDimitry Andric   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2264*81ad6265SDimitry Andric   Streamer.switchSection(XData);
2265e8d8bef9SDimitry Andric   ARM64EmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
22660b57cec5SDimitry Andric }
2267*81ad6265SDimitry Andric 
2268*81ad6265SDimitry Andric void llvm::Win64EH::ARMUnwindEmitter::Emit(MCStreamer &Streamer) const {
2269*81ad6265SDimitry Andric   // Emit the unwind info structs first.
2270*81ad6265SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2271*81ad6265SDimitry Andric     WinEH::FrameInfo *Info = CFI.get();
2272*81ad6265SDimitry Andric     if (Info->empty())
2273*81ad6265SDimitry Andric       continue;
2274*81ad6265SDimitry Andric     MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
2275*81ad6265SDimitry Andric     Streamer.switchSection(XData);
2276*81ad6265SDimitry Andric     ARMEmitUnwindInfo(Streamer, Info);
2277*81ad6265SDimitry Andric   }
2278*81ad6265SDimitry Andric 
2279*81ad6265SDimitry Andric   // Now emit RUNTIME_FUNCTION entries.
2280*81ad6265SDimitry Andric   for (const auto &CFI : Streamer.getWinFrameInfos()) {
2281*81ad6265SDimitry Andric     WinEH::FrameInfo *Info = CFI.get();
2282*81ad6265SDimitry Andric     // ARMEmitUnwindInfo above clears the info struct, so we can't check
2283*81ad6265SDimitry Andric     // empty here. But if a Symbol is set, we should create the corresponding
2284*81ad6265SDimitry Andric     // pdata entry.
2285*81ad6265SDimitry Andric     if (!Info->Symbol)
2286*81ad6265SDimitry Andric       continue;
2287*81ad6265SDimitry Andric     MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
2288*81ad6265SDimitry Andric     Streamer.switchSection(PData);
2289*81ad6265SDimitry Andric     ARMEmitRuntimeFunction(Streamer, Info);
2290*81ad6265SDimitry Andric   }
2291*81ad6265SDimitry Andric }
2292*81ad6265SDimitry Andric 
2293*81ad6265SDimitry Andric void llvm::Win64EH::ARMUnwindEmitter::EmitUnwindInfo(MCStreamer &Streamer,
2294*81ad6265SDimitry Andric                                                      WinEH::FrameInfo *info,
2295*81ad6265SDimitry Andric                                                      bool HandlerData) const {
2296*81ad6265SDimitry Andric   // Called if there's an .seh_handlerdata directive before the end of the
2297*81ad6265SDimitry Andric   // function. This forces writing the xdata record already here - and
2298*81ad6265SDimitry Andric   // in this case, the function isn't actually ended already, but the xdata
2299*81ad6265SDimitry Andric   // record needs to know the function length. In these cases, if the funclet
2300*81ad6265SDimitry Andric   // end hasn't been marked yet, the xdata function length won't cover the
2301*81ad6265SDimitry Andric   // whole function, only up to this point.
2302*81ad6265SDimitry Andric   if (!info->FuncletOrFuncEnd) {
2303*81ad6265SDimitry Andric     Streamer.switchSection(info->TextSection);
2304*81ad6265SDimitry Andric     info->FuncletOrFuncEnd = Streamer.emitCFILabel();
2305*81ad6265SDimitry Andric   }
2306*81ad6265SDimitry Andric   // Switch sections (the static function above is meant to be called from
2307*81ad6265SDimitry Andric   // here and from Emit().
2308*81ad6265SDimitry Andric   MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
2309*81ad6265SDimitry Andric   Streamer.switchSection(XData);
2310*81ad6265SDimitry Andric   ARMEmitUnwindInfo(Streamer, info, /* TryPacked = */ !HandlerData);
2311*81ad6265SDimitry Andric }
2312