diff options
-rw-r--r-- | include/llvm/MC/MCAssembler.h | 23 | ||||
-rw-r--r-- | lib/MC/MCAsmInfo.cpp | 2 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 47 | ||||
-rw-r--r-- | lib/MC/MCContext.cpp | 19 | ||||
-rw-r--r-- | lib/MC/MCObjectStreamer.cpp | 7 | ||||
-rw-r--r-- | test/MC/ELF/compression.s | 18 | ||||
-rw-r--r-- | tools/llvm-mc/llvm-mc.cpp | 6 |
7 files changed, 112 insertions, 10 deletions
diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 4b519dd7c9..506e555e48 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -51,6 +51,7 @@ public: enum FragmentType { FT_Align, FT_Data, + FT_Compressed, FT_CompactEncodedInst, FT_Fill, FT_Relaxable, @@ -160,6 +161,7 @@ public: return false; case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: + case MCFragment::FT_Compressed: case MCFragment::FT_Data: return true; } @@ -194,7 +196,8 @@ public: static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); - return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data; + return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data || + Kind == MCFragment::FT_Compressed; } }; @@ -213,6 +216,11 @@ class MCDataFragment : public MCEncodedFragmentWithFixups { /// Fixups - The list of fixups in this fragment. SmallVector<MCFixup, 4> Fixups; +protected: + MCDataFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0) + : MCEncodedFragmentWithFixups(FType, SD), HasInstructions(false), + AlignToBundleEnd(false) {} + public: MCDataFragment(MCSectionData *SD = 0) : MCEncodedFragmentWithFixups(FT_Data, SD), @@ -246,10 +254,21 @@ public: const_fixup_iterator fixup_end() const override {return Fixups.end();} static bool classof(const MCFragment *F) { - return F->getKind() == MCFragment::FT_Data; + return F->getKind() == MCFragment::FT_Data || + F->getKind() == MCFragment::FT_Compressed; } }; +class MCCompressedFragment: public MCDataFragment { + mutable SmallVector<char, 32> CompressedContents; +public: + MCCompressedFragment(MCSectionData *SD = nullptr) + : MCDataFragment(FT_Compressed, SD) {} + const SmallVectorImpl<char> &getCompressedContents() const; + using MCDataFragment::getContents; + SmallVectorImpl<char> &getContents() override; +}; + /// This is a compact (memory-size-wise) fragment for holding an encoded /// instruction (non-relaxable) that has no fixups registered. When applicable, /// it can be used instead of MCDataFragment and lead to lower memory diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index f09bbd1a66..c78d3d574a 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -100,6 +100,8 @@ MCAsmInfo::MCAsmInfo() { // architecture basis. // - The target subclasses for AArch64, ARM, and X86 handle these cases UseIntegratedAssembler = false; + + CompressDebugSections = false; } MCAsmInfo::~MCAsmInfo() { diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 910295c5d2..fcf1b50a4f 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -28,6 +28,9 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/Host.h" using namespace llvm; @@ -230,6 +233,39 @@ MCEncodedFragmentWithFixups::~MCEncodedFragmentWithFixups() { /* *** */ +const SmallVectorImpl<char> &MCCompressedFragment::getCompressedContents() const { + assert(getParent()->size() == 1 && + "Only compress sections containing a single fragment"); + if (CompressedContents.empty()) { + std::unique_ptr<MemoryBuffer> CompressedSection; + zlib::Status Success = + zlib::compress(StringRef(getContents().data(), getContents().size()), + CompressedSection); + (void)Success; + assert(Success == zlib::StatusOK); + CompressedContents.push_back('Z'); + CompressedContents.push_back('L'); + CompressedContents.push_back('I'); + CompressedContents.push_back('B'); + uint64_t Size = getContents().size(); + if (sys::IsLittleEndianHost) + Size = sys::SwapByteOrder(Size); + CompressedContents.append(reinterpret_cast<char *>(&Size), + reinterpret_cast<char *>(&Size + 1)); + CompressedContents.append(CompressedSection->getBuffer().begin(), + CompressedSection->getBuffer().end()); + } + return CompressedContents; +} + +SmallVectorImpl<char> &MCCompressedFragment::getContents() { + assert(CompressedContents.empty() && + "Fragment contents should not be altered after compression"); + return MCDataFragment::getContents(); +} + +/* *** */ + MCSectionData::MCSectionData() : Section(0) {} MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) @@ -430,6 +466,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: return cast<MCEncodedFragment>(F).getContents().size(); + case MCFragment::FT_Compressed: + return cast<MCCompressedFragment>(F).getCompressedContents().size(); case MCFragment::FT_Fill: return cast<MCFillFragment>(F).getSize(); @@ -618,6 +656,11 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + case MCFragment::FT_Compressed: + ++stats::EmittedDataFragments; + OW->WriteBytes(cast<MCCompressedFragment>(F).getCompressedContents()); + break; + case MCFragment::FT_Data: ++stats::EmittedDataFragments; writeFragmentContents(F, OW); @@ -694,6 +737,7 @@ void MCAssembler::writeSectionData(const MCSectionData *SD, ie = SD->end(); it != ie; ++it) { switch (it->getKind()) { default: llvm_unreachable("Invalid fragment in virtual section!"); + case MCFragment::FT_Compressed: case MCFragment::FT_Data: { // Check that we aren't trying to write a non-zero contents (or fixups) // into a virtual section. This is to support clients which use standard @@ -1021,6 +1065,8 @@ void MCFragment::dump() { switch (getKind()) { case MCFragment::FT_Align: OS << "MCAlignFragment"; break; case MCFragment::FT_Data: OS << "MCDataFragment"; break; + case MCFragment::FT_Compressed: + OS << "MCCompressedFragment"; break; case MCFragment::FT_CompactEncodedInst: OS << "MCCompactEncodedInstFragment"; break; case MCFragment::FT_Fill: OS << "MCFillFragment"; break; @@ -1047,6 +1093,7 @@ void MCFragment::dump() { << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">"; break; } + case MCFragment::FT_Compressed: case MCFragment::FT_Data: { const MCDataFragment *DF = cast<MCDataFragment>(this); OS << "\n "; diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index ede3b3cd23..b228d18ba7 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -37,13 +37,13 @@ typedef std::map<SectionGroupPair, const MCSectionCOFF *> COFFUniqueMapTy; MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, const MCObjectFileInfo *mofi, const SourceMgr *mgr, - bool DoAutoReset) : - SrcMgr(mgr), MAI(mai), MRI(mri), MOFI(mofi), - Allocator(), Symbols(Allocator), UsedNames(Allocator), - NextUniqueID(0), - CurrentDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0), - DwarfLocSeen(false), GenDwarfForAssembly(false), GenDwarfFileNumber(0), - AllowTemporaryLabels(true), DwarfCompileUnitID(0), AutoReset(DoAutoReset) { + bool DoAutoReset) + : SrcMgr(mgr), MAI(mai), MRI(mri), MOFI(mofi), Allocator(), + Symbols(Allocator), UsedNames(Allocator), NextUniqueID(0), + CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), DwarfLocSeen(false), + GenDwarfForAssembly(false), GenDwarfFileNumber(0), + AllowTemporaryLabels(true), DwarfCompileUnitID(0), + AutoReset(DoAutoReset) { error_code EC = llvm::sys::fs::current_path(CompilationDir); if (EC) @@ -251,6 +251,11 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; + SmallString<32> ZDebugName; + if (MAI->compressDebugSections() && Section.startswith(".debug_") && + Section != ".debug_frame") + Section = (".z" + Section.drop_front(1)).toStringRef(ZDebugName); + // Do the lookup, if we have a hit, return it. std::pair<ELFUniqueMapTy::iterator, bool> Entry = Map.insert( std::make_pair(SectionGroupPair(Section, Group), (MCSectionELF *)0)); diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 809cb11e36..35786accb4 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -20,6 +20,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/MC/MCSectionELF.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, MCAsmBackend &TAB, @@ -63,7 +64,11 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { // When bundling is enabled, we don't want to add data to a fragment that // already has instructions (see MCELFStreamer::EmitInstToData for details) if (!F || (Assembler->isBundlingEnabled() && F->hasInstructions())) { - F = new MCDataFragment(); + const auto *Sec = dyn_cast<MCSectionELF>(&getCurrentSectionData()->getSection()); + if (Sec && Sec->getSectionName().startswith(".zdebug_")) + F = new MCCompressedFragment(); + else + F = new MCDataFragment(); insert(F); } return F; diff --git a/test/MC/ELF/compression.s b/test/MC/ELF/compression.s new file mode 100644 index 0000000000..0293a3c9c5 --- /dev/null +++ b/test/MC/ELF/compression.s @@ -0,0 +1,18 @@ +// RUN: llvm-mc -filetype=obj -compress-debug-sections -triple x86_64-pc-linux-gnu %s -o - | llvm-objdump -s - | FileCheck %s + +// CHECK: Contents of section .zdebug_line: +// Check for the 'ZLIB' file magic at the start of the section +// CHECK-NEXT: ZLIB +// We shouldn't compress the debug_frame section, since it can be relaxed +// CHECK: Contents of section .debug_frame +// CHECK-NOT: ZLIB + + .section .debug_line,"",@progbits + .text +foo: + .cfi_startproc + .file 1 "Driver.ii" + .loc 1 2 0 + nop + .cfi_endproc + .cfi_sections .debug_frame diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index a4b4a844f6..b2e7a81488 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -50,6 +50,9 @@ static cl::opt<bool> ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); static cl::opt<bool> +CompressDebugSections("compress-debug-sections", cl::desc("Compress DWARF debug sections")); + +static cl::opt<bool> ShowInst("show-inst", cl::desc("Show internal instruction representation")); static cl::opt<bool> @@ -381,6 +384,9 @@ int main(int argc, char **argv) { std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); assert(MAI && "Unable to create target asm info!"); + if (CompressDebugSections) + MAI->setCompressDebugSections(true); + // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); |