blob: 4058f3317dfbdbbd74f3f48040ca0b745f5984ca [file] [log] [blame]
//===- bolt/Passes/SplitFunctions.h - Split function code -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BOLT_PASSES_SPLIT_FUNCTIONS_H
#define BOLT_PASSES_SPLIT_FUNCTIONS_H
#include "bolt/Core/FunctionLayout.h"
#include "bolt/Passes/BinaryPasses.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/CommandLine.h"
#include <atomic>
namespace llvm {
namespace bolt {
/// Strategy used to partition blocks into fragments.
enum SplitFunctionsStrategy : char {
/// Split each function into a hot and cold fragment using profiling
/// information.
Profile2 = 0,
/// Split each function into a hot and cold fragment at a randomly chosen
/// split point (ignoring any available profiling information).
Random2,
/// Split each function into N fragments at a randomly chosen split points
/// (ignoring any available profiling information).
RandomN,
/// Split all basic blocks of each function into fragments such that each
/// fragment contains exactly a single basic block.
All
};
class SplitStrategy {
public:
using BlockIt = BinaryFunction::BasicBlockOrderType::iterator;
virtual ~SplitStrategy() = default;
virtual bool canSplit(const BinaryFunction &BF) = 0;
virtual bool keepEmpty() = 0;
virtual void fragment(const BlockIt Start, const BlockIt End) = 0;
};
/// Split function code in multiple parts.
class SplitFunctions : public BinaryFunctionPass {
private:
/// Split function body into fragments.
void splitFunction(BinaryFunction &Function, SplitStrategy &Strategy);
struct TrampolineKey {
FragmentNum SourceFN = FragmentNum::main();
const MCSymbol *Target = nullptr;
TrampolineKey() = default;
TrampolineKey(const FragmentNum SourceFN, const MCSymbol *const Target)
: SourceFN(SourceFN), Target(Target) {}
static inline TrampolineKey getEmptyKey() { return TrampolineKey(); };
static inline TrampolineKey getTombstoneKey() {
return TrampolineKey(FragmentNum(UINT_MAX), nullptr);
};
static unsigned getHashValue(const TrampolineKey &Val) {
return llvm::hash_combine(Val.SourceFN.get(), Val.Target);
}
static bool isEqual(const TrampolineKey &LHS, const TrampolineKey &RHS) {
return LHS.SourceFN == RHS.SourceFN && LHS.Target == RHS.Target;
}
};
/// Map basic block labels to their trampoline block labels.
using TrampolineSetType =
DenseMap<TrampolineKey, const MCSymbol *, TrampolineKey>;
using BasicBlockOrderType = BinaryFunction::BasicBlockOrderType;
/// Create trampoline landing pads for exception handling code to guarantee
/// that every landing pad is placed in the same function fragment as the
/// corresponding thrower block. The trampoline landing pad, when created,
/// will redirect the execution to the real landing pad in a different
/// fragment.
TrampolineSetType createEHTrampolines(BinaryFunction &Function) const;
/// Merge trampolines into \p Layout without trampolines. The merge will place
/// a trampoline immediately before its destination. Used to revert the effect
/// of trampolines after createEHTrampolines().
BasicBlockOrderType
mergeEHTrampolines(BinaryFunction &BF, BasicBlockOrderType &Layout,
const TrampolineSetType &Trampolines) const;
std::atomic<uint64_t> SplitBytesHot{0ull};
std::atomic<uint64_t> SplitBytesCold{0ull};
public:
explicit SplitFunctions(const cl::opt<bool> &PrintPass)
: BinaryFunctionPass(PrintPass) {}
bool shouldOptimize(const BinaryFunction &BF) const override;
const char *getName() const override { return "split-functions"; }
void runOnFunctions(BinaryContext &BC) override;
};
} // namespace bolt
} // namespace llvm
#endif