Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit d0089f0

Browse files
author
Mark Seaborn
committed
Cherry-pick r234714: [MC] Write padding into fragments when -mc-relax-all flag is used
Summary: When instruction bundling is enabled and the -mc-relax-all flag is set, we can write bundle padding directly into fragments and avoid creating large number of fragments significantly reducing LLVM MC memory usage. Test Plan: Regression test attached Reviewers: eliben Subscribers: jfb, mseaborn Differential Revision: http://reviews.llvm.org/D8072 BUG=https://code.google.com/p/nativeclient/issues/detail?id=4063 TEST=toolchain trybots [email protected] Review URL: https://codereview.chromium.org/1133723005
1 parent f46b724 commit d0089f0

17 files changed

+180
-37
lines changed

include/llvm/MC/MCAsmLayout.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,6 @@ class MCAsmLayout {
5050
/// \brief Is the layout for this fragment valid?
5151
bool isFragmentValid(const MCFragment *F) const;
5252

53-
/// \brief Compute the amount of padding required before this fragment to
54-
/// obey bundling restrictions.
55-
uint64_t computeBundlePadding(const MCFragment *F,
56-
uint64_t FOffset, uint64_t FSize);
57-
5853
public:
5954
MCAsmLayout(MCAssembler &_Assembler);
6055

include/llvm/MC/MCAssembler.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,11 +1243,23 @@ class MCAssembler {
12431243
FileNames.push_back(FileName);
12441244
}
12451245

1246+
/// \brief Write the necessary bundle padding to the given object writer.
1247+
/// Expects a fragment \p F containing instructions and its size \p FSize.
1248+
void writeFragmentPadding(const MCFragment &F, uint64_t FSize,
1249+
MCObjectWriter *OW) const;
1250+
12461251
/// @}
12471252

12481253
void dump();
12491254
};
12501255

1256+
/// \brief Compute the amount of padding required before the fragment \p F to
1257+
/// obey bundling restrictions, where \p FOffset is the fragment's offset in
1258+
/// its section and \p FSize is the fragment's size.
1259+
uint64_t computeBundlePadding(const MCAssembler &Assembler,
1260+
const MCFragment *F,
1261+
uint64_t FOffset, uint64_t FSize);
1262+
12511263
} // end namespace llvm
12521264

12531265
#endif

include/llvm/MC/MCELFStreamer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ class MCELFStreamer : public MCObjectStreamer {
100100

101101
void fixSymbolsInTLSFixups(const MCExpr *expr);
102102

103+
/// \brief Merge the content of the fragment \p EF into the fragment \p DF.
104+
void mergeFragment(MCDataFragment *, MCEncodedFragmentWithFixups *);
105+
103106
bool SeenIdent;
104107

105108
struct LocalCommon {
@@ -111,6 +114,10 @@ class MCELFStreamer : public MCObjectStreamer {
111114
std::vector<LocalCommon> LocalCommons;
112115

113116
SmallPtrSet<MCSymbol *, 16> BindingExplicitlySet;
117+
118+
/// BundleGroups - The stack of fragments holding the bundle-locked
119+
/// instructions.
120+
llvm::SmallVector<MCDataFragment *, 4> BundleGroups;
114121
};
115122

116123
MCELFStreamer *createARMELFStreamer(MCContext &Context, MCAsmBackend &TAB,

include/llvm/MC/MCObjectStreamer.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ class MCObjectStreamer : public MCStreamer {
4444
void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
4545
void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
4646

47-
// If any labels have been emitted but not assigned fragments, ensure that
48-
// they get assigned, either to F if possible or to a new data fragment.
49-
void flushPendingLabels(MCFragment *F);
50-
5147
protected:
5248
MCObjectStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &_OS,
5349
MCCodeEmitter *_Emitter);
@@ -85,6 +81,12 @@ class MCObjectStreamer : public MCStreamer {
8581
/// fragment is not a data fragment.
8682
MCDataFragment *getOrCreateDataFragment();
8783

84+
/// If any labels have been emitted but not assigned fragments, ensure that
85+
/// they get assigned, either to F if possible or to a new data fragment.
86+
/// Optionally, it is also possible to provide an offset \p FOffset, which
87+
/// will be used as a symbol offset within the fragment.
88+
void flushPendingLabels(MCFragment *F, uint64_t FOffset = 0);
89+
8890
public:
8991
void visitUsedSymbol(const MCSymbol &Sym) override;
9092

lib/MC/MCAssembler.cpp

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,9 @@ uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const {
219219
return getSectionAddressSize(SD);
220220
}
221221

222-
uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *F,
223-
uint64_t FOffset, uint64_t FSize) {
222+
uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler,
223+
const MCFragment *F,
224+
uint64_t FOffset, uint64_t FSize) {
224225
uint64_t BundleSize = Assembler.getBundleAlignSize();
225226
assert(BundleSize > 0 &&
226227
"computeBundlePadding should only be called if bundling is enabled");
@@ -336,6 +337,7 @@ MCSectionData::getSubsectionInsertionPoint(unsigned Subsection) {
336337
getFragmentList().insert(IP, F);
337338
F->setParent(this);
338339
}
340+
339341
return IP;
340342
}
341343

@@ -638,15 +640,21 @@ void MCAsmLayout::layoutFragment(MCFragment *F) {
638640
// The fragment's offset will point to after the padding, and its computed
639641
// size won't include the padding.
640642
//
641-
if (Assembler.isBundlingEnabled() && F->hasInstructions()) {
643+
// When the -mc-relax-all flag is used, we optimize bundling by writting the
644+
// bundle padding directly into fragments when the instructions are emitted
645+
// inside the streamer.
646+
//
647+
if (Assembler.isBundlingEnabled() && !Assembler.getRelaxAll() &&
648+
F->hasInstructions()) {
642649
assert(isa<MCEncodedFragment>(F) &&
643650
"Only MCEncodedFragment implementations have instructions");
644651
uint64_t FSize = Assembler.computeFragmentSize(*this, *F);
645652

646653
if (FSize > Assembler.getBundleAlignSize())
647654
report_fatal_error("Fragment can't be larger than a bundle size");
648655

649-
uint64_t RequiredBundlePadding = computeBundlePadding(F, F->Offset, FSize);
656+
uint64_t RequiredBundlePadding = computeBundlePadding(Assembler, F,
657+
F->Offset, FSize);
650658
if (RequiredBundlePadding > UINT8_MAX)
651659
report_fatal_error("Padding cannot exceed 255 bytes");
652660
F->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
@@ -661,24 +669,18 @@ static void writeFragmentContents(const MCFragment &F, MCObjectWriter *OW) {
661669
OW->WriteBytes(EF.getContents());
662670
}
663671

664-
/// \brief Write the fragment \p F to the output file.
665-
static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
666-
const MCFragment &F) {
667-
MCObjectWriter *OW = &Asm.getWriter();
668-
669-
// FIXME: Embed in fragments instead?
670-
uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F);
671-
672+
void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize,
673+
MCObjectWriter *OW) const {
672674
// Should NOP padding be written out before this fragment?
673675
unsigned BundlePadding = F.getBundlePadding();
674676
if (BundlePadding > 0) {
675-
assert(Asm.isBundlingEnabled() &&
677+
assert(isBundlingEnabled() &&
676678
"Writing bundle padding with disabled bundling");
677679
assert(F.hasInstructions() &&
678680
"Writing bundle padding for a fragment without instructions");
679681

680-
unsigned TotalLength = BundlePadding + static_cast<unsigned>(FragmentSize);
681-
if (F.alignToBundleEnd() && TotalLength > Asm.getBundleAlignSize()) {
682+
unsigned TotalLength = BundlePadding + static_cast<unsigned>(FSize);
683+
if (F.alignToBundleEnd() && TotalLength > getBundleAlignSize()) {
682684
// If the padding itself crosses a bundle boundary, it must be emitted
683685
// in 2 pieces, since even nop instructions must not cross boundaries.
684686
// v--------------v <- BundleAlignSize
@@ -687,16 +689,27 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
687689
// | Prev |####|####| F |
688690
// ----------------------------
689691
// ^-------------------^ <- TotalLength
690-
unsigned DistanceToBoundary = TotalLength - Asm.getBundleAlignSize();
691-
if (!Asm.getBackend().writeNopData(DistanceToBoundary, OW))
692+
unsigned DistanceToBoundary = TotalLength - getBundleAlignSize();
693+
if (!getBackend().writeNopData(DistanceToBoundary, OW))
692694
report_fatal_error("unable to write NOP sequence of " +
693695
Twine(DistanceToBoundary) + " bytes");
694696
BundlePadding -= DistanceToBoundary;
695697
}
696-
if (!Asm.getBackend().writeNopData(BundlePadding, OW))
698+
if (!getBackend().writeNopData(BundlePadding, OW))
697699
report_fatal_error("unable to write NOP sequence of " +
698700
Twine(BundlePadding) + " bytes");
699701
}
702+
}
703+
704+
/// \brief Write the fragment \p F to the output file.
705+
static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
706+
const MCFragment &F) {
707+
MCObjectWriter *OW = &Asm.getWriter();
708+
709+
// FIXME: Embed in fragments instead?
710+
uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F);
711+
712+
Asm.writeFragmentPadding(F, FragmentSize, OW);
700713

701714
// This variable (and its dummy usage) is to participate in the assert at
702715
// the end of the function.

lib/MC/MCELFStreamer.cpp

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/ADT/STLExtras.h"
1616
#include "llvm/ADT/SmallPtrSet.h"
1717
#include "llvm/MC/MCAsmBackend.h"
18+
#include "llvm/MC/MCAsmLayout.h"
1819
#include "llvm/MC/MCAsmInfo.h"
1920
#include "llvm/MC/MCAssembler.h"
2021
#include "llvm/MC/MCCodeEmitter.h"
@@ -39,6 +40,48 @@ using namespace llvm;
3940
MCELFStreamer::~MCELFStreamer() {
4041
}
4142

43+
void MCELFStreamer::mergeFragment(MCDataFragment *DF,
44+
MCEncodedFragmentWithFixups *EF) {
45+
MCAssembler &Assembler = getAssembler();
46+
47+
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
48+
uint64_t FSize = EF->getContents().size();
49+
50+
if (FSize > Assembler.getBundleAlignSize())
51+
report_fatal_error("Fragment can't be larger than a bundle size");
52+
53+
uint64_t RequiredBundlePadding = computeBundlePadding(
54+
Assembler, EF, DF->getContents().size(), FSize);
55+
56+
if (RequiredBundlePadding > UINT8_MAX)
57+
report_fatal_error("Padding cannot exceed 255 bytes");
58+
59+
if (RequiredBundlePadding > 0) {
60+
SmallString<256> Code;
61+
raw_svector_ostream VecOS(Code);
62+
MCObjectWriter *OW = Assembler.getBackend().createObjectWriter(VecOS);
63+
64+
EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
65+
66+
Assembler.writeFragmentPadding(*EF, FSize, OW);
67+
VecOS.flush();
68+
delete OW;
69+
70+
DF->getContents().append(Code.begin(), Code.end());
71+
}
72+
}
73+
74+
flushPendingLabels(DF, DF->getContents().size());
75+
76+
for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) {
77+
EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() +
78+
DF->getContents().size());
79+
DF->getFixups().push_back(EF->getFixups()[i]);
80+
}
81+
DF->setHasInstructions(true);
82+
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
83+
}
84+
4285
void MCELFStreamer::InitSections(bool NoExecStack) {
4386
// This emulates the same behavior of GNU as. This makes it easier
4487
// to compare the output as the major sections are in the same order.
@@ -459,7 +502,16 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
459502

460503
if (Assembler.isBundlingEnabled()) {
461504
MCSectionData *SD = getCurrentSectionData();
462-
if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst())
505+
if (Assembler.getRelaxAll() && SD->isBundleLocked())
506+
// If the -mc-relax-all flag is used and we are bundle-locked, we re-use
507+
// the current bundle group.
508+
DF = BundleGroups.back();
509+
else if (Assembler.getRelaxAll() && !SD->isBundleLocked())
510+
// When not in a bundle-locked group and the -mc-relax-all flag is used,
511+
// we create a new temporary fragment which will be later merged into
512+
// the current fragment.
513+
DF = new MCDataFragment();
514+
else if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst())
463515
// If we are bundle-locked, we re-use the current fragment.
464516
// The bundle-locking directive ensures this is a new data fragment.
465517
DF = cast<MCDataFragment>(getCurrentFragment());
@@ -497,6 +549,14 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
497549
}
498550
DF->setHasInstructions(true);
499551
DF->getContents().append(Code.begin(), Code.end());
552+
553+
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
554+
MCSectionData *SD = getCurrentSectionData();
555+
if (!SD->isBundleLocked()) {
556+
mergeFragment(getOrCreateDataFragment(), DF);
557+
delete DF;
558+
}
559+
}
500560
}
501561

502562
void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
@@ -520,6 +580,12 @@ void MCELFStreamer::EmitBundleLock(bool AlignToEnd) {
520580
if (!SD->isBundleLocked())
521581
SD->setBundleGroupBeforeFirstInst(true);
522582

583+
if (getAssembler().getRelaxAll() && !SD->isBundleLocked()) {
584+
// TODO: drop the lock state and set directly in the fragment
585+
MCDataFragment *DF = new MCDataFragment();
586+
BundleGroups.push_back(DF);
587+
}
588+
523589
SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd :
524590
MCSectionData::BundleLocked);
525591
}
@@ -535,7 +601,27 @@ void MCELFStreamer::EmitBundleUnlock() {
535601
else if (SD->isBundleGroupBeforeFirstInst())
536602
report_fatal_error("Empty bundle-locked group is forbidden");
537603

538-
SD->setBundleLockState(MCSectionData::NotBundleLocked);
604+
// When the -mc-relax-all flag is used, we emit instructions to fragments
605+
// stored on a stack. When the bundle unlock is emited, we pop a fragment
606+
// from the stack a merge it to the one below.
607+
if (getAssembler().getRelaxAll()) {
608+
assert(!BundleGroups.empty() && "There are no bundle groups");
609+
MCDataFragment *DF = BundleGroups.back();
610+
611+
// FIXME: Use BundleGroups to track the lock state instead.
612+
SD->setBundleLockState(MCSectionData::NotBundleLocked);
613+
614+
// FIXME: Use more separate fragments for nested groups.
615+
if (!SD->isBundleLocked()) {
616+
mergeFragment(getOrCreateDataFragment(), DF);
617+
BundleGroups.pop_back();
618+
delete DF;
619+
}
620+
621+
if (SD->getBundleLockState() != MCSectionData::BundleLockedAlignToEnd)
622+
getOrCreateDataFragment()->setAlignToBundleEnd(false);
623+
} else
624+
SD->setBundleLockState(MCSectionData::NotBundleLocked);
539625
}
540626

541627
void MCELFStreamer::Flush() {

lib/MC/MCObjectStreamer.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ MCObjectStreamer::~MCObjectStreamer() {
4242
delete Assembler;
4343
}
4444

45-
void MCObjectStreamer::flushPendingLabels(MCFragment *F) {
45+
void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
4646
if (PendingLabels.size()) {
4747
if (!F) {
4848
F = new MCDataFragment();
@@ -51,7 +51,7 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F) {
5151
}
5252
for (MCSymbolData *SD : PendingLabels) {
5353
SD->setFragment(F);
54-
SD->setOffset(0);
54+
SD->setOffset(FOffset);
5555
}
5656
PendingLabels.clear();
5757
}
@@ -92,7 +92,8 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() {
9292
MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
9393
// When bundling is enabled, we don't want to add data to a fragment that
9494
// already has instructions (see MCELFStreamer::EmitInstToData for details)
95-
if (!F || (Assembler->isBundlingEnabled() && F->hasInstructions())) {
95+
if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() &&
96+
F->hasInstructions())) {
9697
F = new MCDataFragment();
9798
insert(F);
9899
}
@@ -148,7 +149,9 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol) {
148149
// If there is a current fragment, mark the symbol as pointing into it.
149150
// Otherwise queue the label and set its fragment pointer when we emit the
150151
// next fragment.
151-
if (auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment())) {
152+
auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
153+
if (F && !(getAssembler().isBundlingEnabled() &&
154+
getAssembler().getRelaxAll())) {
152155
SD.setFragment(F);
153156
SD.setOffset(F->getContents().size());
154157
} else {
@@ -247,6 +250,9 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst,
247250

248251
void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst,
249252
const MCSubtargetInfo &STI) {
253+
if (getAssembler().getRelaxAll() && getAssembler().isBundlingEnabled())
254+
llvm_unreachable("All instructions should have already been relaxed");
255+
250256
// Always create a new, separate fragment here, because its size can change
251257
// during relaxation.
252258
MCRelaxableFragment *IF = new MCRelaxableFragment(Inst, STI);

test/MC/X86/AlignedBundling/bundle-group-too-large-error.s

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - 2>&1 | FileCheck %s
2+
# RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu -mc-relax-all %s -o - 2>&1 | FileCheck %s
23

34
# CHECK: ERROR: Fragment can't be larger than a bundle size
45

test/MC/X86/AlignedBundling/different-sections.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - \
22
# RUN: | llvm-objdump -disassemble -no-show-raw-insn - | FileCheck %s
3+
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu -mc-relax-all %s -o - \
4+
# RUN: | llvm-objdump -disassemble -no-show-raw-insn - | FileCheck %s
35

46
# Test two different executable sections with bundling.
57

test/MC/X86/AlignedBundling/labeloffset.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# RUN: llvm-mc -triple=i686-linux -filetype=obj %s -o - | \
22
# RUN: llvm-objdump -disassemble -no-show-raw-insn -r - | FileCheck %s
33
# RUN: llvm-mc -triple=i686-nacl -filetype=obj %s -o - | \
4+
# RUN: llvm-objdump -disassemble -no-show-raw-insn -r - | FileCheck %s
5+
# RUN: llvm-mc -triple=i686-nacl -filetype=obj -mc-relax-all %s -o - | \
46
# RUN: llvm-objdump -disassemble -no-show-raw-insn -r - | FileCheck %s
57

68
.bundle_align_mode 5

test/MC/X86/AlignedBundling/long-nop-pad.s

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - \
22
# RUN: | llvm-objdump -disassemble -no-show-raw-insn - | FileCheck %s
3+
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu -mc-relax-all %s -o - \
4+
# RUN: | llvm-objdump -disassemble -no-show-raw-insn - | FileCheck %s
35

46
# Test that long nops are generated for padding where possible.
57

0 commit comments

Comments
 (0)