summaryrefslogtreecommitdiff
path: root/llvm/lib/MC
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC')
-rw-r--r--llvm/lib/MC/DXContainerRootSignature.cpp126
-rw-r--r--llvm/lib/MC/MCDisassembler/Disassembler.cpp21
-rw-r--r--llvm/lib/MC/MCGOFFStreamer.cpp6
-rw-r--r--llvm/lib/MC/MCObjectFileInfo.cpp96
-rw-r--r--llvm/lib/MC/MCSFrame.cpp196
-rw-r--r--llvm/lib/MC/MCWin64EH.cpp24
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;
}