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. llvm-svn: 170718
This commit is contained in:
@@ -49,6 +49,11 @@ private:
|
|||||||
/// \brief Is the layout for this fragment valid?
|
/// \brief Is the layout for this fragment valid?
|
||||||
bool isFragmentValid(const MCFragment *F) const;
|
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:
|
public:
|
||||||
MCAsmLayout(MCAssembler &_Assembler);
|
MCAsmLayout(MCAssembler &_Assembler);
|
||||||
|
|
||||||
|
|||||||
@@ -99,14 +99,35 @@ public:
|
|||||||
unsigned getLayoutOrder() const { return LayoutOrder; }
|
unsigned getLayoutOrder() const { return LayoutOrder; }
|
||||||
void setLayoutOrder(unsigned Value) { LayoutOrder = Value; }
|
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();
|
void dump();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MCEncodedFragment : public MCFragment {
|
class MCEncodedFragment : public MCFragment {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
|
|
||||||
|
uint8_t BundlePadding;
|
||||||
public:
|
public:
|
||||||
MCEncodedFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0)
|
MCEncodedFragment(MCFragment::FragmentType FType, MCSectionData *SD = 0)
|
||||||
: MCFragment(FType, SD) {
|
: MCFragment(FType, SD), BundlePadding(0)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
virtual ~MCEncodedFragment();
|
virtual ~MCEncodedFragment();
|
||||||
|
|
||||||
@@ -124,6 +145,14 @@ public:
|
|||||||
virtual fixup_iterator fixup_end() = 0;
|
virtual fixup_iterator fixup_end() = 0;
|
||||||
virtual const_fixup_iterator fixup_end() const = 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) {
|
static bool classof(const MCFragment *F) {
|
||||||
MCFragment::FragmentType Kind = F->getKind();
|
MCFragment::FragmentType Kind = F->getKind();
|
||||||
return Kind == MCFragment::FT_Inst || Kind == MCFragment::FT_Data;
|
return Kind == MCFragment::FT_Inst || Kind == MCFragment::FT_Data;
|
||||||
@@ -132,14 +161,19 @@ public:
|
|||||||
|
|
||||||
class MCDataFragment : public MCEncodedFragment {
|
class MCDataFragment : public MCEncodedFragment {
|
||||||
virtual void anchor();
|
virtual void anchor();
|
||||||
|
|
||||||
|
/// \brief Does this fragment contain encoded instructions anywhere in it?
|
||||||
|
bool HasInstructions;
|
||||||
|
|
||||||
SmallVector<char, 32> Contents;
|
SmallVector<char, 32> Contents;
|
||||||
|
|
||||||
/// Fixups - The list of fixups in this fragment.
|
/// Fixups - The list of fixups in this fragment.
|
||||||
SmallVector<MCFixup, 4> Fixups;
|
SmallVector<MCFixup, 4> Fixups;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MCDataFragment(MCSectionData *SD = 0)
|
MCDataFragment(MCSectionData *SD = 0)
|
||||||
: MCEncodedFragment(FT_Data, SD) {
|
: MCEncodedFragment(FT_Data, SD),
|
||||||
|
HasInstructions(false)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual SmallVectorImpl<char> &getContents() { return Contents; }
|
virtual SmallVectorImpl<char> &getContents() { return Contents; }
|
||||||
@@ -153,6 +187,9 @@ public:
|
|||||||
return Fixups;
|
return Fixups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool hasInstructions() const { return HasInstructions; }
|
||||||
|
virtual void setHasInstructions(bool V) { HasInstructions = V; }
|
||||||
|
|
||||||
fixup_iterator fixup_begin() { return Fixups.begin(); }
|
fixup_iterator fixup_begin() { return Fixups.begin(); }
|
||||||
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
|
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
|
||||||
|
|
||||||
@@ -196,6 +233,8 @@ public:
|
|||||||
return Fixups;
|
return Fixups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool hasInstructions() const { return true; }
|
||||||
|
|
||||||
fixup_iterator fixup_begin() { return Fixups.begin(); }
|
fixup_iterator fixup_begin() { return Fixups.begin(); }
|
||||||
const_fixup_iterator fixup_begin() const { 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.
|
/// Alignment - The maximum alignment seen in this section.
|
||||||
unsigned Alignment;
|
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
|
/// @name Assembler Backend Data
|
||||||
/// @{
|
/// @{
|
||||||
//
|
//
|
||||||
@@ -502,6 +548,22 @@ public:
|
|||||||
|
|
||||||
bool empty() const { return Fragments.empty(); }
|
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();
|
void dump();
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
@@ -707,6 +769,11 @@ private:
|
|||||||
// refactoring too.
|
// refactoring too.
|
||||||
SmallPtrSet<const MCSymbol*, 64> ThumbFuncs;
|
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 RelaxAll : 1;
|
||||||
unsigned NoExecStack : 1;
|
unsigned NoExecStack : 1;
|
||||||
unsigned SubsectionsViaSymbols : 1;
|
unsigned SubsectionsViaSymbols : 1;
|
||||||
@@ -833,6 +900,20 @@ public:
|
|||||||
bool getNoExecStack() const { return NoExecStack; }
|
bool getNoExecStack() const { return NoExecStack; }
|
||||||
void setNoExecStack(bool Value) { NoExecStack = Value; }
|
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
|
/// @name Section List Access
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ public:
|
|||||||
|
|
||||||
virtual void EmitTCEntry(const MCSymbol &S);
|
virtual void EmitTCEntry(const MCSymbol &S);
|
||||||
|
|
||||||
|
virtual void EmitValueToAlignment(unsigned, int64_t, unsigned, unsigned);
|
||||||
|
|
||||||
virtual void FinishImpl();
|
virtual void FinishImpl();
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
@@ -83,6 +85,10 @@ private:
|
|||||||
virtual void EmitInstToFragment(const MCInst &Inst);
|
virtual void EmitInstToFragment(const MCInst &Inst);
|
||||||
virtual void EmitInstToData(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);
|
void fixSymbolsInTLSFixups(const MCExpr *expr);
|
||||||
|
|
||||||
struct LocalCommon {
|
struct LocalCommon {
|
||||||
|
|||||||
@@ -78,7 +78,14 @@ public:
|
|||||||
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
|
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
|
||||||
virtual void ChangeSection(const MCSection *Section);
|
virtual void ChangeSection(const MCSection *Section);
|
||||||
virtual void EmitInstruction(const MCInst &Inst);
|
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 EmitInstToFragment(const MCInst &Inst);
|
||||||
|
|
||||||
|
virtual void EmitBundleAlignMode(unsigned AlignPow2);
|
||||||
|
virtual void EmitBundleLock();
|
||||||
|
virtual void EmitBundleUnlock();
|
||||||
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
|
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
|
||||||
virtual void EmitValueToAlignment(unsigned ByteAlignment,
|
virtual void EmitValueToAlignment(unsigned ByteAlignment,
|
||||||
int64_t Value = 0,
|
int64_t Value = 0,
|
||||||
|
|||||||
@@ -437,7 +437,6 @@ namespace llvm {
|
|||||||
EmitFill(NumBytes, 0, AddrSpace);
|
EmitFill(NumBytes, 0, AddrSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// EmitValueToAlignment - Emit some number of copies of @p Value until
|
/// EmitValueToAlignment - Emit some number of copies of @p Value until
|
||||||
/// the byte alignment @p ByteAlignment is reached.
|
/// the byte alignment @p ByteAlignment is reached.
|
||||||
///
|
///
|
||||||
@@ -557,6 +556,17 @@ namespace llvm {
|
|||||||
/// section.
|
/// section.
|
||||||
virtual void EmitInstruction(const MCInst &Inst) = 0;
|
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
|
/// EmitRawText - If this file is backed by a assembly streamer, this dumps
|
||||||
/// the specified string in the output .s file. This capability is
|
/// the specified string in the output .s file. This capability is
|
||||||
/// indicated by the hasRawTextSupport() predicate. By default this aborts.
|
/// indicated by the hasRawTextSupport() predicate. By default this aborts.
|
||||||
|
|||||||
@@ -259,6 +259,10 @@ public:
|
|||||||
|
|
||||||
virtual void EmitInstruction(const MCInst &Inst);
|
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
|
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
|
||||||
/// the specified string in the output .s file. This capability is
|
/// the specified string in the output .s file. This capability is
|
||||||
/// indicated by the hasRawTextSupport() predicate.
|
/// indicated by the hasRawTextSupport() predicate.
|
||||||
@@ -1361,6 +1365,21 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
|
|||||||
EmitEOL();
|
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
|
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
|
||||||
/// the specified string in the output .s file. This capability is
|
/// the specified string in the output .s file. This capability is
|
||||||
/// indicated by the hasRawTextSupport() predicate.
|
/// indicated by the hasRawTextSupport() predicate.
|
||||||
|
|||||||
@@ -160,6 +160,22 @@ uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const {
|
|||||||
return getSectionAddressSize(SD);
|
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)) {
|
MCFragment::MCFragment() : Kind(FragmentType(~0)) {
|
||||||
@@ -188,6 +204,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
|
|||||||
: Section(&_Section),
|
: Section(&_Section),
|
||||||
Ordinal(~UINT32_C(0)),
|
Ordinal(~UINT32_C(0)),
|
||||||
Alignment(1),
|
Alignment(1),
|
||||||
|
BundleLocked(false), BundleGroupBeforeFirstInst(false),
|
||||||
HasInstructions(false)
|
HasInstructions(false)
|
||||||
{
|
{
|
||||||
if (A)
|
if (A)
|
||||||
@@ -406,12 +423,42 @@ void MCAsmLayout::layoutFragment(MCFragment *F) {
|
|||||||
++stats::FragmentLayouts;
|
++stats::FragmentLayouts;
|
||||||
|
|
||||||
// Compute fragment offset and size.
|
// Compute fragment offset and size.
|
||||||
uint64_t Offset = 0;
|
|
||||||
if (Prev)
|
if (Prev)
|
||||||
Offset += Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
|
F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
|
||||||
|
else
|
||||||
F->Offset = Offset;
|
F->Offset = 0;
|
||||||
LastValidFragment[F->getParent()] = F;
|
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
|
/// \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,
|
static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
|
||||||
const MCFragment &F) {
|
const MCFragment &F) {
|
||||||
MCObjectWriter *OW = &Asm.getWriter();
|
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();
|
uint64_t Start = OW->getStream().tell();
|
||||||
(void) Start;
|
(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,
|
void MCAssembler::writeSectionData(const MCSectionData *SD,
|
||||||
@@ -875,7 +939,9 @@ void MCFragment::dump() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder
|
OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder
|
||||||
<< " Offset:" << Offset << ">";
|
<< " Offset:" << Offset
|
||||||
|
<< " HasInstructions:" << hasInstructions()
|
||||||
|
<< " BundlePadding:" << getBundlePadding() << ">";
|
||||||
|
|
||||||
switch (getKind()) {
|
switch (getKind()) {
|
||||||
case MCFragment::FT_Align: {
|
case MCFragment::FT_Align: {
|
||||||
@@ -957,7 +1023,8 @@ void MCSectionData::dump() {
|
|||||||
raw_ostream &OS = llvm::errs();
|
raw_ostream &OS = llvm::errs();
|
||||||
|
|
||||||
OS << "<MCSectionData";
|
OS << "<MCSectionData";
|
||||||
OS << " Alignment:" << getAlignment() << " Fragments:[\n ";
|
OS << " Alignment:" << getAlignment()
|
||||||
|
<< " Fragments:[\n ";
|
||||||
for (iterator it = begin(), ie = end(); it != ie; ++it) {
|
for (iterator it = begin(), ie = end(); it != ie; ++it) {
|
||||||
if (it != begin()) OS << ",\n ";
|
if (it != begin()) OS << ",\n ";
|
||||||
it->dump();
|
it->dump();
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MCELFStreamer::ChangeSection(const MCSection *Section) {
|
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();
|
const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup();
|
||||||
if (Grp)
|
if (Grp)
|
||||||
getAssembler().getOrCreateSymbolData(*Grp);
|
getAssembler().getOrCreateSymbolData(*Grp);
|
||||||
@@ -262,10 +265,22 @@ void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
|
|||||||
|
|
||||||
void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
|
void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
|
||||||
unsigned AddrSpace) {
|
unsigned AddrSpace) {
|
||||||
|
if (getCurrentSectionData()->isBundleLocked())
|
||||||
|
report_fatal_error("Emitting values inside a locked bundle is forbidden");
|
||||||
fixSymbolsInTLSFixups(Value);
|
fixSymbolsInTLSFixups(Value);
|
||||||
MCObjectStreamer::EmitValueImpl(Value, Size, AddrSpace);
|
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
|
// 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).
|
// 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) {
|
void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
|
||||||
MCDataFragment *DF = getOrCreateDataFragment();
|
MCAssembler &Assembler = getAssembler();
|
||||||
|
|
||||||
SmallVector<MCFixup, 4> Fixups;
|
SmallVector<MCFixup, 4> Fixups;
|
||||||
SmallString<256> Code;
|
SmallString<256> Code;
|
||||||
raw_svector_ostream VecOS(Code);
|
raw_svector_ostream VecOS(Code);
|
||||||
getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
|
Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
|
||||||
VecOS.flush();
|
VecOS.flush();
|
||||||
|
|
||||||
for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
|
for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
|
||||||
fixSymbolsInTLSFixups(Fixups[i].getValue());
|
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.
|
// Add the fixups and data.
|
||||||
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
|
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
|
||||||
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
||||||
DF->getFixups().push_back(Fixups[i]);
|
DF->getFixups().push_back(Fixups[i]);
|
||||||
}
|
}
|
||||||
|
DF->setHasInstructions(true);
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
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() {
|
void MCELFStreamer::FinishImpl() {
|
||||||
EmitFrames(true);
|
EmitFrames(true);
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,10 @@ namespace {
|
|||||||
StringRef FileName) {}
|
StringRef FileName) {}
|
||||||
virtual void EmitInstruction(const MCInst &Inst) {}
|
virtual void EmitInstruction(const MCInst &Inst) {}
|
||||||
|
|
||||||
|
virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
|
||||||
|
virtual void EmitBundleLock() {}
|
||||||
|
virtual void EmitBundleUnlock() {}
|
||||||
|
|
||||||
virtual void FinishImpl() {}
|
virtual void FinishImpl() {}
|
||||||
|
|
||||||
virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
|
virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
|
||||||
|
|||||||
@@ -180,21 +180,27 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) {
|
|||||||
if (Inst.getOperand(i).isExpr())
|
if (Inst.getOperand(i).isExpr())
|
||||||
AddValueSymbols(Inst.getOperand(i).getExpr());
|
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
|
// Now that a machine instruction has been assembled into this section, make
|
||||||
// a line entry for any .loc directive that has been seen.
|
// a line entry for any .loc directive that has been seen.
|
||||||
MCLineEntry::Make(this, getCurrentSection());
|
MCLineEntry::Make(this, getCurrentSection());
|
||||||
|
|
||||||
// If this instruction doesn't need relaxation, just emit it as data.
|
// 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);
|
EmitInstToData(Inst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, if we are relaxing everything, relax the instruction as much as
|
// Otherwise, relax and emit it as data if either:
|
||||||
// possible and emit it as data.
|
// - The RelaxAll flag was passed
|
||||||
if (getAssembler().getRelaxAll()) {
|
// - 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;
|
MCInst Relaxed;
|
||||||
getAssembler().getBackend().relaxInstruction(Inst, Relaxed);
|
getAssembler().getBackend().relaxInstruction(Inst, Relaxed);
|
||||||
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
|
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
|
||||||
@@ -208,6 +214,8 @@ void MCObjectStreamer::EmitInstruction(const MCInst &Inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MCObjectStreamer::EmitInstToFragment(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());
|
MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData());
|
||||||
|
|
||||||
SmallString<128> Code;
|
SmallString<128> Code;
|
||||||
@@ -217,6 +225,21 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) {
|
|||||||
IF->getContents().append(Code.begin(), Code.end());
|
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,
|
void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
|
||||||
const MCSymbol *LastLabel,
|
const MCSymbol *LastLabel,
|
||||||
const MCSymbol *Label,
|
const MCSymbol *Label,
|
||||||
|
|||||||
@@ -305,6 +305,13 @@ private:
|
|||||||
// ".align{,32}", ".p2align{,w,l}"
|
// ".align{,32}", ".p2align{,w,l}"
|
||||||
bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize);
|
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
|
/// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which
|
||||||
/// accepts a single symbol (which should be a label or an external).
|
/// accepts a single symbol (which should be a label or an external).
|
||||||
bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr);
|
bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr);
|
||||||
@@ -1304,6 +1311,13 @@ bool AsmParser::ParseStatement(ParseStatementInfo &Info) {
|
|||||||
if (IDVal == ".p2alignl")
|
if (IDVal == ".p2alignl")
|
||||||
return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
|
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")
|
if (IDVal == ".org")
|
||||||
return ParseDirectiveOrg();
|
return ParseDirectiveOrg();
|
||||||
|
|
||||||
@@ -2429,6 +2443,59 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
|
|||||||
return false;
|
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
|
/// ParseDirectiveSymbolAttribute
|
||||||
/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
|
/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
|
||||||
bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
|
bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
|
||||||
|
|||||||
@@ -765,6 +765,10 @@ namespace {
|
|||||||
markDefined(*Symbol);
|
markDefined(*Symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
|
||||||
|
virtual void EmitBundleLock() {}
|
||||||
|
virtual void EmitBundleUnlock() {}
|
||||||
|
|
||||||
// Noop calls.
|
// Noop calls.
|
||||||
virtual void ChangeSection(const MCSection *Section) {}
|
virtual void ChangeSection(const MCSection *Section) {}
|
||||||
virtual void InitSections() {}
|
virtual void InitSections() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user