123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- IROutliner.h - Extract similar IR regions into functions --*- 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
- //
- //===----------------------------------------------------------------------===//
- //
- // \file
- // The interface file for the IROutliner which is used by the IROutliner Pass.
- //
- // The outliner uses the IRSimilarityIdentifier to identify the similar regions
- // of code. It evaluates each set of IRSimilarityCandidates with an estimate of
- // whether it will provide code size reduction. Each region is extracted using
- // the code extractor. These extracted functions are consolidated into a single
- // function and called from the extracted call site.
- //
- // For example:
- // \code
- // %1 = add i32 %a, %b
- // %2 = add i32 %b, %a
- // %3 = add i32 %b, %a
- // %4 = add i32 %a, %b
- // \endcode
- // would become function
- // \code
- // define internal void outlined_ir_function(i32 %0, i32 %1) {
- // %1 = add i32 %0, %1
- // %2 = add i32 %1, %0
- // ret void
- // }
- // \endcode
- // with calls:
- // \code
- // call void outlined_ir_function(i32 %a, i32 %b)
- // call void outlined_ir_function(i32 %b, i32 %a)
- // \endcode
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_TRANSFORMS_IPO_IROUTLINER_H
- #define LLVM_TRANSFORMS_IPO_IROUTLINER_H
- #include "llvm/Analysis/IRSimilarityIdentifier.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/Support/InstructionCost.h"
- #include "llvm/Transforms/Utils/CodeExtractor.h"
- struct OutlinableGroup;
- namespace llvm {
- using namespace CallingConv;
- using namespace IRSimilarity;
- class Module;
- class TargetTransformInfo;
- class OptimizationRemarkEmitter;
- /// The OutlinableRegion holds all the information for a specific region, or
- /// sequence of instructions. This includes what values need to be hoisted to
- /// arguments from the extracted function, inputs and outputs to the region, and
- /// mapping from the extracted function arguments to overall function arguments.
- struct OutlinableRegion {
- /// Describes the region of code.
- IRSimilarityCandidate *Candidate = nullptr;
- /// If this region is outlined, the front and back IRInstructionData could
- /// potentially become invalidated if the only new instruction is a call.
- /// This ensures that we replace in the instruction in the IRInstructionData.
- IRInstructionData *NewFront = nullptr;
- IRInstructionData *NewBack = nullptr;
- /// The number of extracted inputs from the CodeExtractor.
- unsigned NumExtractedInputs = 0;
- /// The corresponding BasicBlock with the appropriate stores for this
- /// OutlinableRegion in the overall function.
- unsigned OutputBlockNum = -1;
- /// Mapping the extracted argument number to the argument number in the
- /// overall function. Since there will be inputs, such as elevated constants
- /// that are not the same in each region in a SimilarityGroup, or values that
- /// cannot be sunk into the extracted section in every region, we must keep
- /// track of which extracted argument maps to which overall argument.
- DenseMap<unsigned, unsigned> ExtractedArgToAgg;
- DenseMap<unsigned, unsigned> AggArgToExtracted;
- /// Values in the outlined functions will often be replaced by arguments. When
- /// finding corresponding values from one region to another, the found value
- /// will be the value the argument previously replaced. This structure maps
- /// any replaced values for the region to the aggregate aggregate argument
- /// in the overall function.
- DenseMap<Value *, Value *> RemappedArguments;
- /// Marks whether we need to change the order of the arguments when mapping
- /// the old extracted function call to the new aggregate outlined function
- /// call.
- bool ChangedArgOrder = false;
- /// Marks whether this region ends in a branch, there is special handling
- /// required for the following basic blocks in this case.
- bool EndsInBranch = false;
- /// The PHIBlocks with their corresponding return block based on the return
- /// value as the key.
- DenseMap<Value *, BasicBlock *> PHIBlocks;
- /// Mapping of the argument number in the deduplicated function
- /// to a given constant, which is used when creating the arguments to the call
- /// to the newly created deduplicated function. This is handled separately
- /// since the CodeExtractor does not recognize constants.
- DenseMap<unsigned, Constant *> AggArgToConstant;
- /// The global value numbers that are used as outputs for this section. Once
- /// extracted, each output will be stored to an output register. This
- /// documents the global value numbers that are used in this pattern.
- SmallVector<unsigned, 4> GVNStores;
- /// Used to create an outlined function.
- CodeExtractor *CE = nullptr;
- /// The call site of the extracted region.
- CallInst *Call = nullptr;
- /// The function for the extracted region.
- Function *ExtractedFunction = nullptr;
- /// Flag for whether we have split out the IRSimilarityCanidate. That is,
- /// make the region contained the IRSimilarityCandidate its own BasicBlock.
- bool CandidateSplit = false;
- /// Flag for whether we should not consider this region for extraction.
- bool IgnoreRegion = false;
- /// The BasicBlock that is before the start of the region BasicBlock,
- /// only defined when the region has been split.
- BasicBlock *PrevBB = nullptr;
- /// The BasicBlock that contains the starting instruction of the region.
- BasicBlock *StartBB = nullptr;
- /// The BasicBlock that contains the ending instruction of the region.
- BasicBlock *EndBB = nullptr;
- /// The BasicBlock that is after the start of the region BasicBlock,
- /// only defined when the region has been split.
- BasicBlock *FollowBB = nullptr;
- /// The Outlinable Group that contains this region and structurally similar
- /// regions to this region.
- OutlinableGroup *Parent = nullptr;
- OutlinableRegion(IRSimilarityCandidate &C, OutlinableGroup &Group)
- : Candidate(&C), Parent(&Group) {
- StartBB = C.getStartBB();
- EndBB = C.getEndBB();
- }
- /// For the contained region, split the parent BasicBlock at the starting and
- /// ending instructions of the contained IRSimilarityCandidate.
- void splitCandidate();
- /// For the contained region, reattach the BasicBlock at the starting and
- /// ending instructions of the contained IRSimilarityCandidate, or if the
- /// function has been extracted, the start and end of the BasicBlock
- /// containing the called function.
- void reattachCandidate();
- /// Find a corresponding value for \p V in similar OutlinableRegion \p Other.
- ///
- /// \param Other [in] - The OutlinableRegion to find the corresponding Value
- /// in.
- /// \param V [in] - The Value to look for in the other region.
- /// \return The corresponding Value to \p V if it exists, otherwise nullptr.
- Value *findCorrespondingValueIn(const OutlinableRegion &Other, Value *V);
- /// Find a corresponding BasicBlock for \p BB in similar OutlinableRegion \p Other.
- ///
- /// \param Other [in] - The OutlinableRegion to find the corresponding
- /// BasicBlock in.
- /// \param BB [in] - The BasicBlock to look for in the other region.
- /// \return The corresponding Value to \p V if it exists, otherwise nullptr.
- BasicBlock *findCorrespondingBlockIn(const OutlinableRegion &Other,
- BasicBlock *BB);
- /// Get the size of the code removed from the region.
- ///
- /// \param [in] TTI - The TargetTransformInfo for the parent function.
- /// \returns the code size of the region
- InstructionCost getBenefit(TargetTransformInfo &TTI);
- };
- /// This class is a pass that identifies similarity in a Module, extracts
- /// instances of the similarity, and then consolidating the similar regions
- /// in an effort to reduce code size. It uses the IRSimilarityIdentifier pass
- /// to identify the similar regions of code, and then extracts the similar
- /// sections into a single function. See the above for an example as to
- /// how code is extracted and consolidated into a single function.
- class IROutliner {
- public:
- IROutliner(function_ref<TargetTransformInfo &(Function &)> GTTI,
- function_ref<IRSimilarityIdentifier &(Module &)> GIRSI,
- function_ref<OptimizationRemarkEmitter &(Function &)> GORE)
- : getTTI(GTTI), getIRSI(GIRSI), getORE(GORE) {
-
- // Check that the DenseMap implementation has not changed.
- assert(DenseMapInfo<unsigned>::getEmptyKey() == (unsigned)-1 &&
- "DenseMapInfo<unsigned>'s empty key isn't -1!");
- assert(DenseMapInfo<unsigned>::getTombstoneKey() == (unsigned)-2 &&
- "DenseMapInfo<unsigned>'s tombstone key isn't -2!");
- }
- bool run(Module &M);
- private:
- /// Find repeated similar code sequences in \p M and outline them into new
- /// Functions.
- ///
- /// \param [in] M - The module to outline from.
- /// \returns The number of Functions created.
- unsigned doOutline(Module &M);
- /// Check whether an OutlinableRegion is incompatible with code already
- /// outlined. OutlinableRegions are incomptaible when there are overlapping
- /// instructions, or code that has not been recorded has been added to the
- /// instructions.
- ///
- /// \param [in] Region - The OutlinableRegion to check for conflicts with
- /// already outlined code.
- /// \returns whether the region can safely be outlined.
- bool isCompatibleWithAlreadyOutlinedCode(const OutlinableRegion &Region);
- /// Remove all the IRSimilarityCandidates from \p CandidateVec that have
- /// instructions contained in a previously outlined region and put the
- /// remaining regions in \p CurrentGroup.
- ///
- /// \param [in] CandidateVec - List of similarity candidates for regions with
- /// the same similarity structure.
- /// \param [in,out] CurrentGroup - Contains the potential sections to
- /// be outlined.
- void
- pruneIncompatibleRegions(std::vector<IRSimilarityCandidate> &CandidateVec,
- OutlinableGroup &CurrentGroup);
- /// Create the function based on the overall types found in the current
- /// regions being outlined.
- ///
- /// \param M - The module to outline from.
- /// \param [in,out] CG - The OutlinableGroup for the regions to be outlined.
- /// \param [in] FunctionNameSuffix - How many functions have we previously
- /// created.
- /// \returns the newly created function.
- Function *createFunction(Module &M, OutlinableGroup &CG,
- unsigned FunctionNameSuffix);
- /// Identify the needed extracted inputs in a section, and add to the overall
- /// function if needed.
- ///
- /// \param [in] M - The module to outline from.
- /// \param [in,out] Region - The region to be extracted.
- /// \param [in] NotSame - The global value numbers of the Values in the region
- /// that do not have the same Constant in each strucutrally similar region.
- void findAddInputsOutputs(Module &M, OutlinableRegion &Region,
- DenseSet<unsigned> &NotSame);
- /// Find the number of instructions that will be removed by extracting the
- /// OutlinableRegions in \p CurrentGroup.
- ///
- /// \param [in] CurrentGroup - The collection of OutlinableRegions to be
- /// analyzed.
- /// \returns the number of outlined instructions across all regions.
- InstructionCost findBenefitFromAllRegions(OutlinableGroup &CurrentGroup);
- /// Find the number of instructions that will be added by reloading arguments.
- ///
- /// \param [in] CurrentGroup - The collection of OutlinableRegions to be
- /// analyzed.
- /// \returns the number of added reload instructions across all regions.
- InstructionCost findCostOutputReloads(OutlinableGroup &CurrentGroup);
- /// Find the cost and the benefit of \p CurrentGroup and save it back to
- /// \p CurrentGroup.
- ///
- /// \param [in] M - The module being analyzed
- /// \param [in,out] CurrentGroup - The overall outlined section
- void findCostBenefit(Module &M, OutlinableGroup &CurrentGroup);
- /// Update the output mapping based on the load instruction, and the outputs
- /// of the extracted function.
- ///
- /// \param Region - The region extracted
- /// \param Outputs - The outputs from the extracted function.
- /// \param LI - The load instruction used to update the mapping.
- void updateOutputMapping(OutlinableRegion &Region,
- ArrayRef<Value *> Outputs, LoadInst *LI);
- /// Extract \p Region into its own function.
- ///
- /// \param [in] Region - The region to be extracted into its own function.
- /// \returns True if it was successfully outlined.
- bool extractSection(OutlinableRegion &Region);
- /// For the similarities found, and the extracted sections, create a single
- /// outlined function with appropriate output blocks as necessary.
- ///
- /// \param [in] M - The module to outline from
- /// \param [in] CurrentGroup - The set of extracted sections to consolidate.
- /// \param [in,out] FuncsToRemove - List of functions to remove from the
- /// module after outlining is completed.
- /// \param [in,out] OutlinedFunctionNum - the number of new outlined
- /// functions.
- void deduplicateExtractedSections(Module &M, OutlinableGroup &CurrentGroup,
- std::vector<Function *> &FuncsToRemove,
- unsigned &OutlinedFunctionNum);
- /// If true, enables us to outline from functions that have LinkOnceFromODR
- /// linkages.
- bool OutlineFromLinkODRs = false;
- /// If false, we do not worry if the cost is greater than the benefit. This
- /// is for debugging and testing, so that we can test small cases to ensure
- /// that the outlining is being done correctly.
- bool CostModel = true;
- /// The set of outlined Instructions, identified by their location in the
- /// sequential ordering of instructions in a Module.
- DenseSet<unsigned> Outlined;
- /// TargetTransformInfo lambda for target specific information.
- function_ref<TargetTransformInfo &(Function &)> getTTI;
- /// A mapping from newly created reloaded output values to the original value.
- /// If an value is replace by an output from an outlined region, this maps
- /// that Value, back to its original Value.
- DenseMap<Value *, Value *> OutputMappings;
- /// IRSimilarityIdentifier lambda to retrieve IRSimilarityIdentifier.
- function_ref<IRSimilarityIdentifier &(Module &)> getIRSI;
- /// The optimization remark emitter for the pass.
- function_ref<OptimizationRemarkEmitter &(Function &)> getORE;
- /// The memory allocator used to allocate the CodeExtractors.
- SpecificBumpPtrAllocator<CodeExtractor> ExtractorAllocator;
- /// The memory allocator used to allocate the OutlinableRegions.
- SpecificBumpPtrAllocator<OutlinableRegion> RegionAllocator;
- /// The memory allocator used to allocate new IRInstructionData.
- SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
- /// Custom InstVisitor to classify different instructions for whether it can
- /// be analyzed for similarity. This is needed as there may be instruction we
- /// can identify as having similarity, but are more complicated to outline.
- struct InstructionAllowed : public InstVisitor<InstructionAllowed, bool> {
- InstructionAllowed() = default;
- bool visitBranchInst(BranchInst &BI) { return EnableBranches; }
- bool visitPHINode(PHINode &PN) { return EnableBranches; }
- // TODO: Handle allocas.
- bool visitAllocaInst(AllocaInst &AI) { return false; }
- // VAArg instructions are not allowed since this could cause difficulty when
- // differentiating between different sets of variable instructions in
- // the deduplicated outlined regions.
- bool visitVAArgInst(VAArgInst &VI) { return false; }
- // We exclude all exception handling cases since they are so context
- // dependent.
- bool visitLandingPadInst(LandingPadInst &LPI) { return false; }
- bool visitFuncletPadInst(FuncletPadInst &FPI) { return false; }
- // DebugInfo should be included in the regions, but should not be
- // analyzed for similarity as it has no bearing on the outcome of the
- // program.
- bool visitDbgInfoIntrinsic(DbgInfoIntrinsic &DII) { return true; }
- // TODO: Handle specific intrinsics individually from those that can be
- // handled.
- bool IntrinsicInst(IntrinsicInst &II) { return EnableIntrinsics; }
- // We only handle CallInsts that are not indirect, since we cannot guarantee
- // that they have a name in these cases.
- bool visitCallInst(CallInst &CI) {
- Function *F = CI.getCalledFunction();
- bool IsIndirectCall = CI.isIndirectCall();
- if (IsIndirectCall && !EnableIndirectCalls)
- return false;
- if (!F && !IsIndirectCall)
- return false;
- // Returning twice can cause issues with the state of the function call
- // that were not expected when the function was used, so we do not include
- // the call in outlined functions.
- if (CI.canReturnTwice())
- return false;
- // TODO: Update the outliner to capture whether the outlined function
- // needs these extra attributes.
- // Functions marked with the swifttailcc and tailcc calling conventions
- // require special handling when outlining musttail functions. The
- // calling convention must be passed down to the outlined function as
- // well. Further, there is special handling for musttail calls as well,
- // requiring a return call directly after. For now, the outliner does not
- // support this.
- bool IsTailCC = CI.getCallingConv() == CallingConv::SwiftTail ||
- CI.getCallingConv() == CallingConv::Tail;
- if (IsTailCC && !EnableMustTailCalls)
- return false;
- if (CI.isMustTailCall() && !EnableMustTailCalls)
- return false;
- // The outliner can only handle musttail items if it is also accompanied
- // by the tailcc or swifttailcc calling convention.
- if (CI.isMustTailCall() && !IsTailCC)
- return false;
- return true;
- }
- // TODO: Handle FreezeInsts. Since a frozen value could be frozen inside
- // the outlined region, and then returned as an output, this will have to be
- // handled differently.
- bool visitFreezeInst(FreezeInst &CI) { return false; }
- // TODO: We do not current handle similarity that changes the control flow.
- bool visitInvokeInst(InvokeInst &II) { return false; }
- // TODO: We do not current handle similarity that changes the control flow.
- bool visitCallBrInst(CallBrInst &CBI) { return false; }
- // TODO: Handle interblock similarity.
- bool visitTerminator(Instruction &I) { return false; }
- bool visitInstruction(Instruction &I) { return true; }
- // The flag variable that marks whether we should allow branch instructions
- // to be outlined.
- bool EnableBranches = false;
- // The flag variable that marks whether we should allow indirect calls
- // to be outlined.
- bool EnableIndirectCalls = true;
- // The flag variable that marks whether we should allow intrinsics
- // instructions to be outlined.
- bool EnableIntrinsics = false;
- // The flag variable that marks whether we should allow musttail calls.
- bool EnableMustTailCalls = false;
- };
- /// A InstVisitor used to exclude certain instructions from being outlined.
- InstructionAllowed InstructionClassifier;
- };
- /// Pass to outline similar regions.
- class IROutlinerPass : public PassInfoMixin<IROutlinerPass> {
- public:
- PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
- };
- } // end namespace llvm
- #endif // LLVM_TRANSFORMS_IPO_IROUTLINER_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|