diff options
author | David Sehr <sehr@google.com> | 2012-08-14 10:59:04 -0700 |
---|---|---|
committer | Derek Schuff <dschuff@chromium.org> | 2012-08-14 10:59:04 -0700 |
commit | 4c5c9165c7175ee84c68a589a1b7b68fde48a86a (patch) | |
tree | 7110a946482f552e9ecaa88a67a713bbddc2f039 /lib | |
parent | 539d07aca70682772986ddd2e320cc37b5b3bccf (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.cpp | 70 | ||||
-rw-r--r-- | lib/MC/MCELFStreamer.cpp | 13 |
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 } |