diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /llvm/lib/MC | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'llvm/lib/MC')
| -rw-r--r-- | llvm/lib/MC/DXContainerRootSignature.cpp | 126 | ||||
| -rw-r--r-- | llvm/lib/MC/MCDisassembler/Disassembler.cpp | 21 | ||||
| -rw-r--r-- | llvm/lib/MC/MCGOFFStreamer.cpp | 6 | ||||
| -rw-r--r-- | llvm/lib/MC/MCObjectFileInfo.cpp | 96 | ||||
| -rw-r--r-- | llvm/lib/MC/MCSFrame.cpp | 196 | ||||
| -rw-r--r-- | llvm/lib/MC/MCWin64EH.cpp | 24 |
6 files changed, 356 insertions, 113 deletions
diff --git a/llvm/lib/MC/DXContainerRootSignature.cpp b/llvm/lib/MC/DXContainerRootSignature.cpp index 482280b5ef28..b9ebb7a9e789 100644 --- a/llvm/lib/MC/DXContainerRootSignature.cpp +++ b/llvm/lib/MC/DXContainerRootSignature.cpp @@ -20,49 +20,62 @@ static uint32_t writePlaceholder(raw_svector_ostream &Stream) { return Offset; } -static void rewriteOffsetToCurrentByte(raw_svector_ostream &Stream, - uint32_t Offset) { +static uint32_t rewriteOffsetToCurrentByte(raw_svector_ostream &Stream, + uint32_t Offset) { + uint32_t ByteOffset = Stream.tell(); uint32_t Value = support::endian::byte_swap<uint32_t, llvm::endianness::little>( - Stream.tell()); + ByteOffset); Stream.pwrite(reinterpret_cast<const char *>(&Value), sizeof(Value), Offset); + return ByteOffset; } size_t RootSignatureDesc::getSize() const { - size_t Size = - sizeof(dxbc::RTS0::v1::RootSignatureHeader) + - ParametersContainer.size() * sizeof(dxbc::RTS0::v1::RootParameterHeader) + + uint32_t StaticSamplersOffset = computeStaticSamplersOffset(); + size_t StaticSamplersSize = StaticSamplers.size() * sizeof(dxbc::RTS0::v1::StaticSampler); + return size_t(StaticSamplersOffset) + StaticSamplersSize; +} + +uint32_t RootSignatureDesc::computeRootParametersOffset() const { + return sizeof(dxbc::RTS0::v1::RootSignatureHeader); +} + +uint32_t RootSignatureDesc::computeStaticSamplersOffset() const { + uint32_t Offset = computeRootParametersOffset(); + for (const RootParameterInfo &I : ParametersContainer) { - switch (I.Header.ParameterType) { - case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): - Size += sizeof(dxbc::RTS0::v1::RootConstants); + Offset += sizeof(dxbc::RTS0::v1::RootParameterHeader); + switch (I.Type) { + case dxbc::RootParameterType::Constants32Bit: + Offset += sizeof(dxbc::RTS0::v1::RootConstants); break; - case llvm::to_underlying(dxbc::RootParameterType::CBV): - case llvm::to_underlying(dxbc::RootParameterType::SRV): - case llvm::to_underlying(dxbc::RootParameterType::UAV): + case dxbc::RootParameterType::CBV: + case dxbc::RootParameterType::SRV: + case dxbc::RootParameterType::UAV: if (Version == 1) - Size += sizeof(dxbc::RTS0::v1::RootDescriptor); + Offset += sizeof(dxbc::RTS0::v1::RootDescriptor); else - Size += sizeof(dxbc::RTS0::v2::RootDescriptor); + Offset += sizeof(dxbc::RTS0::v2::RootDescriptor); break; - case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable): + case dxbc::RootParameterType::DescriptorTable: const DescriptorTable &Table = ParametersContainer.getDescriptorTable(I.Location); // 4 bytes for the number of ranges in table and // 4 bytes for the ranges offset - Size += 2 * sizeof(uint32_t); + Offset += 2 * sizeof(uint32_t); if (Version == 1) - Size += sizeof(dxbc::RTS0::v1::DescriptorRange) * Table.Ranges.size(); + Offset += sizeof(dxbc::RTS0::v1::DescriptorRange) * Table.Ranges.size(); else - Size += sizeof(dxbc::RTS0::v2::DescriptorRange) * Table.Ranges.size(); + Offset += sizeof(dxbc::RTS0::v2::DescriptorRange) * Table.Ranges.size(); break; } } - return Size; + + return Offset; } void RootSignatureDesc::write(raw_ostream &OS) const { @@ -76,19 +89,13 @@ void RootSignatureDesc::write(raw_ostream &OS) const { support::endian::write(BOS, NumParameters, llvm::endianness::little); support::endian::write(BOS, RootParameterOffset, llvm::endianness::little); support::endian::write(BOS, NumSamplers, llvm::endianness::little); - uint32_t SSO = StaticSamplersOffset; - if (NumSamplers > 0) - SSO = writePlaceholder(BOS); - else - support::endian::write(BOS, SSO, llvm::endianness::little); + uint32_t SSO = writePlaceholder(BOS); support::endian::write(BOS, Flags, llvm::endianness::little); SmallVector<uint32_t> ParamsOffsets; - for (const RootParameterInfo &P : ParametersContainer) { - support::endian::write(BOS, P.Header.ParameterType, - llvm::endianness::little); - support::endian::write(BOS, P.Header.ShaderVisibility, - llvm::endianness::little); + for (const RootParameterInfo &I : ParametersContainer) { + support::endian::write(BOS, I.Type, llvm::endianness::little); + support::endian::write(BOS, I.Visibility, llvm::endianness::little); ParamsOffsets.push_back(writePlaceholder(BOS)); } @@ -96,11 +103,11 @@ void RootSignatureDesc::write(raw_ostream &OS) const { assert(NumParameters == ParamsOffsets.size()); for (size_t I = 0; I < NumParameters; ++I) { rewriteOffsetToCurrentByte(BOS, ParamsOffsets[I]); - const auto &[Type, Loc] = ParametersContainer.getTypeAndLocForParameter(I); - switch (Type) { - case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): { - const dxbc::RTS0::v1::RootConstants &Constants = - ParametersContainer.getConstant(Loc); + const RootParameterInfo &Info = ParametersContainer.getInfo(I); + switch (Info.Type) { + case dxbc::RootParameterType::Constants32Bit: { + const mcdxbc::RootConstants &Constants = + ParametersContainer.getConstant(Info.Location); support::endian::write(BOS, Constants.ShaderRegister, llvm::endianness::little); support::endian::write(BOS, Constants.RegisterSpace, @@ -109,11 +116,11 @@ void RootSignatureDesc::write(raw_ostream &OS) const { llvm::endianness::little); break; } - case llvm::to_underlying(dxbc::RootParameterType::CBV): - case llvm::to_underlying(dxbc::RootParameterType::SRV): - case llvm::to_underlying(dxbc::RootParameterType::UAV): { - const dxbc::RTS0::v2::RootDescriptor &Descriptor = - ParametersContainer.getRootDescriptor(Loc); + case dxbc::RootParameterType::CBV: + case dxbc::RootParameterType::SRV: + case dxbc::RootParameterType::UAV: { + const mcdxbc::RootDescriptor &Descriptor = + ParametersContainer.getRootDescriptor(Info.Location); support::endian::write(BOS, Descriptor.ShaderRegister, llvm::endianness::little); @@ -123,14 +130,15 @@ void RootSignatureDesc::write(raw_ostream &OS) const { support::endian::write(BOS, Descriptor.Flags, llvm::endianness::little); break; } - case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable): { + case dxbc::RootParameterType::DescriptorTable: { const DescriptorTable &Table = - ParametersContainer.getDescriptorTable(Loc); + ParametersContainer.getDescriptorTable(Info.Location); support::endian::write(BOS, (uint32_t)Table.Ranges.size(), llvm::endianness::little); rewriteOffsetToCurrentByte(BOS, writePlaceholder(BOS)); for (const auto &Range : Table) { - support::endian::write(BOS, Range.RangeType, llvm::endianness::little); + support::endian::write(BOS, static_cast<uint32_t>(Range.RangeType), + llvm::endianness::little); support::endian::write(BOS, Range.NumDescriptors, llvm::endianness::little); support::endian::write(BOS, Range.BaseShaderRegister, @@ -146,23 +154,23 @@ void RootSignatureDesc::write(raw_ostream &OS) const { } } } - if (NumSamplers > 0) { - rewriteOffsetToCurrentByte(BOS, SSO); - for (const auto &S : StaticSamplers) { - support::endian::write(BOS, S.Filter, llvm::endianness::little); - support::endian::write(BOS, S.AddressU, llvm::endianness::little); - support::endian::write(BOS, S.AddressV, llvm::endianness::little); - support::endian::write(BOS, S.AddressW, llvm::endianness::little); - support::endian::write(BOS, S.MipLODBias, llvm::endianness::little); - support::endian::write(BOS, S.MaxAnisotropy, llvm::endianness::little); - support::endian::write(BOS, S.ComparisonFunc, llvm::endianness::little); - support::endian::write(BOS, S.BorderColor, llvm::endianness::little); - support::endian::write(BOS, S.MinLOD, llvm::endianness::little); - support::endian::write(BOS, S.MaxLOD, llvm::endianness::little); - support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little); - support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little); - support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little); - } + [[maybe_unused]] uint32_t Offset = rewriteOffsetToCurrentByte(BOS, SSO); + assert(Offset == computeStaticSamplersOffset() && + "Computed offset does not match written offset"); + for (const auto &S : StaticSamplers) { + support::endian::write(BOS, S.Filter, llvm::endianness::little); + support::endian::write(BOS, S.AddressU, llvm::endianness::little); + support::endian::write(BOS, S.AddressV, llvm::endianness::little); + support::endian::write(BOS, S.AddressW, llvm::endianness::little); + support::endian::write(BOS, S.MipLODBias, llvm::endianness::little); + support::endian::write(BOS, S.MaxAnisotropy, llvm::endianness::little); + support::endian::write(BOS, S.ComparisonFunc, llvm::endianness::little); + support::endian::write(BOS, S.BorderColor, llvm::endianness::little); + support::endian::write(BOS, S.MinLOD, llvm::endianness::little); + support::endian::write(BOS, S.MaxLOD, llvm::endianness::little); + support::endian::write(BOS, S.ShaderRegister, llvm::endianness::little); + support::endian::write(BOS, S.RegisterSpace, llvm::endianness::little); + support::endian::write(BOS, S.ShaderVisibility, llvm::endianness::little); } assert(Storage.size() == getSize()); OS.write(Storage.data(), Storage.size()); diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp index 684413e1e3a5..0429227f0fec 100644 --- a/llvm/lib/MC/MCDisassembler/Disassembler.cpp +++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -17,7 +17,6 @@ #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSchedule.h" @@ -45,20 +44,23 @@ LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU, const char *Features, void *DisInfo, int TagType, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp) { + Triple TheTriple(TT); + // Get the target. std::string Error; - const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error); + const Target *TheTarget = TargetRegistry::lookupTarget(TheTriple, Error); if (!TheTarget) return nullptr; - std::unique_ptr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + std::unique_ptr<const MCRegisterInfo> MRI( + TheTarget->createMCRegInfo(TheTriple)); if (!MRI) return nullptr; MCTargetOptions MCOptions; // Get the assembler info needed to setup the MCContext. std::unique_ptr<const MCAsmInfo> MAI( - TheTarget->createMCAsmInfo(*MRI, TT, MCOptions)); + TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions)); if (!MAI) return nullptr; @@ -67,13 +69,13 @@ LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU, return nullptr; std::unique_ptr<const MCSubtargetInfo> STI( - TheTarget->createMCSubtargetInfo(TT, CPU, Features)); + TheTarget->createMCSubtargetInfo(TheTriple, CPU, Features)); if (!STI) return nullptr; // Set up the MCContext for creating symbols and MCExpr's. std::unique_ptr<MCContext> Ctx( - new MCContext(Triple(TT), MAI.get(), MRI.get(), STI.get())); + new MCContext(TheTriple, MAI.get(), MRI.get(), STI.get())); if (!Ctx) return nullptr; @@ -84,12 +86,13 @@ LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU, return nullptr; std::unique_ptr<MCRelocationInfo> RelInfo( - TheTarget->createMCRelocationInfo(TT, *Ctx)); + TheTarget->createMCRelocationInfo(TheTriple, *Ctx)); if (!RelInfo) return nullptr; - std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer( - TT, GetOpInfo, SymbolLookUp, DisInfo, Ctx.get(), std::move(RelInfo))); + std::unique_ptr<MCSymbolizer> Symbolizer( + TheTarget->createMCSymbolizer(TheTriple, GetOpInfo, SymbolLookUp, DisInfo, + Ctx.get(), std::move(RelInfo))); DisAsm->setSymbolizer(std::move(Symbolizer)); // Set up the instruction printer. diff --git a/llvm/lib/MC/MCGOFFStreamer.cpp b/llvm/lib/MC/MCGOFFStreamer.cpp index 1718e2a4eb2d..8b228db0e8b3 100644 --- a/llvm/lib/MC/MCGOFFStreamer.cpp +++ b/llvm/lib/MC/MCGOFFStreamer.cpp @@ -45,3 +45,9 @@ MCStreamer *llvm::createGOFFStreamer(MCContext &Context, new MCGOFFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); return S; } +llvm::MCGOFFStreamer::MCGOFFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) + : MCObjectStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)) {} diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index d505ac6dd4bf..a0cd09b11d8d 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -849,6 +849,16 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { StackMapSection = Ctx->getCOFFSection(".llvm_stackmaps", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ); + + // Set IMAGE_SCN_MEM_DISCARDABLE so that lld will not truncate section name. + PseudoProbeSection = Ctx->getCOFFSection( + ".pseudo_probe", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ); + PseudoProbeDescSection = Ctx->getCOFFSection( + ".pseudo_probe_desc", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ); } void MCObjectFileInfo::initSPIRVMCObjectFileInfo(const Triple &T) { @@ -1220,44 +1230,68 @@ MCObjectFileInfo::getKCFITrapSection(const MCSection &TextSec) const { MCSection * MCObjectFileInfo::getPseudoProbeSection(const MCSection &TextSec) const { - if (Ctx->getObjectFileType() != MCContext::IsELF) - return PseudoProbeSection; - - const auto &ElfSec = static_cast<const MCSectionELF &>(TextSec); - unsigned Flags = ELF::SHF_LINK_ORDER; - StringRef GroupName; - if (const MCSymbol *Group = ElfSec.getGroup()) { - GroupName = Group->getName(); - Flags |= ELF::SHF_GROUP; + auto ObjFileType = Ctx->getObjectFileType(); + if (ObjFileType == MCContext::IsELF) { + const auto &ElfSec = static_cast<const MCSectionELF &>(TextSec); + unsigned Flags = ELF::SHF_LINK_ORDER; + StringRef GroupName; + if (const MCSymbol *Group = ElfSec.getGroup()) { + GroupName = Group->getName(); + Flags |= ELF::SHF_GROUP; + } + return Ctx->getELFSection( + PseudoProbeSection->getName(), ELF::SHT_PROGBITS, Flags, 0, GroupName, + true, ElfSec.getUniqueID(), + static_cast<const MCSymbolELF *>(TextSec.getBeginSymbol())); + } else if (ObjFileType == MCContext::IsCOFF) { + StringRef COMDATSymName = ""; + int Selection = 0; + unsigned Characteristics = + static_cast<MCSectionCOFF *>(PseudoProbeSection)->getCharacteristics(); + const auto &COFFSec = static_cast<const MCSectionCOFF &>(TextSec); + if (const MCSymbol *COMDATSym = COFFSec.getCOMDATSymbol()) { + // Associate .pseudo_probe to its function section. + COMDATSymName = COMDATSym->getName(); + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; + Selection = COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE; + } + return Ctx->getCOFFSection(PseudoProbeSection->getName(), Characteristics, + COMDATSymName, Selection, COFFSec.getUniqueID()); } - return Ctx->getELFSection( - PseudoProbeSection->getName(), ELF::SHT_PROGBITS, Flags, 0, GroupName, - true, ElfSec.getUniqueID(), - static_cast<const MCSymbolELF *>(TextSec.getBeginSymbol())); + return PseudoProbeSection; } MCSection * MCObjectFileInfo::getPseudoProbeDescSection(StringRef FuncName) const { - if (Ctx->getObjectFileType() == MCContext::IsELF) { - // Create a separate comdat group for each function's descriptor in order - // for the linker to deduplicate. The duplication, must be from different - // tranlation unit, can come from: - // 1. Inline functions defined in header files; - // 2. ThinLTO imported funcions; - // 3. Weak-linkage definitions. - // Use a concatenation of the section name and the function name as the - // group name so that descriptor-only groups won't be folded with groups of - // code. - if (Ctx->getTargetTriple().supportsCOMDAT() && !FuncName.empty()) { - auto *S = static_cast<MCSectionELF *>(PseudoProbeDescSection); - auto Flags = S->getFlags() | ELF::SHF_GROUP; - return Ctx->getELFSection(S->getName(), S->getType(), Flags, - S->getEntrySize(), - S->getName() + "_" + FuncName, - /*IsComdat=*/true); - } + if (!Ctx->getTargetTriple().supportsCOMDAT() || FuncName.empty()) + return PseudoProbeDescSection; + + // Create a separate comdat group for each function's descriptor in order + // for the linker to deduplicate. The duplication, must be from different + // tranlation unit, can come from: + // 1. Inline functions defined in header files; + // 2. ThinLTO imported funcions; + // 3. Weak-linkage definitions. + // Use a concatenation of the section name and the function name as the + // group name so that descriptor-only groups won't be folded with groups of + // code. + auto ObjFileType = Ctx->getObjectFileType(); + if (ObjFileType == MCContext::IsELF) { + auto *S = static_cast<MCSectionELF *>(PseudoProbeDescSection); + auto Flags = S->getFlags() | ELF::SHF_GROUP; + return Ctx->getELFSection(S->getName(), S->getType(), Flags, + S->getEntrySize(), S->getName() + "_" + FuncName, + /*IsComdat=*/true); + } else if (ObjFileType == MCContext::IsCOFF) { + auto *S = static_cast<MCSectionCOFF *>(PseudoProbeDescSection); + unsigned Characteristics = + S->getCharacteristics() | COFF::IMAGE_SCN_LNK_COMDAT; + std::string COMDATSymName = (S->getName() + "_" + FuncName).str(); + return Ctx->getCOFFSection(S->getName(), Characteristics, COMDATSymName, + COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH); } + return PseudoProbeDescSection; } diff --git a/llvm/lib/MC/MCSFrame.cpp b/llvm/lib/MC/MCSFrame.cpp index ee17b774e474..a0d6c80ab72e 100644 --- a/llvm/lib/MC/MCSFrame.cpp +++ b/llvm/lib/MC/MCSFrame.cpp @@ -21,6 +21,24 @@ using namespace sframe; namespace { +// High-level structure to track info needed to emit a +// sframe_frame_row_entry_addrX. On disk these have both a fixed portion of type +// sframe_frame_row_entry_addrX and trailing data of X * S bytes, where X is the +// datum size, and S is 1, 2, or 3 depending on which of CFA, SP, and FP are +// being tracked. +struct SFrameFRE { + // An FRE describes how to find the registers when the PC is at this + // Label from function start. + const MCSymbol *Label = nullptr; + size_t CFAOffset = 0; + size_t FPOffset = 0; + size_t RAOffset = 0; + bool FromFP = false; + bool CFARegSet = false; + + SFrameFRE(const MCSymbol *Start) : Label(Start) {} +}; + // High-level structure to track info needed to emit a sframe_func_desc_entry // and its associated FREs. struct SFrameFDE { @@ -28,6 +46,8 @@ struct SFrameFDE { const MCDwarfFrameInfo &DFrame; // Label where this FDE's FREs start. MCSymbol *FREStart; + // Unwinding fres + SmallVector<SFrameFRE> FREs; SFrameFDE(const MCDwarfFrameInfo &DF, MCSymbol *FRES) : DFrame(DF), FREStart(FRES) {} @@ -53,7 +73,8 @@ struct SFrameFDE { MCFixup::getDataKindForSize(4))); S.emitInt32(0); - // sfde_func_start_num_fres + // sfde_func_num_fres + // TODO: When we actually emit fres, replace 0 with FREs.size() S.emitInt32(0); // sfde_func_info word @@ -76,10 +97,90 @@ class SFrameEmitterImpl { MCObjectStreamer &Streamer; SmallVector<SFrameFDE> FDEs; ABI SFrameABI; + // Target-specific convenience variables to detect when a CFI instruction + // references these registers. Unlike in dwarf frame descriptions, they never + // escape into the sframe section itself. + unsigned SPReg; + unsigned FPReg; + unsigned RAReg; MCSymbol *FDESubSectionStart; MCSymbol *FRESubSectionStart; MCSymbol *FRESubSectionEnd; + bool setCFARegister(SFrameFRE &FRE, const MCCFIInstruction &I) { + if (I.getRegister() == SPReg) { + FRE.CFARegSet = true; + FRE.FromFP = false; + return true; + } + if (I.getRegister() == FPReg) { + FRE.CFARegSet = true; + FRE.FromFP = true; + return true; + } + Streamer.getContext().reportWarning( + I.getLoc(), "canonical Frame Address not in stack- or frame-pointer. " + "Omitting SFrame unwind info for this function"); + return false; + } + + bool setCFAOffset(SFrameFRE &FRE, const SMLoc &Loc, size_t Offset) { + if (!FRE.CFARegSet) { + Streamer.getContext().reportWarning( + Loc, "adjusting CFA offset without a base register. " + "Omitting SFrame unwind info for this function"); + return false; + } + FRE.CFAOffset = Offset; + return true; + } + + // Add the effects of CFI to the current FDE, creating a new FRE when + // necessary. + bool handleCFI(SFrameFDE &FDE, SFrameFRE &FRE, const MCCFIInstruction &CFI) { + switch (CFI.getOperation()) { + case MCCFIInstruction::OpDefCfaRegister: + return setCFARegister(FRE, CFI); + case MCCFIInstruction::OpDefCfa: + case MCCFIInstruction::OpLLVMDefAspaceCfa: + if (!setCFARegister(FRE, CFI)) + return false; + return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset()); + case MCCFIInstruction::OpOffset: + if (CFI.getRegister() == FPReg) + FRE.FPOffset = CFI.getOffset(); + else if (CFI.getRegister() == RAReg) + FRE.RAOffset = CFI.getOffset(); + return true; + case MCCFIInstruction::OpRelOffset: + if (CFI.getRegister() == FPReg) + FRE.FPOffset += CFI.getOffset(); + else if (CFI.getRegister() == RAReg) + FRE.RAOffset += CFI.getOffset(); + return true; + case MCCFIInstruction::OpDefCfaOffset: + return setCFAOffset(FRE, CFI.getLoc(), CFI.getOffset()); + case MCCFIInstruction::OpAdjustCfaOffset: + return setCFAOffset(FRE, CFI.getLoc(), FRE.CFAOffset + CFI.getOffset()); + case MCCFIInstruction::OpRememberState: + // TODO: Implement. Will use FDE. + return true; + case MCCFIInstruction::OpRestore: + // TODO: Implement. Will use FDE. + return true; + case MCCFIInstruction::OpRestoreState: + // TODO: Implement. Will use FDE. + return true; + case MCCFIInstruction::OpEscape: + // TODO: Implement. Will use FDE. + return true; + default: + // Instructions that don't affect the CFA, RA, and SP can be safely + // ignored. + return true; + } + } + public: SFrameEmitterImpl(MCObjectStreamer &Streamer) : Streamer(Streamer) { assert(Streamer.getContext() @@ -88,13 +189,96 @@ public: .has_value()); FDEs.reserve(Streamer.getDwarfFrameInfos().size()); SFrameABI = *Streamer.getContext().getObjectFileInfo()->getSFrameABIArch(); + switch (SFrameABI) { + case ABI::AArch64EndianBig: + case ABI::AArch64EndianLittle: + SPReg = 31; + RAReg = 29; + FPReg = 30; + break; + case ABI::AMD64EndianLittle: + SPReg = 7; + // RARegister untracked in this abi. Value chosen to match + // MCDwarfFrameInfo constructor. + RAReg = static_cast<unsigned>(INT_MAX); + FPReg = 6; + break; + } + FDESubSectionStart = Streamer.getContext().createTempSymbol(); FRESubSectionStart = Streamer.getContext().createTempSymbol(); FRESubSectionEnd = Streamer.getContext().createTempSymbol(); } - void BuildSFDE(const MCDwarfFrameInfo &DF) { - FDEs.emplace_back(DF, Streamer.getContext().createTempSymbol()); + bool atSameLocation(const MCSymbol *Left, const MCSymbol *Right) { + return Left != nullptr && Right != nullptr && + Left->getFragment() == Right->getFragment() && + Left->getOffset() == Right->getOffset(); + } + + bool equalIgnoringLocation(const SFrameFRE &Left, const SFrameFRE &Right) { + return Left.CFAOffset == Right.CFAOffset && + Left.FPOffset == Right.FPOffset && Left.RAOffset == Right.RAOffset && + Left.FromFP == Right.FromFP && Left.CFARegSet == Right.CFARegSet; + } + + void buildSFDE(const MCDwarfFrameInfo &DF) { + bool Valid = true; + SFrameFDE FDE(DF, Streamer.getContext().createTempSymbol()); + // This would have been set via ".cfi_return_column", but + // MCObjectStreamer doesn't emit an MCCFIInstruction for that. It just + // sets the DF.RAReg. + // FIXME: This also prevents providing a proper location for the error. + // LLVM doesn't change the return column itself, so this was + // hand-written assembly. + if (DF.RAReg != RAReg) { + Streamer.getContext().reportWarning( + SMLoc(), "non-default RA register in .cfi_return_column " + + Twine(DF.RAReg) + + ". Omitting SFrame unwind info for this function"); + Valid = false; + } + MCSymbol *LastLabel = DF.Begin; + SFrameFRE BaseFRE(LastLabel); + if (!DF.IsSimple) { + for (const auto &CFI : + Streamer.getContext().getAsmInfo()->getInitialFrameState()) + if (!handleCFI(FDE, BaseFRE, CFI)) + Valid = false; + } + FDE.FREs.push_back(BaseFRE); + + for (const auto &CFI : DF.Instructions) { + // Instructions from InitialFrameState may not have a label, but if these + // instructions don't, then they are in dead code or otherwise unused. + // TODO: This check follows MCDwarf.cpp + // FrameEmitterImplementation::emitCFIInstructions, but nothing in the + // testsuite triggers it. We should see if it can be removed in both + // places, or alternately, add a test to exercise it. + auto *L = CFI.getLabel(); + if (L && !L->isDefined()) + continue; + + SFrameFRE FRE = FDE.FREs.back(); + if (!handleCFI(FDE, FRE, CFI)) + Valid = false; + + // If nothing relevant but the location changed, don't add the FRE. + if (equalIgnoringLocation(FRE, FDE.FREs.back())) + continue; + + // If the location stayed the same, then update the current + // row. Otherwise, add a new one. + if (atSameLocation(LastLabel, L)) + FDE.FREs.back() = FRE; + else { + FDE.FREs.push_back(FRE); + FDE.FREs.back().Label = L; + LastLabel = L; + } + } + if (Valid) + FDEs.push_back(FDE); } void emitPreamble() { @@ -116,7 +300,9 @@ public: // shf_num_fdes Streamer.emitInt32(FDEs.size()); // shf_num_fres - Streamer.emitInt32(0); + uint32_t TotalFREs = 0; + Streamer.emitInt32(TotalFREs); + // shf_fre_len Streamer.emitAbsoluteSymbolDiff(FRESubSectionEnd, FRESubSectionStart, sizeof(int32_t)); @@ -161,7 +347,7 @@ void MCSFrameEmitter::emit(MCObjectStreamer &Streamer) { // Both the header itself and the FDEs include various offsets and counts. // Therefore, all of this must be precomputed. for (const auto &DFrame : FrameArray) - Emitter.BuildSFDE(DFrame); + Emitter.buildSFDE(DFrame); MCSection *Section = Context.getObjectFileInfo()->getSFrameSection(); // Not strictly necessary, but gas always aligns to 8, so match that. diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp index a87648afde7d..8111ccb8bc69 100644 --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -22,6 +22,7 @@ class MCSection; /// MCExpr that represents the epilog unwind code in an unwind table. class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr { + const MCSymbol *Function; const MCSymbol *FunctionEnd; const MCSymbol *UnwindV2Start; const MCSymbol *EpilogEnd; @@ -31,7 +32,7 @@ class MCUnwindV2EpilogTargetExpr final : public MCTargetExpr { MCUnwindV2EpilogTargetExpr(const WinEH::FrameInfo &FrameInfo, const WinEH::FrameInfo::Epilog &Epilog, uint8_t EpilogSize_) - : FunctionEnd(FrameInfo.FuncletOrFuncEnd), + : Function(FrameInfo.Function), FunctionEnd(FrameInfo.FuncletOrFuncEnd), UnwindV2Start(Epilog.UnwindV2Start), EpilogEnd(Epilog.End), EpilogSize(EpilogSize_), Loc(Epilog.Loc) {} @@ -253,13 +254,15 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { OS->getAssembler(), LastEpilog.End, LastEpilog.UnwindV2Start); if (!MaybeSize) { context.reportError(LastEpilog.Loc, - "Failed to evaluate epilog size for Unwind v2"); + "Failed to evaluate epilog size for Unwind v2 in " + + info->Function->getName()); return; } assert(*MaybeSize >= 0); if (*MaybeSize >= (int64_t)UINT8_MAX) { context.reportError(LastEpilog.Loc, - "Epilog size is too large for Unwind v2"); + "Epilog size is too large for Unwind v2 in " + + info->Function->getName()); return; } EpilogSize = *MaybeSize + 1; @@ -282,7 +285,8 @@ static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) { // Too many epilogs to handle. if ((size_t)numCodes + numEpilogCodes > UINT8_MAX) { context.reportError(info->FunctionLoc, - "Too many unwind codes with Unwind v2 enabled"); + "Too many unwind codes with Unwind v2 enabled in " + + info->Function->getName()); return; } @@ -383,14 +387,16 @@ bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl( auto Offset = GetOptionalAbsDifference(*Asm, FunctionEnd, UnwindV2Start); if (!Offset) { Asm->getContext().reportError( - Loc, "Failed to evaluate epilog offset for Unwind v2"); + Loc, "Failed to evaluate epilog offset for Unwind v2 in " + + Function->getName()); return false; } assert(*Offset > 0); constexpr uint16_t MaxEpilogOffset = 0x0fff; if (*Offset > MaxEpilogOffset) { - Asm->getContext().reportError(Loc, - "Epilog offset is too large for Unwind v2"); + Asm->getContext().reportError( + Loc, + "Epilog offset is too large for Unwind v2 in " + Function->getName()); return false; } @@ -398,8 +404,8 @@ bool MCUnwindV2EpilogTargetExpr::evaluateAsRelocatableImpl( auto Size = GetOptionalAbsDifference(*Asm, EpilogEnd, UnwindV2Start); if (Size != (EpilogSize - 1)) { Asm->getContext().reportError( - Loc, - "Size of this epilog does not match size of last epilog in function"); + Loc, "Size of this epilog does not match size of last epilog in " + + Function->getName()); return false; } |
