diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -299,6 +299,43 @@ return *MaybeDiff; } +static void checkARM64Instructions(MCStreamer &Streamer, + ArrayRef Insns, + const MCSymbol *Begin, const MCSymbol *End, + StringRef Name, StringRef Type) { + if (!End) + return; + Optional MaybeDistance = + GetOptionalAbsDifference(Streamer, End, Begin); + if (!MaybeDistance) + return; + uint32_t Distance = (uint32_t)*MaybeDistance; + + for (const auto &I : Insns) { + switch (static_cast(I.Operation)) { + default: + break; + case Win64EH::UOP_TrapFrame: + case Win64EH::UOP_PushMachFrame: + case Win64EH::UOP_Context: + case Win64EH::UOP_ClearUnwoundToCall: + // Can't reason about these opcodes and how they map to actual + // instructions. + return; + } + } + // Exclude the end opcode which doesn't map to an instruction. + uint32_t InstructionBytes = 4 * (Insns.size() - 1); + if (Distance != InstructionBytes) { + Streamer.getContext().reportError( + SMLoc(), "Incorrect size for " + Name + " " + Type + ": " + + Twine(Distance) + + " bytes of instructions in range, but .seh directives " + "corresponding to " + + Twine(InstructionBytes) + " bytes\n"); + } +} + static uint32_t ARM64CountOfUnwindCodes(ArrayRef Insns) { uint32_t Count = 0; for (const auto &I : Insns) { @@ -984,6 +1021,10 @@ static void ARM64FindSegmentsInFunction(MCStreamer &streamer, WinEH::FrameInfo *info, int64_t RawFuncLength) { + if (info->PrologEnd) + checkARM64Instructions(streamer, info->Instructions, info->Begin, + info->PrologEnd, info->Function->getName(), + "prologue"); struct EpilogStartEnd { MCSymbol *Start; int64_t Offset; @@ -995,6 +1036,8 @@ MCSymbol *Start = I.first; auto &Instrs = I.second.Instructions; int64_t Offset = GetAbsDifference(streamer, Start, info->Begin); + checkARM64Instructions(streamer, Instrs, Start, I.second.End, + info->Function->getName(), "epilogue"); assert((Epilogs.size() == 0 || Offset >= Epilogs.back().End) && "Epilogs should be monotonically ordered"); // Exclue the end opcode from Instrs.size() when calculating the end of the diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp @@ -202,6 +202,8 @@ WinEH::Instruction Inst = WinEH::Instruction(Win64EH::UOP_End, /*Label=*/nullptr, -1, 0); CurFrame->EpilogMap[CurrentEpilog].Instructions.push_back(Inst); + MCSymbol *Label = S.emitCFILabel(); + CurFrame->EpilogMap[CurrentEpilog].End = Label; CurrentEpilog = nullptr; }