aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Sehr <sehr@google.com>2012-08-14 10:59:04 -0700
committerDerek Schuff <dschuff@chromium.org>2012-08-14 10:59:04 -0700
commit4c5c9165c7175ee84c68a589a1b7b68fde48a86a (patch)
tree7110a946482f552e9ecaa88a67a713bbddc2f039 /lib
parent539d07aca70682772986ddd2e320cc37b5b3bccf (diff)
Add an API to MCSectionData that tracks known offsets for text emitted into a
section. When the offset is known and an instruction would not span a bundle boundary, the streamer can continue extending an MCFragment. BUG= http://code.google.com/p/nativeclient/issues/detail?id=2545 TEST=none Review URL: http://codereview.chromium.org/10825312/
Diffstat (limited to 'lib')
-rw-r--r--lib/MC/MCAssembler.cpp70
-rw-r--r--lib/MC/MCELFStreamer.cpp13
2 files changed, 71 insertions, 12 deletions
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 321b2832b9..76dac99850 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -186,13 +186,14 @@ MCFragment::~MCFragment() {
}
MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent)
- : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)),
+ : Kind(_Kind),
// @LOCALMOD-BEGIN
BundleAlign(BundleAlignNone),
BundleGroupStart(false),
BundleGroupEnd(false),
- BundlePadding(~UINT8_C(0))
+ BundlePadding(~UINT8_C(0)),
// @LOCALMOD-END
+ Parent(_Parent), Atom(0), Offset(~UINT64_C(0))
{
if (Parent)
Parent->getFragmentList().push_back(this);
@@ -226,14 +227,16 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
BundlingEnabled(false),
BundleLocked(false),
BundleGroupFirstFrag(false),
- BundleAlignNext(MCFragment::BundleAlignNone)
+ BundleAlignNext(MCFragment::BundleAlignNone),
+ BundleOffsetKnown(false),
+ BundleOffset(0)
// @LOCALMOD-END
{
if (A)
A->getSectionList().push_back(this);
// @LOCALMOD-BEGIN
- unsigned BundleSize = A->getBackend().getBundleSize();
+ BundleSize = A->getBackend().getBundleSize();
if (BundleSize && _Section.UseCodeAlign()) {
BundlingEnabled = true;
setAlignment(BundleSize);
@@ -241,6 +244,65 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
// @LOCALMOD-END
}
+// @LOCALMOD-BEGIN
+void MCSectionData::setAlignment(unsigned Value) {
+ Alignment = Value;
+ // If the alignment is at least as big as a bundle, then we know the offset
+ // relative to the start of a bundle.
+ if (Alignment >= BundleSize) {
+ BundleOffsetKnown = true;
+ BundleOffset = 0;
+ } else {
+ BundleOffsetKnown = false;
+ BundleOffset = 0;
+ }
+}
+
+void MCSectionData::MarkBundleOffsetUnknown() {
+ BundleOffsetKnown = false;
+ BundleOffset = 0;
+}
+
+// Only create a new fragment if:
+// 1) we are emitting the first instruction of a bundle locked sequence.
+// 2) we are not currently emitting a bundle locked sequence and we cannot
+// guarantee the instruction would not span a bundle boundary.
+// Otherwise, append to the current fragment to reduce the number of fragments.
+bool MCSectionData::ShouldCreateNewFragment(size_t Size) {
+ // The first instruction of a bundle locked region starts a new fragment.
+ if (isBundleLocked() && isBundleGroupFirstFrag())
+ return true;
+ // Unless we know the relative offset of the end of the current fragment,
+ // we need to create a new fragment.
+ if (!isBundleLocked() && !BundleOffsetKnown)
+ return true;
+ assert(BundleSize != 0 && "BundleSize needs to be non-zero");
+ assert(Size < BundleSize && "Instruction size must be less than BundleSize");
+ // If inserting the instruction would overlap a bundle boundary, start a
+ // new fragment.
+ // TODO(sehr): we could still explicitly insert a NOP and continue here.
+ if (BundleOffset + (unsigned) Size > BundleSize)
+ return true;
+ return false;
+}
+
+void MCSectionData::UpdateBundleOffset(size_t Size) {
+ // A bundle locked fragment could move if it spans a bundle boundary.
+ if (isBundleLocked()) {
+ BundleOffsetKnown = false;
+ return;
+ }
+ // If inserting the instruction would overlap a bundle boundary, starting a
+ // new fragment moves the known offset to the end of the instruction in the
+ // next bundle.
+ // TODO(sehr): we could insert a NOP and continue the fragment.
+ if (BundleOffset + (unsigned) Size > BundleSize)
+ BundleOffset = Size;
+ else
+ BundleOffset = BundleOffset + Size;
+}
+// @LOCALMOD-END
+
/* *** */
MCSymbolData::MCSymbolData() : Symbol(0) {}
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp
index 26b171ed21..6d7c78bb22 100644
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
@@ -359,6 +359,7 @@ void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
// TODO: This is exactly the same as WinCOFFStreamer. Consider merging into
// MCObjectStreamer.
getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end());
+ getCurrentSectionData()->MarkBundleOffsetUnknown(); // @LOCALMOD
}
void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment,
@@ -395,6 +396,7 @@ void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
unsigned AddrSpace) {
fixSymbolsInTLSFixups(Value);
MCObjectStreamer::EmitValueImpl(Value, Size, AddrSpace);
+ getCurrentSectionData()->MarkBundleOffsetUnknown(); // @LOCALMOD
}
@@ -463,6 +465,7 @@ void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) {
for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i)
fixSymbolsInTLSFixups(F.getFixups()[i].getValue());
+ getCurrentSectionData()->MarkBundleOffsetUnknown(); // @LOCALMOD
}
void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
@@ -487,18 +490,12 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
}
DF->getContents().append(Code.begin(), Code.end());
} else {
- // Only create a new fragment if:
- // 1) there is no current fragment,
- // 2) we are not currently emitting a bundle locked sequence, or
- // 3) we are emitting the first instruction of a bundle locked sequence.
- // Otherwise, append to the current fragment to reduce the number of
- // fragments.
MCTinyFragment *TF = dyn_cast_or_null<MCTinyFragment>(getCurrentFragment());
MCSectionData *SD = getCurrentSectionData();
- if (!TF || !SD->isBundleLocked() || SD->isBundleGroupFirstFrag()) {
+ if (!TF || SD->ShouldCreateNewFragment(Code.size()))
TF = new MCTinyFragment(SD);
- }
TF->getContents().append(Code.begin(), Code.end());
+ SD->UpdateBundleOffset(Code.size());
}
// @LOCALMOD-END
}