mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-12 06:06:32 +00:00
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
This commit is contained in:
parent
5d3cfa6d1f
commit
4766ef41b3
@ -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);
|
||||
|
||||
|
@ -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
|
||||
/// @{
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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() {}
|
||||
|
Loading…
Reference in New Issue
Block a user