aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCWin64EH.cpp
diff options
context:
space:
mode:
authorMartin Storsjö <martin@martin.st>2022-05-13 10:42:56 +0300
committerMartin Storsjö <martin@martin.st>2022-05-17 00:41:39 +0300
commitcabefea2ec99f80ecdf9d3d5fe955831532ff4b0 (patch)
treee70e33ea274eb0cc3e8495e20be9b22328057cd7 /llvm/lib/MC/MCWin64EH.cpp
parent68f37e7991bf41a6f3fb3dd12d0e7a42822de347 (diff)
downloadllvm-cabefea2ec99f80ecdf9d3d5fe955831532ff4b0.zip
llvm-cabefea2ec99f80ecdf9d3d5fe955831532ff4b0.tar.gz
llvm-cabefea2ec99f80ecdf9d3d5fe955831532ff4b0.tar.bz2
[MC] [Win64EH] Try writing an ARM64 "packed epilog" even if the epilog doesn't share opcodes with the prolog
The "packed epilog" form only implies that the epilog is located exactly at the end of the function (so the location of the epilog is implicit from the epilog opcodes), but it doesn't have to share opcodes with the prolog - as long as the total number of opcode bytes and the offset to the epilog fit within the bitfields. This avoids writing a 4 byte epilog scope in many cases. (I haven't measured how much this shrinks actual xdata sections in practice though.) Differential Revision: https://reviews.llvm.org/D125536
Diffstat (limited to 'llvm/lib/MC/MCWin64EH.cpp')
-rw-r--r--llvm/lib/MC/MCWin64EH.cpp60
1 files changed, 37 insertions, 23 deletions
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
index 0aa066e..73d3a53 100644
--- a/llvm/lib/MC/MCWin64EH.cpp
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -614,24 +614,33 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
const std::vector<WinEH::Instruction> &Epilog =
info->EpilogMap.begin()->second;
+ // Check that the epilog actually is at the very end of the function,
+ // otherwise it can't be packed.
+ uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference(
+ streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
+ if (DistanceFromEnd / 4 != Epilog.size())
+ return -1;
+
+ int RetVal = -1;
+ // Even if we don't end up sharing opcodes with the prolog, we can still
+ // write the offset as a packed offset, if the single epilog is located at
+ // the end of the function and the offset (pointing after the prolog) fits
+ // as a packed offset.
+ if (PrologCodeBytes <= 31 &&
+ PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124)
+ RetVal = PrologCodeBytes;
+
// Can pack if the epilog is a subset of the prolog but not vice versa
if (Epilog.size() > info->Instructions.size())
- return -1;
+ return RetVal;
// Check that the epilog actually is a perfect match for the end (backwrds)
// of the prolog.
for (int I = Epilog.size() - 1; I >= 0; I--) {
if (info->Instructions[I] != Epilog[Epilog.size() - 1 - I])
- return -1;
+ return RetVal;
}
- // Check that the epilog actually is at the very end of the function,
- // otherwise it can't be packed.
- uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference(
- streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first);
- if (DistanceFromEnd / 4 != Epilog.size())
- return -1;
-
int Offset = Epilog.size() == info->Instructions.size()
? 0
: ARM64CountOfUnwindCodes(ArrayRef<WinEH::Instruction>(
@@ -642,8 +651,10 @@ static int checkPackedEpilog(MCStreamer &streamer, WinEH::FrameInfo *info,
// unclear whether the epilog count in the extension word can be taken
// as packed epilog offset.
if (Offset > 31 || PrologCodeBytes > 124)
- return -1;
+ return RetVal;
+ // As we choose to express the epilog as part of the prolog, remove the
+ // epilog from the map, so we don't try to emit its opcodes.
info->EpilogMap.clear();
return Offset;
}
@@ -952,8 +963,9 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
int PackedEpilogOffset = checkPackedEpilog(streamer, info, PrologCodeBytes);
- if (PackedEpilogOffset >= 0 && !info->HandlesExceptions &&
- FuncLength <= 0x7ff && TryPacked) {
+ if (PackedEpilogOffset >= 0 &&
+ uint32_t(PackedEpilogOffset) < PrologCodeBytes &&
+ !info->HandlesExceptions && FuncLength <= 0x7ff && TryPacked) {
// Matching prolog/epilog and no exception handlers; check if the
// prolog matches the patterns that can be described by the packed
// format.
@@ -1025,17 +1037,19 @@ static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info,
streamer.emitInt32(row2);
}
- // Epilog Start Index, Epilog Start Offset
- for (auto &I : EpilogInfo) {
- MCSymbol *EpilogStart = I.first;
- uint32_t EpilogIndex = I.second;
- uint32_t EpilogOffset =
- (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
- if (EpilogOffset)
- EpilogOffset /= 4;
- uint32_t row3 = EpilogOffset;
- row3 |= (EpilogIndex & 0x3FF) << 22;
- streamer.emitInt32(row3);
+ if (PackedEpilogOffset < 0) {
+ // Epilog Start Index, Epilog Start Offset
+ for (auto &I : EpilogInfo) {
+ MCSymbol *EpilogStart = I.first;
+ uint32_t EpilogIndex = I.second;
+ uint32_t EpilogOffset =
+ (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
+ if (EpilogOffset)
+ EpilogOffset /= 4;
+ uint32_t row3 = EpilogOffset;
+ row3 |= (EpilogIndex & 0x3FF) << 22;
+ streamer.emitInt32(row3);
+ }
}
// Emit prolog unwind instructions (in reverse order).