28class MCUnwindV2EpilogTargetExpr final :
public MCTargetExpr {
29 const WinEH::FrameInfo &FrameInfo;
35 MCUnwindV2EpilogTargetExpr(
const WinEH::FrameInfo &FrameInfo,
36 const WinEH::FrameInfo::Epilog &
Epilog,
38 : FrameInfo(FrameInfo), UnwindV2Start(
Epilog.UnwindV2Start),
39 EpilogEnd(
Epilog.End), EpilogSize(EpilogSize_), Loc(
Epilog.Loc) {
40 assert(UnwindV2Start &&
"Epilog must have a start");
41 assert(EpilogEnd &&
"Epilog must have an end");
45 static MCUnwindV2EpilogTargetExpr *
46 create(
const WinEH::FrameInfo &FrameInfo,
47 const WinEH::FrameInfo::Epilog &
Epilog, uint8_t EpilogSize_,
49 return new (Ctx) MCUnwindV2EpilogTargetExpr(FrameInfo,
Epilog, EpilogSize_);
52 void printImpl(raw_ostream &OS,
const MCAsmInfo *MAI)
const override {
54 UnwindV2Start->
print(OS, MAI);
57 bool evaluateAsRelocatableImpl(MCValue &Res,
58 const MCAssembler *Asm)
const override;
60 void visitUsedExpr(MCStreamer &Streamer)
const override {
64 MCFragment *findAssociatedFragment()
const override {
74 for (
const auto &
I : Insns) {
93 Count += (
I.Offset > 512 * 1024 - 8) ? 3 : 2;
124 if (inst.
Offset > 512 * 1024 - 8) {
137 b2 |= (((inst.
Offset - 8) >> 3) & 0x0F) << 4;
213static std::optional<int64_t>
224 if (!Diff->evaluateAsAbsolute(value, Assembler))
240 info->Symbol = Label;
243 bool LastEpilogIsAtEnd =
false;
244 bool AddPaddingEpilogCode =
false;
246 bool EnableUnwindV2 = (
info->Version >= 2) && !
info->EpilogMap.empty();
247 if (EnableUnwindV2) {
248 auto &LastEpilog =
info->EpilogMap.back().second;
257 LastEpilog.UnwindV2Start &&
258 "If unwind v2 is enabled, epilog must have a unwind v2 start marker");
259 assert(LastEpilog.End &&
"Epilog must have an end");
261 OS->
getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start);
264 "Failed to evaluate epilog size for Unwind v2 in " +
265 info->Function->getName());
269 if (*MaybeSize >= (int64_t)UINT8_MAX) {
271 "Epilog size is too large for Unwind v2 in " +
272 info->Function->getName());
275 EpilogSize = *MaybeSize + 1;
286 LastEpilogIsAtEnd = (LastEpilogToFuncEnd == EpilogSize);
290 size_t numEpilogCodes =
291 info->EpilogMap.size() + (LastEpilogIsAtEnd ? 0 : 1);
292 if ((numEpilogCodes % 2) != 0) {
293 AddPaddingEpilogCode =
true;
298 if ((
size_t)numCodes + numEpilogCodes > UINT8_MAX) {
300 "Too many unwind codes with Unwind v2 enabled in " +
301 info->Function->getName());
305 numCodes += numEpilogCodes;
310 if (
info->ChainedParent)
313 if (
info->HandlesUnwind)
315 if (
info->HandlesExceptions)
328 if (
info->LastFrameInst >= 0) {
336 if (EnableUnwindV2) {
345 uint8_t Flags = LastEpilogIsAtEnd ? 0x01 : 0;
349 if (LastEpilogIsAtEnd)
356 auto *MCE = MCUnwindV2EpilogTargetExpr::create(*
info,
Epilog.second,
357 EpilogSize, context);
362 if (AddPaddingEpilogCode)
367 for (
uint8_t c = 0; c < numInst; ++c) {
369 info->Instructions.pop_back();
388 else if (numCodes == 0) {
396bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl(
402 Asm->getContext().reportError(
403 Loc,
"Failed to evaluate epilog offset for Unwind v2 in " +
408 constexpr uint16_t MaxEpilogOffset = 0x0fff;
409 if (*
Offset > MaxEpilogOffset) {
410 Asm->getContext().reportError(
411 Loc,
"Epilog offset is too large for Unwind v2 in " +
418 if (
Size != (EpilogSize - 1)) {
419 Asm->getContext().reportError(
420 Loc,
"Size of this epilog does not match size of last epilog in " +
425 auto HighBits = *
Offset >> 8;
449 bool HandlerData)
const {
479 std::optional<int64_t> MaybeDiff =
492 std::optional<int64_t> MaybeDistance =
498 for (
const auto &
I : Insns) {
514 if (Distance != InstructionBytes) {
516 SMLoc(),
"Incorrect size for " + Name +
" " +
Type +
": " +
518 " bytes of instructions in range, but .seh directives "
519 "corresponding to " +
520 Twine(InstructionBytes) +
" bytes\n");
526 for (
const auto &
I : Insns) {
641 b = (inst.
Offset >> 4) & 0x1F;
658 b = (w & 0x00FF0000) >> 16;
660 b = (w & 0x0000FF00) >> 8;
682 b |= (inst.
Offset >> 3) & 0x1F;
687 b |= ((inst.
Offset >> 3) - 1) & 0x3F;
692 b |= (inst.
Offset >> 3) & 0x3F;
698 b = 0xD0 | ((reg & 0xC) >> 2);
700 b = ((reg & 0x3) << 6) | (inst.
Offset >> 3);
706 b = 0xD4 | ((reg & 0x8) >> 3);
708 b = ((reg & 0x7) << 5) | ((inst.
Offset >> 3) - 1);
714 b = 0xC8 | ((reg & 0xC) >> 2);
716 b = ((reg & 0x3) << 6) | (inst.
Offset >> 3);
722 b = 0xCC | ((reg & 0xC) >> 2);
724 b = ((reg & 0x3) << 6) | ((inst.
Offset >> 3) - 1);
730 assert((reg % 2) == 0 &&
"Saved reg must be 19+2*X");
732 b = 0xD6 | ((reg & 0x7) >> 2);
734 b = ((reg & 0x3) << 6) | (inst.
Offset >> 3);
740 b = 0xDC | ((reg & 0x4) >> 2);
742 b = ((reg & 0x3) << 6) | (inst.
Offset >> 3);
750 b = ((reg & 0x7) << 5) | ((inst.
Offset >> 3) - 1);
756 b = 0xD8 | ((reg & 0x4) >> 2);
758 b = ((reg & 0x3) << 6) | (inst.
Offset >> 3);
764 b = 0xDA | ((reg & 0x4) >> 2);
766 b = ((reg & 0x3) << 6) | ((inst.
Offset >> 3) - 1);
815 int Writeback =
Op / 6;
819 if (Writeback || Paired ||
Mode == 2)
826 b = inst.
Register | (Writeback << 5) | (Paired << 6);
845 b = ((inst.
Offset & 0xC0) >> 1) | reg;
847 b = 0xC0 | (inst.
Offset & 0x3F);
857 b = ((inst.
Offset & 0xC0) >> 1) | 0x10 | reg;
859 b = 0xC0 | (inst.
Offset & 0x3F);
872 const std::vector<MCSymbol *>& Epilogs,
874 for (
auto *EpilogStart : Epilogs) {
875 auto InstrsIter =
info->EpilogMap.find(EpilogStart);
877 "Epilog not found in EpilogMap");
878 const auto &Instrs = InstrsIter->second.Instructions;
880 if (Instrs.size() != EpilogInstrs.size())
884 for (
unsigned i = 0; i < Instrs.size(); ++i)
885 if (Instrs[i] != EpilogInstrs[i]) {
898 unsigned PrevOffset = -1;
899 unsigned PrevRegister = -1;
911 Inst.Register == 29) {
915 Inst.Register == 19 && Inst.Offset <= 248) {
921 Inst.Register == PrevRegister + 2 &&
922 Inst.Offset == PrevOffset + 16) {
937 PrevRegister = Inst.Register;
939 PrevOffset = Inst.Offset;
940 PrevRegister = Inst.Register;
954 const std::vector<WinEH::Instruction> &
Epilog) {
961 for (
int I =
Epilog.size() - 1;
I >= 0;
I--) {
976 int PrologCodeBytes) {
982 const std::vector<WinEH::Instruction> &
Epilog =
983 info->EpilogMap[Sym].Instructions;
989 if (DistanceFromEnd / 4 !=
Epilog.size())
997 if (PrologCodeBytes <= 31 &&
999 RetVal = PrologCodeBytes;
1008 if (
Offset > 31 || PrologCodeBytes > 124)
1013 info->EpilogMap.erase(Sym);
1018 int PackedEpilogOffset) {
1019 if (PackedEpilogOffset == 0) {
1025 }
else if (PackedEpilogOffset == 1) {
1035 unsigned RegI = 0, RegF = 0;
1036 int Predecrement = 0;
1048 bool StandaloneLR =
false, FPLRPair =
false;
1058 for (
auto It =
info->Instructions.begin(), EndIt =
info->Instructions.end();
1059 It != EndIt; It++) {
1063 if (Location != Start)
1068 if (Location != Start2)
1074 if (Location != Start2 && Location != Start3)
1076 Predecrement = Inst.
Offset;
1081 if (Location != Start2 && Location != Start3)
1083 Predecrement = Inst.
Offset;
1087 StandaloneLR =
true;
1091 Location = FloatRegs;
1118 StandaloneLR =
true;
1122 Location = FloatRegs;
1129 StandaloneLR =
true;
1130 Location = FloatRegs;
1137 if (Location != FloatRegs || RegF == 0 || Inst.
Register != 8 + RegF ||
1138 Inst.
Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1141 Location = InputArgs;
1144 if ((Location != Start2 && Location != Start3) || Inst.
Register != 8)
1146 Predecrement = Inst.
Offset;
1148 Location = FloatRegs;
1151 if ((Location !=
IntRegs && Location != FloatRegs) ||
1153 Inst.
Offset != 8 * (RegI + (StandaloneLR ? 1 : 0) + RegF))
1156 Location = FloatRegs;
1161 else if (Location == FloatRegs)
1167 if (Location !=
IntRegs && Location != FloatRegs && Location != InputArgs)
1169 Location = InputArgs;
1174 if (Location != Start2 && Location != Start3 && Location !=
IntRegs &&
1175 Location != FloatRegs && Location != InputArgs &&
1176 Location != StackAdjust)
1182 if (Location == Start2) {
1183 auto NextIt = It + 1;
1184 if (NextIt != EndIt) {
1188 assert(Predecrement == 0);
1191 Predecrement = Inst.
Offset;
1193 StandaloneLR =
true;
1194 Location = FloatRegs;
1208 Location = StackAdjust;
1213 if (Location != Start2 && Location != Start3 && Location !=
IntRegs &&
1214 Location != FloatRegs && Location != InputArgs)
1217 Location = FrameRecord;
1222 if (Location != StackAdjust || Inst.
Offset != 0)
1224 Location = FrameRecord;
1228 if (Location != FrameRecord)
1272 if (RegI > 10 || RegF > 8)
1274 if (StandaloneLR && FPLRPair)
1276 if (FPLRPair && Location != End)
1278 if (Nops != 0 && Nops != 4)
1280 if (PAC && !FPLRPair)
1307 if (StandaloneLR && RegI == 1 && RegF > 0)
1309 int IntSZ = 8 * RegI;
1312 int FpSZ = 8 * RegF;
1313 int SavSZ = (IntSZ + FpSZ + 8 * 8 *
H + 0xF) & ~0xF;
1314 if (Predecrement != SavSZ)
1321 if (FrameSize > 0x1FF)
1323 assert(RegF != 1 &&
"One single float reg not allowed");
1326 assert(FuncLength <= 0x7FF &&
"FuncLength should have been checked earlier");
1328 int CR = PAC ? 2 : FPLRPair ? 3 : StandaloneLR ? 1 : 0;
1329 info->PackedInfo |= Flag << 0;
1330 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
1331 info->PackedInfo |= (RegF & 0x7) << 13;
1332 info->PackedInfo |= (RegI & 0xF) << 16;
1333 info->PackedInfo |= (
H & 0x1) << 20;
1334 info->PackedInfo |= (CR & 0x3) << 21;
1335 info->PackedInfo |= (FrameSize & 0x1FF) << 23;
1344 std::vector<MCSymbol *> EpilogStarts;
1346 EpilogStarts.push_back(
I.first);
1349 std::vector<MCSymbol *> AddedEpilogs;
1350 for (
auto *S : EpilogStarts) {
1352 auto &EpilogInstrs =
info->EpilogMap[S].Instructions;
1358 if (MatchingEpilog) {
1359 assert(EpilogInfo.contains(MatchingEpilog) &&
1360 "Duplicate epilog not found");
1361 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
1364 EpilogInstrs.clear();
1366 EpilogInstrs)) >= 0) {
1367 EpilogInfo[EpilogStart] = PrologOffset;
1371 EpilogInfo[EpilogStart] += 1;
1374 EpilogInstrs.clear();
1376 EpilogInfo[EpilogStart] = TotalCodeBytes;
1377 TotalCodeBytes += CodeBytes;
1378 AddedEpilogs.push_back(EpilogStart);
1385 int64_t RawFuncLength) {
1386 if (
info->PrologEnd)
1388 info->PrologEnd,
info->Function->getName(),
1390 struct EpilogStartEnd {
1397 for (
auto &
I :
info->EpilogMap) {
1399 auto &Instrs =
I.second.Instructions;
1402 info->Function->getName(),
"epilogue");
1404 "Epilogs should be monotonically ordered");
1411 int64_t SegLimit = 0xFFFFC;
1412 int64_t SegOffset = 0;
1414 if (RawFuncLength > SegLimit) {
1416 int64_t RemainingLength = RawFuncLength;
1418 while (RemainingLength > SegLimit) {
1422 int64_t SegLength = SegLimit;
1423 int64_t SegEnd = SegOffset + SegLength;
1427 while (
E < Epilogs.
size() && Epilogs[
E].End < SegEnd) {
1429 EpilogsInSegment[Epilogs[
E].Start] = Epilogs[
E].Offset;
1440 if (
E < Epilogs.
size() && Epilogs[
E].Offset <= SegEnd)
1442 SegLength = Epilogs[
E].Offset - SegOffset;
1445 SegOffset, SegLength, !SegOffset);
1446 Seg.Epilogs = std::move(EpilogsInSegment);
1447 info->Segments.push_back(Seg);
1449 SegOffset += SegLength;
1450 RemainingLength -= SegLength;
1459 for (;
E < Epilogs.
size(); ++
E)
1460 LastSeg.Epilogs[Epilogs[
E].Start] = Epilogs[
E].Offset;
1461 info->Segments.push_back(LastSeg);
1467 bool TryPacked =
true) {
1476 info->Symbol = Label;
1479 bool HasEpilogs = (Seg.
Epilogs.size() != 0);
1484 int PackedEpilogOffset = HasEpilogs ?
1491 if (
info->Segments.size() == 1 && PackedEpilogOffset >= 0 &&
1492 uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
1493 !
info->HandlesExceptions && SegLength <= 0x7ff && TryPacked) {
1508 PrologCodeBytes += 1;
1509 if (PackedEpilogOffset >= 0)
1510 PackedEpilogOffset += 1;
1518 PackedEpilogOffset = 0;
1521 uint32_t TotalCodeBytes = PrologCodeBytes;
1529 uint32_t CodeWords = TotalCodeBytes / 4;
1530 uint32_t CodeWordsMod = TotalCodeBytes % 4;
1534 PackedEpilogOffset >= 0 ? PackedEpilogOffset : Seg.
Epilogs.size();
1535 bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
1536 if (!ExtensionWord) {
1537 row1 |= (EpilogCount & 0x1F) << 22;
1538 row1 |= (CodeWords & 0x1F) << 27;
1540 if (
info->HandlesExceptions)
1542 if (PackedEpilogOffset >= 0)
1544 row1 |= SegLength & 0x3FFFF;
1548 if (ExtensionWord) {
1550 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
1552 "SEH unwind data splitting is only implemented for large functions, "
1553 "cases of too many code words or too many epilogs will be done "
1556 row2 |= (CodeWords & 0xFF) << 16;
1557 row2 |= (EpilogCount & 0xFFFF);
1561 if (PackedEpilogOffset < 0) {
1563 for (
auto &
I : EpilogInfo) {
1571 row3 |= (EpilogIndex & 0x3FF) << 22;
1592 auto &EpilogInstrs =
info->EpilogMap[
I.first].Instructions;
1597 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
1599 for (
int i = 0; i < BytesMod; i++)
1602 if (
info->HandlesExceptions)
1612 bool TryPacked =
true) {
1620 if (
info->empty()) {
1621 info->EmitAttempted =
true;
1624 if (
info->EmitAttempted) {
1631 SMLoc(),
"Earlier .seh_handlerdata for " +
info->Function->getName() +
1632 " skipped due to no unwind info at the time "
1633 "(.seh_handlerdata too early?), but the function later "
1634 "did get unwind info that can't be emitted");
1639 for (
auto &
I :
info->EpilogMap)
1642 int64_t RawFuncLength;
1643 if (!
info->FuncletOrFuncEnd) {
1682 for (
auto &S :
info->Segments)
1686 info->Instructions.clear();
1691 for (
const auto &
I : Insns) {
1749 for (J = 3; J > 0; J--)
1750 if (
I.Offset & (0xffu << (8 * J)))
1761 bool *HasCustom =
nullptr) {
1763 for (
const auto &
I : Insns) {
1825 std::optional<int64_t> MaybeDistance =
1830 bool HasCustom =
false;
1834 if (Distance != InstructionBytes) {
1836 SMLoc(),
"Incorrect size for " + Name +
" " +
Type +
": " +
1838 " bytes of instructions in range, but .seh directives "
1839 "corresponding to " +
1840 Twine(InstructionBytes) +
" bytes\n");
1872 w = 0x8000 | (inst.
Register & 0x1fff) | (lr << 13);
1873 streamer.
emitInt8((w >> 8) & 0xff);
1874 streamer.
emitInt8((w >> 0) & 0xff);
1897 w = 0xe800 | (inst.
Offset / 4);
1898 streamer.
emitInt8((w >> 8) & 0xff);
1899 streamer.
emitInt8((w >> 0) & 0xff);
1904 w = 0xec00 | (inst.
Register & 0x0ff) | (lr << 8);
1905 streamer.
emitInt8((w >> 8) & 0xff);
1906 streamer.
emitInt8((w >> 0) & 0xff);
1933 streamer.
emitInt8((w >> 8) & 0xff);
1934 streamer.
emitInt8((w >> 0) & 0xff);
1941 streamer.
emitInt8((w >> 16) & 0xff);
1942 streamer.
emitInt8((w >> 8) & 0xff);
1943 streamer.
emitInt8((w >> 0) & 0xff);
1950 streamer.
emitInt8((w >> 8) & 0xff);
1951 streamer.
emitInt8((w >> 0) & 0xff);
1958 streamer.
emitInt8((w >> 16) & 0xff);
1959 streamer.
emitInt8((w >> 8) & 0xff);
1960 streamer.
emitInt8((w >> 0) & 0xff);
1978 for (i = 3; i > 0; i--)
1979 if (inst.
Offset & (0xffu << (8 * i)))
1994 const std::vector<WinEH::Instruction> &
Epilog,
1995 bool CanTweakProlog) {
2004 int EndIdx = CanTweakProlog ? 1 : 0;
2005 for (
int I =
Epilog.size() - 1;
I >= EndIdx;
I--) {
2012 if (CanTweakProlog) {
2030 int PrologCodeBytes) {
2032 if (
info->EpilogMap.size() != 1)
2037 if (EpilogInfo.Condition != 0xe)
2040 const std::vector<WinEH::Instruction> &
Epilog = EpilogInfo.Instructions;
2042 if (
info->Instructions.empty() ||
Epilog.empty())
2048 streamer,
info->FuncletOrFuncEnd,
info->EpilogMap.begin()->first);
2053 if (DistanceFromEnd != InstructionBytes)
2061 if (PrologCodeBytes <= 31 &&
2063 RetVal = PrologCodeBytes;
2073 if (
Offset > 31 || PrologCodeBytes > 63)
2082 info->EpilogMap.clear();
2087 unsigned &Folded,
int &
IntRegs) {
2088 if (Mask & (1 << 14)) {
2092 if (Mask & (1 << 11)) {
2102 while ((Mask & 1) == 0) {
2106 if ((Mask & (Mask + 1)) != 0)
2110 while (Mask & (1 <<
N))
2129 bool Homing =
false;
2130 bool HasR11 =
false;
2131 bool HasChain =
false;
2136 unsigned StackAdjust = 0;
2171 if (Step != 1 && Step != 2)
2186 if (Step == 1 && Inst.
Register == 0x0f) {
2194 if (Step != 1 && Step != 2)
2206 if (Step != 3 || !HasR11 ||
IntRegs >= 0 || PF > 0)
2213 if (Step != 3 || !HasR11 || (
IntRegs < 0 && PF == 0))
2220 if (Step != 1 && Step != 2 && Step != 3 && Step != 4)
2233 if (Step != 1 && Step != 2 && Step != 3 && Step != 4 && Step != 5)
2237 if (Inst.
Offset / 4 >= 0x3f4)
2239 StackAdjust = Inst.
Offset / 4;
2244 if (HasR11 && !HasChain) {
2253 if (HasChain && !HasLR)
2257 if (
info->EpilogMap.size() > 1)
2262 if (
info->EpilogMap.size() == 0) {
2269 info->EpilogMap.begin()->second;
2270 if (EpilogInfo.Condition != 0xe)
2272 const std::vector<WinEH::Instruction> &
Epilog = EpilogInfo.Instructions;
2274 streamer,
info->FuncletOrFuncEnd,
info->EpilogMap.begin()->first);
2279 if (DistanceFromEnd != InstructionBytes)
2282 bool GotStackAdjust =
false;
2283 bool GotFloatRegs =
false;
2284 bool GotIntRegs =
false;
2285 bool GotHomingRestore =
false;
2286 bool GotLRRestore =
false;
2287 bool NeedsReturn =
false;
2288 bool GotReturn =
false;
2310 if (Inst.
Offset / 4 >= 0x3f4)
2313 if (Homing && FloatRegs < 0 &&
IntRegs < 0 && StackAdjust == 0 &&
2314 PF == 0 && Inst.
Offset == 16) {
2315 GotHomingRestore =
true;
2318 if (StackAdjust > 0) {
2320 if (StackAdjust != Inst.
Offset / 4)
2322 GotStackAdjust =
true;
2323 }
else if (PF == Inst.
Offset / 4) {
2325 StackAdjust = Inst.
Offset / 4;
2326 GotStackAdjust =
true;
2333 }
else if (Step == 7 || Step == 8 || Step == 9) {
2334 if (!Homing || Inst.
Offset != 16)
2336 GotHomingRestore =
true;
2343 if (Step != 6 && Step != 7)
2346 if (FloatRegs != (
int)(Inst.
Register - 8))
2348 GotFloatRegs =
true;
2355 if (Step != 6 && Step != 7 && Step != 8)
2359 if (Homing && HasLR) {
2363 GotLRRestore =
true;
2369 if (HasLR != (Inst.
Offset == 1))
2372 GotLRRestore = Inst.
Offset == 1;
2391 if (Step != 6 && Step != 7 && Step != 8)
2396 bool CurHasLR =
false, CurHasR11 =
false;
2401 if (EF != PF && EF != StackAdjust)
2404 if (Homing && HasLR) {
2408 GotLRRestore =
true;
2414 if (CurHasLR != HasLR)
2416 GotLRRestore = CurHasLR;
2443 if (Step != 6 && Step != 7 && Step != 8 && Step != 9)
2445 if (!Homing || Inst.
Offset != 20 || GotLRRestore)
2447 GotLRRestore =
true;
2448 GotHomingRestore =
true;
2458 if (Step != 6 && Step != 7 && Step != 8 && Step != 9 && Step != 10)
2467 if (StackAdjust > 0 && !GotStackAdjust && EF == 0)
2469 if (FloatRegs >= 0 && !GotFloatRegs)
2471 if (
IntRegs >= 0 && !GotIntRegs)
2473 if (Homing && !GotHomingRestore)
2475 if (HasLR && !GotLRRestore)
2477 if (NeedsReturn && !GotReturn)
2481 assert(PF == 0 || EF == 0 ||
2483 if (PF > 0 || EF > 0) {
2484 StackAdjust = PF > 0 ? (PF - 1) : (EF - 1);
2485 assert(StackAdjust <= 3);
2486 StackAdjust |= 0x3f0;
2488 StackAdjust |= 1 << 2;
2490 StackAdjust |= 1 << 3;
2493 assert(FuncLength <= 0x7FF &&
"FuncLength should have been checked earlier");
2494 int Flag =
info->Fragment ? 0x02 : 0x01;
2495 int H = Homing ? 1 : 0;
2496 int L = HasLR ? 1 : 0;
2497 int C = HasChain ? 1 : 0;
2504 }
else if (FloatRegs >= 0) {
2513 info->PackedInfo |= Flag << 0;
2514 info->PackedInfo |= (FuncLength & 0x7FF) << 2;
2515 info->PackedInfo |= (Ret & 0x3) << 13;
2516 info->PackedInfo |=
H << 15;
2517 info->PackedInfo |=
Reg << 16;
2518 info->PackedInfo |= R << 19;
2519 info->PackedInfo |= L << 20;
2520 info->PackedInfo |=
C << 21;
2521 assert(StackAdjust <= 0x3ff);
2522 info->PackedInfo |= StackAdjust << 22;
2529 bool TryPacked =
true) {
2537 if (
info->empty()) {
2538 info->EmitAttempted =
true;
2541 if (
info->EmitAttempted) {
2548 SMLoc(),
"Earlier .seh_handlerdata for " +
info->Function->getName() +
2549 " skipped due to no unwind info at the time "
2550 "(.seh_handlerdata too early?), but the function later "
2551 "did get unwind info that can't be emitted");
2560 info->Symbol = Label;
2562 if (!
info->PrologEnd)
2564 info->Function->getName() +
2565 " not correctly terminated");
2567 if (
info->PrologEnd && !
info->Fragment)
2569 info->PrologEnd,
info->Function->getName(),
2571 for (
auto &
I :
info->EpilogMap) {
2575 info->Function->getName(),
"epilogue");
2576 if (
Epilog.Instructions.empty() ||
2579 SMLoc(),
"Epilogue in " +
info->Function->getName() +
2580 " not correctly terminated");
2583 std::optional<int64_t> RawFuncLength;
2584 const MCExpr *FuncLengthExpr =
nullptr;
2585 if (!
info->FuncletOrFuncEnd) {
2604 FuncLength = (
uint32_t)*RawFuncLength / 2;
2605 if (FuncLength > 0x3FFFF)
2608 uint32_t TotalCodeBytes = PrologCodeBytes;
2610 if (!
info->HandlesExceptions && RawFuncLength && FuncLength <= 0x7ff &&
2624 int PackedEpilogOffset =
2630 std::vector<MCSymbol *> AddedEpilogs;
2632 bool CanTweakProlog =
true;
2633 for (
auto &
I :
info->EpilogMap) {
2635 auto &EpilogInstrs =
I.second.Instructions;
2641 if (MatchingEpilog) {
2642 assert(EpilogInfo.contains(MatchingEpilog) &&
2643 "Duplicate epilog not found");
2644 EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
2647 EpilogInstrs.clear();
2649 info->Instructions, EpilogInstrs, CanTweakProlog)) >= 0) {
2650 if (CanTweakProlog) {
2653 info->Instructions.front() = EpilogInstrs.back();
2655 CanTweakProlog =
false;
2657 EpilogInfo[EpilogStart] = PrologOffset;
2660 EpilogInstrs.clear();
2662 EpilogInfo[EpilogStart] = TotalCodeBytes;
2663 TotalCodeBytes += CodeBytes;
2664 AddedEpilogs.push_back(EpilogStart);
2670 uint32_t CodeWords = TotalCodeBytes / 4;
2671 uint32_t CodeWordsMod = TotalCodeBytes % 4;
2675 PackedEpilogOffset >= 0 ? PackedEpilogOffset :
info->EpilogMap.size();
2676 bool ExtensionWord = EpilogCount > 31 || CodeWords > 15;
2677 if (!ExtensionWord) {
2678 row1 |= (EpilogCount & 0x1F) << 23;
2679 row1 |= (CodeWords & 0x0F) << 28;
2681 if (
info->HandlesExceptions)
2683 if (PackedEpilogOffset >= 0)
2687 row1 |= FuncLength & 0x3FFFF;
2697 if (ExtensionWord) {
2699 if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
2702 row2 |= (CodeWords & 0xFF) << 16;
2703 row2 |= (EpilogCount & 0xFFFF);
2707 if (PackedEpilogOffset < 0) {
2709 for (
auto &
I : EpilogInfo) {
2713 std::optional<int64_t> MaybeEpilogOffset =
2715 const MCExpr *OffsetExpr =
nullptr;
2717 if (MaybeEpilogOffset)
2718 EpilogOffset = *MaybeEpilogOffset / 2;
2722 assert(
info->EpilogMap.contains(EpilogStart));
2723 unsigned Condition =
info->EpilogMap[EpilogStart].Condition;
2724 assert(Condition <= 0xf);
2727 row3 |= Condition << 20;
2728 row3 |= (EpilogIndex & 0x3FF) << 24;
2729 if (MaybeEpilogOffset)
2741 for (
uint8_t c = 0; c < numInst; ++c) {
2743 info->Instructions.pop_back();
2748 for (
auto &
I :
info->EpilogMap) {
2749 auto &EpilogInstrs =
I.second.Instructions;
2754 int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
2756 for (
int i = 0; i < BytesMod; i++)
2759 if (
info->HandlesExceptions)
2771 for (
const auto &S :
info->Segments) {
2773 if (
info->PackedInfo)
2790 if (
info->PackedInfo)
2826 bool HandlerData)
const {
2833 if (!
info->FuncletOrFuncEnd) {
2871 bool HandlerData)
const {
2878 if (!
info->FuncletOrFuncEnd) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static int checkARM64PackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, int PrologCodeBytes)
static void ARM64EmitUnwindInfoForSegment(MCStreamer &streamer, WinEH::FrameInfo *info, WinEH::FrameInfo::Segment &Seg, bool TryPacked=true)
static uint32_t ARMCountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
static uint32_t ARM64CountOfUnwindCodes(ArrayRef< WinEH::Instruction > Insns)
static void checkARMInstructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
static bool isARMTerminator(const WinEH::Instruction &inst)
static void ARM64EmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
static void simplifyARM64Opcodes(std::vector< WinEH::Instruction > &Instructions, bool Reverse)
static void ARMEmitUnwindCode(MCStreamer &streamer, const WinEH::Instruction &inst)
static std::optional< int64_t > GetOptionalAbsDifference(const MCAssembler &Assembler, const MCSymbol *LHS, const MCSymbol *RHS)
static int getARM64OffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog)
static void ARMEmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static bool tryARM64PackedUnwind(WinEH::FrameInfo *info, uint32_t FuncLength, int PackedEpilogOffset)
static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info)
static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, WinEH::Instruction &inst)
static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
static int getARMOffsetInProlog(const std::vector< WinEH::Instruction > &Prolog, const std::vector< WinEH::Instruction > &Epilog, bool CanTweakProlog)
static void ARM64EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static void EmitSymbolRefWithOfs(MCStreamer &streamer, const MCSymbol *Base, int64_t Offset)
static bool parseRegMask(unsigned Mask, bool &HasLR, bool &HasR11, unsigned &Folded, int &IntRegs)
static int checkARMPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info, int PrologCodeBytes)
static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
static void ARM64FindSegmentsInFunction(MCStreamer &streamer, WinEH::FrameInfo *info, int64_t RawFuncLength)
static bool tryARMPackedUnwind(MCStreamer &streamer, WinEH::FrameInfo *info, uint32_t FuncLength)
static MCSymbol * FindMatchingEpilog(const std::vector< WinEH::Instruction > &EpilogInstrs, const std::vector< MCSymbol * > &Epilogs, const WinEH::FrameInfo *info)
static void EmitRuntimeFunction(MCStreamer &streamer, const WinEH::FrameInfo *info)
static void checkARM64Instructions(MCStreamer &Streamer, ArrayRef< WinEH::Instruction > Insns, const MCSymbol *Begin, const MCSymbol *End, StringRef Name, StringRef Type)
static const MCExpr * GetSubDivExpr(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS, int Div)
static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS, const MCSymbol *RHS)
static void ARMEmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info, bool TryPacked=true)
static uint32_t ARMCountOfInstructionBytes(ArrayRef< WinEH::Instruction > Insns, bool *HasCustom=nullptr)
static void ARM64ProcessEpilogs(WinEH::FrameInfo *info, WinEH::FrameInfo::Segment *Seg, uint32_t &TotalCodeBytes, MapVector< MCSymbol *, uint32_t > &EpilogInfo)
static uint8_t CountOfUnwindCodes(std::vector< WinEH::Instruction > &Insns)
static void printImpl(const MCAsmInfo &MAI, raw_ostream &OS, const MCSpecifierExpr &Expr)
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
static const MCPhysReg IntRegs[32]
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
Tagged union holding either a T or a Error.
MCContext & getContext() const
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
static const MCBinaryExpr * createOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static const MCBinaryExpr * createDiv(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static const MCBinaryExpr * createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Context object for machine code objects.
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
Base class for the full range of assembler expressions which are needed for parsing.
Streaming object file generation interface.
MCAssembler & getAssembler()
void appendContents(ArrayRef< char > Contents)
void addFixup(const MCExpr *Value, MCFixupKind Kind)
void ensureHeadroom(size_t Headroom)
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Streaming machine code generation interface.
virtual MCSymbol * emitCFILabel()
When emitting an object file, create and emit a real label.
MCSection * getAssociatedPDataSection(const MCSection *TextSec)
Get the .pdata section used for the given section.
MCContext & getContext() const
MCSection * getAssociatedXDataSection(const MCSection *TextSec)
Get the .xdata section used for the given section.
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
virtual void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0)
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
void emitInt16(uint64_t Value)
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
void emitInt32(uint64_t Value)
ArrayRef< std::unique_ptr< WinEH::FrameInfo > > getWinFrameInfos() const
void emitInt8(uint64_t Value)
Represent a reference to a symbol from inside an expression.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
StringRef getName() const
getName - Get the symbol name.
MCFragment * getFragment() const
static MCValue get(const MCSymbol *SymA, const MCSymbol *SymB=nullptr, int64_t Val=0, uint32_t Specifier=0)
This class implements a map that also provides access to all stored values in a deterministic order.
Represents a location in source code.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
void Emit(MCStreamer &Streamer) const override
This emits the unwind info sections (.pdata and .xdata in PE/COFF).
void EmitUnwindInfo(MCStreamer &Streamer, WinEH::FrameInfo *FI, bool HandlerData) const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
@ UNW_TerminateHandler
UNW_TerminateHandler - Specifies that this function has a termination handler.
@ UNW_ExceptionHandler
UNW_ExceptionHandler - Specifies that this function has an exception handler.
@ UNW_ChainInfo
UNW_ChainInfo - Specifies that this UnwindInfo structure is chained to another one.
UnwindOpcodes
UnwindOpcodes - Enumeration whose values specify a single operation in the prolog of a function.
@ UOP_WideSaveRegsR4R11LR
This is an optimization pass for GlobalISel generic memory operations.
auto reverse(ContainerTy &&C)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
FunctionAddr VTableAddr Count
auto reverse_conditionally(ContainerTy &&C, bool ShouldReverse)
Return a range that conditionally reverses C.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
@ FK_Data_2
A two-byte fixup.
DWARFExpression::Operation Op
This struct is a compact representation of a valid (non-zero power of two) alignment.
MapVector< MCSymbol *, int64_t > Epilogs
const MCSymbol * Function