aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCAssembler.cpp
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2024-06-09 23:05:05 -0700
committerFangrui Song <i@maskray.me>2024-06-09 23:05:05 -0700
commit9d0754ada5dbbc0c009bcc2f7824488419cc5530 (patch)
tree8a31f077ffa3bd8ed235527c1f029bf9d776b7da /llvm/lib/MC/MCAssembler.cpp
parentcb1a727dea9f063085db10190971dbd7aa7fb8e2 (diff)
downloadllvm-9d0754ada5dbbc0c009bcc2f7824488419cc5530.zip
llvm-9d0754ada5dbbc0c009bcc2f7824488419cc5530.tar.gz
llvm-9d0754ada5dbbc0c009bcc2f7824488419cc5530.tar.bz2
[MC] Relax fragments eagerly
Lazy relaxation caused hash table lookups (`getFragmentOffset`) and complex use/compute interdependencies. Some expressions involding forward declared symbols (e.g. `subsection-if.s`) cannot be computed. Recursion detection requires complex `IsBeingLaidOut` (https://reviews.llvm.org/D79570). D76114's `invalidateFragmentsFrom` makes lazy relaxation even less useful. Switch to eager relaxation to greatly simplify code and resolve these issues. This change also removes a `getPrevNode` use, which makes it more feasible to replace the fragment representation, which might yield a large peak RSS win. Minor downsides: The number of section relaxations may increase (offset by avoiding the hash table lookup). For relax-recompute-align.s, the computed layout is not optimal.
Diffstat (limited to 'llvm/lib/MC/MCAssembler.cpp')
-rw-r--r--llvm/lib/MC/MCAssembler.cpp117
1 files changed, 42 insertions, 75 deletions
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
index ad30b5c..c56d28b 100644
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -66,7 +66,6 @@ STATISTIC(EmittedFillFragments,
STATISTIC(EmittedNopsFragments, "Number of emitted assembler fragments - nops");
STATISTIC(EmittedOrgFragments, "Number of emitted assembler fragments - org");
STATISTIC(evaluateFixup, "Number of evaluated fixups");
-STATISTIC(FragmentLayouts, "Number of fragment layouts");
STATISTIC(ObjectBytes, "Number of emitted object file bytes");
STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps");
STATISTIC(RelaxedInstructions, "Number of relaxed instructions");
@@ -404,29 +403,7 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout,
llvm_unreachable("invalid fragment kind");
}
-void MCAsmLayout::layoutFragment(MCFragment *F) {
- MCFragment *Prev = F->getPrevNode();
-
- // We should never try to recompute something which is valid.
- assert(!isFragmentValid(F) && "Attempt to recompute a valid fragment!");
- // We should never try to compute the fragment layout if its predecessor
- // isn't valid.
- assert((!Prev || isFragmentValid(Prev)) &&
- "Attempt to compute fragment before its predecessor!");
-
- assert(!F->IsBeingLaidOut && "Already being laid out!");
- F->IsBeingLaidOut = true;
-
- ++stats::FragmentLayouts;
-
- // Compute fragment offset and size.
- if (Prev)
- F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
- else
- F->Offset = 0;
- F->IsBeingLaidOut = false;
- LastValidFragment[F->getParent()] = F;
-
+void MCAsmLayout::layoutBundle(MCFragment *F) {
// If bundling is enabled and this fragment has instructions in it, it has to
// obey the bundling restrictions. With padding, we'll have:
//
@@ -454,21 +431,40 @@ void MCAsmLayout::layoutFragment(MCFragment *F) {
// within-fragment padding (which would produce less padding when N is less
// than the bundle size), but for now we don't.
//
- if (Assembler.isBundlingEnabled() && F->hasInstructions()) {
- assert(isa<MCEncodedFragment>(F) &&
- "Only MCEncodedFragment implementations have instructions");
- MCEncodedFragment *EF = cast<MCEncodedFragment>(F);
- uint64_t FSize = Assembler.computeFragmentSize(*this, *EF);
-
- if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize())
- report_fatal_error("Fragment can't be larger than a bundle size");
-
- uint64_t RequiredBundlePadding =
- computeBundlePadding(Assembler, EF, EF->Offset, FSize);
- if (RequiredBundlePadding > UINT8_MAX)
- report_fatal_error("Padding cannot exceed 255 bytes");
- EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
- EF->Offset += RequiredBundlePadding;
+ assert(isa<MCEncodedFragment>(F) &&
+ "Only MCEncodedFragment implementations have instructions");
+ MCEncodedFragment *EF = cast<MCEncodedFragment>(F);
+ uint64_t FSize = Assembler.computeFragmentSize(*this, *EF);
+
+ if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize())
+ report_fatal_error("Fragment can't be larger than a bundle size");
+
+ uint64_t RequiredBundlePadding =
+ computeBundlePadding(Assembler, EF, EF->Offset, FSize);
+ if (RequiredBundlePadding > UINT8_MAX)
+ report_fatal_error("Padding cannot exceed 255 bytes");
+ EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
+ EF->Offset += RequiredBundlePadding;
+}
+
+uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const {
+ ensureValid(F);
+ return F->Offset;
+}
+
+void MCAsmLayout::ensureValid(const MCFragment *Frag) const {
+ MCSection &Sec = *Frag->getParent();
+ if (Sec.hasLayout())
+ return;
+ Sec.setHasLayout(true);
+ uint64_t Offset = 0;
+ for (MCFragment &F : Sec) {
+ F.Offset = Offset;
+ if (Assembler.isBundlingEnabled() && F.hasInstructions()) {
+ const_cast<MCAsmLayout *>(this)->layoutBundle(&F);
+ Offset = F.Offset;
+ }
+ Offset += getAssembler().computeFragmentSize(*this, F);
}
}
@@ -848,7 +844,7 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
// another. If any fragment has changed size, we have to re-layout (and
// as a result possibly further relax) all.
for (MCSection &Sec : *this)
- Layout.invalidateFragmentsFrom(&*Sec.begin());
+ Sec.setHasLayout(false);
}
DEBUG_WITH_TYPE("mc-dump", {
@@ -1109,7 +1105,6 @@ bool MCAssembler::relaxBoundaryAlign(MCAsmLayout &Layout,
if (NewSize == BF.getSize())
return false;
BF.setSize(NewSize);
- Layout.invalidateFragmentsFrom(&BF);
return true;
}
@@ -1219,47 +1214,19 @@ bool MCAssembler::relaxFragment(MCAsmLayout &Layout, MCFragment &F) {
}
}
-bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
- // Holds the first fragment which needed relaxing during this layout. It will
- // remain NULL if none were relaxed.
- // When a fragment is relaxed, all the fragments following it should get
- // invalidated because their offset is going to change.
- MCFragment *FirstRelaxedFragment = nullptr;
-
- // Attempt to relax all the fragments in the section.
- for (MCFragment &Frag : Sec) {
- // Check if this is a fragment that needs relaxation.
- bool RelaxedFrag = relaxFragment(Layout, Frag);
- if (RelaxedFrag && !FirstRelaxedFragment)
- FirstRelaxedFragment = &Frag;
- }
- if (FirstRelaxedFragment) {
- Layout.invalidateFragmentsFrom(FirstRelaxedFragment);
- return true;
- }
- return false;
-}
-
bool MCAssembler::layoutOnce(MCAsmLayout &Layout) {
++stats::RelaxationSteps;
- bool WasRelaxed = false;
- for (MCSection &Sec : *this) {
- while (layoutSectionOnce(Layout, Sec))
- WasRelaxed = true;
- }
-
- return WasRelaxed;
+ bool Changed = false;
+ for (MCSection &Sec : *this)
+ for (MCFragment &Frag : Sec)
+ if (relaxFragment(Layout, Frag))
+ Changed = true;
+ return Changed;
}
void MCAssembler::finishLayout(MCAsmLayout &Layout) {
assert(getBackendPtr() && "Expected assembler backend");
- // The layout is done. Mark every fragment as valid.
- for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
- MCSection &Section = *Layout.getSectionOrder()[i];
- Layout.getFragmentOffset(&*Section.getFragmentList().rbegin());
- computeFragmentSize(Layout, *Section.getFragmentList().rbegin());
- }
getBackend().finishLayout(*this, Layout);
}