brintos

brintos / llvm-project-archived public Read only

0
0
Text · 123.7 KiB · 6e1ca9c Raw
3020 lines · cpp
1//===- IROutliner.cpp -- Outline Similar Regions ----------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10// Implementation for the IROutliner which is used by the IROutliner Pass.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Transforms/IPO/IROutliner.h"15#include "llvm/Analysis/IRSimilarityIdentifier.h"16#include "llvm/Analysis/OptimizationRemarkEmitter.h"17#include "llvm/Analysis/TargetTransformInfo.h"18#include "llvm/IR/Attributes.h"19#include "llvm/IR/DIBuilder.h"20#include "llvm/IR/DebugInfo.h"21#include "llvm/IR/DebugInfoMetadata.h"22#include "llvm/IR/Dominators.h"23#include "llvm/IR/Mangler.h"24#include "llvm/IR/PassManager.h"25#include "llvm/Support/CommandLine.h"26#include "llvm/Transforms/IPO.h"27#include "llvm/Transforms/Utils/ValueMapper.h"28#include <optional>29#include <vector>30 31#define DEBUG_TYPE "iroutliner"32 33using namespace llvm;34using namespace IRSimilarity;35 36// A command flag to be used for debugging to exclude branches from similarity37// matching and outlining.38namespace llvm {39extern cl::opt<bool> DisableBranches;40 41// A command flag to be used for debugging to indirect calls from similarity42// matching and outlining.43extern cl::opt<bool> DisableIndirectCalls;44 45// A command flag to be used for debugging to exclude intrinsics from similarity46// matching and outlining.47extern cl::opt<bool> DisableIntrinsics;48 49} // namespace llvm50 51// Set to true if the user wants the ir outliner to run on linkonceodr linkage52// functions. This is false by default because the linker can dedupe linkonceodr53// functions. Since the outliner is confined to a single module (modulo LTO),54// this is off by default. It should, however, be the default behavior in55// LTO.56static cl::opt<bool> EnableLinkOnceODRIROutlining(57    "enable-linkonceodr-ir-outlining", cl::Hidden,58    cl::desc("Enable the IR outliner on linkonceodr functions"),59    cl::init(false));60 61// This is a debug option to test small pieces of code to ensure that outlining62// works correctly.63static cl::opt<bool> NoCostModel(64    "ir-outlining-no-cost", cl::init(false), cl::ReallyHidden,65    cl::desc("Debug option to outline greedily, without restriction that "66             "calculated benefit outweighs cost"));67 68/// The OutlinableGroup holds all the overarching information for outlining69/// a set of regions that are structurally similar to one another, such as the70/// types of the overall function, the output blocks, the sets of stores needed71/// and a list of the different regions. This information is used in the72/// deduplication of extracted regions with the same structure.73struct OutlinableGroup {74  /// The sections that could be outlined75  std::vector<OutlinableRegion *> Regions;76 77  /// The argument types for the function created as the overall function to78  /// replace the extracted function for each region.79  std::vector<Type *> ArgumentTypes;80  /// The FunctionType for the overall function.81  FunctionType *OutlinedFunctionType = nullptr;82  /// The Function for the collective overall function.83  Function *OutlinedFunction = nullptr;84 85  /// Flag for whether we should not consider this group of OutlinableRegions86  /// for extraction.87  bool IgnoreGroup = false;88 89  /// The return blocks for the overall function.90  DenseMap<Value *, BasicBlock *> EndBBs;91 92  /// The PHIBlocks with their corresponding return block based on the return93  /// value as the key.94  DenseMap<Value *, BasicBlock *> PHIBlocks;95 96  /// A set containing the different GVN store sets needed. Each array contains97  /// a sorted list of the different values that need to be stored into output98  /// registers.99  DenseSet<ArrayRef<unsigned>> OutputGVNCombinations;100 101  /// Flag for whether the \ref ArgumentTypes have been defined after the102  /// extraction of the first region.103  bool InputTypesSet = false;104 105  /// The number of input values in \ref ArgumentTypes.  Anything after this106  /// index in ArgumentTypes is an output argument.107  unsigned NumAggregateInputs = 0;108 109  /// The mapping of the canonical numbering of the values in outlined sections110  /// to specific arguments.111  DenseMap<unsigned, unsigned> CanonicalNumberToAggArg;112 113  /// The number of branches in the region target a basic block that is outside114  /// of the region.115  unsigned BranchesToOutside = 0;116 117  /// Tracker counting backwards from the highest unsigned value possible to118  /// avoid conflicting with the GVNs of assigned values.  We start at -3 since119  /// -2 and -1 are assigned by the DenseMap.120  unsigned PHINodeGVNTracker = -3;121 122  DenseMap<unsigned,123           std::pair<std::pair<unsigned, unsigned>, SmallVector<unsigned, 2>>>124      PHINodeGVNToGVNs;125  DenseMap<hash_code, unsigned> GVNsToPHINodeGVN;126 127  /// The number of instructions that will be outlined by extracting \ref128  /// Regions.129  InstructionCost Benefit = 0;130  /// The number of added instructions needed for the outlining of the \ref131  /// Regions.132  InstructionCost Cost = 0;133 134  /// The argument that needs to be marked with the swifterr attribute.  If not135  /// needed, there is no value.136  std::optional<unsigned> SwiftErrorArgument;137 138  /// For the \ref Regions, we look at every Value.  If it is a constant,139  /// we check whether it is the same in Region.140  ///141  /// \param [in,out] NotSame contains the global value numbers where the142  /// constant is not always the same, and must be passed in as an argument.143  void findSameConstants(DenseSet<unsigned> &NotSame);144 145  /// For the regions, look at each set of GVN stores needed and account for146  /// each combination.  Add an argument to the argument types if there is147  /// more than one combination.148  ///149  /// \param [in] M - The module we are outlining from.150  void collectGVNStoreSets(Module &M);151};152 153/// Move the contents of \p SourceBB to before the last instruction of \p154/// TargetBB.155/// \param SourceBB - the BasicBlock to pull Instructions from.156/// \param TargetBB - the BasicBlock to put Instruction into.157static void moveBBContents(BasicBlock &SourceBB, BasicBlock &TargetBB) {158  TargetBB.splice(TargetBB.end(), &SourceBB);159}160 161/// A function to sort the keys of \p Map, which must be a mapping of constant162/// values to basic blocks and return it in \p SortedKeys163///164/// \param SortedKeys - The vector the keys will be return in and sorted.165/// \param Map - The DenseMap containing keys to sort.166static void getSortedConstantKeys(std::vector<Value *> &SortedKeys,167                                  DenseMap<Value *, BasicBlock *> &Map) {168  for (auto &VtoBB : Map)169    SortedKeys.push_back(VtoBB.first);170 171  // Here we expect to have either 1 value that is void (nullptr) or multiple172  // values that are all constant integers.173  if (SortedKeys.size() == 1) {174    assert(!SortedKeys[0] && "Expected a single void value.");175    return;176  }177 178  stable_sort(SortedKeys, [](const Value *LHS, const Value *RHS) {179    assert(LHS && RHS && "Expected non void values.");180    const ConstantInt *LHSC = cast<ConstantInt>(LHS);181    const ConstantInt *RHSC = cast<ConstantInt>(RHS);182 183    return LHSC->getLimitedValue() < RHSC->getLimitedValue();184  });185}186 187Value *OutlinableRegion::findCorrespondingValueIn(const OutlinableRegion &Other,188                                                  Value *V) {189  std::optional<unsigned> GVN = Candidate->getGVN(V);190  assert(GVN && "No GVN for incoming value");191  std::optional<unsigned> CanonNum = Candidate->getCanonicalNum(*GVN);192  std::optional<unsigned> FirstGVN =193      Other.Candidate->fromCanonicalNum(*CanonNum);194  std::optional<Value *> FoundValueOpt = Other.Candidate->fromGVN(*FirstGVN);195  return FoundValueOpt.value_or(nullptr);196}197 198BasicBlock *199OutlinableRegion::findCorrespondingBlockIn(const OutlinableRegion &Other,200                                           BasicBlock *BB) {201  Instruction *FirstNonPHI = &*BB->getFirstNonPHIOrDbg();202  assert(FirstNonPHI && "block is empty?");203  Value *CorrespondingVal = findCorrespondingValueIn(Other, FirstNonPHI);204  if (!CorrespondingVal)205    return nullptr;206  BasicBlock *CorrespondingBlock =207      cast<Instruction>(CorrespondingVal)->getParent();208  return CorrespondingBlock;209}210 211/// Rewrite the BranchInsts in the incoming blocks to \p PHIBlock that are found212/// in \p Included to branch to BasicBlock \p Replace if they currently branch213/// to the BasicBlock \p Find.  This is used to fix up the incoming basic blocks214/// when PHINodes are included in outlined regions.215///216/// \param PHIBlock - The BasicBlock containing the PHINodes that need to be217/// checked.218/// \param Find - The successor block to be replaced.219/// \param Replace - The new succesor block to branch to.220/// \param Included - The set of blocks about to be outlined.221static void replaceTargetsFromPHINode(BasicBlock *PHIBlock, BasicBlock *Find,222                                      BasicBlock *Replace,223                                      DenseSet<BasicBlock *> &Included) {224  for (PHINode &PN : PHIBlock->phis()) {225    for (unsigned Idx = 0, PNEnd = PN.getNumIncomingValues(); Idx != PNEnd;226         ++Idx) {227      // Check if the incoming block is included in the set of blocks being228      // outlined.229      BasicBlock *Incoming = PN.getIncomingBlock(Idx);230      if (!Included.contains(Incoming))231        continue;232 233      BranchInst *BI = dyn_cast<BranchInst>(Incoming->getTerminator());234      assert(BI && "Not a branch instruction?");235      // Look over the branching instructions into this block to see if we236      // used to branch to Find in this outlined block.237      for (unsigned Succ = 0, End = BI->getNumSuccessors(); Succ != End;238           Succ++) {239        // If we have found the block to replace, we do so here.240        if (BI->getSuccessor(Succ) != Find)241          continue;242        BI->setSuccessor(Succ, Replace);243      }244    }245  }246}247 248 249void OutlinableRegion::splitCandidate() {250  assert(!CandidateSplit && "Candidate already split!");251 252  Instruction *BackInst = Candidate->backInstruction();253 254  Instruction *EndInst = nullptr;255  // Check whether the last instruction is a terminator, if it is, we do256  // not split on the following instruction. We leave the block as it is.  We257  // also check that this is not the last instruction in the Module, otherwise258  // the check for whether the current following instruction matches the259  // previously recorded instruction will be incorrect.260  if (!BackInst->isTerminator() ||261      BackInst->getParent() != &BackInst->getFunction()->back()) {262    EndInst = Candidate->end()->Inst;263    assert(EndInst && "Expected an end instruction?");264  }265 266  // We check if the current instruction following the last instruction in the267  // region is the same as the recorded instruction following the last268  // instruction. If they do not match, there could be problems in rewriting269  // the program after outlining, so we ignore it.270  if (!BackInst->isTerminator() && EndInst != BackInst->getNextNode())271    return;272 273  Instruction *StartInst = (*Candidate->begin()).Inst;274  assert(StartInst && "Expected a start instruction?");275  StartBB = StartInst->getParent();276  PrevBB = StartBB;277 278  DenseSet<BasicBlock *> BBSet;279  Candidate->getBasicBlocks(BBSet);280 281  // We iterate over the instructions in the region, if we find a PHINode, we282  // check if there are predecessors outside of the region, if there are,283  // we ignore this region since we are unable to handle the severing of the284  // phi node right now.285 286  // TODO: Handle extraneous inputs for PHINodes through variable number of287  // inputs, similar to how outputs are handled.288  BasicBlock::iterator It = StartInst->getIterator();289  EndBB = BackInst->getParent();290  BasicBlock *IBlock;291  BasicBlock *PHIPredBlock = nullptr;292  bool EndBBTermAndBackInstDifferent = EndBB->getTerminator() != BackInst;293  while (PHINode *PN = dyn_cast<PHINode>(&*It)) {294    unsigned NumPredsOutsideRegion = 0;295    for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {296      if (!BBSet.contains(PN->getIncomingBlock(i))) {297        PHIPredBlock = PN->getIncomingBlock(i);298        ++NumPredsOutsideRegion;299        continue;300      }301 302      // We must consider the case there the incoming block to the PHINode is303      // the same as the final block of the OutlinableRegion.  If this is the304      // case, the branch from this block must also be outlined to be valid.305      IBlock = PN->getIncomingBlock(i);306      if (IBlock == EndBB && EndBBTermAndBackInstDifferent) {307        PHIPredBlock = PN->getIncomingBlock(i);308        ++NumPredsOutsideRegion;309      }310    }311 312    if (NumPredsOutsideRegion > 1)313      return;314    315    It++;316  }317 318  // If the region starts with a PHINode, but is not the initial instruction of319  // the BasicBlock, we ignore this region for now.320  if (isa<PHINode>(StartInst) && StartInst != &*StartBB->begin())321    return;322  323  // If the region ends with a PHINode, but does not contain all of the phi node324  // instructions of the region, we ignore it for now.325  if (isa<PHINode>(BackInst) &&326      BackInst != &*std::prev(EndBB->getFirstInsertionPt()))327    return;328 329  // The basic block gets split like so:330  // block:                 block:331  //   inst1                  inst1332  //   inst2                  inst2333  //   region1               br block_to_outline334  //   region2              block_to_outline:335  //   region3          ->    region1336  //   region4                region2337  //   inst3                  region3338  //   inst4                  region4339  //                          br block_after_outline340  //                        block_after_outline:341  //                          inst3342  //                          inst4343 344  std::string OriginalName = PrevBB->getName().str();345 346  StartBB = PrevBB->splitBasicBlock(StartInst, OriginalName + "_to_outline");347  PrevBB->replaceSuccessorsPhiUsesWith(PrevBB, StartBB);348  // If there was a PHINode with an incoming block outside the region,349  // make sure is correctly updated in the newly split block.350  if (PHIPredBlock)351    PrevBB->replaceSuccessorsPhiUsesWith(PHIPredBlock, PrevBB);352 353  CandidateSplit = true;354  if (!BackInst->isTerminator()) {355    EndBB = EndInst->getParent();356    FollowBB = EndBB->splitBasicBlock(EndInst, OriginalName + "_after_outline");357    EndBB->replaceSuccessorsPhiUsesWith(EndBB, FollowBB);358    FollowBB->replaceSuccessorsPhiUsesWith(PrevBB, FollowBB);359  } else {360    EndBB = BackInst->getParent();361    EndsInBranch = true;362    FollowBB = nullptr;363  }364 365  // Refind the basic block set.366  BBSet.clear();367  Candidate->getBasicBlocks(BBSet);368  // For the phi nodes in the new starting basic block of the region, we369  // reassign the targets of the basic blocks branching instructions.370  replaceTargetsFromPHINode(StartBB, PrevBB, StartBB, BBSet);371  if (FollowBB)372    replaceTargetsFromPHINode(FollowBB, EndBB, FollowBB, BBSet);373}374 375void OutlinableRegion::reattachCandidate() {376  assert(CandidateSplit && "Candidate is not split!");377 378  // The basic block gets reattached like so:379  // block:                        block:380  //   inst1                         inst1381  //   inst2                         inst2382  //   br block_to_outline           region1383  // block_to_outline:        ->     region2384  //   region1                       region3385  //   region2                       region4386  //   region3                       inst3387  //   region4                       inst4388  //   br block_after_outline389  // block_after_outline:390  //   inst3391  //   inst4392  assert(StartBB != nullptr && "StartBB for Candidate is not defined!");393 394  assert(PrevBB->getTerminator() && "Terminator removed from PrevBB!");395  // Make sure PHINode references to the block we are merging into are396  // updated to be incoming blocks from the predecessor to the current block.397 398  // NOTE: If this is updated such that the outlined block can have more than399  // one incoming block to a PHINode, this logic will have to updated400  // to handle multiple precessors instead.401 402  // We only need to update this if the outlined section contains a PHINode, if403  // it does not, then the incoming block was never changed in the first place.404  // On the other hand, if PrevBB has no predecessors, it means that all405  // incoming blocks to the first block are contained in the region, and there406  // will be nothing to update.407  Instruction *StartInst = (*Candidate->begin()).Inst;408  if (isa<PHINode>(StartInst) && !PrevBB->hasNPredecessors(0)) {409    assert(!PrevBB->hasNPredecessorsOrMore(2) &&410         "PrevBB has more than one predecessor. Should be 0 or 1.");411    BasicBlock *BeforePrevBB = PrevBB->getSinglePredecessor();412    PrevBB->replaceSuccessorsPhiUsesWith(PrevBB, BeforePrevBB);413  }414  PrevBB->getTerminator()->eraseFromParent();415 416  // If we reattaching after outlining, we iterate over the phi nodes to417  // the initial block, and reassign the branch instructions of the incoming418  // blocks to the block we are remerging into.419  if (!ExtractedFunction) {420    DenseSet<BasicBlock *> BBSet;421    Candidate->getBasicBlocks(BBSet);422 423    replaceTargetsFromPHINode(StartBB, StartBB, PrevBB, BBSet);424    if (!EndsInBranch)425      replaceTargetsFromPHINode(FollowBB, FollowBB, EndBB, BBSet);426  }427 428  moveBBContents(*StartBB, *PrevBB);429 430  BasicBlock *PlacementBB = PrevBB;431  if (StartBB != EndBB)432    PlacementBB = EndBB;433  if (!EndsInBranch && PlacementBB->getUniqueSuccessor() != nullptr) {434    assert(FollowBB != nullptr && "FollowBB for Candidate is not defined!");435    assert(PlacementBB->getTerminator() && "Terminator removed from EndBB!");436    PlacementBB->getTerminator()->eraseFromParent();437    moveBBContents(*FollowBB, *PlacementBB);438    PlacementBB->replaceSuccessorsPhiUsesWith(FollowBB, PlacementBB);439    FollowBB->eraseFromParent();440  }441 442  PrevBB->replaceSuccessorsPhiUsesWith(StartBB, PrevBB);443  StartBB->eraseFromParent();444 445  // Make sure to save changes back to the StartBB.446  StartBB = PrevBB;447  EndBB = nullptr;448  PrevBB = nullptr;449  FollowBB = nullptr;450 451  CandidateSplit = false;452}453 454/// Find whether \p V matches the Constants previously found for the \p GVN.455///456/// \param V - The value to check for consistency.457/// \param GVN - The global value number assigned to \p V.458/// \param GVNToConstant - The mapping of global value number to Constants.459/// \returns true if the Value matches the Constant mapped to by V and false if460/// it \p V is a Constant but does not match.461/// \returns std::nullopt if \p V is not a Constant.462static std::optional<bool>463constantMatches(Value *V, unsigned GVN,464                DenseMap<unsigned, Constant *> &GVNToConstant) {465  // See if we have a constants466  Constant *CST = dyn_cast<Constant>(V);467  if (!CST)468    return std::nullopt;469 470  // Holds a mapping from a global value number to a Constant.471  DenseMap<unsigned, Constant *>::iterator GVNToConstantIt;472  bool Inserted;473 474 475  // If we have a constant, try to make a new entry in the GVNToConstant.476  std::tie(GVNToConstantIt, Inserted) =477      GVNToConstant.insert(std::make_pair(GVN, CST));478  // If it was found and is not equal, it is not the same. We do not479  // handle this case yet, and exit early.480  if (Inserted || (GVNToConstantIt->second == CST))481    return true;482 483  return false;484}485 486InstructionCost OutlinableRegion::getBenefit(TargetTransformInfo &TTI) {487  InstructionCost Benefit = 0;488 489  // Estimate the benefit of outlining a specific sections of the program.  We490  // delegate mostly this task to the TargetTransformInfo so that if the target491  // has specific changes, we can have a more accurate estimate.492 493  // However, getInstructionCost delegates the code size calculation for494  // arithmetic instructions to getArithmeticInstrCost in495  // include/Analysis/TargetTransformImpl.h, where it always estimates that the496  // code size for a division and remainder instruction to be equal to 4, and497  // everything else to 1.  This is not an accurate representation of the498  // division instruction for targets that have a native division instruction.499  // To be overly conservative, we only add 1 to the number of instructions for500  // each division instruction.501  for (IRInstructionData &ID : *Candidate) {502    Instruction *I = ID.Inst;503    switch (I->getOpcode()) {504    case Instruction::FDiv:505    case Instruction::FRem:506    case Instruction::SDiv:507    case Instruction::SRem:508    case Instruction::UDiv:509    case Instruction::URem:510      Benefit += 1;511      break;512    default:513      Benefit += TTI.getInstructionCost(I, TargetTransformInfo::TCK_CodeSize);514      break;515    }516  }517 518  return Benefit;519}520 521/// Check the \p OutputMappings structure for value \p Input, if it exists522/// it has been used as an output for outlining, and has been renamed, and we523/// return the new value, otherwise, we return the same value.524///525/// \param OutputMappings [in] - The mapping of values to their renamed value526/// after being used as an output for an outlined region.527/// \param Input [in] - The value to find the remapped value of, if it exists.528/// \return The remapped value if it has been renamed, and the same value if has529/// not.530static Value *findOutputMapping(const DenseMap<Value *, Value *> OutputMappings,531                                Value *Input) {532  DenseMap<Value *, Value *>::const_iterator OutputMapping =533      OutputMappings.find(Input);534  if (OutputMapping != OutputMappings.end())535    return OutputMapping->second;536  return Input;537}538 539/// Find whether \p Region matches the global value numbering to Constant540/// mapping found so far.541///542/// \param Region - The OutlinableRegion we are checking for constants543/// \param GVNToConstant - The mapping of global value number to Constants.544/// \param NotSame - The set of global value numbers that do not have the same545/// constant in each region.546/// \returns true if all Constants are the same in every use of a Constant in \p547/// Region and false if not548static bool549collectRegionsConstants(OutlinableRegion &Region,550                        DenseMap<unsigned, Constant *> &GVNToConstant,551                        DenseSet<unsigned> &NotSame) {552  bool ConstantsTheSame = true;553 554  IRSimilarityCandidate &C = *Region.Candidate;555  for (IRInstructionData &ID : C) {556 557    // Iterate over the operands in an instruction. If the global value number,558    // assigned by the IRSimilarityCandidate, has been seen before, we check if559    // the number has been found to be not the same value in each instance.560    for (Value *V : ID.OperVals) {561      std::optional<unsigned> GVNOpt = C.getGVN(V);562      assert(GVNOpt && "Expected a GVN for operand?");563      unsigned GVN = *GVNOpt;564 565      // Check if this global value has been found to not be the same already.566      if (NotSame.contains(GVN)) {567        if (isa<Constant>(V))568          ConstantsTheSame = false;569        continue;570      }571 572      // If it has been the same so far, we check the value for if the573      // associated Constant value match the previous instances of the same574      // global value number.  If the global value does not map to a Constant,575      // it is considered to not be the same value.576      std::optional<bool> ConstantMatches =577          constantMatches(V, GVN, GVNToConstant);578      if (ConstantMatches) {579        if (*ConstantMatches)580          continue;581        else582          ConstantsTheSame = false;583      }584 585      // While this value is a register, it might not have been previously,586      // make sure we don't already have a constant mapped to this global value587      // number.588      if (GVNToConstant.contains(GVN))589        ConstantsTheSame = false;590 591      NotSame.insert(GVN);592    }593  }594 595  return ConstantsTheSame;596}597 598void OutlinableGroup::findSameConstants(DenseSet<unsigned> &NotSame) {599  DenseMap<unsigned, Constant *> GVNToConstant;600 601  for (OutlinableRegion *Region : Regions)602    collectRegionsConstants(*Region, GVNToConstant, NotSame);603}604 605void OutlinableGroup::collectGVNStoreSets(Module &M) {606  for (OutlinableRegion *OS : Regions)607    OutputGVNCombinations.insert(OS->GVNStores);608 609  // We are adding an extracted argument to decide between which output path610  // to use in the basic block.  It is used in a switch statement and only611  // needs to be an integer.612  if (OutputGVNCombinations.size() > 1)613    ArgumentTypes.push_back(Type::getInt32Ty(M.getContext()));614}615 616/// Get the subprogram if it exists for one of the outlined regions.617///618/// \param [in] Group - The set of regions to find a subprogram for.619/// \returns the subprogram if it exists, or nullptr.620static DISubprogram *getSubprogramOrNull(OutlinableGroup &Group) {621  for (OutlinableRegion *OS : Group.Regions)622    if (Function *F = OS->Call->getFunction())623      if (DISubprogram *SP = F->getSubprogram())624        return SP;625 626  return nullptr;627}628 629Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group,630                                     unsigned FunctionNameSuffix) {631  assert(!Group.OutlinedFunction && "Function is already defined!");632 633  Type *RetTy = Type::getVoidTy(M.getContext());634  // All extracted functions _should_ have the same return type at this point635  // since the similarity identifier ensures that all branches outside of the636  // region occur in the same place.637 638  // NOTE: Should we ever move to the model that uses a switch at every point639  // needed, meaning that we could branch within the region or out, it is640  // possible that we will need to switch to using the most general case all of641  // the time.642  for (OutlinableRegion *R : Group.Regions) {643    Type *ExtractedFuncType = R->ExtractedFunction->getReturnType();644    if ((RetTy->isVoidTy() && !ExtractedFuncType->isVoidTy()) ||645        (RetTy->isIntegerTy(1) && ExtractedFuncType->isIntegerTy(16)))646      RetTy = ExtractedFuncType;647  }648 649  Group.OutlinedFunctionType = FunctionType::get(650      RetTy, Group.ArgumentTypes, false);651 652  // These functions will only be called from within the same module, so653  // we can set an internal linkage.654  Group.OutlinedFunction = Function::Create(655      Group.OutlinedFunctionType, GlobalValue::InternalLinkage,656      "outlined_ir_func_" + std::to_string(FunctionNameSuffix), M);657 658  // Transfer the swifterr attribute to the correct function parameter.659  if (Group.SwiftErrorArgument)660    Group.OutlinedFunction->addParamAttr(*Group.SwiftErrorArgument,661                                         Attribute::SwiftError);662 663  Group.OutlinedFunction->addFnAttr(Attribute::OptimizeForSize);664  Group.OutlinedFunction->addFnAttr(Attribute::MinSize);665 666  // If there's a DISubprogram associated with this outlined function, then667  // emit debug info for the outlined function.668  if (DISubprogram *SP = getSubprogramOrNull(Group)) {669    Function *F = Group.OutlinedFunction;670    // We have a DISubprogram. Get its DICompileUnit.671    DICompileUnit *CU = SP->getUnit();672    DIBuilder DB(M, true, CU);673    DIFile *Unit = SP->getFile();674    Mangler Mg;675    // Get the mangled name of the function for the linkage name.676    std::string Dummy;677    llvm::raw_string_ostream MangledNameStream(Dummy);678    Mg.getNameWithPrefix(MangledNameStream, F, false);679 680    DISubprogram *OutlinedSP = DB.createFunction(681        Unit /* Context */, F->getName(), Dummy, Unit /* File */,682        0 /* Line 0 is reserved for compiler-generated code. */,683        DB.createSubroutineType(DB.getOrCreateTypeArray({})), /* void type */684        0, /* Line 0 is reserved for compiler-generated code. */685        DINode::DIFlags::FlagArtificial /* Compiler-generated code. */,686        /* Outlined code is optimized code by definition. */687        DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized);688 689    // Attach subprogram to the function.690    F->setSubprogram(OutlinedSP);691    // We're done with the DIBuilder.692    DB.finalize();693  }694 695  return Group.OutlinedFunction;696}697 698/// Move each BasicBlock in \p Old to \p New.699///700/// \param [in] Old - The function to move the basic blocks from.701/// \param [in] New - The function to move the basic blocks to.702/// \param [out] NewEnds - The return blocks of the new overall function.703static void moveFunctionData(Function &Old, Function &New,704                             DenseMap<Value *, BasicBlock *> &NewEnds) {705  for (BasicBlock &CurrBB : llvm::make_early_inc_range(Old)) {706    CurrBB.removeFromParent();707    CurrBB.insertInto(&New);708    Instruction *I = CurrBB.getTerminator();709 710    // For each block we find a return instruction is, it is a potential exit711    // path for the function.  We keep track of each block based on the return712    // value here.713    if (ReturnInst *RI = dyn_cast<ReturnInst>(I))714      NewEnds.insert(std::make_pair(RI->getReturnValue(), &CurrBB));715 716    for (Instruction &Val : CurrBB) {717      // Since debug-info originates from many different locations in the718      // program, it will cause incorrect reporting from a debugger if we keep719      // the same debug instructions. Drop non-intrinsic DbgVariableRecords720      // here, collect intrinsics for removal later.721      Val.dropDbgRecords();722 723      // We must handle the scoping of called functions differently than724      // other outlined instructions.725      if (!isa<CallInst>(&Val)) {726        // Remove the debug information for outlined functions.727        Val.setDebugLoc(DebugLoc::getDropped());728 729        // Loop info metadata may contain line locations. Update them to have no730        // value in the new subprogram since the outlined code could be from731        // several locations.732        auto updateLoopInfoLoc = [&New](Metadata *MD) -> Metadata * {733          if (DISubprogram *SP = New.getSubprogram())734            if (auto *Loc = dyn_cast_or_null<DILocation>(MD))735              return DILocation::get(New.getContext(), Loc->getLine(),736                                     Loc->getColumn(), SP, nullptr);737          return MD;738        };739        updateLoopMetadataDebugLocations(Val, updateLoopInfoLoc);740        continue;741      }742 743      // Edit the scope of called functions inside of outlined functions.744      if (DISubprogram *SP = New.getSubprogram()) {745        DILocation *DI = DILocation::get(New.getContext(), 0, 0, SP);746        Val.setDebugLoc(DI);747      }748    }749  }750}751 752/// Find the constants that will need to be lifted into arguments753/// as they are not the same in each instance of the region.754///755/// \param [in] C - The IRSimilarityCandidate containing the region we are756/// analyzing.757/// \param [in] NotSame - The set of global value numbers that do not have a758/// single Constant across all OutlinableRegions similar to \p C.759/// \param [out] Inputs - The list containing the global value numbers of the760/// arguments needed for the region of code.761static void findConstants(IRSimilarityCandidate &C, DenseSet<unsigned> &NotSame,762                          std::vector<unsigned> &Inputs) {763  DenseSet<unsigned> Seen;764  // Iterate over the instructions, and find what constants will need to be765  // extracted into arguments.766  for (IRInstructionDataList::iterator IDIt = C.begin(), EndIDIt = C.end();767       IDIt != EndIDIt; IDIt++) {768    for (Value *V : (*IDIt).OperVals) {769      // Since these are stored before any outlining, they will be in the770      // global value numbering.771      unsigned GVN = *C.getGVN(V);772      if (isa<Constant>(V))773        if (NotSame.contains(GVN) && Seen.insert(GVN).second)774          Inputs.push_back(GVN);775    }776  }777}778 779/// Find the GVN for the inputs that have been found by the CodeExtractor.780///781/// \param [in] C - The IRSimilarityCandidate containing the region we are782/// analyzing.783/// \param [in] CurrentInputs - The set of inputs found by the784/// CodeExtractor.785/// \param [in] OutputMappings - The mapping of values that have been replaced786/// by a new output value.787/// \param [out] EndInputNumbers - The global value numbers for the extracted788/// arguments.789static void mapInputsToGVNs(IRSimilarityCandidate &C,790                            SetVector<Value *> &CurrentInputs,791                            const DenseMap<Value *, Value *> &OutputMappings,792                            std::vector<unsigned> &EndInputNumbers) {793  // Get the Global Value Number for each input.  We check if the Value has been794  // replaced by a different value at output, and use the original value before795  // replacement.796  for (Value *Input : CurrentInputs) {797    assert(Input && "Have a nullptr as an input");798    auto It = OutputMappings.find(Input);799    if (It != OutputMappings.end())800      Input = It->second;801    assert(C.getGVN(Input) && "Could not find a numbering for the given input");802    EndInputNumbers.push_back(*C.getGVN(Input));803  }804}805 806/// Find the original value for the \p ArgInput values if any one of them was807/// replaced during a previous extraction.808///809/// \param [in] ArgInputs - The inputs to be extracted by the code extractor.810/// \param [in] OutputMappings - The mapping of values that have been replaced811/// by a new output value.812/// \param [out] RemappedArgInputs - The remapped values according to813/// \p OutputMappings that will be extracted.814static void815remapExtractedInputs(const ArrayRef<Value *> ArgInputs,816                     const DenseMap<Value *, Value *> &OutputMappings,817                     SetVector<Value *> &RemappedArgInputs) {818  // Get the global value number for each input that will be extracted as an819  // argument by the code extractor, remapping if needed for reloaded values.820  for (Value *Input : ArgInputs) {821    auto It = OutputMappings.find(Input);822    if (It != OutputMappings.end())823      Input = It->second;824    RemappedArgInputs.insert(Input);825  }826}827 828/// Find the input GVNs and the output values for a region of Instructions.829/// Using the code extractor, we collect the inputs to the extracted function.830///831/// The \p Region can be identified as needing to be ignored in this function.832/// It should be checked whether it should be ignored after a call to this833/// function.834///835/// \param [in,out] Region - The region of code to be analyzed.836/// \param [out] InputGVNs - The global value numbers for the extracted837/// arguments.838/// \param [in] NotSame - The global value numbers in the region that do not839/// have the same constant value in the regions structurally similar to840/// \p Region.841/// \param [in] OutputMappings - The mapping of values that have been replaced842/// by a new output value after extraction.843/// \param [out] ArgInputs - The values of the inputs to the extracted function.844/// \param [out] Outputs - The set of values extracted by the CodeExtractor845/// as outputs.846static void getCodeExtractorArguments(847    OutlinableRegion &Region, std::vector<unsigned> &InputGVNs,848    DenseSet<unsigned> &NotSame, DenseMap<Value *, Value *> &OutputMappings,849    SetVector<Value *> &ArgInputs, SetVector<Value *> &Outputs) {850  IRSimilarityCandidate &C = *Region.Candidate;851 852  // OverallInputs are the inputs to the region found by the CodeExtractor,853  // SinkCands and HoistCands are used by the CodeExtractor to find sunken854  // allocas of values whose lifetimes are contained completely within the855  // outlined region. PremappedInputs are the arguments found by the856  // CodeExtractor, removing conditions such as sunken allocas, but that857  // may need to be remapped due to the extracted output values replacing858  // the original values. We use DummyOutputs for this first run of finding859  // inputs and outputs since the outputs could change during findAllocas,860  // the correct set of extracted outputs will be in the final Outputs ValueSet.861  SetVector<Value *> OverallInputs, PremappedInputs, SinkCands, HoistCands,862      DummyOutputs;863 864  // Use the code extractor to get the inputs and outputs, without sunken865  // allocas or removing llvm.assumes.866  CodeExtractor *CE = Region.CE;867  CE->findInputsOutputs(OverallInputs, DummyOutputs, SinkCands);868  assert(Region.StartBB && "Region must have a start BasicBlock!");869  Function *OrigF = Region.StartBB->getParent();870  CodeExtractorAnalysisCache CEAC(*OrigF);871  BasicBlock *Dummy = nullptr;872 873  // The region may be ineligible due to VarArgs in the parent function. In this874  // case we ignore the region.875  if (!CE->isEligible()) {876    Region.IgnoreRegion = true;877    return;878  }879 880  // Find if any values are going to be sunk into the function when extracted881  CE->findAllocas(CEAC, SinkCands, HoistCands, Dummy);882  CE->findInputsOutputs(PremappedInputs, Outputs, SinkCands);883 884  // TODO: Support regions with sunken allocas: values whose lifetimes are885  // contained completely within the outlined region.  These are not guaranteed886  // to be the same in every region, so we must elevate them all to arguments887  // when they appear.  If these values are not equal, it means there is some888  // Input in OverallInputs that was removed for ArgInputs.889  if (OverallInputs.size() != PremappedInputs.size()) {890    Region.IgnoreRegion = true;891    return;892  }893 894  findConstants(C, NotSame, InputGVNs);895 896  mapInputsToGVNs(C, OverallInputs, OutputMappings, InputGVNs);897 898  remapExtractedInputs(PremappedInputs.getArrayRef(), OutputMappings,899                       ArgInputs);900 901  // Sort the GVNs, since we now have constants included in the \ref InputGVNs902  // we need to make sure they are in a deterministic order.903  stable_sort(InputGVNs);904}905 906/// Look over the inputs and map each input argument to an argument in the907/// overall function for the OutlinableRegions.  This creates a way to replace908/// the arguments of the extracted function with the arguments of the new909/// overall function.910///911/// \param [in,out] Region - The region of code to be analyzed.912/// \param [in] InputGVNs - The global value numbering of the input values913/// collected.914/// \param [in] ArgInputs - The values of the arguments to the extracted915/// function.916static void917findExtractedInputToOverallInputMapping(OutlinableRegion &Region,918                                        std::vector<unsigned> &InputGVNs,919                                        SetVector<Value *> &ArgInputs) {920 921  IRSimilarityCandidate &C = *Region.Candidate;922  OutlinableGroup &Group = *Region.Parent;923 924  // This counts the argument number in the overall function.925  unsigned TypeIndex = 0;926 927  // This counts the argument number in the extracted function.928  unsigned OriginalIndex = 0;929 930  // Find the mapping of the extracted arguments to the arguments for the931  // overall function. Since there may be extra arguments in the overall932  // function to account for the extracted constants, we have two different933  // counters as we find extracted arguments, and as we come across overall934  // arguments.935 936  // Additionally, in our first pass, for the first extracted function,937  // we find argument locations for the canonical value numbering.  This938  // numbering overrides any discovered location for the extracted code.939  for (unsigned InputVal : InputGVNs) {940    std::optional<unsigned> CanonicalNumberOpt = C.getCanonicalNum(InputVal);941    assert(CanonicalNumberOpt && "Canonical number not found?");942    unsigned CanonicalNumber = *CanonicalNumberOpt;943 944    std::optional<Value *> InputOpt = C.fromGVN(InputVal);945    assert(InputOpt && "Global value number not found?");946    Value *Input = *InputOpt;947 948    DenseMap<unsigned, unsigned>::iterator AggArgIt =949        Group.CanonicalNumberToAggArg.find(CanonicalNumber);950 951    if (!Group.InputTypesSet) {952      Group.ArgumentTypes.push_back(Input->getType());953      // If the input value has a swifterr attribute, make sure to mark the954      // argument in the overall function.955      if (Input->isSwiftError()) {956        assert(957            !Group.SwiftErrorArgument &&958            "Argument already marked with swifterr for this OutlinableGroup!");959        Group.SwiftErrorArgument = TypeIndex;960      }961    }962 963    // Check if we have a constant. If we do add it to the overall argument964    // number to Constant map for the region, and continue to the next input.965    if (Constant *CST = dyn_cast<Constant>(Input)) {966      if (AggArgIt != Group.CanonicalNumberToAggArg.end())967        Region.AggArgToConstant.insert(std::make_pair(AggArgIt->second, CST));968      else {969        Group.CanonicalNumberToAggArg.insert(970            std::make_pair(CanonicalNumber, TypeIndex));971        Region.AggArgToConstant.insert(std::make_pair(TypeIndex, CST));972      }973      TypeIndex++;974      continue;975    }976 977    // It is not a constant, we create the mapping from extracted argument list978    // to the overall argument list, using the canonical location, if it exists.979    assert(ArgInputs.count(Input) && "Input cannot be found!");980 981    if (AggArgIt != Group.CanonicalNumberToAggArg.end()) {982      if (OriginalIndex != AggArgIt->second)983        Region.ChangedArgOrder = true;984      Region.ExtractedArgToAgg.insert(985          std::make_pair(OriginalIndex, AggArgIt->second));986      Region.AggArgToExtracted.insert(987          std::make_pair(AggArgIt->second, OriginalIndex));988    } else {989      Group.CanonicalNumberToAggArg.insert(990          std::make_pair(CanonicalNumber, TypeIndex));991      Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex));992      Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex));993    }994    OriginalIndex++;995    TypeIndex++;996  }997 998  // If the function type definitions for the OutlinableGroup holding the region999  // have not been set, set the length of the inputs here.  We should have the1000  // same inputs for all of the different regions contained in the1001  // OutlinableGroup since they are all structurally similar to one another.1002  if (!Group.InputTypesSet) {1003    Group.NumAggregateInputs = TypeIndex;1004    Group.InputTypesSet = true;1005  }1006 1007  Region.NumExtractedInputs = OriginalIndex;1008}1009 1010/// Check if the \p V has any uses outside of the region other than \p PN.1011///1012/// \param V [in] - The value to check.1013/// \param PHILoc [in] - The location in the PHINode of \p V.1014/// \param PN [in] - The PHINode using \p V.1015/// \param Exits [in] - The potential blocks we exit to from the outlined1016/// region.1017/// \param BlocksInRegion [in] - The basic blocks contained in the region.1018/// \returns true if \p V has any use soutside its region other than \p PN.1019static bool outputHasNonPHI(Value *V, unsigned PHILoc, PHINode &PN,1020                            SmallPtrSet<BasicBlock *, 1> &Exits,1021                            DenseSet<BasicBlock *> &BlocksInRegion) {1022  // We check to see if the value is used by the PHINode from some other1023  // predecessor not included in the region.  If it is, we make sure1024  // to keep it as an output.1025  if (any_of(llvm::seq<unsigned>(0, PN.getNumIncomingValues()),1026             [PHILoc, &PN, V, &BlocksInRegion](unsigned Idx) {1027               return (Idx != PHILoc && V == PN.getIncomingValue(Idx) &&1028                       !BlocksInRegion.contains(PN.getIncomingBlock(Idx)));1029             }))1030    return true;1031 1032  // Check if the value is used by any other instructions outside the region.1033  return any_of(V->users(), [&Exits, &BlocksInRegion](User *U) {1034    Instruction *I = dyn_cast<Instruction>(U);1035    if (!I)1036      return false;1037 1038    // If the use of the item is inside the region, we skip it.  Uses1039    // inside the region give us useful information about how the item could be1040    // used as an output.1041    BasicBlock *Parent = I->getParent();1042    if (BlocksInRegion.contains(Parent))1043      return false;1044 1045    // If it's not a PHINode then we definitely know the use matters.  This1046    // output value will not completely combined with another item in a PHINode1047    // as it is directly reference by another non-phi instruction1048    if (!isa<PHINode>(I))1049      return true;1050 1051    // If we have a PHINode outside one of the exit locations, then it1052    // can be considered an outside use as well.  If there is a PHINode1053    // contained in the Exit where this values use matters, it will be1054    // caught when we analyze that PHINode.1055    if (!Exits.contains(Parent))1056      return true;1057 1058    return false;1059  });1060}1061 1062/// Test whether \p CurrentExitFromRegion contains any PhiNodes that should be1063/// considered outputs. A PHINodes is an output when more than one incoming1064/// value has been marked by the CodeExtractor as an output.1065///1066/// \param CurrentExitFromRegion [in] - The block to analyze.1067/// \param PotentialExitsFromRegion [in] - The potential exit blocks from the1068/// region.1069/// \param RegionBlocks [in] - The basic blocks in the region.1070/// \param Outputs [in, out] - The existing outputs for the region, we may add1071/// PHINodes to this as we find that they replace output values.1072/// \param OutputsReplacedByPHINode [out] - A set containing outputs that are1073/// totally replaced  by a PHINode.1074/// \param OutputsWithNonPhiUses [out] - A set containing outputs that are used1075/// in PHINodes, but have other uses, and should still be considered outputs.1076static void analyzeExitPHIsForOutputUses(1077    BasicBlock *CurrentExitFromRegion,1078    SmallPtrSet<BasicBlock *, 1> &PotentialExitsFromRegion,1079    DenseSet<BasicBlock *> &RegionBlocks, SetVector<Value *> &Outputs,1080    DenseSet<Value *> &OutputsReplacedByPHINode,1081    DenseSet<Value *> &OutputsWithNonPhiUses) {1082  for (PHINode &PN : CurrentExitFromRegion->phis()) {1083    // Find all incoming values from the outlining region.1084    SmallVector<unsigned, 2> IncomingVals;1085    for (unsigned I = 0, E = PN.getNumIncomingValues(); I < E; ++I)1086      if (RegionBlocks.contains(PN.getIncomingBlock(I)))1087        IncomingVals.push_back(I);1088 1089    // Do not process PHI if there are no predecessors from region.1090    unsigned NumIncomingVals = IncomingVals.size();1091    if (NumIncomingVals == 0)1092      continue;1093 1094    // If there is one predecessor, we mark it as a value that needs to be kept1095    // as an output.1096    if (NumIncomingVals == 1) {1097      Value *V = PN.getIncomingValue(*IncomingVals.begin());1098      OutputsWithNonPhiUses.insert(V);1099      OutputsReplacedByPHINode.erase(V);1100      continue;1101    }1102 1103    // This PHINode will be used as an output value, so we add it to our list.1104    Outputs.insert(&PN);1105 1106    // Not all of the incoming values should be ignored as other inputs and1107    // outputs may have uses in outlined region.  If they have other uses1108    // outside of the single PHINode we should not skip over it.1109    for (unsigned Idx : IncomingVals) {1110      Value *V = PN.getIncomingValue(Idx);1111      if (!isa<Constant>(V) &&1112          outputHasNonPHI(V, Idx, PN, PotentialExitsFromRegion, RegionBlocks)) {1113        OutputsWithNonPhiUses.insert(V);1114        OutputsReplacedByPHINode.erase(V);1115        continue;1116      }1117      if (!OutputsWithNonPhiUses.contains(V))1118        OutputsReplacedByPHINode.insert(V);1119    }1120  }1121}1122 1123// Represents the type for the unsigned number denoting the output number for1124// phi node, along with the canonical number for the exit block.1125using ArgLocWithBBCanon = std::pair<unsigned, unsigned>;1126// The list of canonical numbers for the incoming values to a PHINode.1127using CanonList = SmallVector<unsigned, 2>;1128// The pair type representing the set of canonical values being combined in the1129// PHINode, along with the location data for the PHINode.1130using PHINodeData = std::pair<ArgLocWithBBCanon, CanonList>;1131 1132/// Encode \p PND as an integer for easy lookup based on the argument location,1133/// the parent BasicBlock canonical numbering, and the canonical numbering of1134/// the values stored in the PHINode.1135///1136/// \param PND - The data to hash.1137/// \returns The hash code of \p PND.1138static hash_code encodePHINodeData(PHINodeData &PND) {1139  return llvm::hash_combine(llvm::hash_value(PND.first.first),1140                            llvm::hash_value(PND.first.second),1141                            llvm::hash_combine_range(PND.second));1142}1143 1144/// Create a special GVN for PHINodes that will be used outside of1145/// the region.  We create a hash code based on the Canonical number of the1146/// parent BasicBlock, the canonical numbering of the values stored in the1147/// PHINode and the aggregate argument location.  This is used to find whether1148/// this PHINode type has been given a canonical numbering already.  If not, we1149/// assign it a value and store it for later use.  The value is returned to1150/// identify different output schemes for the set of regions.1151///1152/// \param Region - The region that \p PN is an output for.1153/// \param PN - The PHINode we are analyzing.1154/// \param Blocks - The blocks for the region we are analyzing.1155/// \param AggArgIdx - The argument \p PN will be stored into.1156/// \returns An optional holding the assigned canonical number, or std::nullopt1157/// if there is some attribute of the PHINode blocking it from being used.1158static std::optional<unsigned> getGVNForPHINode(OutlinableRegion &Region,1159                                                PHINode *PN,1160                                                DenseSet<BasicBlock *> &Blocks,1161                                                unsigned AggArgIdx) {1162  OutlinableGroup &Group = *Region.Parent;1163  IRSimilarityCandidate &Cand = *Region.Candidate;1164  BasicBlock *PHIBB = PN->getParent();1165  CanonList PHIGVNs;1166  Value *Incoming;1167  BasicBlock *IncomingBlock;1168  for (unsigned Idx = 0, EIdx = PN->getNumIncomingValues(); Idx < EIdx; Idx++) {1169    Incoming = PN->getIncomingValue(Idx);1170    IncomingBlock = PN->getIncomingBlock(Idx);1171    // If the incoming block isn't in the region, we don't have to worry about1172    // this incoming value.1173    if (!Blocks.contains(IncomingBlock))1174      continue;1175 1176    // If we cannot find a GVN, and the incoming block is included in the region1177    // this means that the input to the PHINode is not included in the region we1178    // are trying to analyze, meaning, that if it was outlined, we would be1179    // adding an extra input.  We ignore this case for now, and so ignore the1180    // region.1181    std::optional<unsigned> OGVN = Cand.getGVN(Incoming);1182    if (!OGVN) {1183      Region.IgnoreRegion = true;1184      return std::nullopt;1185    }1186 1187    // Collect the canonical numbers of the values in the PHINode.1188    unsigned GVN = *OGVN;1189    OGVN = Cand.getCanonicalNum(GVN);1190    assert(OGVN && "No GVN found for incoming value?");1191    PHIGVNs.push_back(*OGVN);1192 1193    // Find the incoming block and use the canonical numbering as well to define1194    // the hash for the PHINode.1195    OGVN = Cand.getGVN(IncomingBlock);1196 1197    // If there is no number for the incoming block, it is because we have1198    // split the candidate basic blocks.  So we use the previous block that it1199    // was split from to find the valid global value numbering for the PHINode.1200    if (!OGVN) {1201      assert(Cand.getStartBB() == IncomingBlock &&1202             "Unknown basic block used in exit path PHINode.");1203 1204      BasicBlock *PrevBlock = nullptr;1205      // Iterate over the predecessors to the incoming block of the1206      // PHINode, when we find a block that is not contained in the region1207      // we know that this is the first block that we split from, and should1208      // have a valid global value numbering.1209      for (BasicBlock *Pred : predecessors(IncomingBlock))1210        if (!Blocks.contains(Pred)) {1211          PrevBlock = Pred;1212          break;1213        }1214      assert(PrevBlock && "Expected a predecessor not in the reigon!");1215      OGVN = Cand.getGVN(PrevBlock);1216    }1217    GVN = *OGVN;1218    OGVN = Cand.getCanonicalNum(GVN);1219    assert(OGVN && "No GVN found for incoming block?");1220    PHIGVNs.push_back(*OGVN);1221  }1222 1223  // Now that we have the GVNs for the incoming values, we are going to combine1224  // them with the GVN of the incoming bock, and the output location of the1225  // PHINode to generate a hash value representing this instance of the PHINode.1226  DenseMap<hash_code, unsigned>::iterator GVNToPHIIt;1227  DenseMap<unsigned, PHINodeData>::iterator PHIToGVNIt;1228  std::optional<unsigned> BBGVN = Cand.getGVN(PHIBB);1229  assert(BBGVN && "Could not find GVN for the incoming block!");1230 1231  BBGVN = Cand.getCanonicalNum(*BBGVN);1232  assert(BBGVN && "Could not find canonical number for the incoming block!");1233  // Create a pair of the exit block canonical value, and the aggregate1234  // argument location, connected to the canonical numbers stored in the1235  // PHINode.1236  PHINodeData TemporaryPair =1237      std::make_pair(std::make_pair(*BBGVN, AggArgIdx), PHIGVNs);1238  hash_code PHINodeDataHash = encodePHINodeData(TemporaryPair);1239 1240  // Look for and create a new entry in our connection between canonical1241  // numbers for PHINodes, and the set of objects we just created.1242  GVNToPHIIt = Group.GVNsToPHINodeGVN.find(PHINodeDataHash);1243  if (GVNToPHIIt == Group.GVNsToPHINodeGVN.end()) {1244    bool Inserted = false;1245    std::tie(PHIToGVNIt, Inserted) = Group.PHINodeGVNToGVNs.insert(1246        std::make_pair(Group.PHINodeGVNTracker, TemporaryPair));1247    std::tie(GVNToPHIIt, Inserted) = Group.GVNsToPHINodeGVN.insert(1248        std::make_pair(PHINodeDataHash, Group.PHINodeGVNTracker--));1249  }1250 1251  return GVNToPHIIt->second;1252}1253 1254/// Create a mapping of the output arguments for the \p Region to the output1255/// arguments of the overall outlined function.1256///1257/// \param [in,out] Region - The region of code to be analyzed.1258/// \param [in] Outputs - The values found by the code extractor.1259static void1260findExtractedOutputToOverallOutputMapping(Module &M, OutlinableRegion &Region,1261                                          SetVector<Value *> &Outputs) {1262  OutlinableGroup &Group = *Region.Parent;1263  IRSimilarityCandidate &C = *Region.Candidate;1264 1265  SmallVector<BasicBlock *> BE;1266  DenseSet<BasicBlock *> BlocksInRegion;1267  C.getBasicBlocks(BlocksInRegion, BE);1268 1269  // Find the exits to the region.1270  SmallPtrSet<BasicBlock *, 1> Exits;1271  for (BasicBlock *Block : BE)1272    for (BasicBlock *Succ : successors(Block))1273      if (!BlocksInRegion.contains(Succ))1274        Exits.insert(Succ);1275 1276  // After determining which blocks exit to PHINodes, we add these PHINodes to1277  // the set of outputs to be processed.  We also check the incoming values of1278  // the PHINodes for whether they should no longer be considered outputs.1279  DenseSet<Value *> OutputsReplacedByPHINode;1280  DenseSet<Value *> OutputsWithNonPhiUses;1281  for (BasicBlock *ExitBB : Exits)1282    analyzeExitPHIsForOutputUses(ExitBB, Exits, BlocksInRegion, Outputs,1283                                 OutputsReplacedByPHINode,1284                                 OutputsWithNonPhiUses);1285 1286  // This counts the argument number in the extracted function.1287  unsigned OriginalIndex = Region.NumExtractedInputs;1288 1289  // This counts the argument number in the overall function.1290  unsigned TypeIndex = Group.NumAggregateInputs;1291  bool TypeFound;1292  DenseSet<unsigned> AggArgsUsed;1293 1294  // Iterate over the output types and identify if there is an aggregate pointer1295  // type whose base type matches the current output type. If there is, we mark1296  // that we will use this output register for this value. If not we add another1297  // type to the overall argument type list. We also store the GVNs used for1298  // stores to identify which values will need to be moved into an special1299  // block that holds the stores to the output registers.1300  for (Value *Output : Outputs) {1301    TypeFound = false;1302    // We can do this since it is a result value, and will have a number1303    // that is necessarily the same. BUT if in the future, the instructions1304    // do not have to be in same order, but are functionally the same, we will1305    // have to use a different scheme, as one-to-one correspondence is not1306    // guaranteed.1307    unsigned ArgumentSize = Group.ArgumentTypes.size();1308 1309    // If the output is combined in a PHINode, we make sure to skip over it.1310    if (OutputsReplacedByPHINode.contains(Output))1311      continue;1312 1313    unsigned AggArgIdx = 0;1314    for (unsigned Jdx = TypeIndex; Jdx < ArgumentSize; Jdx++) {1315      if (!isa<PointerType>(Group.ArgumentTypes[Jdx]))1316        continue;1317 1318      if (!AggArgsUsed.insert(Jdx).second)1319        continue;1320 1321      TypeFound = true;1322      Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, Jdx));1323      Region.AggArgToExtracted.insert(std::make_pair(Jdx, OriginalIndex));1324      AggArgIdx = Jdx;1325      break;1326    }1327 1328    // We were unable to find an unused type in the output type set that matches1329    // the output, so we add a pointer type to the argument types of the overall1330    // function to handle this output and create a mapping to it.1331    if (!TypeFound) {1332      Group.ArgumentTypes.push_back(PointerType::get(Output->getContext(),1333          M.getDataLayout().getAllocaAddrSpace()));1334      // Mark the new pointer type as the last value in the aggregate argument1335      // list.1336      unsigned ArgTypeIdx = Group.ArgumentTypes.size() - 1;1337      AggArgsUsed.insert(ArgTypeIdx);1338      Region.ExtractedArgToAgg.insert(1339          std::make_pair(OriginalIndex, ArgTypeIdx));1340      Region.AggArgToExtracted.insert(1341          std::make_pair(ArgTypeIdx, OriginalIndex));1342      AggArgIdx = ArgTypeIdx;1343    }1344 1345    // TODO: Adapt to the extra input from the PHINode.1346    PHINode *PN = dyn_cast<PHINode>(Output);1347 1348    std::optional<unsigned> GVN;1349    if (PN && !BlocksInRegion.contains(PN->getParent())) {1350      // Values outside the region can be combined into PHINode when we1351      // have multiple exits. We collect both of these into a list to identify1352      // which values are being used in the PHINode. Each list identifies a1353      // different PHINode, and a different output. We store the PHINode as it's1354      // own canonical value.  These canonical values are also dependent on the1355      // output argument it is saved to.1356 1357      // If two PHINodes have the same canonical values, but different aggregate1358      // argument locations, then they will have distinct Canonical Values.1359      GVN = getGVNForPHINode(Region, PN, BlocksInRegion, AggArgIdx);1360      if (!GVN)1361        return;1362    } else {1363      // If we do not have a PHINode we use the global value numbering for the1364      // output value, to find the canonical number to add to the set of stored1365      // values.1366      GVN = C.getGVN(Output);1367      GVN = C.getCanonicalNum(*GVN);1368    }1369 1370    // Each region has a potentially unique set of outputs.  We save which1371    // values are output in a list of canonical values so we can differentiate1372    // among the different store schemes.1373    Region.GVNStores.push_back(*GVN);1374 1375    OriginalIndex++;1376    TypeIndex++;1377  }1378 1379  // We sort the stored values to make sure that we are not affected by analysis1380  // order when determining what combination of items were stored.1381  stable_sort(Region.GVNStores);1382}1383 1384void IROutliner::findAddInputsOutputs(Module &M, OutlinableRegion &Region,1385                                      DenseSet<unsigned> &NotSame) {1386  std::vector<unsigned> Inputs;1387  SetVector<Value *> ArgInputs, Outputs;1388 1389  getCodeExtractorArguments(Region, Inputs, NotSame, OutputMappings, ArgInputs,1390                            Outputs);1391 1392  if (Region.IgnoreRegion)1393    return;1394 1395  // Map the inputs found by the CodeExtractor to the arguments found for1396  // the overall function.1397  findExtractedInputToOverallInputMapping(Region, Inputs, ArgInputs);1398 1399  // Map the outputs found by the CodeExtractor to the arguments found for1400  // the overall function.1401  findExtractedOutputToOverallOutputMapping(M, Region, Outputs);1402}1403 1404/// Replace the extracted function in the Region with a call to the overall1405/// function constructed from the deduplicated similar regions, replacing and1406/// remapping the values passed to the extracted function as arguments to the1407/// new arguments of the overall function.1408///1409/// \param [in] M - The module to outline from.1410/// \param [in] Region - The regions of extracted code to be replaced with a new1411/// function.1412/// \returns a call instruction with the replaced function.1413CallInst *replaceCalledFunction(Module &M, OutlinableRegion &Region) {1414  std::vector<Value *> NewCallArgs;1415  DenseMap<unsigned, unsigned>::iterator ArgPair;1416 1417  OutlinableGroup &Group = *Region.Parent;1418  CallInst *Call = Region.Call;1419  assert(Call && "Call to replace is nullptr?");1420  Function *AggFunc = Group.OutlinedFunction;1421  assert(AggFunc && "Function to replace with is nullptr?");1422 1423  // If the arguments are the same size, there are not values that need to be1424  // made into an argument, the argument ordering has not been change, or1425  // different output registers to handle.  We can simply replace the called1426  // function in this case.1427  if (!Region.ChangedArgOrder && AggFunc->arg_size() == Call->arg_size()) {1428    LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to "1429                      << *AggFunc << " with same number of arguments\n");1430    Call->setCalledFunction(AggFunc);1431    return Call;1432  }1433 1434  // We have a different number of arguments than the new function, so1435  // we need to use our previously mappings off extracted argument to overall1436  // function argument, and constants to overall function argument to create the1437  // new argument list.1438  for (unsigned AggArgIdx = 0; AggArgIdx < AggFunc->arg_size(); AggArgIdx++) {1439 1440    if (AggArgIdx == AggFunc->arg_size() - 1 &&1441        Group.OutputGVNCombinations.size() > 1) {1442      // If we are on the last argument, and we need to differentiate between1443      // output blocks, add an integer to the argument list to determine1444      // what block to take1445      LLVM_DEBUG(dbgs() << "Set switch block argument to "1446                        << Region.OutputBlockNum << "\n");1447      NewCallArgs.push_back(ConstantInt::get(Type::getInt32Ty(M.getContext()),1448                                             Region.OutputBlockNum));1449      continue;1450    }1451 1452    ArgPair = Region.AggArgToExtracted.find(AggArgIdx);1453    if (ArgPair != Region.AggArgToExtracted.end()) {1454      Value *ArgumentValue = Call->getArgOperand(ArgPair->second);1455      // If we found the mapping from the extracted function to the overall1456      // function, we simply add it to the argument list.  We use the same1457      // value, it just needs to honor the new order of arguments.1458      LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value "1459                        << *ArgumentValue << "\n");1460      NewCallArgs.push_back(ArgumentValue);1461      continue;1462    }1463 1464    // If it is a constant, we simply add it to the argument list as a value.1465    if (auto It = Region.AggArgToConstant.find(AggArgIdx);1466        It != Region.AggArgToConstant.end()) {1467      Constant *CST = It->second;1468      LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value "1469                        << *CST << "\n");1470      NewCallArgs.push_back(CST);1471      continue;1472    }1473 1474    // Add a nullptr value if the argument is not found in the extracted1475    // function.  If we cannot find a value, it means it is not in use1476    // for the region, so we should not pass anything to it.1477    LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to nullptr\n");1478    NewCallArgs.push_back(ConstantPointerNull::get(1479        static_cast<PointerType *>(AggFunc->getArg(AggArgIdx)->getType())));1480  }1481 1482  LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to "1483                    << *AggFunc << " with new set of arguments\n");1484  // Create the new call instruction and erase the old one.1485  Call = CallInst::Create(AggFunc->getFunctionType(), AggFunc, NewCallArgs, "",1486                          Call->getIterator());1487 1488  // It is possible that the call to the outlined function is either the first1489  // instruction is in the new block, the last instruction, or both.  If either1490  // of these is the case, we need to make sure that we replace the instruction1491  // in the IRInstructionData struct with the new call.1492  CallInst *OldCall = Region.Call;1493  if (Region.NewFront->Inst == OldCall)1494    Region.NewFront->Inst = Call;1495  if (Region.NewBack->Inst == OldCall)1496    Region.NewBack->Inst = Call;1497 1498  // Transfer any debug information.1499  Call->setDebugLoc(Region.Call->getDebugLoc());1500  // Since our output may determine which branch we go to, we make sure to1501  // propagate this new call value through the module.1502  OldCall->replaceAllUsesWith(Call);1503 1504  // Remove the old instruction.1505  OldCall->eraseFromParent();1506  Region.Call = Call;1507 1508  // Make sure that the argument in the new function has the SwiftError1509  // argument.1510  if (Group.SwiftErrorArgument)1511    Call->addParamAttr(*Group.SwiftErrorArgument, Attribute::SwiftError);1512 1513  return Call;1514}1515 1516/// Find or create a BasicBlock in the outlined function containing PhiBlocks1517/// for \p RetVal.1518///1519/// \param Group - The OutlinableGroup containing the information about the1520/// overall outlined function.1521/// \param RetVal - The return value or exit option that we are currently1522/// evaluating.1523/// \returns The found or newly created BasicBlock to contain the needed1524/// PHINodes to be used as outputs.1525static BasicBlock *findOrCreatePHIBlock(OutlinableGroup &Group, Value *RetVal) {1526  // Find if a PHIBlock exists for this return value already.  If it is1527  // the first time we are analyzing this, we will not, so we record it.1528  auto [PhiBlockForRetVal, Inserted] = Group.PHIBlocks.try_emplace(RetVal);1529  if (!Inserted)1530    return PhiBlockForRetVal->second;1531 1532  auto ReturnBlockForRetVal = Group.EndBBs.find(RetVal);1533  assert(ReturnBlockForRetVal != Group.EndBBs.end() &&1534         "Could not find output value!");1535  BasicBlock *ReturnBB = ReturnBlockForRetVal->second;1536 1537  // If we did not find a block, we create one, and insert it into the1538  // overall function and record it.1539  BasicBlock *PHIBlock = BasicBlock::Create(ReturnBB->getContext(), "phi_block",1540                                            ReturnBB->getParent());1541  PhiBlockForRetVal->second = PHIBlock;1542 1543  // We find the predecessors of the return block in the newly created outlined1544  // function in order to point them to the new PHIBlock rather than the already1545  // existing return block.1546  SmallVector<BranchInst *, 2> BranchesToChange;1547  for (BasicBlock *Pred : predecessors(ReturnBB))1548    BranchesToChange.push_back(cast<BranchInst>(Pred->getTerminator()));1549 1550  // Now we mark the branch instructions found, and change the references of the1551  // return block to the newly created PHIBlock.1552  for (BranchInst *BI : BranchesToChange)1553    for (unsigned Succ = 0, End = BI->getNumSuccessors(); Succ < End; Succ++) {1554      if (BI->getSuccessor(Succ) != ReturnBB)1555        continue;1556      BI->setSuccessor(Succ, PHIBlock);1557    }1558 1559  BranchInst::Create(ReturnBB, PHIBlock);1560 1561  return PhiBlockForRetVal->second;1562}1563 1564/// For the function call now representing the \p Region, find the passed value1565/// to that call that represents Argument \p A at the call location if the1566/// call has already been replaced with a call to the  overall, aggregate1567/// function.1568///1569/// \param A - The Argument to get the passed value for.1570/// \param Region - The extracted Region corresponding to the outlined function.1571/// \returns The Value representing \p A at the call site.1572static Value *1573getPassedArgumentInAlreadyOutlinedFunction(const Argument *A,1574                                           const OutlinableRegion &Region) {1575  // If we don't need to adjust the argument number at all (since the call1576  // has already been replaced by a call to the overall outlined function)1577  // we can just get the specified argument.1578  return Region.Call->getArgOperand(A->getArgNo());1579}1580 1581/// For the function call now representing the \p Region, find the passed value1582/// to that call that represents Argument \p A at the call location if the1583/// call has only been replaced by the call to the aggregate function.1584///1585/// \param A - The Argument to get the passed value for.1586/// \param Region - The extracted Region corresponding to the outlined function.1587/// \returns The Value representing \p A at the call site.1588static Value *1589getPassedArgumentAndAdjustArgumentLocation(const Argument *A,1590                                           const OutlinableRegion &Region) {1591  unsigned ArgNum = A->getArgNo();1592  1593  // If it is a constant, we can look at our mapping from when we created1594  // the outputs to figure out what the constant value is.1595  if (auto It = Region.AggArgToConstant.find(ArgNum);1596      It != Region.AggArgToConstant.end())1597    return It->second;1598 1599  // If it is not a constant, and we are not looking at the overall function, we1600  // need to adjust which argument we are looking at.1601  ArgNum = Region.AggArgToExtracted.find(ArgNum)->second;1602  return Region.Call->getArgOperand(ArgNum);1603}1604 1605/// Find the canonical numbering for the incoming Values into the PHINode \p PN.1606///1607/// \param PN [in] - The PHINode that we are finding the canonical numbers for.1608/// \param Region [in] - The OutlinableRegion containing \p PN.1609/// \param OutputMappings [in] - The mapping of output values from outlined1610/// region to their original values.1611/// \param CanonNums [out] - The canonical numbering for the incoming values to1612/// \p PN paired with their incoming block.1613/// \param ReplacedWithOutlinedCall - A flag to use the extracted function call1614/// of \p Region rather than the overall function's call.1615static void findCanonNumsForPHI(1616    PHINode *PN, OutlinableRegion &Region,1617    const DenseMap<Value *, Value *> &OutputMappings,1618    SmallVector<std::pair<unsigned, BasicBlock *>> &CanonNums,1619    bool ReplacedWithOutlinedCall = true) {1620  // Iterate over the incoming values.1621  for (unsigned Idx = 0, EIdx = PN->getNumIncomingValues(); Idx < EIdx; Idx++) {1622    Value *IVal = PN->getIncomingValue(Idx);1623    BasicBlock *IBlock = PN->getIncomingBlock(Idx);1624    // If we have an argument as incoming value, we need to grab the passed1625    // value from the call itself.1626    if (Argument *A = dyn_cast<Argument>(IVal)) {1627      if (ReplacedWithOutlinedCall)1628        IVal = getPassedArgumentInAlreadyOutlinedFunction(A, Region);1629      else1630        IVal = getPassedArgumentAndAdjustArgumentLocation(A, Region);1631    }1632 1633    // Get the original value if it has been replaced by an output value.1634    IVal = findOutputMapping(OutputMappings, IVal);1635 1636    // Find and add the canonical number for the incoming value.1637    std::optional<unsigned> GVN = Region.Candidate->getGVN(IVal);1638    assert(GVN && "No GVN for incoming value");1639    std::optional<unsigned> CanonNum = Region.Candidate->getCanonicalNum(*GVN);1640    assert(CanonNum && "No Canonical Number for GVN");1641    CanonNums.push_back(std::make_pair(*CanonNum, IBlock));1642  }1643}1644 1645/// Find, or add PHINode \p PN to the combined PHINode Block \p OverallPHIBlock1646/// in order to condense the number of instructions added to the outlined1647/// function.1648///1649/// \param PN [in] - The PHINode that we are finding the canonical numbers for.1650/// \param Region [in] - The OutlinableRegion containing \p PN.1651/// \param OverallPhiBlock [in] - The overall PHIBlock we are trying to find1652/// \p PN in.1653/// \param OutputMappings [in] - The mapping of output values from outlined1654/// region to their original values.1655/// \param UsedPHIs [in, out] - The PHINodes in the block that have already been1656/// matched.1657/// \return the newly found or created PHINode in \p OverallPhiBlock.1658static PHINode*1659findOrCreatePHIInBlock(PHINode &PN, OutlinableRegion &Region,1660                       BasicBlock *OverallPhiBlock,1661                       const DenseMap<Value *, Value *> &OutputMappings,1662                       DenseSet<PHINode *> &UsedPHIs) {1663  OutlinableGroup &Group = *Region.Parent;1664  1665  1666  // A list of the canonical numbering assigned to each incoming value, paired1667  // with the incoming block for the PHINode passed into this function.1668  SmallVector<std::pair<unsigned, BasicBlock *>> PNCanonNums;1669 1670  // We have to use the extracted function since we have merged this region into1671  // the overall function yet.  We make sure to reassign the argument numbering1672  // since it is possible that the argument ordering is different between the1673  // functions.1674  findCanonNumsForPHI(&PN, Region, OutputMappings, PNCanonNums,1675                      /* ReplacedWithOutlinedCall = */ false);1676 1677  OutlinableRegion *FirstRegion = Group.Regions[0];1678 1679  // A list of the canonical numbering assigned to each incoming value, paired1680  // with the incoming block for the PHINode that we are currently comparing1681  // the passed PHINode to.1682  SmallVector<std::pair<unsigned, BasicBlock *>> CurrentCanonNums;1683 1684  // Find the Canonical Numbering for each PHINode, if it matches, we replace1685  // the uses of the PHINode we are searching for, with the found PHINode.1686  for (PHINode &CurrPN : OverallPhiBlock->phis()) {1687    // If this PHINode has already been matched to another PHINode to be merged,1688    // we skip it.1689    if (UsedPHIs.contains(&CurrPN))1690      continue;1691 1692    CurrentCanonNums.clear();1693    findCanonNumsForPHI(&CurrPN, *FirstRegion, OutputMappings, CurrentCanonNums,1694                        /* ReplacedWithOutlinedCall = */ true);1695 1696    // If the list of incoming values is not the same length, then they cannot1697    // match since there is not an analogue for each incoming value.1698    if (PNCanonNums.size() != CurrentCanonNums.size())1699      continue;1700 1701    bool FoundMatch = true;1702 1703    // We compare the canonical value for each incoming value in the passed1704    // in PHINode to one already present in the outlined region.  If the1705    // incoming values do not match, then the PHINodes do not match.1706 1707    // We also check to make sure that the incoming block matches as well by1708    // finding the corresponding incoming block in the combined outlined region1709    // for the current outlined region.1710    for (unsigned Idx = 0, Edx = PNCanonNums.size(); Idx < Edx; ++Idx) {1711      std::pair<unsigned, BasicBlock *> ToCompareTo = CurrentCanonNums[Idx];1712      std::pair<unsigned, BasicBlock *> ToAdd = PNCanonNums[Idx];1713      if (ToCompareTo.first != ToAdd.first) {1714        FoundMatch = false;1715        break;1716      }1717 1718      BasicBlock *CorrespondingBlock =1719          Region.findCorrespondingBlockIn(*FirstRegion, ToAdd.second);1720      assert(CorrespondingBlock && "Found block is nullptr");1721      if (CorrespondingBlock != ToCompareTo.second) {1722        FoundMatch = false;1723        break;1724      }1725    }1726 1727    // If all incoming values and branches matched, then we can merge1728    // into the found PHINode.1729    if (FoundMatch) {1730      UsedPHIs.insert(&CurrPN);1731      return &CurrPN;1732    }1733  }1734 1735  // If we've made it here, it means we weren't able to replace the PHINode, so1736  // we must insert it ourselves.1737  PHINode *NewPN = cast<PHINode>(PN.clone());1738  NewPN->insertBefore(OverallPhiBlock->begin());1739  for (unsigned Idx = 0, Edx = NewPN->getNumIncomingValues(); Idx < Edx;1740       Idx++) {1741    Value *IncomingVal = NewPN->getIncomingValue(Idx);1742    BasicBlock *IncomingBlock = NewPN->getIncomingBlock(Idx);1743 1744    // Find corresponding basic block in the overall function for the incoming1745    // block.1746    BasicBlock *BlockToUse =1747        Region.findCorrespondingBlockIn(*FirstRegion, IncomingBlock);1748    NewPN->setIncomingBlock(Idx, BlockToUse);1749 1750    // If we have an argument we make sure we replace using the argument from1751    // the correct function.1752    if (Argument *A = dyn_cast<Argument>(IncomingVal)) {1753      Value *Val = Group.OutlinedFunction->getArg(A->getArgNo());1754      NewPN->setIncomingValue(Idx, Val);1755      continue;1756    }1757    1758    // Find the corresponding value in the overall function.1759    IncomingVal = findOutputMapping(OutputMappings, IncomingVal);1760    Value *Val = Region.findCorrespondingValueIn(*FirstRegion, IncomingVal);1761    assert(Val && "Value is nullptr?");1762    DenseMap<Value *, Value *>::iterator RemappedIt =1763        FirstRegion->RemappedArguments.find(Val);1764    if (RemappedIt != FirstRegion->RemappedArguments.end())1765      Val = RemappedIt->second;1766    NewPN->setIncomingValue(Idx, Val);1767  }1768  return NewPN;1769}1770 1771// Within an extracted function, replace the argument uses of the extracted1772// region with the arguments of the function for an OutlinableGroup.1773//1774/// \param [in] Region - The region of extracted code to be changed.1775/// \param [in,out] OutputBBs - The BasicBlock for the output stores for this1776/// region.1777/// \param [in] FirstFunction - A flag to indicate whether we are using this1778/// function to define the overall outlined function for all the regions, or1779/// if we are operating on one of the following regions.1780static void1781replaceArgumentUses(OutlinableRegion &Region,1782                    DenseMap<Value *, BasicBlock *> &OutputBBs,1783                    const DenseMap<Value *, Value *> &OutputMappings,1784                    bool FirstFunction = false) {1785  OutlinableGroup &Group = *Region.Parent;1786  assert(Region.ExtractedFunction && "Region has no extracted function?");1787 1788  Function *DominatingFunction = Region.ExtractedFunction;1789  if (FirstFunction)1790    DominatingFunction = Group.OutlinedFunction;1791  DominatorTree DT(*DominatingFunction);1792  DenseSet<PHINode *> UsedPHIs;1793 1794  for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size();1795       ArgIdx++) {1796    assert(Region.ExtractedArgToAgg.contains(ArgIdx) &&1797           "No mapping from extracted to outlined?");1798    unsigned AggArgIdx = Region.ExtractedArgToAgg.find(ArgIdx)->second;1799    Argument *AggArg = Group.OutlinedFunction->getArg(AggArgIdx);1800    Argument *Arg = Region.ExtractedFunction->getArg(ArgIdx);1801    // The argument is an input, so we can simply replace it with the overall1802    // argument value1803    if (ArgIdx < Region.NumExtractedInputs) {1804      LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function "1805                        << *Region.ExtractedFunction << " with " << *AggArg1806                        << " in function " << *Group.OutlinedFunction << "\n");1807      Arg->replaceAllUsesWith(AggArg);1808      Value *V = Region.Call->getArgOperand(ArgIdx);1809      Region.RemappedArguments.insert(std::make_pair(V, AggArg));1810      continue;1811    }1812 1813    // If we are replacing an output, we place the store value in its own1814    // block inside the overall function before replacing the use of the output1815    // in the function.1816    assert(Arg->hasOneUse() && "Output argument can only have one use");1817    User *InstAsUser = Arg->user_back();1818    assert(InstAsUser && "User is nullptr!");1819 1820    Instruction *I = cast<Instruction>(InstAsUser);1821    BasicBlock *BB = I->getParent();1822    SmallVector<BasicBlock *, 4> Descendants;1823    DT.getDescendants(BB, Descendants);1824    bool EdgeAdded = false;1825    if (Descendants.size() == 0) {1826      EdgeAdded = true;1827      DT.insertEdge(&DominatingFunction->getEntryBlock(), BB);1828      DT.getDescendants(BB, Descendants);1829    }1830 1831    // Iterate over the following blocks, looking for return instructions,1832    // if we find one, find the corresponding output block for the return value1833    // and move our store instruction there.1834    for (BasicBlock *DescendBB : Descendants) {1835      ReturnInst *RI = dyn_cast<ReturnInst>(DescendBB->getTerminator());1836      if (!RI)1837        continue;1838      Value *RetVal = RI->getReturnValue();1839      auto VBBIt = OutputBBs.find(RetVal);1840      assert(VBBIt != OutputBBs.end() && "Could not find output value!");1841 1842      // If this is storing a PHINode, we must make sure it is included in the1843      // overall function.1844      StoreInst *SI = cast<StoreInst>(I);1845 1846      Value *ValueOperand = SI->getValueOperand();1847 1848      StoreInst *NewI = cast<StoreInst>(I->clone());1849      NewI->setDebugLoc(DebugLoc::getDropped());1850      BasicBlock *OutputBB = VBBIt->second;1851      NewI->insertInto(OutputBB, OutputBB->end());1852      LLVM_DEBUG(dbgs() << "Move store for instruction " << *I << " to "1853                        << *OutputBB << "\n");1854 1855      // If this is storing a PHINode, we must make sure it is included in the1856      // overall function.1857      if (!isa<PHINode>(ValueOperand) ||1858          Region.Candidate->getGVN(ValueOperand).has_value()) {1859        if (FirstFunction)1860          continue;1861        Value *CorrVal =1862            Region.findCorrespondingValueIn(*Group.Regions[0], ValueOperand);1863        assert(CorrVal && "Value is nullptr?");1864        NewI->setOperand(0, CorrVal);1865        continue;1866      }1867      PHINode *PN = cast<PHINode>(SI->getValueOperand());1868      // If it has a value, it was not split by the code extractor, which1869      // is what we are looking for.1870      if (Region.Candidate->getGVN(PN))1871        continue;1872 1873      // We record the parent block for the PHINode in the Region so that1874      // we can exclude it from checks later on.1875      Region.PHIBlocks.insert(std::make_pair(RetVal, PN->getParent()));1876 1877      // If this is the first function, we do not need to worry about mergiing1878      // this with any other block in the overall outlined function, so we can1879      // just continue.1880      if (FirstFunction) {1881        BasicBlock *PHIBlock = PN->getParent();1882        Group.PHIBlocks.insert(std::make_pair(RetVal, PHIBlock));1883        continue;1884      }1885 1886      // We look for the aggregate block that contains the PHINodes leading into1887      // this exit path. If we can't find one, we create one.1888      BasicBlock *OverallPhiBlock = findOrCreatePHIBlock(Group, RetVal);1889 1890      // For our PHINode, we find the combined canonical numbering, and1891      // attempt to find a matching PHINode in the overall PHIBlock.  If we1892      // cannot, we copy the PHINode and move it into this new block.1893      PHINode *NewPN = findOrCreatePHIInBlock(*PN, Region, OverallPhiBlock,1894                                              OutputMappings, UsedPHIs);1895      NewI->setOperand(0, NewPN);1896    }1897 1898    // If we added an edge for basic blocks without a predecessor, we remove it1899    // here.1900    if (EdgeAdded)1901      DT.deleteEdge(&DominatingFunction->getEntryBlock(), BB);1902    I->eraseFromParent();1903 1904    LLVM_DEBUG(dbgs() << "Replacing uses of output " << *Arg << " in function "1905                      << *Region.ExtractedFunction << " with " << *AggArg1906                      << " in function " << *Group.OutlinedFunction << "\n");1907    Arg->replaceAllUsesWith(AggArg);1908  }1909}1910 1911/// Within an extracted function, replace the constants that need to be lifted1912/// into arguments with the actual argument.1913///1914/// \param Region [in] - The region of extracted code to be changed.1915void replaceConstants(OutlinableRegion &Region) {1916  OutlinableGroup &Group = *Region.Parent;1917  Function *OutlinedFunction = Group.OutlinedFunction;1918  ValueToValueMapTy VMap;1919 1920  // Iterate over the constants that need to be elevated into arguments1921  for (std::pair<unsigned, Constant *> &Const : Region.AggArgToConstant) {1922    unsigned AggArgIdx = Const.first;1923    assert(OutlinedFunction && "Overall Function is not defined?");1924    Constant *CST = Const.second;1925    Argument *Arg = Group.OutlinedFunction->getArg(AggArgIdx);1926    // Identify the argument it will be elevated to, and replace instances of1927    // that constant in the function.1928    VMap[CST] = Arg;1929    LLVM_DEBUG(dbgs() << "Replacing uses of constant " << *CST1930                      << " in function " << *OutlinedFunction << " with "1931                      << *Arg << '\n');1932  }1933 1934  RemapFunction(*OutlinedFunction, VMap,1935                RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);1936}1937 1938/// It is possible that there is a basic block that already performs the same1939/// stores. This returns a duplicate block, if it exists1940///1941/// \param OutputBBs [in] the blocks we are looking for a duplicate of.1942/// \param OutputStoreBBs [in] The existing output blocks.1943/// \returns an optional value with the number output block if there is a match.1944std::optional<unsigned> findDuplicateOutputBlock(1945    DenseMap<Value *, BasicBlock *> &OutputBBs,1946    std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs) {1947 1948  bool Mismatch = false;1949  unsigned MatchingNum = 0;1950  // We compare the new set output blocks to the other sets of output blocks.1951  // If they are the same number, and have identical instructions, they are1952  // considered to be the same.1953  for (DenseMap<Value *, BasicBlock *> &CompBBs : OutputStoreBBs) {1954    Mismatch = false;1955    for (std::pair<Value *, BasicBlock *> &VToB : CompBBs) {1956      DenseMap<Value *, BasicBlock *>::iterator OutputBBIt =1957          OutputBBs.find(VToB.first);1958      if (OutputBBIt == OutputBBs.end()) {1959        Mismatch = true;1960        break;1961      }1962 1963      BasicBlock *CompBB = VToB.second;1964      BasicBlock *OutputBB = OutputBBIt->second;1965      if (CompBB->size() - 1 != OutputBB->size()) {1966        Mismatch = true;1967        break;1968      }1969 1970      BasicBlock::iterator NIt = OutputBB->begin();1971      for (Instruction &I : *CompBB) {1972        if (isa<BranchInst>(&I))1973          continue;1974 1975        if (!I.isIdenticalTo(&(*NIt))) {1976          Mismatch = true;1977          break;1978        }1979 1980        NIt++;1981      }1982    }1983 1984    if (!Mismatch)1985      return MatchingNum;1986 1987    MatchingNum++;1988  }1989 1990  return std::nullopt;1991}1992 1993/// Remove empty output blocks from the outlined region.1994///1995/// \param BlocksToPrune - Mapping of return values output blocks for the \p1996/// Region.1997/// \param Region - The OutlinableRegion we are analyzing.1998static bool1999analyzeAndPruneOutputBlocks(DenseMap<Value *, BasicBlock *> &BlocksToPrune,2000                            OutlinableRegion &Region) {2001  bool AllRemoved = true;2002  Value *RetValueForBB;2003  BasicBlock *NewBB;2004  SmallVector<Value *, 4> ToRemove;2005  // Iterate over the output blocks created in the outlined section.2006  for (std::pair<Value *, BasicBlock *> &VtoBB : BlocksToPrune) {2007    RetValueForBB = VtoBB.first;2008    NewBB = VtoBB.second;2009  2010    // If there are no instructions, we remove it from the module, and also2011    // mark the value for removal from the return value to output block mapping.2012    if (NewBB->size() == 0) {2013      NewBB->eraseFromParent();2014      ToRemove.push_back(RetValueForBB);2015      continue;2016    }2017    2018    // Mark that we could not remove all the blocks since they were not all2019    // empty.2020    AllRemoved = false;2021  }2022 2023  // Remove the return value from the mapping.2024  for (Value *V : ToRemove)2025    BlocksToPrune.erase(V);2026 2027  // Mark the region as having the no output scheme.2028  if (AllRemoved)2029    Region.OutputBlockNum = -1;2030  2031  return AllRemoved;2032}2033 2034/// For the outlined section, move needed the StoreInsts for the output2035/// registers into their own block. Then, determine if there is a duplicate2036/// output block already created.2037///2038/// \param [in] OG - The OutlinableGroup of regions to be outlined.2039/// \param [in] Region - The OutlinableRegion that is being analyzed.2040/// \param [in,out] OutputBBs - the blocks that stores for this region will be2041/// placed in.2042/// \param [in] EndBBs - the final blocks of the extracted function.2043/// \param [in] OutputMappings - OutputMappings the mapping of values that have2044/// been replaced by a new output value.2045/// \param [in,out] OutputStoreBBs - The existing output blocks.2046static void alignOutputBlockWithAggFunc(2047    OutlinableGroup &OG, OutlinableRegion &Region,2048    DenseMap<Value *, BasicBlock *> &OutputBBs,2049    DenseMap<Value *, BasicBlock *> &EndBBs,2050    const DenseMap<Value *, Value *> &OutputMappings,2051    std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs) {2052  // If none of the output blocks have any instructions, this means that we do2053  // not have to determine if it matches any of the other output schemes, and we2054  // don't have to do anything else.2055  if (analyzeAndPruneOutputBlocks(OutputBBs, Region))2056    return;2057 2058  // Determine is there is a duplicate set of blocks.2059  std::optional<unsigned> MatchingBB =2060      findDuplicateOutputBlock(OutputBBs, OutputStoreBBs);2061 2062  // If there is, we remove the new output blocks.  If it does not,2063  // we add it to our list of sets of output blocks.2064  if (MatchingBB) {2065    LLVM_DEBUG(dbgs() << "Set output block for region in function"2066                      << Region.ExtractedFunction << " to " << *MatchingBB);2067 2068    Region.OutputBlockNum = *MatchingBB;2069    for (std::pair<Value *, BasicBlock *> &VtoBB : OutputBBs)2070      VtoBB.second->eraseFromParent();2071    return;2072  }2073 2074  Region.OutputBlockNum = OutputStoreBBs.size();2075 2076  Value *RetValueForBB;2077  BasicBlock *NewBB;2078  OutputStoreBBs.push_back(DenseMap<Value *, BasicBlock *>());2079  for (std::pair<Value *, BasicBlock *> &VtoBB : OutputBBs) {2080    RetValueForBB = VtoBB.first;2081    NewBB = VtoBB.second;2082    DenseMap<Value *, BasicBlock *>::iterator VBBIt =2083        EndBBs.find(RetValueForBB);2084    LLVM_DEBUG(dbgs() << "Create output block for region in"2085                      << Region.ExtractedFunction << " to "2086                      << *NewBB);2087    BranchInst::Create(VBBIt->second, NewBB);2088    OutputStoreBBs.back().insert(std::make_pair(RetValueForBB, NewBB));2089  }2090}2091 2092/// Takes in a mapping, \p OldMap of ConstantValues to BasicBlocks, sorts keys,2093/// before creating a basic block for each \p NewMap, and inserting into the new2094/// block. Each BasicBlock is named with the scheme "<basename>_<key_idx>".2095///2096/// \param OldMap [in] - The mapping to base the new mapping off of.2097/// \param NewMap [out] - The output mapping using the keys of \p OldMap.2098/// \param ParentFunc [in] - The function to put the new basic block in.2099/// \param BaseName [in] - The start of the BasicBlock names to be appended to2100/// by an index value.2101static void createAndInsertBasicBlocks(DenseMap<Value *, BasicBlock *> &OldMap,2102                                       DenseMap<Value *, BasicBlock *> &NewMap,2103                                       Function *ParentFunc, Twine BaseName) {2104  unsigned Idx = 0;2105  std::vector<Value *> SortedKeys;2106  2107  getSortedConstantKeys(SortedKeys, OldMap);2108 2109  for (Value *RetVal : SortedKeys) {2110    BasicBlock *NewBB = BasicBlock::Create(2111        ParentFunc->getContext(), Twine(BaseName) + Twine("_") + Twine(Idx++),2112        ParentFunc);2113    NewMap.insert(std::make_pair(RetVal, NewBB));2114  }2115}2116 2117/// Create the switch statement for outlined function to differentiate between2118/// all the output blocks.2119///2120/// For the outlined section, determine if an outlined block already exists that2121/// matches the needed stores for the extracted section.2122/// \param [in] M - The module we are outlining from.2123/// \param [in] OG - The group of regions to be outlined.2124/// \param [in] EndBBs - The final blocks of the extracted function.2125/// \param [in,out] OutputStoreBBs - The existing output blocks.2126void createSwitchStatement(2127    Module &M, OutlinableGroup &OG, DenseMap<Value *, BasicBlock *> &EndBBs,2128    std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs) {2129  // We only need the switch statement if there is more than one store2130  // combination, or there is more than one set of output blocks.  The first2131  // will occur when we store different sets of values for two different2132  // regions.  The second will occur when we have two outputs that are combined2133  // in a PHINode outside of the region in one outlined instance, and are used2134  // seaparately in another. This will create the same set of OutputGVNs, but2135  // will generate two different output schemes.2136  if (OG.OutputGVNCombinations.size() > 1) {2137    Function *AggFunc = OG.OutlinedFunction;2138    // Create a final block for each different return block.2139    DenseMap<Value *, BasicBlock *> ReturnBBs;2140    createAndInsertBasicBlocks(OG.EndBBs, ReturnBBs, AggFunc, "final_block");2141 2142    for (std::pair<Value *, BasicBlock *> &RetBlockPair : ReturnBBs) {2143      std::pair<Value *, BasicBlock *> &OutputBlock =2144          *OG.EndBBs.find(RetBlockPair.first);2145      BasicBlock *ReturnBlock = RetBlockPair.second;2146      BasicBlock *EndBB = OutputBlock.second;2147      Instruction *Term = EndBB->getTerminator();2148      // Move the return value to the final block instead of the original exit2149      // stub.2150      Term->moveBefore(*ReturnBlock, ReturnBlock->end());2151      // Put the switch statement in the old end basic block for the function2152      // with a fall through to the new return block.2153      LLVM_DEBUG(dbgs() << "Create switch statement in " << *AggFunc << " for "2154                        << OutputStoreBBs.size() << "\n");2155      SwitchInst *SwitchI =2156          SwitchInst::Create(AggFunc->getArg(AggFunc->arg_size() - 1),2157                             ReturnBlock, OutputStoreBBs.size(), EndBB);2158 2159      unsigned Idx = 0;2160      for (DenseMap<Value *, BasicBlock *> &OutputStoreBB : OutputStoreBBs) {2161        DenseMap<Value *, BasicBlock *>::iterator OSBBIt =2162            OutputStoreBB.find(OutputBlock.first);2163 2164        if (OSBBIt == OutputStoreBB.end())2165          continue;2166 2167        BasicBlock *BB = OSBBIt->second;2168        SwitchI->addCase(2169            ConstantInt::get(Type::getInt32Ty(M.getContext()), Idx), BB);2170        Term = BB->getTerminator();2171        Term->setSuccessor(0, ReturnBlock);2172        Idx++;2173      }2174    }2175    return;2176  }2177 2178  assert(OutputStoreBBs.size() < 2 && "Different store sets not handled!");2179 2180  // If there needs to be stores, move them from the output blocks to their2181  // corresponding ending block.  We do not check that the OutputGVNCombinations2182  // is equal to 1 here since that could just been the case where there are 02183  // outputs. Instead, we check whether there is more than one set of output2184  // blocks since this is the only case where we would have to move the2185  // stores, and erase the extraneous blocks.2186  if (OutputStoreBBs.size() == 1) {2187    LLVM_DEBUG(dbgs() << "Move store instructions to the end block in "2188                      << *OG.OutlinedFunction << "\n");2189    DenseMap<Value *, BasicBlock *> OutputBlocks = OutputStoreBBs[0];2190    for (std::pair<Value *, BasicBlock *> &VBPair : OutputBlocks) {2191      DenseMap<Value *, BasicBlock *>::iterator EndBBIt =2192          EndBBs.find(VBPair.first);2193      assert(EndBBIt != EndBBs.end() && "Could not find end block");2194      BasicBlock *EndBB = EndBBIt->second;2195      BasicBlock *OutputBB = VBPair.second;2196      Instruction *Term = OutputBB->getTerminator();2197      Term->eraseFromParent();2198      Term = EndBB->getTerminator();2199      moveBBContents(*OutputBB, *EndBB);2200      Term->moveBefore(*EndBB, EndBB->end());2201      OutputBB->eraseFromParent();2202    }2203  }2204}2205 2206/// Fill the new function that will serve as the replacement function for all of2207/// the extracted regions of a certain structure from the first region in the2208/// list of regions.  Replace this first region's extracted function with the2209/// new overall function.2210///2211/// \param [in] M - The module we are outlining from.2212/// \param [in] CurrentGroup - The group of regions to be outlined.2213/// \param [in,out] OutputStoreBBs - The output blocks for each different2214/// set of stores needed for the different functions.2215/// \param [in,out] FuncsToRemove - Extracted functions to erase from module2216/// once outlining is complete.2217/// \param [in] OutputMappings - Extracted functions to erase from module2218/// once outlining is complete.2219static void fillOverallFunction(2220    Module &M, OutlinableGroup &CurrentGroup,2221    std::vector<DenseMap<Value *, BasicBlock *>> &OutputStoreBBs,2222    std::vector<Function *> &FuncsToRemove,2223    const DenseMap<Value *, Value *> &OutputMappings) {2224  OutlinableRegion *CurrentOS = CurrentGroup.Regions[0];2225 2226  // Move first extracted function's instructions into new function.2227  LLVM_DEBUG(dbgs() << "Move instructions from "2228                    << *CurrentOS->ExtractedFunction << " to instruction "2229                    << *CurrentGroup.OutlinedFunction << "\n");2230  moveFunctionData(*CurrentOS->ExtractedFunction,2231                   *CurrentGroup.OutlinedFunction, CurrentGroup.EndBBs);2232 2233  // Transfer the attributes from the function to the new function.2234  for (Attribute A : CurrentOS->ExtractedFunction->getAttributes().getFnAttrs())2235    CurrentGroup.OutlinedFunction->addFnAttr(A);2236 2237  // Create a new set of output blocks for the first extracted function.2238  DenseMap<Value *, BasicBlock *> NewBBs;2239  createAndInsertBasicBlocks(CurrentGroup.EndBBs, NewBBs,2240                             CurrentGroup.OutlinedFunction, "output_block_0");2241  CurrentOS->OutputBlockNum = 0;2242 2243  replaceArgumentUses(*CurrentOS, NewBBs, OutputMappings, true);2244  replaceConstants(*CurrentOS);2245 2246  // We first identify if any output blocks are empty, if they are we remove2247  // them. We then create a branch instruction to the basic block to the return2248  // block for the function for each non empty output block.2249  if (!analyzeAndPruneOutputBlocks(NewBBs, *CurrentOS)) {2250    OutputStoreBBs.push_back(DenseMap<Value *, BasicBlock *>());2251    for (std::pair<Value *, BasicBlock *> &VToBB : NewBBs) {2252      DenseMap<Value *, BasicBlock *>::iterator VBBIt =2253          CurrentGroup.EndBBs.find(VToBB.first);2254      BasicBlock *EndBB = VBBIt->second;2255      BranchInst::Create(EndBB, VToBB.second);2256      OutputStoreBBs.back().insert(VToBB);2257    }2258  }2259 2260  // Replace the call to the extracted function with the outlined function.2261  CurrentOS->Call = replaceCalledFunction(M, *CurrentOS);2262 2263  // We only delete the extracted functions at the end since we may need to2264  // reference instructions contained in them for mapping purposes.2265  FuncsToRemove.push_back(CurrentOS->ExtractedFunction);2266}2267 2268void IROutliner::deduplicateExtractedSections(2269    Module &M, OutlinableGroup &CurrentGroup,2270    std::vector<Function *> &FuncsToRemove, unsigned &OutlinedFunctionNum) {2271  createFunction(M, CurrentGroup, OutlinedFunctionNum);2272 2273  std::vector<DenseMap<Value *, BasicBlock *>> OutputStoreBBs;2274 2275  OutlinableRegion *CurrentOS;2276 2277  fillOverallFunction(M, CurrentGroup, OutputStoreBBs, FuncsToRemove,2278                      OutputMappings);2279 2280  for (unsigned Idx = 1; Idx < CurrentGroup.Regions.size(); Idx++) {2281    CurrentOS = CurrentGroup.Regions[Idx];2282    AttributeFuncs::mergeAttributesForOutlining(*CurrentGroup.OutlinedFunction,2283                                               *CurrentOS->ExtractedFunction);2284 2285    // Create a set of BasicBlocks, one for each return block, to hold the2286    // needed store instructions.2287    DenseMap<Value *, BasicBlock *> NewBBs;2288    createAndInsertBasicBlocks(CurrentGroup.EndBBs, NewBBs,2289                               CurrentGroup.OutlinedFunction,2290                               "output_block_" + Twine(Idx));2291    replaceArgumentUses(*CurrentOS, NewBBs, OutputMappings);2292    alignOutputBlockWithAggFunc(CurrentGroup, *CurrentOS, NewBBs,2293                                CurrentGroup.EndBBs, OutputMappings,2294                                OutputStoreBBs);2295 2296    CurrentOS->Call = replaceCalledFunction(M, *CurrentOS);2297    FuncsToRemove.push_back(CurrentOS->ExtractedFunction);2298  }2299 2300  // Create a switch statement to handle the different output schemes.2301  createSwitchStatement(M, CurrentGroup, CurrentGroup.EndBBs, OutputStoreBBs);2302 2303  OutlinedFunctionNum++;2304}2305 2306/// Checks that the next instruction in the InstructionDataList matches the2307/// next instruction in the module.  If they do not, there could be the2308/// possibility that extra code has been inserted, and we must ignore it.2309///2310/// \param ID - The IRInstructionData to check the next instruction of.2311/// \returns true if the InstructionDataList and actual instruction match.2312static bool nextIRInstructionDataMatchesNextInst(IRInstructionData &ID) {2313  // We check if there is a discrepancy between the InstructionDataList2314  // and the actual next instruction in the module.  If there is, it means2315  // that an extra instruction was added, likely by the CodeExtractor.2316 2317  // Since we do not have any similarity data about this particular2318  // instruction, we cannot confidently outline it, and must discard this2319  // candidate.2320  IRInstructionDataList::iterator NextIDIt = std::next(ID.getIterator());2321  Instruction *NextIDLInst = NextIDIt->Inst;2322  Instruction *NextModuleInst = nullptr;2323  if (!ID.Inst->isTerminator())2324    NextModuleInst = ID.Inst->getNextNode();2325  else if (NextIDLInst != nullptr)2326    NextModuleInst =2327        &*NextIDIt->Inst->getParent()->instructionsWithoutDebug().begin();2328 2329  if (NextIDLInst && NextIDLInst != NextModuleInst)2330    return false;2331 2332  return true;2333}2334 2335bool IROutliner::isCompatibleWithAlreadyOutlinedCode(2336    const OutlinableRegion &Region) {2337  IRSimilarityCandidate *IRSC = Region.Candidate;2338  unsigned StartIdx = IRSC->getStartIdx();2339  unsigned EndIdx = IRSC->getEndIdx();2340 2341  // A check to make sure that we are not about to attempt to outline something2342  // that has already been outlined.2343  for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)2344    if (Outlined.contains(Idx))2345      return false;2346 2347  // We check if the recorded instruction matches the actual next instruction,2348  // if it does not, we fix it in the InstructionDataList.2349  if (!Region.Candidate->backInstruction()->isTerminator()) {2350    Instruction *NewEndInst =2351        Region.Candidate->backInstruction()->getNextNode();2352    assert(NewEndInst && "Next instruction is a nullptr?");2353    if (Region.Candidate->end()->Inst != NewEndInst) {2354      IRInstructionDataList *IDL = Region.Candidate->front()->IDL;2355      IRInstructionData *NewEndIRID = new (InstDataAllocator.Allocate())2356          IRInstructionData(*NewEndInst,2357                            InstructionClassifier.visit(*NewEndInst), *IDL);2358 2359      // Insert the first IRInstructionData of the new region after the2360      // last IRInstructionData of the IRSimilarityCandidate.2361      IDL->insert(Region.Candidate->end(), *NewEndIRID);2362    }2363  }2364 2365  return none_of(*IRSC, [this](IRInstructionData &ID) {2366    if (!nextIRInstructionDataMatchesNextInst(ID))2367      return true;2368 2369    return !this->InstructionClassifier.visit(ID.Inst);2370  });2371}2372 2373void IROutliner::pruneIncompatibleRegions(2374    std::vector<IRSimilarityCandidate> &CandidateVec,2375    OutlinableGroup &CurrentGroup) {2376  bool PreviouslyOutlined;2377 2378  // Sort from beginning to end, so the IRSimilarityCandidates are in order.2379  stable_sort(CandidateVec, [](const IRSimilarityCandidate &LHS,2380                               const IRSimilarityCandidate &RHS) {2381    return LHS.getStartIdx() < RHS.getStartIdx();2382  });2383 2384  IRSimilarityCandidate &FirstCandidate = CandidateVec[0];2385  // Since outlining a call and a branch instruction will be the same as only2386  // outlinining a call instruction, we ignore it as a space saving.2387  if (FirstCandidate.getLength() == 2) {2388    if (isa<CallInst>(FirstCandidate.front()->Inst) &&2389        isa<BranchInst>(FirstCandidate.back()->Inst))2390      return;2391  }2392 2393  unsigned CurrentEndIdx = 0;2394  for (IRSimilarityCandidate &IRSC : CandidateVec) {2395    PreviouslyOutlined = false;2396    unsigned StartIdx = IRSC.getStartIdx();2397    unsigned EndIdx = IRSC.getEndIdx();2398    const Function &FnForCurrCand = *IRSC.getFunction();2399 2400    for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)2401      if (Outlined.contains(Idx)) {2402        PreviouslyOutlined = true;2403        break;2404      }2405 2406    if (PreviouslyOutlined)2407      continue;2408 2409    // Check over the instructions, and if the basic block has its address2410    // taken for use somewhere else, we do not outline that block.2411    bool BBHasAddressTaken = any_of(IRSC, [](IRInstructionData &ID){2412      return ID.Inst->getParent()->hasAddressTaken();2413    });2414 2415    if (BBHasAddressTaken)2416      continue;2417 2418    if (FnForCurrCand.hasOptNone())2419      continue;2420 2421    if (FnForCurrCand.hasFnAttribute("nooutline")) {2422      LLVM_DEBUG({2423        dbgs() << "... Skipping function with nooutline attribute: "2424               << FnForCurrCand.getName() << "\n";2425      });2426      continue;2427    }2428 2429    if (IRSC.front()->Inst->getFunction()->hasLinkOnceODRLinkage() &&2430        !OutlineFromLinkODRs)2431      continue;2432 2433    // Greedily prune out any regions that will overlap with already chosen2434    // regions.2435    if (CurrentEndIdx != 0 && StartIdx <= CurrentEndIdx)2436      continue;2437 2438    bool BadInst = any_of(IRSC, [this](IRInstructionData &ID) {2439      if (!nextIRInstructionDataMatchesNextInst(ID))2440        return true;2441 2442      return !this->InstructionClassifier.visit(ID.Inst);2443    });2444 2445    if (BadInst)2446      continue;2447 2448    OutlinableRegion *OS = new (RegionAllocator.Allocate())2449        OutlinableRegion(IRSC, CurrentGroup);2450    CurrentGroup.Regions.push_back(OS);2451 2452    CurrentEndIdx = EndIdx;2453  }2454}2455 2456InstructionCost2457IROutliner::findBenefitFromAllRegions(OutlinableGroup &CurrentGroup) {2458  InstructionCost RegionBenefit = 0;2459  for (OutlinableRegion *Region : CurrentGroup.Regions) {2460    TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());2461    // We add the number of instructions in the region to the benefit as an2462    // estimate as to how much will be removed.2463    RegionBenefit += Region->getBenefit(TTI);2464    LLVM_DEBUG(dbgs() << "Adding: " << RegionBenefit2465                      << " saved instructions to overfall benefit.\n");2466  }2467 2468  return RegionBenefit;2469}2470 2471/// For the \p OutputCanon number passed in find the value represented by this2472/// canonical number. If it is from a PHINode, we pick the first incoming2473/// value and return that Value instead.2474///2475/// \param Region - The OutlinableRegion to get the Value from.2476/// \param OutputCanon - The canonical number to find the Value from.2477/// \returns The Value represented by a canonical number \p OutputCanon in \p2478/// Region.2479static Value *findOutputValueInRegion(OutlinableRegion &Region,2480                                      unsigned OutputCanon) {2481  OutlinableGroup &CurrentGroup = *Region.Parent;2482  // If the value is greater than the value in the tracker, we have a2483  // PHINode and will instead use one of the incoming values to find the2484  // type.2485  if (OutputCanon > CurrentGroup.PHINodeGVNTracker) {2486    auto It = CurrentGroup.PHINodeGVNToGVNs.find(OutputCanon);2487    assert(It != CurrentGroup.PHINodeGVNToGVNs.end() &&2488           "Could not find GVN set for PHINode number!");2489    assert(It->second.second.size() > 0 && "PHINode does not have any values!");2490    OutputCanon = *It->second.second.begin();2491  }2492  std::optional<unsigned> OGVN =2493      Region.Candidate->fromCanonicalNum(OutputCanon);2494  assert(OGVN && "Could not find GVN for Canonical Number?");2495  std::optional<Value *> OV = Region.Candidate->fromGVN(*OGVN);2496  assert(OV && "Could not find value for GVN?");2497  return *OV;2498}2499 2500InstructionCost2501IROutliner::findCostOutputReloads(OutlinableGroup &CurrentGroup) {2502  InstructionCost OverallCost = 0;2503  for (OutlinableRegion *Region : CurrentGroup.Regions) {2504    TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());2505 2506    // Each output incurs a load after the call, so we add that to the cost.2507    for (unsigned OutputCanon : Region->GVNStores) {2508      Value *V = findOutputValueInRegion(*Region, OutputCanon);2509      InstructionCost LoadCost =2510          TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0,2511                              TargetTransformInfo::TCK_CodeSize);2512 2513      LLVM_DEBUG(dbgs() << "Adding: " << LoadCost2514                        << " instructions to cost for output of type "2515                        << *V->getType() << "\n");2516      OverallCost += LoadCost;2517    }2518  }2519 2520  return OverallCost;2521}2522 2523/// Find the extra instructions needed to handle any output values for the2524/// region.2525///2526/// \param [in] M - The Module to outline from.2527/// \param [in] CurrentGroup - The collection of OutlinableRegions to analyze.2528/// \param [in] TTI - The TargetTransformInfo used to collect information for2529/// new instruction costs.2530/// \returns the additional cost to handle the outputs.2531static InstructionCost findCostForOutputBlocks(Module &M,2532                                               OutlinableGroup &CurrentGroup,2533                                               TargetTransformInfo &TTI) {2534  InstructionCost OutputCost = 0;2535  unsigned NumOutputBranches = 0;2536 2537  OutlinableRegion &FirstRegion = *CurrentGroup.Regions[0];2538  IRSimilarityCandidate &Candidate = *CurrentGroup.Regions[0]->Candidate;2539  DenseSet<BasicBlock *> CandidateBlocks;2540  Candidate.getBasicBlocks(CandidateBlocks);2541 2542  // Count the number of different output branches that point to blocks outside2543  // of the region.2544  DenseSet<BasicBlock *> FoundBlocks;2545  for (IRInstructionData &ID : Candidate) {2546    if (!isa<BranchInst>(ID.Inst))2547      continue;2548 2549    for (Value *V : ID.OperVals) {2550      BasicBlock *BB = static_cast<BasicBlock *>(V);2551      if (!CandidateBlocks.contains(BB) && FoundBlocks.insert(BB).second)2552        NumOutputBranches++;2553    }2554  }2555 2556  CurrentGroup.BranchesToOutside = NumOutputBranches;2557 2558  for (const ArrayRef<unsigned> &OutputUse :2559       CurrentGroup.OutputGVNCombinations) {2560    for (unsigned OutputCanon : OutputUse) {2561      Value *V = findOutputValueInRegion(FirstRegion, OutputCanon);2562      InstructionCost StoreCost =2563          TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0,2564                              TargetTransformInfo::TCK_CodeSize);2565 2566      // An instruction cost is added for each store set that needs to occur for2567      // various output combinations inside the function, plus a branch to2568      // return to the exit block.2569      LLVM_DEBUG(dbgs() << "Adding: " << StoreCost2570                        << " instructions to cost for output of type "2571                        << *V->getType() << "\n");2572      OutputCost += StoreCost * NumOutputBranches;2573    }2574 2575    InstructionCost BranchCost =2576        TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize);2577    LLVM_DEBUG(dbgs() << "Adding " << BranchCost << " to the current cost for"2578                      << " a branch instruction\n");2579    OutputCost += BranchCost * NumOutputBranches;2580  }2581 2582  // If there is more than one output scheme, we must have a comparison and2583  // branch for each different item in the switch statement.2584  if (CurrentGroup.OutputGVNCombinations.size() > 1) {2585    InstructionCost ComparisonCost = TTI.getCmpSelInstrCost(2586        Instruction::ICmp, Type::getInt32Ty(M.getContext()),2587        Type::getInt32Ty(M.getContext()), CmpInst::BAD_ICMP_PREDICATE,2588        TargetTransformInfo::TCK_CodeSize);2589    InstructionCost BranchCost =2590        TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize);2591 2592    unsigned DifferentBlocks = CurrentGroup.OutputGVNCombinations.size();2593    InstructionCost TotalCost = ComparisonCost * BranchCost * DifferentBlocks;2594 2595    LLVM_DEBUG(dbgs() << "Adding: " << TotalCost2596                      << " instructions for each switch case for each different"2597                      << " output path in a function\n");2598    OutputCost += TotalCost * NumOutputBranches;2599  }2600 2601  return OutputCost;2602}2603 2604void IROutliner::findCostBenefit(Module &M, OutlinableGroup &CurrentGroup) {2605  InstructionCost RegionBenefit = findBenefitFromAllRegions(CurrentGroup);2606  CurrentGroup.Benefit += RegionBenefit;2607  LLVM_DEBUG(dbgs() << "Current Benefit: " << CurrentGroup.Benefit << "\n");2608 2609  InstructionCost OutputReloadCost = findCostOutputReloads(CurrentGroup);2610  CurrentGroup.Cost += OutputReloadCost;2611  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");2612 2613  InstructionCost AverageRegionBenefit =2614      RegionBenefit / CurrentGroup.Regions.size();2615  unsigned OverallArgumentNum = CurrentGroup.ArgumentTypes.size();2616  unsigned NumRegions = CurrentGroup.Regions.size();2617  TargetTransformInfo &TTI =2618      getTTI(*CurrentGroup.Regions[0]->Candidate->getFunction());2619 2620  // We add one region to the cost once, to account for the instructions added2621  // inside of the newly created function.2622  LLVM_DEBUG(dbgs() << "Adding: " << AverageRegionBenefit2623                    << " instructions to cost for body of new function.\n");2624  CurrentGroup.Cost += AverageRegionBenefit;2625  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");2626 2627  // For each argument, we must add an instruction for loading the argument2628  // out of the register and into a value inside of the newly outlined function.2629  LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum2630                    << " instructions to cost for each argument in the new"2631                    << " function.\n");2632  CurrentGroup.Cost +=2633      OverallArgumentNum * TargetTransformInfo::TCC_Basic;2634  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");2635 2636  // Each argument needs to either be loaded into a register or onto the stack.2637  // Some arguments will only be loaded into the stack once the argument2638  // registers are filled.2639  LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum2640                    << " instructions to cost for each argument in the new"2641                    << " function " << NumRegions << " times for the "2642                    << "needed argument handling at the call site.\n");2643  CurrentGroup.Cost +=2644      2 * OverallArgumentNum * TargetTransformInfo::TCC_Basic * NumRegions;2645  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");2646 2647  CurrentGroup.Cost += findCostForOutputBlocks(M, CurrentGroup, TTI);2648  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");2649}2650 2651void IROutliner::updateOutputMapping(OutlinableRegion &Region,2652                                     ArrayRef<Value *> Outputs,2653                                     LoadInst *LI) {2654  // For and load instructions following the call2655  Value *Operand = LI->getPointerOperand();2656  std::optional<unsigned> OutputIdx;2657  // Find if the operand it is an output register.2658  for (unsigned ArgIdx = Region.NumExtractedInputs;2659       ArgIdx < Region.Call->arg_size(); ArgIdx++) {2660    if (Operand == Region.Call->getArgOperand(ArgIdx)) {2661      OutputIdx = ArgIdx - Region.NumExtractedInputs;2662      break;2663    }2664  }2665 2666  // If we found an output register, place a mapping of the new value2667  // to the original in the mapping.2668  if (!OutputIdx)2669    return;2670 2671  auto It = OutputMappings.find(Outputs[*OutputIdx]);2672  if (It == OutputMappings.end()) {2673    LLVM_DEBUG(dbgs() << "Mapping extracted output " << *LI << " to "2674                      << *Outputs[*OutputIdx] << "\n");2675    OutputMappings.insert(std::make_pair(LI, Outputs[*OutputIdx]));2676  } else {2677    Value *Orig = It->second;2678    LLVM_DEBUG(dbgs() << "Mapping extracted output " << *Orig << " to "2679                      << *Outputs[*OutputIdx] << "\n");2680    OutputMappings.insert(std::make_pair(LI, Orig));2681  }2682}2683 2684bool IROutliner::extractSection(OutlinableRegion &Region) {2685  SetVector<Value *> ArgInputs, Outputs;2686  assert(Region.StartBB && "StartBB for the OutlinableRegion is nullptr!");2687  BasicBlock *InitialStart = Region.StartBB;2688  Function *OrigF = Region.StartBB->getParent();2689  CodeExtractorAnalysisCache CEAC(*OrigF);2690  Region.ExtractedFunction =2691      Region.CE->extractCodeRegion(CEAC, ArgInputs, Outputs);2692 2693  // If the extraction was successful, find the BasicBlock, and reassign the2694  // OutlinableRegion blocks2695  if (!Region.ExtractedFunction) {2696    LLVM_DEBUG(dbgs() << "CodeExtractor failed to outline " << Region.StartBB2697                      << "\n");2698    Region.reattachCandidate();2699    return false;2700  }2701 2702  // Get the block containing the called branch, and reassign the blocks as2703  // necessary.  If the original block still exists, it is because we ended on2704  // a branch instruction, and so we move the contents into the block before2705  // and assign the previous block correctly.2706  User *InstAsUser = Region.ExtractedFunction->user_back();2707  BasicBlock *RewrittenBB = cast<Instruction>(InstAsUser)->getParent();2708  Region.PrevBB = RewrittenBB->getSinglePredecessor();2709  assert(Region.PrevBB && "PrevBB is nullptr?");2710  if (Region.PrevBB == InitialStart) {2711    BasicBlock *NewPrev = InitialStart->getSinglePredecessor();2712    Instruction *BI = NewPrev->getTerminator();2713    BI->eraseFromParent();2714    moveBBContents(*InitialStart, *NewPrev);2715    Region.PrevBB = NewPrev;2716    InitialStart->eraseFromParent();2717  }2718 2719  Region.StartBB = RewrittenBB;2720  Region.EndBB = RewrittenBB;2721 2722  // The sequences of outlinable regions has now changed.  We must fix the2723  // IRInstructionDataList for consistency.  Although they may not be illegal2724  // instructions, they should not be compared with anything else as they2725  // should not be outlined in this round.  So marking these as illegal is2726  // allowed.2727  IRInstructionDataList *IDL = Region.Candidate->front()->IDL;2728  Instruction *BeginRewritten = &*RewrittenBB->begin();2729  Instruction *EndRewritten = &*RewrittenBB->begin();2730  Region.NewFront = new (InstDataAllocator.Allocate()) IRInstructionData(2731      *BeginRewritten, InstructionClassifier.visit(*BeginRewritten), *IDL);2732  Region.NewBack = new (InstDataAllocator.Allocate()) IRInstructionData(2733      *EndRewritten, InstructionClassifier.visit(*EndRewritten), *IDL);2734 2735  // Insert the first IRInstructionData of the new region in front of the2736  // first IRInstructionData of the IRSimilarityCandidate.2737  IDL->insert(Region.Candidate->begin(), *Region.NewFront);2738  // Insert the first IRInstructionData of the new region after the2739  // last IRInstructionData of the IRSimilarityCandidate.2740  IDL->insert(Region.Candidate->end(), *Region.NewBack);2741  // Remove the IRInstructionData from the IRSimilarityCandidate.2742  IDL->erase(Region.Candidate->begin(), std::prev(Region.Candidate->end()));2743 2744  assert(RewrittenBB != nullptr &&2745         "Could not find a predecessor after extraction!");2746 2747  // Iterate over the new set of instructions to find the new call2748  // instruction.2749  for (Instruction &I : *RewrittenBB)2750    if (CallInst *CI = dyn_cast<CallInst>(&I)) {2751      if (Region.ExtractedFunction == CI->getCalledFunction())2752        Region.Call = CI;2753    } else if (LoadInst *LI = dyn_cast<LoadInst>(&I))2754      updateOutputMapping(Region, Outputs.getArrayRef(), LI);2755  Region.reattachCandidate();2756  return true;2757}2758 2759unsigned IROutliner::doOutline(Module &M) {2760  // Find the possible similarity sections.2761  InstructionClassifier.EnableBranches = !DisableBranches;2762  InstructionClassifier.EnableIndirectCalls = !DisableIndirectCalls;2763  InstructionClassifier.EnableIntrinsics = !DisableIntrinsics;2764 2765  IRSimilarityIdentifier &Identifier = getIRSI(M);2766  SimilarityGroupList &SimilarityCandidates = *Identifier.getSimilarity();2767 2768  // Sort them by size of extracted sections2769  unsigned OutlinedFunctionNum = 0;2770  // If we only have one SimilarityGroup in SimilarityCandidates, we do not have2771  // to sort them by the potential number of instructions to be outlined2772  if (SimilarityCandidates.size() > 1)2773    llvm::stable_sort(SimilarityCandidates,2774                      [](const std::vector<IRSimilarityCandidate> &LHS,2775                         const std::vector<IRSimilarityCandidate> &RHS) {2776                        return LHS[0].getLength() * LHS.size() >2777                               RHS[0].getLength() * RHS.size();2778                      });2779  // Creating OutlinableGroups for each SimilarityCandidate to be used in2780  // each of the following for loops to avoid making an allocator.2781  std::vector<OutlinableGroup> PotentialGroups(SimilarityCandidates.size());2782 2783  DenseSet<unsigned> NotSame;2784  std::vector<OutlinableGroup *> NegativeCostGroups;2785  std::vector<OutlinableRegion *> OutlinedRegions;2786  // Iterate over the possible sets of similarity.2787  unsigned PotentialGroupIdx = 0;2788  for (SimilarityGroup &CandidateVec : SimilarityCandidates) {2789    OutlinableGroup &CurrentGroup = PotentialGroups[PotentialGroupIdx++];2790 2791    // Remove entries that were previously outlined2792    pruneIncompatibleRegions(CandidateVec, CurrentGroup);2793 2794    // We pruned the number of regions to 0 to 1, meaning that it's not worth2795    // trying to outlined since there is no compatible similar instance of this2796    // code.2797    if (CurrentGroup.Regions.size() < 2)2798      continue;2799 2800    // Determine if there are any values that are the same constant throughout2801    // each section in the set.2802    NotSame.clear();2803    CurrentGroup.findSameConstants(NotSame);2804 2805    if (CurrentGroup.IgnoreGroup)2806      continue;2807 2808    // Create a CodeExtractor for each outlinable region. Identify inputs and2809    // outputs for each section using the code extractor and create the argument2810    // types for the Aggregate Outlining Function.2811    OutlinedRegions.clear();2812    for (OutlinableRegion *OS : CurrentGroup.Regions) {2813      // Break the outlinable region out of its parent BasicBlock into its own2814      // BasicBlocks (see function implementation).2815      OS->splitCandidate();2816 2817      // There's a chance that when the region is split, extra instructions are2818      // added to the region. This makes the region no longer viable2819      // to be split, so we ignore it for outlining.2820      if (!OS->CandidateSplit)2821        continue;2822 2823      SmallVector<BasicBlock *> BE;2824      DenseSet<BasicBlock *> BlocksInRegion;2825      OS->Candidate->getBasicBlocks(BlocksInRegion, BE);2826      OS->CE = new (ExtractorAllocator.Allocate())2827          CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,2828                        false, nullptr, "outlined");2829      findAddInputsOutputs(M, *OS, NotSame);2830      if (!OS->IgnoreRegion)2831        OutlinedRegions.push_back(OS);2832 2833      // We recombine the blocks together now that we have gathered all the2834      // needed information.2835      OS->reattachCandidate();2836    }2837 2838    CurrentGroup.Regions = std::move(OutlinedRegions);2839 2840    if (CurrentGroup.Regions.empty())2841      continue;2842 2843    CurrentGroup.collectGVNStoreSets(M);2844 2845    if (CostModel)2846      findCostBenefit(M, CurrentGroup);2847 2848    // If we are adhering to the cost model, skip those groups where the cost2849    // outweighs the benefits.2850    if (CurrentGroup.Cost >= CurrentGroup.Benefit && CostModel) {2851      OptimizationRemarkEmitter &ORE =2852          getORE(*CurrentGroup.Regions[0]->Candidate->getFunction());2853      ORE.emit([&]() {2854        IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate;2855        OptimizationRemarkMissed R(DEBUG_TYPE, "WouldNotDecreaseSize",2856                                   C->frontInstruction());2857        R << "did not outline "2858          << ore::NV(std::to_string(CurrentGroup.Regions.size()))2859          << " regions due to estimated increase of "2860          << ore::NV("InstructionIncrease",2861                     CurrentGroup.Cost - CurrentGroup.Benefit)2862          << " instructions at locations ";2863        interleave(2864            CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(),2865            [&R](OutlinableRegion *Region) {2866              R << ore::NV(2867                  "DebugLoc",2868                  Region->Candidate->frontInstruction()->getDebugLoc());2869            },2870            [&R]() { R << " "; });2871        return R;2872      });2873      continue;2874    }2875 2876    NegativeCostGroups.push_back(&CurrentGroup);2877  }2878 2879  ExtractorAllocator.DestroyAll();2880 2881  if (NegativeCostGroups.size() > 1)2882    stable_sort(NegativeCostGroups,2883                [](const OutlinableGroup *LHS, const OutlinableGroup *RHS) {2884                  return LHS->Benefit - LHS->Cost > RHS->Benefit - RHS->Cost;2885                });2886 2887  std::vector<Function *> FuncsToRemove;2888  for (OutlinableGroup *CG : NegativeCostGroups) {2889    OutlinableGroup &CurrentGroup = *CG;2890 2891    OutlinedRegions.clear();2892    for (OutlinableRegion *Region : CurrentGroup.Regions) {2893      // We check whether our region is compatible with what has already been2894      // outlined, and whether we need to ignore this item.2895      if (!isCompatibleWithAlreadyOutlinedCode(*Region))2896        continue;2897      OutlinedRegions.push_back(Region);2898    }2899 2900    if (OutlinedRegions.size() < 2)2901      continue;2902 2903    // Reestimate the cost and benefit of the OutlinableGroup. Continue only if2904    // we are still outlining enough regions to make up for the added cost.2905    CurrentGroup.Regions = std::move(OutlinedRegions);2906    if (CostModel) {2907      CurrentGroup.Benefit = 0;2908      CurrentGroup.Cost = 0;2909      findCostBenefit(M, CurrentGroup);2910      if (CurrentGroup.Cost >= CurrentGroup.Benefit)2911        continue;2912    }2913    OutlinedRegions.clear();2914    for (OutlinableRegion *Region : CurrentGroup.Regions) {2915      Region->splitCandidate();2916      if (!Region->CandidateSplit)2917        continue;2918      OutlinedRegions.push_back(Region);2919    }2920 2921    CurrentGroup.Regions = std::move(OutlinedRegions);2922    if (CurrentGroup.Regions.size() < 2) {2923      for (OutlinableRegion *R : CurrentGroup.Regions)2924        R->reattachCandidate();2925      continue;2926    }2927 2928    LLVM_DEBUG(dbgs() << "Outlining regions with cost " << CurrentGroup.Cost2929                      << " and benefit " << CurrentGroup.Benefit << "\n");2930 2931    // Create functions out of all the sections, and mark them as outlined.2932    OutlinedRegions.clear();2933    for (OutlinableRegion *OS : CurrentGroup.Regions) {2934      SmallVector<BasicBlock *> BE;2935      DenseSet<BasicBlock *> BlocksInRegion;2936      OS->Candidate->getBasicBlocks(BlocksInRegion, BE);2937      OS->CE = new (ExtractorAllocator.Allocate())2938          CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false,2939                        false, nullptr, "outlined");2940      bool FunctionOutlined = extractSection(*OS);2941      if (FunctionOutlined) {2942        unsigned StartIdx = OS->Candidate->getStartIdx();2943        unsigned EndIdx = OS->Candidate->getEndIdx();2944        for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++)2945          Outlined.insert(Idx);2946 2947        OutlinedRegions.push_back(OS);2948      }2949    }2950 2951    LLVM_DEBUG(dbgs() << "Outlined " << OutlinedRegions.size()2952                      << " with benefit " << CurrentGroup.Benefit2953                      << " and cost " << CurrentGroup.Cost << "\n");2954 2955    CurrentGroup.Regions = std::move(OutlinedRegions);2956 2957    if (CurrentGroup.Regions.empty())2958      continue;2959 2960    OptimizationRemarkEmitter &ORE =2961        getORE(*CurrentGroup.Regions[0]->Call->getFunction());2962    ORE.emit([&]() {2963      IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate;2964      OptimizationRemark R(DEBUG_TYPE, "Outlined", C->front()->Inst);2965      R << "outlined " << ore::NV(std::to_string(CurrentGroup.Regions.size()))2966        << " regions with decrease of "2967        << ore::NV("Benefit", CurrentGroup.Benefit - CurrentGroup.Cost)2968        << " instructions at locations ";2969      interleave(2970          CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(),2971          [&R](OutlinableRegion *Region) {2972            R << ore::NV("DebugLoc",2973                         Region->Candidate->frontInstruction()->getDebugLoc());2974          },2975          [&R]() { R << " "; });2976      return R;2977    });2978 2979    deduplicateExtractedSections(M, CurrentGroup, FuncsToRemove,2980                                 OutlinedFunctionNum);2981  }2982 2983  for (Function *F : FuncsToRemove)2984    F->eraseFromParent();2985 2986  return OutlinedFunctionNum;2987}2988 2989bool IROutliner::run(Module &M) {2990  CostModel = !NoCostModel;2991  OutlineFromLinkODRs = EnableLinkOnceODRIROutlining;2992 2993  return doOutline(M) > 0;2994}2995 2996PreservedAnalyses IROutlinerPass::run(Module &M, ModuleAnalysisManager &AM) {2997  auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();2998 2999  std::function<TargetTransformInfo &(Function &)> GTTI =3000      [&FAM](Function &F) -> TargetTransformInfo & {3001    return FAM.getResult<TargetIRAnalysis>(F);3002  };3003 3004  std::function<IRSimilarityIdentifier &(Module &)> GIRSI =3005      [&AM](Module &M) -> IRSimilarityIdentifier & {3006    return AM.getResult<IRSimilarityAnalysis>(M);3007  };3008 3009  std::unique_ptr<OptimizationRemarkEmitter> ORE;3010  std::function<OptimizationRemarkEmitter &(Function &)> GORE =3011      [&ORE](Function &F) -> OptimizationRemarkEmitter & {3012    ORE.reset(new OptimizationRemarkEmitter(&F));3013    return *ORE;3014  };3015 3016  if (IROutliner(GTTI, GIRSI, GORE).run(M))3017    return PreservedAnalyses::none();3018  return PreservedAnalyses::all();3019}3020