//===- ConstantHoisting.cpp - Prepare code for expensive constants --------===// // // 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 // //===----------------------------------------------------------------------===// // // This pass identifies expensive constants to hoist and coalesces them to // better prepare it for SelectionDAG-based code generation. This works around // the limitations of the basic-block-at-a-time approach. // // First it scans all instructions for integer constants and calculates its // cost. If the constant can be folded into the instruction (the cost is // TCC_Free) or the cost is just a simple operation (TCC_BASIC), then we don't // consider it expensive and leave it alone. This is the default behavior and // the default implementation of getIntImmCostInst will always return TCC_Free. // // If the cost is more than TCC_BASIC, then the integer constant can't be folded // into the instruction and it might be beneficial to hoist the constant. // Similar constants are coalesced to reduce register pressure and // materialization code. // // When a constant is hoisted, it is also hidden behind a bitcast to force it to // be live-out of the basic block. Otherwise the constant would be just // duplicated and each basic block would have its own copy in the SelectionDAG. // The SelectionDAG recognizes such constants as opaque and doesn't perform // certain transformations on them, which would create a new expensive constant. // // This optimization is only applied to integer constants in instructions and // simple (this means not nested) constant cast expressions. For example: // %0 = load i64* inttoptr (i64 big_constant to i64*) //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/ConstantHoisting.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Value.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SizeOpts.h" #include <algorithm> #include <cassert> #include <cstdint> #include <iterator> #include <tuple> #include <utility> usingnamespacellvm; usingnamespaceconsthoist; #define DEBUG_TYPE … STATISTIC(NumConstantsHoisted, "Number of constants hoisted"); STATISTIC(NumConstantsRebased, "Number of constants rebased"); static cl::opt<bool> ConstHoistWithBlockFrequency( "consthoist-with-block-frequency", cl::init(true), cl::Hidden, cl::desc("Enable the use of the block frequency analysis to reduce the " "chance to execute const materialization more frequently than " "without hoisting.")); static cl::opt<bool> ConstHoistGEP( "consthoist-gep", cl::init(false), cl::Hidden, cl::desc("Try hoisting constant gep expressions")); static cl::opt<unsigned> MinNumOfDependentToRebase("consthoist-min-num-to-rebase", cl::desc("Do not rebase if number of dependent constants of a Base is less " "than this number."), cl::init(0), cl::Hidden); namespace { /// The constant hoisting pass. class ConstantHoistingLegacyPass : public FunctionPass { … }; } // end anonymous namespace char ConstantHoistingLegacyPass::ID = …; INITIALIZE_PASS_BEGIN(ConstantHoistingLegacyPass, "consthoist", "Constant Hoisting", false, false) INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_END(ConstantHoistingLegacyPass, "consthoist", "Constant Hoisting", false, false) FunctionPass *llvm::createConstantHoistingPass() { … } /// Perform the constant hoisting optimization for the given function. bool ConstantHoistingLegacyPass::runOnFunction(Function &Fn) { … } void ConstantHoistingPass::collectMatInsertPts( const RebasedConstantListType &RebasedConstants, SmallVectorImpl<BasicBlock::iterator> &MatInsertPts) const { … } /// Find the constant materialization insertion point. BasicBlock::iterator ConstantHoistingPass::findMatInsertPt(Instruction *Inst, unsigned Idx) const { … } /// Given \p BBs as input, find another set of BBs which collectively /// dominates \p BBs and have the minimal sum of frequencies. Return the BB /// set found in \p BBs. static void findBestInsertionSet(DominatorTree &DT, BlockFrequencyInfo &BFI, BasicBlock *Entry, SetVector<BasicBlock *> &BBs) { … } /// Find an insertion point that dominates all uses. SetVector<BasicBlock::iterator> ConstantHoistingPass::findConstantInsertionPoint( const ConstantInfo &ConstInfo, const ArrayRef<BasicBlock::iterator> MatInsertPts) const { … } /// Record constant integer ConstInt for instruction Inst at operand /// index Idx. /// /// The operand at index Idx is not necessarily the constant integer itself. It /// could also be a cast instruction or a constant expression that uses the /// constant integer. void ConstantHoistingPass::collectConstantCandidates( ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx, ConstantInt *ConstInt) { … } /// Record constant GEP expression for instruction Inst at operand index Idx. void ConstantHoistingPass::collectConstantCandidates( ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx, ConstantExpr *ConstExpr) { … } /// Check the operand for instruction Inst at index Idx. void ConstantHoistingPass::collectConstantCandidates( ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx) { … } /// Scan the instruction for expensive integer constants and record them /// in the constant candidate vector. void ConstantHoistingPass::collectConstantCandidates( ConstCandMapType &ConstCandMap, Instruction *Inst) { … } /// Collect all integer constants in the function that cannot be folded /// into an instruction itself. void ConstantHoistingPass::collectConstantCandidates(Function &Fn) { … } // This helper function is necessary to deal with values that have different // bit widths (APInt Operator- does not like that). If the value cannot be // represented in uint64 we return an "empty" APInt. This is then interpreted // as the value is not in range. static std::optional<APInt> calculateOffsetDiff(const APInt &V1, const APInt &V2) { … } // From a list of constants, one needs to picked as the base and the other // constants will be transformed into an offset from that base constant. The // question is which we can pick best? For example, consider these constants // and their number of uses: // // Constants| 2 | 4 | 12 | 42 | // NumUses | 3 | 2 | 8 | 7 | // // Selecting constant 12 because it has the most uses will generate negative // offsets for constants 2 and 4 (i.e. -10 and -8 respectively). If negative // offsets lead to less optimal code generation, then there might be better // solutions. Suppose immediates in the range of 0..35 are most optimally // supported by the architecture, then selecting constant 2 is most optimal // because this will generate offsets: 0, 2, 10, 40. Offsets 0, 2 and 10 are in // range 0..35, and thus 3 + 2 + 8 = 13 uses are in range. Selecting 12 would // have only 8 uses in range, so choosing 2 as a base is more optimal. Thus, in // selecting the base constant the range of the offsets is a very important // factor too that we take into account here. This algorithm calculates a total // costs for selecting a constant as the base and substract the costs if // immediates are out of range. It has quadratic complexity, so we call this // function only when we're optimising for size and there are less than 100 // constants, we fall back to the straightforward algorithm otherwise // which does not do all the offset calculations. unsigned ConstantHoistingPass::maximizeConstantsInRange(ConstCandVecType::iterator S, ConstCandVecType::iterator E, ConstCandVecType::iterator &MaxCostItr) { … } /// Find the base constant within the given range and rebase all other /// constants with respect to the base constant. void ConstantHoistingPass::findAndMakeBaseConstant( ConstCandVecType::iterator S, ConstCandVecType::iterator E, SmallVectorImpl<consthoist::ConstantInfo> &ConstInfoVec) { … } /// Finds and combines constant candidates that can be easily /// rematerialized with an add from a common base constant. void ConstantHoistingPass::findBaseConstants(GlobalVariable *BaseGV) { … } /// Updates the operand at Idx in instruction Inst with the result of /// instruction Mat. If the instruction is a PHI node then special /// handling for duplicate values from the same incoming basic block is /// required. /// \return The update will always succeed, but the return value indicated if /// Mat was used for the update or not. static bool updateOperand(Instruction *Inst, unsigned Idx, Instruction *Mat) { … } /// Emit materialization code for all rebased constants and update their /// users. void ConstantHoistingPass::emitBaseConstants(Instruction *Base, UserAdjustment *Adj) { … } /// Hoist and hide the base constant behind a bitcast and emit /// materialization code for derived constants. bool ConstantHoistingPass::emitBaseConstants(GlobalVariable *BaseGV) { … } /// Check all cast instructions we made a copy of and remove them if they /// have no more users. void ConstantHoistingPass::deleteDeadCastInst() const { … } /// Optimize expensive integer constants in the given function. bool ConstantHoistingPass::runImpl(Function &Fn, TargetTransformInfo &TTI, DominatorTree &DT, BlockFrequencyInfo *BFI, BasicBlock &Entry, ProfileSummaryInfo *PSI) { … } PreservedAnalyses ConstantHoistingPass::run(Function &F, FunctionAnalysisManager &AM) { … }