Add the align_to_end option to .bundle_lock in the MC implementation of aligned

bundling. The document describing this feature and the implementation has also
been updated:

https://sites.google.com/a/chromium.org/dev/nativeclient/pnacl/aligned-bundling-support-in-llvm


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171797 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eli Bendersky 2013-01-07 21:51:08 +00:00
parent d3ae2866d1
commit 6c1d4972cf
13 changed files with 103 additions and 28 deletions

View File

@ -100,9 +100,12 @@ public:
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.
/// this is false, but specific fragment types may set it to true.
virtual bool hasInstructions() const { return false; }
/// \brief Should this fragment be placed at the end of an aligned bundle?
virtual bool alignToBundleEnd() 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
@ -165,6 +168,9 @@ class MCDataFragment : public MCEncodedFragment {
/// \brief Does this fragment contain encoded instructions anywhere in it?
bool HasInstructions;
/// \brief Should this fragment be aligned to the end of a bundle?
bool AlignToBundleEnd;
SmallVector<char, 32> Contents;
/// Fixups - The list of fixups in this fragment.
@ -172,7 +178,7 @@ class MCDataFragment : public MCEncodedFragment {
public:
MCDataFragment(MCSectionData *SD = 0)
: MCEncodedFragment(FT_Data, SD),
HasInstructions(false)
HasInstructions(false), AlignToBundleEnd(false)
{
}
@ -190,6 +196,9 @@ public:
virtual bool hasInstructions() const { return HasInstructions; }
virtual void setHasInstructions(bool V) { HasInstructions = V; }
virtual bool alignToBundleEnd() const { return AlignToBundleEnd; }
virtual void setAlignToBundleEnd(bool V) { AlignToBundleEnd = V; }
fixup_iterator fixup_begin() { return Fixups.begin(); }
const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
@ -476,6 +485,12 @@ public:
typedef FragmentListType::const_reverse_iterator const_reverse_iterator;
typedef FragmentListType::reverse_iterator reverse_iterator;
/// \brief Express the state of bundle locked groups while emitting code.
enum BundleLockStateType {
NotBundleLocked,
BundleLocked,
BundleLockedAlignToEnd
};
private:
FragmentListType Fragments;
const MCSection *Section;
@ -489,8 +504,8 @@ private:
/// Alignment - The maximum alignment seen in this section.
unsigned Alignment;
/// \brief We're currently inside a bundle-locked group.
bool BundleLocked;
/// \brief Keeping track of bundle-locked state.
BundleLockStateType BundleLockState;
/// \brief We've seen a bundle_lock directive but not its first instruction
/// yet.
@ -549,11 +564,15 @@ public:
bool empty() const { return Fragments.empty(); }
bool isBundleLocked() const {
return BundleLocked;
return BundleLockState != NotBundleLocked;
}
void setBundleLocked(bool IsLocked) {
BundleLocked = IsLocked;
BundleLockStateType getBundleLockState() const {
return BundleLockState;
}
void setBundleLockState(BundleLockStateType NewState) {
BundleLockState = NewState;
}
bool isBundleGroupBeforeFirstInst() const {

View File

@ -85,7 +85,7 @@ private:
virtual void EmitInstToData(const MCInst &Inst);
virtual void EmitBundleAlignMode(unsigned AlignPow2);
virtual void EmitBundleLock();
virtual void EmitBundleLock(bool AlignToEnd);
virtual void EmitBundleUnlock();
void fixSymbolsInTLSFixups(const MCExpr *expr);

View File

@ -84,7 +84,7 @@ public:
virtual void EmitInstToFragment(const MCInst &Inst);
virtual void EmitBundleAlignMode(unsigned AlignPow2);
virtual void EmitBundleLock();
virtual void EmitBundleLock(bool AlignToEnd);
virtual void EmitBundleUnlock();
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
virtual void EmitValueToAlignment(unsigned ByteAlignment,

View File

@ -562,7 +562,10 @@ namespace llvm {
virtual void EmitBundleAlignMode(unsigned AlignPow2) = 0;
/// \brief The following instructions are a bundle-locked group.
virtual void EmitBundleLock() = 0;
///
/// \param AlignToEnd - If true, the bundle-locked group will be aligned to
/// the end of a bundle.
virtual void EmitBundleLock(bool AlignToEnd) = 0;
/// \brief Ends a bundle-locked group.
virtual void EmitBundleUnlock() = 0;

View File

@ -260,7 +260,7 @@ public:
virtual void EmitInstruction(const MCInst &Inst);
virtual void EmitBundleAlignMode(unsigned AlignPow2);
virtual void EmitBundleLock();
virtual void EmitBundleLock(bool AlignToEnd);
virtual void EmitBundleUnlock();
/// EmitRawText - If this file is backed by an assembly streamer, this dumps
@ -1370,8 +1370,10 @@ void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
EmitEOL();
}
void MCAsmStreamer::EmitBundleLock() {
void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) {
OS << "\t.bundle_lock";
if (AlignToEnd)
OS << " align_to_end";
EmitEOL();
}

View File

@ -167,10 +167,34 @@ uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *F,
"computeBundlePadding should only be called if bundling is enabled");
uint64_t BundleMask = BundleSize - 1;
uint64_t OffsetInBundle = FOffset & BundleMask;
uint64_t EndOfFragment = OffsetInBundle + FSize;
// If the fragment would cross a bundle boundary, add enough padding until
// the end of the current bundle.
if (OffsetInBundle + FSize > BundleSize)
// There are two kinds of bundling restrictions:
//
// 1) For alignToBundleEnd(), add padding to ensure that the fragment will
// *end* on a bundle boundary.
// 2) Otherwise, check if the fragment would cross a bundle boundary. If it
// would, add padding until the end of the bundle so that the fragment
// will start in a new one.
if (F->alignToBundleEnd()) {
// Three possibilities here:
//
// A) The fragment just happens to end at a bundle boundary, so we're good.
// B) The fragment ends before the current bundle boundary: pad it just
// enough to reach the boundary.
// C) The fragment ends after the current bundle boundary: pad it until it
// reaches the end of the next bundle boundary.
//
// Note: this code could be made shorter with some modulo trickery, but it's
// intentionally kept in its more explicit form for simplicity.
if (EndOfFragment == BundleSize)
return 0;
else if (EndOfFragment < BundleSize)
return BundleSize - EndOfFragment;
else { // EndOfFragment > BundleSize
return 2 * BundleSize - EndOfFragment;
}
} else if (EndOfFragment > BundleSize)
return BundleSize - OffsetInBundle;
else
return 0;
@ -204,7 +228,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(&_Section),
Ordinal(~UINT32_C(0)),
Alignment(1),
BundleLocked(false), BundleGroupBeforeFirstInst(false),
BundleLockState(NotBundleLocked), BundleGroupBeforeFirstInst(false),
HasInstructions(false)
{
if (A)

View File

@ -379,8 +379,14 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
MCSectionData *SD = getCurrentSectionData();
if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst())
DF = getOrCreateDataFragment();
else
else {
DF = new MCDataFragment(SD);
if (SD->getBundleLockState() == MCSectionData::BundleLockedAlignToEnd) {
// If this is a new fragment created for a bundle-locked group, and the
// group was marked as "align_to_end", set a flag in the fragment.
DF->setAlignToBundleEnd(true);
}
}
// We're now emitting an instruction in a bundle group, so this flag has
// to be turned off.
@ -407,7 +413,7 @@ void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
report_fatal_error(".bundle_align_mode should be only set once per file");
}
void MCELFStreamer::EmitBundleLock() {
void MCELFStreamer::EmitBundleLock(bool AlignToEnd) {
MCSectionData *SD = getCurrentSectionData();
// Sanity checks
@ -417,7 +423,8 @@ void MCELFStreamer::EmitBundleLock() {
else if (SD->isBundleLocked())
report_fatal_error("Nesting of .bundle_lock is forbidden");
SD->setBundleLocked(true);
SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd :
MCSectionData::BundleLocked);
SD->setBundleGroupBeforeFirstInst(true);
}
@ -432,7 +439,7 @@ void MCELFStreamer::EmitBundleUnlock() {
else if (SD->isBundleGroupBeforeFirstInst())
report_fatal_error("Empty bundle-locked group is forbidden");
SD->setBundleLocked(false);
SD->setBundleLockState(MCSectionData::NotBundleLocked);
}
void MCELFStreamer::FinishImpl() {

View File

@ -96,7 +96,7 @@ namespace {
virtual void EmitInstruction(const MCInst &Inst) {}
virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
virtual void EmitBundleLock() {}
virtual void EmitBundleLock(bool AlignToEnd) {}
virtual void EmitBundleUnlock() {}
virtual void FinishImpl() {}

View File

@ -233,7 +233,7 @@ void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
llvm_unreachable(BundlingNotImplementedMsg);
}
void MCObjectStreamer::EmitBundleLock() {
void MCObjectStreamer::EmitBundleLock(bool AlignToEnd) {
llvm_unreachable(BundlingNotImplementedMsg);
}

View File

@ -2473,15 +2473,31 @@ bool AsmParser::ParseDirectiveBundleAlignMode() {
}
/// ParseDirectiveBundleLock
/// ::= {.bundle_lock}
/// ::= {.bundle_lock} [align_to_end]
bool AsmParser::ParseDirectiveBundleLock() {
CheckForValidSection();
bool AlignToEnd = false;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
StringRef Option;
SMLoc Loc = getTok().getLoc();
const char *kInvalidOptionError =
"invalid option for '.bundle_lock' directive";
if (ParseIdentifier(Option))
return Error(Loc, kInvalidOptionError);
if (Option != "align_to_end")
return Error(Loc, kInvalidOptionError);
else if (getLexer().isNot(AsmToken::EndOfStatement))
return Error(Loc,
"unexpected token after '.bundle_lock' directive option");
AlignToEnd = true;
}
if (getLexer().isNot(AsmToken::EndOfStatement))
return TokError("unexpected token in '.bundle_lock' directive");
Lex();
getStreamer().EmitBundleLock();
getStreamer().EmitBundleLock(AlignToEnd);
return false;
}

View File

@ -2,7 +2,7 @@
# RUN: | llvm-objdump -no-show-raw-insn -triple armv7 -disassemble - | FileCheck %s
# On ARM each instruction is 4 bytes long so padding for individual
# instructions should not be inserted. However, for bundle=locked groups
# instructions should not be inserted. However, for bundle-locked groups
# it can be.
.syntax unified

View File

@ -14,5 +14,9 @@ foo:
jle .L_ELSE
.bundle_unlock
# CHECK: .bundle_unlock
.bundle_lock align_to_end
# CHECK: .bundle_lock align_to_end
add %rbx, %rdx
.bundle_unlock

View File

@ -766,7 +766,7 @@ namespace {
}
virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
virtual void EmitBundleLock() {}
virtual void EmitBundleLock(bool AlignToEnd) {}
virtual void EmitBundleUnlock() {}
// Noop calls.