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