summaryrefslogtreecommitdiffstats
path: root/llvm/lib/MC/MCCodePadder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC/MCCodePadder.cpp')
-rw-r--r--llvm/lib/MC/MCCodePadder.cpp371
1 files changed, 371 insertions, 0 deletions
diff --git a/llvm/lib/MC/MCCodePadder.cpp b/llvm/lib/MC/MCCodePadder.cpp
new file mode 100644
index 00000000000..57547814e59
--- /dev/null
+++ b/llvm/lib/MC/MCCodePadder.cpp
@@ -0,0 +1,371 @@
+//===- MCCodePadder.cpp - Target MC Code Padder ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCCodePadder.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include <algorithm>
+#include <limits>
+#include <numeric>
+
+using namespace llvm;
+
+//---------------------------------------------------------------------------
+// MCCodePadder
+//
+
+MCCodePadder::~MCCodePadder() {
+ for (auto *Policy : CodePaddingPolicies)
+ delete Policy;
+}
+
+bool MCCodePadder::addPolicy(MCCodePaddingPolicy *Policy) {
+ assert(Policy && "Policy must be valid");
+ return CodePaddingPolicies.insert(Policy).second;
+}
+
+void MCCodePadder::handleBasicBlockStart(MCObjectStreamer *OS,
+ const MCCodePaddingContext &Context) {
+ assert(OS != nullptr && "OS must be valid");
+ assert(this->OS == nullptr && "Still handling another basic block");
+ this->OS = OS;
+
+ ArePoliciesActive = usePoliciesForBasicBlock(Context);
+
+ bool InsertionPoint = basicBlockRequiresInsertionPoint(Context);
+ assert((!InsertionPoint ||
+ OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) &&
+ "Cannot insert padding nops right after an alignment fragment as it "
+ "will ruin the alignment");
+
+ uint64_t PoliciesMask = MCPaddingFragment::PFK_None;
+ if (ArePoliciesActive) {
+ PoliciesMask = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(),
+ MCPaddingFragment::PFK_None,
+ [&Context](uint64_t Mask,
+ const MCCodePaddingPolicy *Policy) -> uint64_t {
+ return Policy->basicBlockRequiresPaddingFragment(Context)
+ ? (Mask | Policy->getKindMask())
+ : Mask;
+ });
+ }
+
+ if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None) {
+ MCPaddingFragment *PaddingFragment = OS->getOrCreatePaddingFragment();
+ if (InsertionPoint)
+ PaddingFragment->setAsInsertionPoint();
+ PaddingFragment->setPaddingPoliciesMask(
+ PaddingFragment->getPaddingPoliciesMask() | PoliciesMask);
+ }
+}
+
+void MCCodePadder::handleBasicBlockEnd(const MCCodePaddingContext &Context) {
+ assert(this->OS != nullptr && "Not handling a basic block");
+ OS = nullptr;
+}
+
+void MCCodePadder::handleInstructionBegin(const MCInst &Inst) {
+ if (!OS)
+ return; // instruction was emitted outside a function
+
+ assert(CurrHandledInstFragment == nullptr && "Can't start handling an "
+ "instruction while still "
+ "handling another instruction");
+
+ bool InsertionPoint = instructionRequiresInsertionPoint(Inst);
+ assert((!InsertionPoint ||
+ OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) &&
+ "Cannot insert padding nops right after an alignment fragment as it "
+ "will ruin the alignment");
+
+ uint64_t PoliciesMask = MCPaddingFragment::PFK_None;
+ if (ArePoliciesActive) {
+ PoliciesMask = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(),
+ MCPaddingFragment::PFK_None,
+ [&Inst](uint64_t Mask, const MCCodePaddingPolicy *Policy) -> uint64_t {
+ return Policy->instructionRequiresPaddingFragment(Inst)
+ ? (Mask | Policy->getKindMask())
+ : Mask;
+ });
+ }
+ MCFragment *CurrFragment = OS->getCurrentFragment();
+ // CurrFragment can be a previously created MCPaddingFragment. If so, let's
+ // update it with the information we have, such as the instruction that it
+ // should point to.
+ bool needToUpdateCurrFragment =
+ CurrFragment != nullptr &&
+ CurrFragment->getKind() == MCFragment::FT_Padding;
+ if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None ||
+ needToUpdateCurrFragment) {
+ // temporarily holding the fragment as CurrHandledInstFragment, to be
+ // updated after the instruction will be written
+ CurrHandledInstFragment = OS->getOrCreatePaddingFragment();
+ if (InsertionPoint)
+ CurrHandledInstFragment->setAsInsertionPoint();
+ CurrHandledInstFragment->setPaddingPoliciesMask(
+ CurrHandledInstFragment->getPaddingPoliciesMask() | PoliciesMask);
+ }
+}
+
+void MCCodePadder::handleInstructionEnd(const MCInst &Inst) {
+ if (!OS)
+ return; // instruction was emitted outside a function
+ if (CurrHandledInstFragment == nullptr)
+ return;
+
+ MCFragment *InstFragment = OS->getCurrentFragment();
+ if (MCDataFragment *InstDataFragment =
+ dyn_cast_or_null<MCDataFragment>(InstFragment))
+ // Inst is a fixed size instruction and was encoded into a MCDataFragment.
+ // Let the fragment hold it and its size. Its size is the current size of
+ // the data fragment, as the padding fragment was inserted right before it
+ // and nothing was written yet except Inst
+ CurrHandledInstFragment->setInstAndInstSize(
+ Inst, InstDataFragment->getContents().size());
+ else if (MCRelaxableFragment *InstRelaxableFragment =
+ dyn_cast_or_null<MCRelaxableFragment>(InstFragment))
+ // Inst may be relaxed and its size may vary.
+ // Let the fragment hold the instruction and the MCRelaxableFragment
+ // that's holding it.
+ CurrHandledInstFragment->setInstAndInstFragment(Inst,
+ InstRelaxableFragment);
+ else
+ llvm_unreachable("After encoding an instruction current fragment must be "
+ "either a MCDataFragment or a MCRelaxableFragment");
+
+ CurrHandledInstFragment = nullptr;
+}
+
+MCPFRange &MCCodePadder::getJurisdiction(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ auto JurisdictionLocation = FragmentToJurisdiction.find(Fragment);
+ if (JurisdictionLocation != FragmentToJurisdiction.end())
+ return JurisdictionLocation->second;
+
+ MCPFRange Jurisdiction;
+
+ // Forward scanning the fragments in this section, starting from the given
+ // fragments, and adding relevant MCPaddingFragments to the Jurisdiction
+ for (MCFragment *CurrFragment = Fragment; CurrFragment != nullptr;
+ CurrFragment = CurrFragment->getNextNode()) {
+
+ MCPaddingFragment *CurrPaddingFragment =
+ dyn_cast<MCPaddingFragment>(CurrFragment);
+ if (CurrPaddingFragment == nullptr)
+ continue;
+
+ if (CurrPaddingFragment != Fragment &&
+ CurrPaddingFragment->isInsertionPoint())
+ // Found next insertion point Fragment. From now on it's its jurisdiction.
+ break;
+ for (const auto *Policy : CodePaddingPolicies) {
+ if (CurrPaddingFragment->hasPaddingPolicy(Policy->getKindMask())) {
+ Jurisdiction.push_back(CurrPaddingFragment);
+ break;
+ }
+ }
+ }
+
+ auto InsertionResult =
+ FragmentToJurisdiction.insert(std::make_pair(Fragment, Jurisdiction));
+ assert(InsertionResult.second &&
+ "Insertion to FragmentToJurisdiction failed");
+ return InsertionResult.first->second;
+}
+
+uint64_t MCCodePadder::getMaxWindowSize(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ auto MaxFragmentSizeLocation = FragmentToMaxWindowSize.find(Fragment);
+ if (MaxFragmentSizeLocation != FragmentToMaxWindowSize.end())
+ return MaxFragmentSizeLocation->second;
+
+ MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout);
+ uint64_t JurisdictionMask = MCPaddingFragment::PFK_None;
+ for (const auto *Protege : Jurisdiction)
+ JurisdictionMask |= Protege->getPaddingPoliciesMask();
+
+ uint64_t MaxFragmentSize = UINT64_C(0);
+ for (const auto *Policy : CodePaddingPolicies)
+ if ((JurisdictionMask & Policy->getKindMask()) !=
+ MCPaddingFragment::PFK_None)
+ MaxFragmentSize = std::max(MaxFragmentSize, Policy->getWindowSize());
+
+ auto InsertionResult =
+ FragmentToMaxWindowSize.insert(std::make_pair(Fragment, MaxFragmentSize));
+ assert(InsertionResult.second &&
+ "Insertion to FragmentToMaxWindowSize failed");
+ return InsertionResult.first->second;
+}
+
+bool MCCodePadder::relaxFragment(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ if (!Fragment->isInsertionPoint())
+ return false;
+ uint64_t OldSize = Fragment->getSize();
+
+ uint64_t MaxWindowSize = getMaxWindowSize(Fragment, Layout);
+ if (MaxWindowSize == UINT64_C(0))
+ return false;
+ assert(isPowerOf2_64(MaxWindowSize) &&
+ "MaxWindowSize must be an integer power of 2");
+ uint64_t SectionAlignment = Fragment->getParent()->getAlignment();
+ assert(isPowerOf2_64(SectionAlignment) &&
+ "SectionAlignment must be an integer power of 2");
+
+ MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout);
+ uint64_t OptimalSize = UINT64_C(0);
+ double OptimalWeight = std::numeric_limits<double>::max();
+ uint64_t MaxFragmentSize = MaxWindowSize - UINT16_C(1);
+ for (uint64_t Size = UINT64_C(0); Size <= MaxFragmentSize; ++Size) {
+ Fragment->setSize(Size);
+ Layout.invalidateFragmentsFrom(Fragment);
+ double SizeWeight = 0.0;
+ // The section is guaranteed to be aligned to SectionAlignment, but that
+ // doesn't guarantee the exact section offset w.r.t. the policies window
+ // size.
+ // As a concrete example, the section could be aligned to 16B, but a
+ // policy's window size can be 32B. That means that the section actual start
+ // address can either be 0mod32 or 16mod32. The said policy will act
+ // differently for each case, so we need to take both into consideration.
+ for (uint64_t Offset = UINT64_C(0); Offset < MaxWindowSize;
+ Offset += SectionAlignment) {
+ double OffsetWeight = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(), 0.0,
+ [&Jurisdiction, &Offset, &Layout](
+ double Weight, const MCCodePaddingPolicy *Policy) -> double {
+ double PolicyWeight =
+ Policy->computeRangePenaltyWeight(Jurisdiction, Offset, Layout);
+ assert(PolicyWeight >= 0.0 && "A penalty weight must be positive");
+ return Weight + PolicyWeight;
+ });
+ SizeWeight = std::max(SizeWeight, OffsetWeight);
+ }
+ if (SizeWeight < OptimalWeight) {
+ OptimalWeight = SizeWeight;
+ OptimalSize = Size;
+ }
+ if (OptimalWeight == 0.0)
+ break;
+ }
+
+ Fragment->setSize(OptimalSize);
+ Layout.invalidateFragmentsFrom(Fragment);
+ return OldSize != OptimalSize;
+}
+
+//---------------------------------------------------------------------------
+// MCCodePaddingPolicy
+//
+
+uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment,
+ const MCAsmLayout &Layout) {
+ assert(Fragment != nullptr && "Fragment cannot be null");
+ MCFragment const *NextFragment = Fragment->getNextNode();
+ return NextFragment == nullptr
+ ? Layout.getSectionAddressSize(Fragment->getParent())
+ : Layout.getFragmentOffset(NextFragment);
+}
+
+uint64_t
+MCCodePaddingPolicy::getFragmentInstByte(const MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) const {
+ uint64_t InstByte = getNextFragmentOffset(Fragment, Layout);
+ if (InstByteIsLastByte)
+ InstByte += Fragment->getInstSize() - UINT64_C(1);
+ return InstByte;
+}
+
+uint64_t
+MCCodePaddingPolicy::computeWindowEndAddress(const MCPaddingFragment *Fragment,
+ uint64_t Offset,
+ MCAsmLayout &Layout) const {
+ uint64_t InstByte = getFragmentInstByte(Fragment, Layout);
+ return alignTo(InstByte + UINT64_C(1) + Offset, WindowSize) - Offset;
+}
+
+double MCCodePaddingPolicy::computeRangePenaltyWeight(
+ const MCPFRange &Range, uint64_t Offset, MCAsmLayout &Layout) const {
+
+ SmallVector<MCPFRange, 8> Windows;
+ SmallVector<MCPFRange, 8>::iterator CurrWindowLocation = Windows.end();
+ for (const MCPaddingFragment *Fragment : Range) {
+ if (!Fragment->hasPaddingPolicy(getKindMask()))
+ continue;
+ uint64_t FragmentWindowEndAddress =
+ computeWindowEndAddress(Fragment, Offset, Layout);
+ if (CurrWindowLocation == Windows.end() ||
+ FragmentWindowEndAddress !=
+ computeWindowEndAddress(*CurrWindowLocation->begin(), Offset,
+ Layout)) {
+ // next window is starting
+ Windows.push_back(MCPFRange());
+ CurrWindowLocation = Windows.end() - 1;
+ }
+ CurrWindowLocation->push_back(Fragment);
+ }
+
+ if (Windows.empty())
+ return 0.0;
+
+ double RangeWeight = 0.0;
+ SmallVector<MCPFRange, 8>::iterator I = Windows.begin();
+ RangeWeight += computeFirstWindowPenaltyWeight(*I, Offset, Layout);
+ ++I;
+ RangeWeight += std::accumulate(
+ I, Windows.end(), 0.0,
+ [this, &Layout, &Offset](double Weight, MCPFRange &Window) -> double {
+ return Weight += computeWindowPenaltyWeight(Window, Offset, Layout);
+ });
+ return RangeWeight;
+}
+
+double MCCodePaddingPolicy::computeFirstWindowPenaltyWeight(
+ const MCPFRange &Window, uint64_t Offset, MCAsmLayout &Layout) const {
+ if (Window.empty())
+ return 0.0;
+ uint64_t WindowEndAddress =
+ computeWindowEndAddress(*Window.begin(), Offset, Layout);
+
+ MCPFRange FullWindowFirstPart; // will hold all the fragments that are in the
+ // same window as the fragments in the given
+ // window but their penalty weight should not
+ // be added
+ for (const MCFragment *Fragment = (*Window.begin())->getPrevNode();
+ Fragment != nullptr; Fragment = Fragment->getPrevNode()) {
+ const MCPaddingFragment *PaddingNopFragment =
+ dyn_cast<MCPaddingFragment>(Fragment);
+ if (PaddingNopFragment == nullptr ||
+ !PaddingNopFragment->hasPaddingPolicy(getKindMask()))
+ continue;
+ if (WindowEndAddress !=
+ computeWindowEndAddress(PaddingNopFragment, Offset, Layout))
+ break;
+
+ FullWindowFirstPart.push_back(PaddingNopFragment);
+ }
+
+ std::reverse(FullWindowFirstPart.begin(), FullWindowFirstPart.end());
+ double FullWindowFirstPartWeight =
+ computeWindowPenaltyWeight(FullWindowFirstPart, Offset, Layout);
+
+ MCPFRange FullWindow(
+ FullWindowFirstPart); // will hold all the fragments that are in the
+ // same window as the fragments in the given
+ // window, whether their weight should be added
+ // or not
+ FullWindow.append(Window.begin(), Window.end());
+ double FullWindowWeight =
+ computeWindowPenaltyWeight(FullWindow, Offset, Layout);
+
+ assert(FullWindowWeight >= FullWindowFirstPartWeight &&
+ "More fragments necessarily means bigger weight");
+ return FullWindowWeight - FullWindowFirstPartWeight;
+}
OpenPOWER on IntegriCloud