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:
Eli Bendersky 2012-12-20 19:05:53 +00:00
parent 2705333253
commit f483ff9204
12 changed files with 393 additions and 19 deletions

View File

@ -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);

View File

@ -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
/// @{

View File

@ -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 {

View File

@ -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,

View File

@ -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.

View File

@ -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.

View File

@ -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();

View File

@ -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);

View File

@ -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) {

View File

@ -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,

View File

@ -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) {

View File

@ -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() {}