aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@google.com>2012-12-20 19:05:53 +0000
committerEli Bendersky <eliben@google.com>2012-12-20 19:05:53 +0000
commit4766ef41b31e4f97bce1179c3b0398303bf65356 (patch)
tree9c7d834025eea913e5887165099d31af8464cfe0
parent5d3cfa6d1f6d3069893d50af39511cbf5576be91 (diff)
Aligned bundling support. Following the discussion here:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-December/056754.html The proposal and implementation are fully documented here: https://sites.google.com/a/chromium.org/dev/nativeclient/pnacl/aligned-bundling-support-in-llvm Tests will follow shortly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@170718 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/MC/MCAsmLayout.h5
-rw-r--r--include/llvm/MC/MCAssembler.h87
-rw-r--r--include/llvm/MC/MCELFStreamer.h6
-rw-r--r--include/llvm/MC/MCObjectStreamer.h7
-rw-r--r--include/llvm/MC/MCStreamer.h12
-rw-r--r--lib/MC/MCAsmStreamer.cpp19
-rw-r--r--lib/MC/MCAssembler.cpp81
-rw-r--r--lib/MC/MCELFStreamer.cpp87
-rw-r--r--lib/MC/MCNullStreamer.cpp4
-rw-r--r--lib/MC/MCObjectStreamer.cpp33
-rw-r--r--lib/MC/MCParser/AsmParser.cpp67
-rw-r--r--tools/lto/LTOModule.cpp4
12 files changed, 393 insertions, 19 deletions
diff --git a/include/llvm/MC/MCAsmLayout.h b/include/llvm/MC/MCAsmLayout.h
index 267e3a57f5..8cb4601283 100644
--- a/include/llvm/MC/MCAsmLayout.h
+++ b/include/llvm/MC/MCAsmLayout.h
@@ -49,6 +49,11 @@ private:
/// \brief Is the layout for this fragment valid?
bool isFragmentValid(const MCFragment *F) const;
+ /// \brief Compute the amount of padding required before this fragment to
+ /// obey bundling restrictions.
+ uint64_t computeBundlePadding(const MCFragment *F,
+ uint64_t FOffset, uint64_t FSize);
+
public:
MCAsmLayout(MCAssembler &_Assembler);
diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h
index 8dba3b9c09..6c2fdc5396 100644
--- a/include/llvm/MC/MCAssembler.h
+++ b/include/llvm/MC/MCAssembler.h
@@ -99,14 +99,35 @@ public:
unsigned getLayoutOrder() const { return LayoutOrder; }
void setLayoutOrder(unsigned Value) { LayoutOrder = Value; }
+ /// \brief Does this fragment have instructions emitted into it? By default
+ /// this is false, but specific fragment types may set it to true.
+ virtual bool hasInstructions() const { return false; }
+
+ /// \brief Get the padding size that must be inserted before this fragment.
+ /// Used for bundling. By default, no padding is inserted.
+ /// Note that padding size is restricted to 8 bits. This is an optimization
+ /// to reduce the amount of space used for each fragment. In practice, larger
+ /// padding should never be required.
+ virtual uint8_t getBundlePadding() const {
+ return 0;
+ }
+
+ /// \brief Set the padding size for this fragment. By default it's a no-op,
+ /// and only some fragments have a meaningful implementation.
+ virtual void setBundlePadding(uint8_t N) {
+ }
+
void dump();
};
class MCEncodedFragment : public MCFragment {
virtual void anchor();
+
+ uint8_t BundlePadding;
public:
MCEncodedFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0)
- : MCFragment(FType, SD) {
+ : MCFragment(FType, SD), BundlePadding(0)
+ {
}
virtual ~MCEncodedFragment();
@@ -124,6 +145,14 @@ public:
virtual fixup_iterator fixup_end() = 0;
virtual const_fixup_iterator fixup_end() const = 0;
+ virtual uint8_t getBundlePadding() const {
+ return BundlePadding;
+ }
+
+ virtual void setBundlePadding(uint8_t N) {
+ BundlePadding = N;
+ }
+
static bool classof(const MCFragment *F) {
MCFragment::FragmentType Kind = F->getKind();
return Kind == MCFragment::FT_Inst || Kind == MCFragment::FT_Data;
@@ -132,14 +161,19 @@ public:
class MCDataFragment : public MCEncodedFragment {
virtual void anchor();
+
+ /// \brief Does this fragment contain encoded instructions anywhere in it?
+ bool HasInstructions;
+
SmallVector<char, 32> Contents;
/// Fixups - The list of fixups in this fragment.
SmallVector<MCFixup, 4> Fixups;
-
public:
MCDataFragment(MCSectionData *SD = 0)
- : MCEncodedFragment(FT_Data, SD) {
+ : MCEncodedFragment(FT_Data, SD),
+ HasInstructions(false)
+ {
}
virtual SmallVectorImpl<char> &getContents() { return Contents; }
@@ -153,6 +187,9 @@ public:
return Fixups;
}
+ virtual bool hasInstructions() const { return HasInstructions; }
+ virtual void setHasInstructions(bool V) { HasInstructions = V; }
+
fixup_iterator fixup_begin() { return Fixups.begin(); }
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
@@ -196,6 +233,8 @@ public:
return Fixups;
}
+ virtual bool hasInstructions() const { return true; }
+
fixup_iterator fixup_begin() { return Fixups.begin(); }
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
@@ -450,6 +489,13 @@ private:
/// Alignment - The maximum alignment seen in this section.
unsigned Alignment;
+ /// \brief We're currently inside a bundle-locked group.
+ bool BundleLocked;
+
+ /// \brief We've seen a bundle_lock directive but not its first instruction
+ /// yet.
+ bool BundleGroupBeforeFirstInst;
+
/// @name Assembler Backend Data
/// @{
//
@@ -502,6 +548,22 @@ public:
bool empty() const { return Fragments.empty(); }
+ bool isBundleLocked() const {
+ return BundleLocked;
+ }
+
+ void setBundleLocked(bool IsLocked) {
+ BundleLocked = IsLocked;
+ }
+
+ bool isBundleGroupBeforeFirstInst() const {
+ return BundleGroupBeforeFirstInst;
+ }
+
+ void setBundleGroupBeforeFirstInst(bool IsFirst) {
+ BundleGroupBeforeFirstInst = IsFirst;
+ }
+
void dump();
/// @}
@@ -707,6 +769,11 @@ private:
// refactoring too.
SmallPtrSet<const MCSymbol*, 64> ThumbFuncs;
+ /// \brief The bundle alignment size currently set in the assembler.
+ ///
+ /// By default it's 0, which means bundling is disabled.
+ unsigned BundleAlignSize;
+
unsigned RelaxAll : 1;
unsigned NoExecStack : 1;
unsigned SubsectionsViaSymbols : 1;
@@ -833,6 +900,20 @@ public:
bool getNoExecStack() const { return NoExecStack; }
void setNoExecStack(bool Value) { NoExecStack = Value; }
+ bool isBundlingEnabled() const {
+ return BundleAlignSize != 0;
+ }
+
+ unsigned getBundleAlignSize() const {
+ return BundleAlignSize;
+ }
+
+ void setBundleAlignSize(unsigned Size) {
+ assert((Size == 0 || !(Size & (Size - 1))) &&
+ "Expect a power-of-two bundle align size");
+ BundleAlignSize = Size;
+ }
+
/// @name Section List Access
/// @{
diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h
index 03a57c7ee3..6608d96e4b 100644
--- a/include/llvm/MC/MCELFStreamer.h
+++ b/include/llvm/MC/MCELFStreamer.h
@@ -76,6 +76,8 @@ public:
virtual void EmitTCEntry(const MCSymbol &S);
+ virtual void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned);
+
virtual void FinishImpl();
/// @}
@@ -83,6 +85,10 @@ private:
virtual void EmitInstToFragment(const MCInst &Inst);
virtual void EmitInstToData(const MCInst &Inst);
+ virtual void EmitBundleAlignMode(unsigned AlignPow2);
+ virtual void EmitBundleLock();
+ virtual void EmitBundleUnlock();
+
void fixSymbolsInTLSFixups(const MCExpr *expr);
struct LocalCommon {
diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h
index df98fea41c..4bc24d48c7 100644
--- a/include/llvm/MC/MCObjectStreamer.h
+++ b/include/llvm/MC/MCObjectStreamer.h
@@ -78,7 +78,14 @@ public:
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
virtual void ChangeSection(const MCSection *Section);
virtual void EmitInstruction(const MCInst &Inst);
+
+ /// \brief Emit an instruction to a special fragment, because this instruction
+ /// can change its size during relaxation.
virtual void EmitInstToFragment(const MCInst &Inst);
+
+ virtual void EmitBundleAlignMode(unsigned AlignPow2);
+ virtual void EmitBundleLock();
+ virtual void EmitBundleUnlock();
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
virtual void EmitValueToAlignment(unsigned ByteAlignment,
int64_t Value = 0,
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index ecf5e78b5e..8be46b5f1b 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -437,7 +437,6 @@ namespace llvm {
EmitFill(NumBytes, 0, AddrSpace);
}
-
/// EmitValueToAlignment - Emit some number of copies of @p Value until
/// the byte alignment @p ByteAlignment is reached.
///
@@ -557,6 +556,17 @@ namespace llvm {
/// section.
virtual void EmitInstruction(const MCInst &Inst) = 0;
+ /// \brief Set the bundle alignment mode from now on in the section.
+ /// The argument is the power of 2 to which the alignment is set. The
+ /// value 0 means turn the bundle alignment off.
+ virtual void EmitBundleAlignMode(unsigned AlignPow2) = 0;
+
+ /// \brief The following instructions are a bundle-locked group.
+ virtual void EmitBundleLock() = 0;
+
+ /// \brief Ends a bundle-locked group.
+ virtual void EmitBundleUnlock() = 0;
+
/// EmitRawText - If this file is backed by a assembly streamer, this dumps
/// the specified string in the output .s file. This capability is
/// indicated by the hasRawTextSupport() predicate. By default this aborts.
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 6302f970d8..9b7074d3b2 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -259,6 +259,10 @@ public:
virtual void EmitInstruction(const MCInst &Inst);
+ virtual void EmitBundleAlignMode(unsigned AlignPow2);
+ virtual void EmitBundleLock();
+ virtual void EmitBundleUnlock();
+
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
/// the specified string in the output .s file. This capability is
/// indicated by the hasRawTextSupport() predicate.
@@ -1361,6 +1365,21 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
EmitEOL();
}
+void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
+ OS << "\t.bundle_align_mode " << AlignPow2;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBundleLock() {
+ OS << "\t.bundle_lock";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBundleUnlock() {
+ OS << "\t.bundle_unlock";
+ EmitEOL();
+}
+
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
/// the specified string in the output .s file. This capability is
/// indicated by the hasRawTextSupport() predicate.
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 2558eff045..f4c3fc55d3 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -160,6 +160,22 @@ uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const {
return getSectionAddressSize(SD);
}
+uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *F,
+ uint64_t FOffset, uint64_t FSize) {
+ uint64_t BundleSize = Assembler.getBundleAlignSize();
+ assert(BundleSize > 0 &&
+ "computeBundlePadding should only be called if bundling is enabled");
+ uint64_t BundleMask = BundleSize - 1;
+ uint64_t OffsetInBundle = FOffset & BundleMask;
+
+ // If the fragment would cross a bundle boundary, add enough padding until
+ // the end of the current bundle.
+ if (OffsetInBundle + FSize > BundleSize)
+ return BundleSize - OffsetInBundle;
+ else
+ return 0;
+}
+
/* *** */
MCFragment::MCFragment() : Kind(FragmentType(~0)) {
@@ -188,6 +204,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(&_Section),
Ordinal(~UINT32_C(0)),
Alignment(1),
+ BundleLocked(false), BundleGroupBeforeFirstInst(false),
HasInstructions(false)
{
if (A)
@@ -406,12 +423,42 @@ void MCAsmLayout::layoutFragment(MCFragment *F) {
++stats::FragmentLayouts;
// Compute fragment offset and size.
- uint64_t Offset = 0;
if (Prev)
- Offset += Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
-
- F->Offset = Offset;
+ F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
+ else
+ F->Offset = 0;
LastValidFragment[F->getParent()] = F;
+
+ // If bundling is enabled and this fragment has instructions in it, it has to
+ // obey the bundling restrictions. With padding, we'll have:
+ //
+ //
+ // BundlePadding
+ // |||
+ // -------------------------------------
+ // Prev |##########| F |
+ // -------------------------------------
+ // ^
+ // |
+ // F->Offset
+ //
+ // The fragment's offset will point to after the padding, and its computed
+ // size won't include the padding.
+ //
+ if (Assembler.isBundlingEnabled() && F->hasInstructions()) {
+ assert(isa<MCEncodedFragment>(F) &&
+ "Only MCEncodedFragment implementations have instructions");
+ uint64_t FSize = Assembler.computeFragmentSize(*this, *F);
+
+ if (FSize > Assembler.getBundleAlignSize())
+ report_fatal_error("Fragment can't be larger than a bundle size");
+
+ uint64_t RequiredBundlePadding = computeBundlePadding(F, F->Offset, FSize);
+ if (RequiredBundlePadding > UINT8_MAX)
+ report_fatal_error("Padding cannot exceed 255 bytes");
+ F->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
+ F->Offset += RequiredBundlePadding;
+ }
}
/// \brief Write the contents of a fragment to the given object writer. Expects
@@ -425,6 +472,22 @@ static void writeFragmentContents(const MCFragment &F, MCObjectWriter *OW) {
static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFragment &F) {
MCObjectWriter *OW = &Asm.getWriter();
+
+ // Should NOP padding be written out before this fragment?
+ unsigned BundlePadding = F.getBundlePadding();
+ if (BundlePadding > 0) {
+ assert(Asm.isBundlingEnabled() &&
+ "Writing bundle padding with disabled bundling");
+ assert(F.hasInstructions() &&
+ "Writing bundle padding for a fragment without instructions");
+
+ if (!Asm.getBackend().writeNopData(BundlePadding, OW))
+ report_fatal_error("unable to write NOP sequence of " +
+ Twine(BundlePadding) + " bytes");
+ }
+
+ // This variable (and its dummy usage) is to participate in the assert at
+ // the end of the function.
uint64_t Start = OW->getStream().tell();
(void) Start;
@@ -529,7 +592,8 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
}
}
- assert(OW->getStream().tell() - Start == FragmentSize);
+ assert(OW->getStream().tell() - Start == FragmentSize &&
+ "The stream should advance by fragment size");
}
void MCAssembler::writeSectionData(const MCSectionData *SD,
@@ -875,7 +939,9 @@ void MCFragment::dump() {
}
OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder
- << " Offset:" << Offset << ">";
+ << " Offset:" << Offset
+ << " HasInstructions:" << hasInstructions()
+ << " BundlePadding:" << getBundlePadding() << ">";
switch (getKind()) {
case MCFragment::FT_Align: {
@@ -957,7 +1023,8 @@ void MCSectionData::dump() {
raw_ostream &OS = llvm::errs();
OS << "<MCSectionData";
- OS << " Alignment:" << getAlignment() << " Fragments:[\n ";
+ OS << " Alignment:" << getAlignment()
+ << " Fragments:[\n ";
for (iterator it = begin(), ie = end(); it != ie; ++it) {
if (it != begin()) OS << ",\n ";
it->dump();
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp
index 9771ef0549..e3acc44a85 100644
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
@@ -105,6 +105,9 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
}
void MCELFStreamer::ChangeSection(const MCSection *Section) {
+ MCSectionData *CurSection = getCurrentSectionData();
+ if (CurSection && CurSection->isBundleLocked())
+ report_fatal_error("Unterminated .bundle_lock when changing a section");
const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup();
if (Grp)
getAssembler().getOrCreateSymbolData(*Grp);
@@ -262,10 +265,22 @@ void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
unsigned AddrSpace) {
+ if (getCurrentSectionData()->isBundleLocked())
+ report_fatal_error("Emitting values inside a locked bundle is forbidden");
fixSymbolsInTLSFixups(Value);
MCObjectStreamer::EmitValueImpl(Value, Size, AddrSpace);
}
+void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment,
+ int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (getCurrentSectionData()->isBundleLocked())
+ report_fatal_error("Emitting values inside a locked bundle is forbidden");
+ MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value,
+ ValueSize, MaxBytesToEmit);
+}
+
// Add a symbol for the file name of this module. This is the second
// entry in the module's symbol table (the first being the null symbol).
@@ -335,25 +350,91 @@ void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) {
}
void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
- MCDataFragment *DF = getOrCreateDataFragment();
-
+ MCAssembler &Assembler = getAssembler();
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
- getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
+ Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
VecOS.flush();
for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
fixSymbolsInTLSFixups(Fixups[i].getValue());
+ // There are several possibilities here:
+ //
+ // If bundling is disabled, append the encoded instruction to the current data
+ // fragment (or create a new such fragment if the current fragment is not a
+ // data fragment).
+ //
+ // If bundling is enabled:
+ // - If we're not in a bundle-locked group, emit the instruction into a data
+ // fragment of its own.
+ // - If we're in a bundle-locked group, append the instruction to the current
+ // data fragment because we want all the instructions in a group to get into
+ // the same fragment. Be careful not to do that for the first instruction in
+ // the group, though.
+ MCDataFragment *DF;
+
+ if (Assembler.isBundlingEnabled()) {
+ MCSectionData *SD = getCurrentSectionData();
+ if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst())
+ DF = getOrCreateDataFragment();
+ else
+ DF = new MCDataFragment(SD);
+
+ // We're now emitting an instruction in a bundle group, so this flag has
+ // to be turned off.
+ SD->setBundleGroupBeforeFirstInst(false);
+ } else {
+ DF = getOrCreateDataFragment();
+ }
+
// Add the fixups and data.
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixups[i]);
}
+ DF->setHasInstructions(true);
DF->getContents().append(Code.begin(), Code.end());
}
+void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
+ assert(AlignPow2 <= 30 && "Invalid bundle alignment");
+ MCAssembler &Assembler = getAssembler();
+ if (Assembler.getBundleAlignSize() == 0 && AlignPow2 > 0)
+ Assembler.setBundleAlignSize(1 << AlignPow2);
+ else
+ report_fatal_error(".bundle_align_mode should be only set once per file");
+}
+
+void MCELFStreamer::EmitBundleLock() {
+ MCSectionData *SD = getCurrentSectionData();
+
+ // Sanity checks
+ //
+ if (!getAssembler().isBundlingEnabled())
+ report_fatal_error(".bundle_lock forbidden when bundling is disabled");
+ else if (SD->isBundleLocked())
+ report_fatal_error("Nesting of .bundle_lock is forbidden");
+
+ SD->setBundleLocked(true);
+ SD->setBundleGroupBeforeFirstInst(true);
+}
+
+void MCELFStreamer::EmitBundleUnlock() {
+ MCSectionData *SD = getCurrentSectionData();
+
+ // Sanity checks
+ if (!getAssembler().isBundlingEnabled())
+ report_fatal_error(".bundle_unlock forbidden when bundling is disabled");
+ else if (!SD->isBundleLocked())
+ report_fatal_error(".bundle_unlock without matching lock");
+ else if (SD->isBundleGroupBeforeFirstInst())
+ report_fatal_error("Empty bundle-locked group is forbidden");
+
+ SD->setBundleLocked(false);
+}
+
void MCELFStreamer::FinishImpl() {
EmitFrames(true);
diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp
index bb84c4f22f..d1cd0064ad 100644
--- a/lib/MC/MCNullStreamer.cpp
+++ b/lib/MC/MCNullStreamer.cpp
@@ -95,6 +95,10 @@ namespace {
StringRef FileName) {}
virtual void EmitInstruction(const MCInst &Inst) {}
+ virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
+ virtual void EmitBundleLock() {}
+ virtual void EmitBundleUnlock() {}
+
virtual void FinishImpl() {}
virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index 4d6900f7c4..e36e181ff5 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/lib/MC/MCObjectStreamer.cpp
@@ -180,21 +180,27 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) {
if (Inst.getOperand(i).isExpr())
AddValueSymbols(Inst.getOperand(i).getExpr());
- getCurrentSectionData()->setHasInstructions(true);
+ MCSectionData *SD = getCurrentSectionData();
+ SD->setHasInstructions(true);
// Now that a machine instruction has been assembled into this section, make
// a line entry for any .loc directive that has been seen.
MCLineEntry::Make(this, getCurrentSection());
// If this instruction doesn't need relaxation, just emit it as data.
- if (!getAssembler().getBackend().mayNeedRelaxation(Inst)) {
+ MCAssembler &Assembler = getAssembler();
+ if (!Assembler.getBackend().mayNeedRelaxation(Inst)) {
EmitInstToData(Inst);
return;
}
- // Otherwise, if we are relaxing everything, relax the instruction as much as
- // possible and emit it as data.
- if (getAssembler().getRelaxAll()) {
+ // Otherwise, relax and emit it as data if either:
+ // - The RelaxAll flag was passed
+ // - Bundling is enabled and this instruction is inside a bundle-locked
+ // group. We want to emit all such instructions into the same data
+ // fragment.
+ if (Assembler.getRelaxAll() ||
+ (Assembler.isBundlingEnabled() && SD->isBundleLocked())) {
MCInst Relaxed;
getAssembler().getBackend().relaxInstruction(Inst, Relaxed);
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
@@ -208,6 +214,8 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) {
}
void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) {
+ // Always create a new, separate fragment here, because its size can change
+ // during relaxation.
MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData());
SmallString<128> Code;
@@ -217,6 +225,21 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) {
IF->getContents().append(Code.begin(), Code.end());
}
+const char *BundlingNotImplementedMsg =
+ "Aligned bundling is not implemented for this object format";
+
+void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
+void MCObjectStreamer::EmitBundleLock() {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
+void MCObjectStreamer::EmitBundleUnlock() {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
const MCSymbol *LastLabel,
const MCSymbol *Label,
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index 85d31872a7..ab1210302d 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -305,6 +305,13 @@ private:
// ".align{,32}", ".p2align{,w,l}"
bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize);
+ // ".bundle_align_mode"
+ bool ParseDirectiveBundleAlignMode();
+ // ".bundle_lock"
+ bool ParseDirectiveBundleLock();
+ // ".bundle_unlock"
+ bool ParseDirectiveBundleUnlock();
+
/// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which
/// accepts a single symbol (which should be a label or an external).
bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr);
@@ -1304,6 +1311,13 @@ bool AsmParser::ParseStatement(ParseStatementInfo &Info) {
if (IDVal == ".p2alignl")
return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
+ if (IDVal == ".bundle_align_mode")
+ return ParseDirectiveBundleAlignMode();
+ if (IDVal == ".bundle_lock")
+ return ParseDirectiveBundleLock();
+ if (IDVal == ".bundle_unlock")
+ return ParseDirectiveBundleUnlock();
+
if (IDVal == ".org")
return ParseDirectiveOrg();
@@ -2429,6 +2443,59 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
return false;
}
+
+/// ParseDirectiveBundleAlignMode
+/// ::= {.bundle_align_mode} expression
+bool AsmParser::ParseDirectiveBundleAlignMode() {
+ CheckForValidSection();
+
+ // Expect a single argument: an expression that evaluates to a constant
+ // in the inclusive range 0-30.
+ SMLoc ExprLoc = getLexer().getLoc();
+ int64_t AlignSizePow2;
+ if (ParseAbsoluteExpression(AlignSizePow2))
+ return true;
+ else if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token after expression in"
+ " '.bundle_align_mode' directive");
+ else if (AlignSizePow2 < 0 || AlignSizePow2 > 30)
+ return Error(ExprLoc,
+ "invalid bundle alignment size (expected between 0 and 30)");
+
+ Lex();
+
+ // Because of AlignSizePow2's verified range we can safely truncate it to
+ // unsigned.
+ getStreamer().EmitBundleAlignMode(static_cast<unsigned>(AlignSizePow2));
+ return false;
+}
+
+/// ParseDirectiveBundleLock
+/// ::= {.bundle_lock}
+bool AsmParser::ParseDirectiveBundleLock() {
+ CheckForValidSection();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.bundle_lock' directive");
+ Lex();
+
+ getStreamer().EmitBundleLock();
+ return false;
+}
+
+/// ParseDirectiveBundleLock
+/// ::= {.bundle_lock}
+bool AsmParser::ParseDirectiveBundleUnlock() {
+ CheckForValidSection();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.bundle_unlock' directive");
+ Lex();
+
+ getStreamer().EmitBundleUnlock();
+ return false;
+}
+
/// ParseDirectiveSymbolAttribute
/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp
index 9d2f9c7848..9b5917de16 100644
--- a/tools/lto/LTOModule.cpp
+++ b/tools/lto/LTOModule.cpp
@@ -765,6 +765,10 @@ namespace {
markDefined(*Symbol);
}
+ virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
+ virtual void EmitBundleLock() {}
+ virtual void EmitBundleUnlock() {}
+
// Noop calls.
virtual void ChangeSection(const MCSection *Section) {}
virtual void InitSections() {}