diff --git a/llvm/include/llvm/MC/MCWinEH.h b/llvm/include/llvm/MC/MCWinEH.h --- a/llvm/include/llvm/MC/MCWinEH.h +++ b/llvm/include/llvm/MC/MCWinEH.h @@ -55,6 +55,9 @@ const FrameInfo *ChainedParent = nullptr; std::vector Instructions; MapVector> EpilogMap; +#ifndef NDEBUG + MapVector EpilogEnd; +#endif FrameInfo() = default; FrameInfo(const MCSymbol *Function, const MCSymbol *BeginFuncEHLabel) 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 @@ -1189,7 +1189,8 @@ return Count; } -static uint32_t ARMCountOfInstructionBytes(ArrayRef Insns) { +static uint32_t ARMCountOfInstructionBytes(ArrayRef Insns, + bool *HasCustom = nullptr) { uint32_t Count = 0; for (const auto &I : Insns) { switch (static_cast(I.Operation)) { @@ -1239,12 +1240,37 @@ // We can't reason about what instructions this maps to; return a // phony number to make sure we don't accidentally do epilog packing. Count += 1000; + if (HasCustom) + *HasCustom = true; break; } } return Count; } +#ifndef NDEBUG +static void checkInstructions(MCStreamer &Streamer, + ArrayRef Insns, + const MCSymbol *Begin, const MCSymbol *End, + StringRef Name, StringRef Type) { + Optional MaybeDistance = + GetOptionalAbsDifference(Streamer, End, Begin); + if (!MaybeDistance) + return; + uint32_t Distance = (uint32_t)*MaybeDistance; + bool HasCustom = false; + uint32_t InstructionBytes = ARMCountOfInstructionBytes(Insns, &HasCustom); + if (HasCustom) + return; + if (Distance != InstructionBytes) { + errs() << "Incorrect size for " << Name << " " << Type << ": Symbol diff " + << Distance << " bytes, instructions map to " << InstructionBytes + << " bytes\n"; + std::abort(); + } +} +#endif + // Unwind opcode encodings and restrictions are documented at // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling static void ARMEmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin, @@ -1906,6 +1932,21 @@ streamer.emitLabel(Label); info->Symbol = Label; +#ifndef NDEBUG + if (info->PrologEnd) + checkInstructions(streamer, info->Instructions, info->Begin, info->PrologEnd, + info->Function->getName(), "prolog"); + for (auto &I : info->EpilogMap) { + MCSymbol *EpilogStart = I.first; + auto &EpilogInstrs = I.second; + if (info->EpilogEnd.find(EpilogStart) != info->EpilogEnd.end()) { + checkInstructions(streamer, EpilogInstrs, EpilogStart, + info->EpilogEnd[EpilogStart], info->Function->getName(), + "epilog"); + } + } +#endif + Optional RawFuncLength; const MCExpr *FuncLengthExpr = nullptr; if (!info->FuncletOrFuncEnd) { diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp @@ -252,6 +252,10 @@ InEpilogCFI = false; WinEH::Instruction Inst = WinEH::Instruction(UnwindCode, nullptr, -1, 0); CurFrame->EpilogMap[CurrentEpilog].push_back(Inst); +#ifndef NDEBUG + MCSymbol *Label = S.emitCFILabel(); + CurFrame->EpilogEnd[CurrentEpilog] = Label; +#endif CurrentEpilog = nullptr; }