Index: lib/MC/MCELFStreamer.cpp |
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp |
index 7702658f3b8ca8c0fea2bf496c031a4e3cd33fb2..bb3afa0ca8f46a7c36080813c12376c19e65eecd 100644 |
--- a/lib/MC/MCELFStreamer.cpp |
+++ b/lib/MC/MCELFStreamer.cpp |
@@ -15,6 +15,7 @@ |
#include "llvm/ADT/STLExtras.h" |
#include "llvm/ADT/SmallPtrSet.h" |
#include "llvm/MC/MCAsmBackend.h" |
+#include "llvm/MC/MCAsmLayout.h" |
#include "llvm/MC/MCAsmInfo.h" |
#include "llvm/MC/MCAssembler.h" |
#include "llvm/MC/MCCodeEmitter.h" |
@@ -39,6 +40,48 @@ using namespace llvm; |
MCELFStreamer::~MCELFStreamer() { |
} |
+void MCELFStreamer::mergeFragment(MCDataFragment *DF, |
+ MCEncodedFragmentWithFixups *EF) { |
+ MCAssembler &Assembler = getAssembler(); |
+ |
+ if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { |
+ uint64_t FSize = EF->getContents().size(); |
+ |
+ if (FSize > Assembler.getBundleAlignSize()) |
+ report_fatal_error("Fragment can't be larger than a bundle size"); |
+ |
+ uint64_t RequiredBundlePadding = computeBundlePadding( |
+ Assembler, EF, DF->getContents().size(), FSize); |
+ |
+ if (RequiredBundlePadding > UINT8_MAX) |
+ report_fatal_error("Padding cannot exceed 255 bytes"); |
+ |
+ if (RequiredBundlePadding > 0) { |
+ SmallString<256> Code; |
+ raw_svector_ostream VecOS(Code); |
+ MCObjectWriter *OW = Assembler.getBackend().createObjectWriter(VecOS); |
+ |
+ EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); |
+ |
+ Assembler.writeFragmentPadding(*EF, FSize, OW); |
+ VecOS.flush(); |
+ delete OW; |
+ |
+ DF->getContents().append(Code.begin(), Code.end()); |
+ } |
+ } |
+ |
+ flushPendingLabels(DF, DF->getContents().size()); |
+ |
+ for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) { |
+ EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() + |
+ DF->getContents().size()); |
+ DF->getFixups().push_back(EF->getFixups()[i]); |
+ } |
+ DF->setHasInstructions(true); |
+ DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); |
+} |
+ |
void MCELFStreamer::InitSections(bool NoExecStack) { |
// This emulates the same behavior of GNU as. This makes it easier |
// to compare the output as the major sections are in the same order. |
@@ -459,7 +502,16 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, |
if (Assembler.isBundlingEnabled()) { |
MCSectionData *SD = getCurrentSectionData(); |
- if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst()) |
+ if (Assembler.getRelaxAll() && SD->isBundleLocked()) |
+ // If the -mc-relax-all flag is used and we are bundle-locked, we re-use |
+ // the current bundle group. |
+ DF = BundleGroups.back(); |
+ else if (Assembler.getRelaxAll() && !SD->isBundleLocked()) |
+ // When not in a bundle-locked group and the -mc-relax-all flag is used, |
+ // we create a new temporary fragment which will be later merged into |
+ // the current fragment. |
+ DF = new MCDataFragment(); |
+ else if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst()) |
// If we are bundle-locked, we re-use the current fragment. |
// The bundle-locking directive ensures this is a new data fragment. |
DF = cast<MCDataFragment>(getCurrentFragment()); |
@@ -497,6 +549,14 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, |
} |
DF->setHasInstructions(true); |
DF->getContents().append(Code.begin(), Code.end()); |
+ |
+ if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { |
+ MCSectionData *SD = getCurrentSectionData(); |
+ if (!SD->isBundleLocked()) { |
+ mergeFragment(getOrCreateDataFragment(), DF); |
+ delete DF; |
+ } |
+ } |
} |
void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { |
@@ -520,6 +580,12 @@ void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { |
if (!SD->isBundleLocked()) |
SD->setBundleGroupBeforeFirstInst(true); |
+ if (getAssembler().getRelaxAll() && !SD->isBundleLocked()) { |
+ // TODO: drop the lock state and set directly in the fragment |
+ MCDataFragment *DF = new MCDataFragment(); |
+ BundleGroups.push_back(DF); |
+ } |
+ |
SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd : |
MCSectionData::BundleLocked); |
} |
@@ -535,7 +601,27 @@ void MCELFStreamer::EmitBundleUnlock() { |
else if (SD->isBundleGroupBeforeFirstInst()) |
report_fatal_error("Empty bundle-locked group is forbidden"); |
- SD->setBundleLockState(MCSectionData::NotBundleLocked); |
+ // When the -mc-relax-all flag is used, we emit instructions to fragments |
+ // stored on a stack. When the bundle unlock is emited, we pop a fragment |
+ // from the stack a merge it to the one below. |
+ if (getAssembler().getRelaxAll()) { |
+ assert(!BundleGroups.empty() && "There are no bundle groups"); |
+ MCDataFragment *DF = BundleGroups.back(); |
+ |
+ // FIXME: Use BundleGroups to track the lock state instead. |
+ SD->setBundleLockState(MCSectionData::NotBundleLocked); |
+ |
+ // FIXME: Use more separate fragments for nested groups. |
+ if (!SD->isBundleLocked()) { |
+ mergeFragment(getOrCreateDataFragment(), DF); |
+ BundleGroups.pop_back(); |
+ delete DF; |
+ } |
+ |
+ if (SD->getBundleLockState() != MCSectionData::BundleLockedAlignToEnd) |
+ getOrCreateDataFragment()->setAlignToBundleEnd(false); |
+ } else |
+ SD->setBundleLockState(MCSectionData::NotBundleLocked); |
} |
void MCELFStreamer::Flush() { |