[llvm] 6df161a - [IROutliner] Adding a cost model, and debug option to turn the model off.

Andrew Litteken via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 29 10:43:49 PST 2020


Author: Andrew Litteken
Date: 2020-12-29T12:43:41-06:00
New Revision: 6df161a2fbf62bd4ab7297fe1fb234cdc972a48b

URL: https://github.com/llvm/llvm-project/commit/6df161a2fbf62bd4ab7297fe1fb234cdc972a48b
DIFF: https://github.com/llvm/llvm-project/commit/6df161a2fbf62bd4ab7297fe1fb234cdc972a48b.diff

LOG: [IROutliner] Adding a cost model, and debug option to turn the model off.

This adds a cost model that takes into account the total number of
machine instructions to be removed from each region, the number of
instructions added by adding a new function with a set of instructions,
and the instructions added by handling arguments.

Tests not adding flags:

llvm/test/Transforms/IROutliner/outlining-cost-model.ll

Reviewers: jroelofs, paquette

Differential Revision: https://reviews.llvm.org/D87299

Added: 
    llvm/test/Transforms/IROutliner/outlining-cost-model.ll
    llvm/test/Transforms/IROutliner/outlining-debug-statements.ll

Modified: 
    llvm/include/llvm/Transforms/IPO/IROutliner.h
    llvm/lib/Transforms/IPO/IROutliner.cpp
    llvm/test/Transforms/IROutliner/extraction.ll
    llvm/test/Transforms/IROutliner/illegal-allocas.ll
    llvm/test/Transforms/IROutliner/illegal-assumes.ll
    llvm/test/Transforms/IROutliner/illegal-branches.ll
    llvm/test/Transforms/IROutliner/illegal-callbr.ll
    llvm/test/Transforms/IROutliner/illegal-calls.ll
    llvm/test/Transforms/IROutliner/illegal-catchpad.ll
    llvm/test/Transforms/IROutliner/illegal-cleanup.ll
    llvm/test/Transforms/IROutliner/illegal-frozen.ll
    llvm/test/Transforms/IROutliner/illegal-gep.ll
    llvm/test/Transforms/IROutliner/illegal-invoke.ll
    llvm/test/Transforms/IROutliner/illegal-landingpad.ll
    llvm/test/Transforms/IROutliner/illegal-memcpy.ll
    llvm/test/Transforms/IROutliner/illegal-memmove.ll
    llvm/test/Transforms/IROutliner/illegal-memset.ll
    llvm/test/Transforms/IROutliner/illegal-phi-nodes.ll
    llvm/test/Transforms/IROutliner/illegal-vaarg.ll
    llvm/test/Transforms/IROutliner/legal-debug.ll
    llvm/test/Transforms/IROutliner/outlining-address-taken.ll
    llvm/test/Transforms/IROutliner/outlining-commutative-fp.ll
    llvm/test/Transforms/IROutliner/outlining-commutative.ll
    llvm/test/Transforms/IROutliner/outlining-constants-vs-registers.ll
    llvm/test/Transforms/IROutliner/outlining-different-constants.ll
    llvm/test/Transforms/IROutliner/outlining-different-globals.ll
    llvm/test/Transforms/IROutliner/outlining-different-output-blocks.ll
    llvm/test/Transforms/IROutliner/outlining-different-structure.ll
    llvm/test/Transforms/IROutliner/outlining-remapped-outputs.ll
    llvm/test/Transforms/IROutliner/outlining-same-constants.ll
    llvm/test/Transforms/IROutliner/outlining-same-globals.ll
    llvm/test/Transforms/IROutliner/outlining-same-output-blocks.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/IROutliner.h b/llvm/include/llvm/Transforms/IPO/IROutliner.h
index 2048d6d6d1a1..0cba35f637c6 100644
--- a/llvm/include/llvm/Transforms/IPO/IROutliner.h
+++ b/llvm/include/llvm/Transforms/IPO/IROutliner.h
@@ -145,6 +145,12 @@ struct OutlinableRegion {
   /// function has been extracted, the start and end of the BasicBlock
   /// containing the called function.
   void reattachCandidate();
+
+  /// Get the size of the code removed from the region.
+  ///
+  /// \param [in] TTI - The TargetTransformInfo for the parent function.
+  /// \returns the code size of the region
+  unsigned getBenefit(TargetTransformInfo &TTI);
 };
 
 /// This class is a pass that identifies similarity in a Module, extracts
@@ -201,6 +207,28 @@ class IROutliner {
   void findAddInputsOutputs(Module &M, OutlinableRegion &Region,
                             DenseSet<unsigned> &NotSame);
 
+  /// Find the number of instructions that will be removed by extracting the
+  /// OutlinableRegions in \p CurrentGroup.
+  ///
+  /// \param [in] CurrentGroup - The collection of OutlinableRegions to be
+  /// analyzed.
+  /// \returns the number of outlined instructions across all regions.
+  unsigned findBenefitFromAllRegions(OutlinableGroup &CurrentGroup);
+
+  /// Find the number of instructions that will be added by reloading arguments.
+  ///
+  /// \param [in] CurrentGroup - The collection of OutlinableRegions to be
+  /// analyzed.
+  /// \returns the number of added reload instructions across all regions.
+  unsigned findCostOutputReloads(OutlinableGroup &CurrentGroup);
+
+  /// Find the cost and the benefit of \p CurrentGroup and save it back to
+  /// \p CurrentGroup.
+  ///
+  /// \param [in] M - The module being analyzed
+  /// \param [in,out] CurrentGroup - The overall outlined section
+  void findCostBenefit(Module &M, OutlinableGroup &CurrentGroup);
+
   /// Update the output mapping based on the load instruction, and the outputs
   /// of the extracted function.
   ///
@@ -229,6 +257,11 @@ class IROutliner {
                                     std::vector<Function *> &FuncsToRemove,
                                     unsigned &OutlinedFunctionNum);
 
+  /// If false, we do not worry if the cost is greater than the benefit.  This
+  /// is for debugging and testing, so that we can test small cases to ensure
+  /// that the outlining is being done correctly.
+  bool CostModel = true;
+
   /// The set of outlined Instructions, identified by their location in the
   /// sequential ordering of instructions in a Module.
   DenseSet<unsigned> Outlined;

diff  --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index 4c0e09911ab9..da90f1a12871 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -29,6 +29,13 @@
 using namespace llvm;
 using namespace IRSimilarity;
 
+// This is a debug option to test small pieces of code to ensure that outlining
+// works correctly.
+static cl::opt<bool> NoCostModel(
+    "ir-outlining-no-cost", cl::init(false), cl::ReallyHidden,
+    cl::desc("Debug option to outline greedily, without restriction that "
+             "calculated benefit outweighs cost"));
+
 /// The OutlinableGroup holds all the overarching information for outlining
 /// a set of regions that are structurally similar to one another, such as the
 /// types of the overall function, the output blocks, the sets of stores needed
@@ -66,6 +73,13 @@ struct OutlinableGroup {
   /// index in ArgumentTypes is an output argument.
   unsigned NumAggregateInputs = 0;
 
+  /// The number of instructions that will be outlined by extracting \ref
+  /// Regions.
+  unsigned Benefit = 0;
+  /// The number of added instructions needed for the outlining of the \ref
+  /// Regions.
+  unsigned Cost = 0;
+
   /// For the \ref Regions, we look at every Value.  If it is a constant,
   /// we check whether it is the same in Region.
   ///
@@ -213,6 +227,40 @@ constantMatches(Value *V, unsigned GVN,
   return false;
 }
 
+unsigned OutlinableRegion::getBenefit(TargetTransformInfo &TTI) {
+  InstructionCost Benefit(0);
+
+  // Estimate the benefit of outlining a specific sections of the program.  We
+  // delegate mostly this task to the TargetTransformInfo so that if the target
+  // has specific changes, we can have a more accurate estimate.
+
+  // However, getInstructionCost delegates the code size calculation for
+  // arithmetic instructions to getArithmeticInstrCost in
+  // include/Analysis/TargetTransformImpl.h, where it always estimates that the
+  // code size for a division and remainder instruction to be equal to 4, and
+  // everything else to 1.  This is not an accurate representation of the
+  // division instruction for targets that have a native division instruction.
+  // To be overly conservative, we only add 1 to the number of instructions for
+  // each division instruction.
+  for (Instruction &I : *StartBB) {
+    switch (I.getOpcode()) {
+    case Instruction::FDiv:
+    case Instruction::FRem:
+    case Instruction::SDiv:
+    case Instruction::SRem:
+    case Instruction::UDiv:
+    case Instruction::URem:
+      Benefit += 1;
+      break;
+    default:
+      Benefit += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize);
+      break;
+    }
+  }
+
+  return *Benefit.getValue();
+}
+
 /// Find whether \p Region matches the global value numbering to Constant
 /// mapping found so far.
 ///
@@ -279,7 +327,7 @@ void OutlinableGroup::findSameConstants(DenseSet<unsigned> &NotSame) {
 }
 
 void OutlinableGroup::collectGVNStoreSets(Module &M) {
-  for (OutlinableRegion *OS : Regions) 
+  for (OutlinableRegion *OS : Regions)
     OutputGVNCombinations.insert(OS->GVNStores);
 
   // We are adding an extracted argument to decide between which output path
@@ -874,7 +922,7 @@ findDuplicateOutputBlock(BasicBlock *OutputBB,
       MatchingNum++;
       continue;
     }
-    
+
     WrongSize = false;
     BasicBlock::iterator NIt = OutputBB->begin();
     for (Instruction &I : *CompBB) {
@@ -888,7 +936,7 @@ findDuplicateOutputBlock(BasicBlock *OutputBB,
 
       NIt++;
     }
-    if (!WrongInst && !WrongSize) 
+    if (!WrongInst && !WrongSize)
       return MatchingNum;
 
     MatchingNum++;
@@ -963,7 +1011,7 @@ alignOutputBlockWithAggFunc(OutlinableGroup &OG, OutlinableRegion &Region,
     Region.OutputBlockNum = -1;
     OutputBB->eraseFromParent();
     return;
-  } 
+  }
 
   // Determine is there is a duplicate block.
   Optional<unsigned> MatchingBB =
@@ -1189,6 +1237,152 @@ void IROutliner::pruneIncompatibleRegions(
   }
 }
 
+unsigned IROutliner::findBenefitFromAllRegions(OutlinableGroup &CurrentGroup) {
+  unsigned RegionBenefit = 0;
+  for (OutlinableRegion *Region : CurrentGroup.Regions) {
+    TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());
+    // We add the number of instructions in the region to the benefit as an
+    // estimate as to how much will be removed.
+    RegionBenefit += Region->getBenefit(TTI);
+    LLVM_DEBUG(dbgs() << "Adding: " << RegionBenefit
+                      << " saved instructions to overfall benefit.\n");
+    CurrentGroup.Benefit += RegionBenefit;
+  }
+
+  return RegionBenefit;
+}
+
+unsigned IROutliner::findCostOutputReloads(OutlinableGroup &CurrentGroup) {
+  unsigned OverallCost = 0;
+  for (OutlinableRegion *Region : CurrentGroup.Regions) {
+    TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent());
+
+    // Each output incurs a load after the call, so we add that to the cost.
+    for (unsigned OutputGVN : Region->GVNStores) {
+      Optional<Value *> OV = Region->Candidate->fromGVN(OutputGVN);
+      assert(OV.hasValue() && "Could not find value for GVN?");
+      Value *V = OV.getValue();
+      unsigned LoadCost =
+          TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0,
+                              TargetTransformInfo::TCK_CodeSize);
+
+      LLVM_DEBUG(dbgs() << "Adding: " << LoadCost
+                        << " instructions to cost for output of type "
+                        << *V->getType() << "\n");
+      OverallCost += LoadCost;
+    }
+  }
+
+  return OverallCost;
+}
+
+/// Find the extra instructions needed to handle any output values for the
+/// region.
+///
+/// \param [in] M - The Module to outline from.
+/// \param [in] CurrentGroup - The collection of OutlinableRegions to analyze.
+/// \param [in] TTI - The TargetTransformInfo used to collect information for
+/// new instruction costs.
+/// \returns the additional cost to handle the outputs.
+static unsigned findCostForOutputBlocks(Module &M,
+                                        OutlinableGroup &CurrentGroup,
+                                        TargetTransformInfo &TTI) {
+  unsigned OutputCost = 0;
+
+  for (const ArrayRef<unsigned> &OutputUse :
+       CurrentGroup.OutputGVNCombinations) {
+    IRSimilarityCandidate &Candidate = *CurrentGroup.Regions[0]->Candidate;
+    for (unsigned GVN : OutputUse) {
+      Optional<Value *> OV = Candidate.fromGVN(GVN);
+      assert(OV.hasValue() && "Could not find value for GVN?");
+      Value *V = OV.getValue();
+      unsigned StoreCost =
+          TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0,
+                              TargetTransformInfo::TCK_CodeSize);
+
+      // An instruction cost is added for each store set that needs to occur for
+      // various output combinations inside the function, plus a branch to
+      // return to the exit block.
+      LLVM_DEBUG(dbgs() << "Adding: " << StoreCost
+                        << " instructions to cost for output of type "
+                        << *V->getType() << "\n");
+      OutputCost += StoreCost;
+    }
+
+    unsigned BranchCost =
+        TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize);
+    LLVM_DEBUG(dbgs() << "Adding " << BranchCost << " to the current cost for"
+                      << " a branch instruction\n");
+    OutputCost += BranchCost;
+  }
+
+  // If there is more than one output scheme, we must have a comparison and
+  // branch for each 
diff erent item in the switch statement.
+  if (CurrentGroup.OutputGVNCombinations.size() > 1) {
+    unsigned ComparisonCost = TTI.getCmpSelInstrCost(
+        Instruction::ICmp, Type::getInt32Ty(M.getContext()),
+        Type::getInt32Ty(M.getContext()), CmpInst::BAD_ICMP_PREDICATE,
+        TargetTransformInfo::TCK_CodeSize);
+    unsigned BranchCost =
+        TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize);
+
+    unsigned DifferentBlocks = CurrentGroup.OutputGVNCombinations.size();
+    unsigned TotalCost = ComparisonCost * BranchCost * DifferentBlocks;
+
+    LLVM_DEBUG(dbgs() << "Adding: " << TotalCost
+                      << " instructions for each switch case for each 
diff erent"
+                      << " output path in a function\n");
+    OutputCost += TotalCost;
+  }
+
+  return OutputCost;
+}
+
+void IROutliner::findCostBenefit(Module &M, OutlinableGroup &CurrentGroup) {
+  unsigned RegionBenefit = findBenefitFromAllRegions(CurrentGroup);
+  CurrentGroup.Benefit += RegionBenefit;
+  LLVM_DEBUG(dbgs() << "Current Benefit: " << CurrentGroup.Benefit << "\n");
+
+  unsigned OutputReloadCost = findCostOutputReloads(CurrentGroup);
+  CurrentGroup.Cost += OutputReloadCost;
+  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
+
+  unsigned AverageRegionBenefit = RegionBenefit / CurrentGroup.Regions.size();
+  unsigned OverallArgumentNum = CurrentGroup.ArgumentTypes.size();
+  unsigned NumRegions = CurrentGroup.Regions.size();
+  TargetTransformInfo &TTI =
+      getTTI(*CurrentGroup.Regions[0]->Candidate->getFunction());
+
+  // We add one region to the cost once, to account for the instructions added
+  // inside of the newly created function.
+  LLVM_DEBUG(dbgs() << "Adding: " << AverageRegionBenefit
+                    << " instructions to cost for body of new function.\n");
+  CurrentGroup.Cost += AverageRegionBenefit;
+  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
+
+  // For each argument, we must add an instruction for loading the argument
+  // out of the register and into a value inside of the newly outlined function.
+  LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum
+                    << " instructions to cost for each argument in the new"
+                    << " function.\n");
+  CurrentGroup.Cost += 2 * OverallArgumentNum * TargetTransformInfo::TCC_Basic;
+  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
+
+  // Each argument needs to either be loaded into a register or onto the stack.
+  // Some arguments will only be loaded into the stack once the argument
+  // registers are filled.
+  LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum
+                    << " instructions to cost for each argument in the new"
+                    << " function " << NumRegions << " times for the "
+                    << "needed argument handling at the call site.\n");
+  CurrentGroup.Cost +=
+      2 * OverallArgumentNum * TargetTransformInfo::TCC_Basic * NumRegions;
+  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
+
+  CurrentGroup.Cost += findCostForOutputBlocks(M, CurrentGroup, TTI);
+  LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n");
+}
+
 void IROutliner::updateOutputMapping(OutlinableRegion &Region,
                                      ArrayRef<Value *> Outputs,
                                      LoadInst *LI) {
@@ -1348,6 +1542,19 @@ unsigned IROutliner::doOutline(Module &M) {
 
     CurrentGroup.collectGVNStoreSets(M);
 
+    if (CostModel)
+      findCostBenefit(M, CurrentGroup);
+
+    // If we are adhering to the cost model, reattach all the candidates
+    if (CurrentGroup.Cost >= CurrentGroup.Benefit && CostModel) {
+      for (OutlinableRegion *OS : CurrentGroup.Regions)
+        OS->reattachCandidate();
+      continue;
+    }
+
+    LLVM_DEBUG(dbgs() << "Outlining regions with cost " << CurrentGroup.Cost
+                      << " and benefit " << CurrentGroup.Benefit << "\n");
+
     // Create functions out of all the sections, and mark them as outlined.
     OutlinedRegions.clear();
     for (OutlinableRegion *OS : CurrentGroup.Regions) {
@@ -1377,7 +1584,11 @@ unsigned IROutliner::doOutline(Module &M) {
   return OutlinedFunctionNum;
 }
 
-bool IROutliner::run(Module &M) { return doOutline(M) > 0; }
+bool IROutliner::run(Module &M) {
+  CostModel = !NoCostModel;
+
+  return doOutline(M) > 0;
+}
 
 // Pass Manager Boilerplate
 class IROutlinerLegacyPass : public ModulePass {

diff  --git a/llvm/test/Transforms/IROutliner/extraction.ll b/llvm/test/Transforms/IROutliner/extraction.ll
index 889b7a2d3a84..0a268c7b6a2e 100644
--- a/llvm/test/Transforms/IROutliner/extraction.ll
+++ b/llvm/test/Transforms/IROutliner/extraction.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test makes sure we are extracting the found similarity sections
 ; correctly at the call site.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-allocas.ll b/llvm/test/Transforms/IROutliner/illegal-allocas.ll
index 123ce6b24862..379ef288ccb8 100644
--- a/llvm/test/Transforms/IROutliner/illegal-allocas.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-allocas.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner  -ir-outlining-no-cost < %s | FileCheck %s
 
 ; Show that we do not extract allocas, as outlining allocas may cause
 ; inconsistencies with the CodeExtractor's algorithm.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-assumes.ll b/llvm/test/Transforms/IROutliner/illegal-assumes.ll
index 1da29c12338e..f8e624d39589 100644
--- a/llvm/test/Transforms/IROutliner/illegal-assumes.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-assumes.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test ensures that we do not include llvm.assumes.  There are exceptions
 ; in the CodeExtractor's algorithm for llvm.assumes, so we ignore it for now.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-branches.ll b/llvm/test/Transforms/IROutliner/illegal-branches.ll
index 23d2e6cd7830..833638bbc582 100644
--- a/llvm/test/Transforms/IROutliner/illegal-branches.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-branches.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; Show that we do not extract sections with branches as it would require extra
 ; label and control flow checking.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-callbr.ll b/llvm/test/Transforms/IROutliner/illegal-callbr.ll
index c836f718173c..3ac6ada99a01 100644
--- a/llvm/test/Transforms/IROutliner/illegal-callbr.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-callbr.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that we do not outline callbr instruction since as we do not
 ; outline any control flow change instructions.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-calls.ll b/llvm/test/Transforms/IROutliner/illegal-calls.ll
index 442df08001b7..99c8f6fa838d 100644
--- a/llvm/test/Transforms/IROutliner/illegal-calls.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-calls.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that we do not outline calls.  Special calls, such as
 ; indirect or nameless calls require extra handling to ensure that there

diff  --git a/llvm/test/Transforms/IROutliner/illegal-catchpad.ll b/llvm/test/Transforms/IROutliner/illegal-catchpad.ll
index 83b82435d680..5881efc9aa58 100644
--- a/llvm/test/Transforms/IROutliner/illegal-catchpad.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-catchpad.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that catchpad instructions are not outlined even if they
 ; in a similar section.  Dealing with exception handling inside of an outlined

diff  --git a/llvm/test/Transforms/IROutliner/illegal-cleanup.ll b/llvm/test/Transforms/IROutliner/illegal-cleanup.ll
index d48797bec2cd..84c53ec9096d 100644
--- a/llvm/test/Transforms/IROutliner/illegal-cleanup.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-cleanup.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that cleanuppad instructions are not outlined even if they
 ; in a similar section.  Dealing with exception handling inside of an outlined

diff  --git a/llvm/test/Transforms/IROutliner/illegal-frozen.ll b/llvm/test/Transforms/IROutliner/illegal-frozen.ll
index 4ab11550ec86..ec8e71acfa60 100644
--- a/llvm/test/Transforms/IROutliner/illegal-frozen.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-frozen.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; Show that we do not extract freeze instructions, since extra handling is
 ; required to mark any outputs used with freeze.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-gep.ll b/llvm/test/Transforms/IROutliner/illegal-gep.ll
index e99ffb6a034f..a625106105b0 100644
--- a/llvm/test/Transforms/IROutliner/illegal-gep.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-gep.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks to make sure that we do not outline getelementptr
 ; instructions since we must make extra checks on the final operands.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-invoke.ll b/llvm/test/Transforms/IROutliner/illegal-invoke.ll
index 6c3841ab420b..dfbedce587c6 100644
--- a/llvm/test/Transforms/IROutliner/illegal-invoke.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-invoke.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that invoke instructions are not outlined even if they
 ; in a similar section.  Outlining does not currently handle control flow

diff  --git a/llvm/test/Transforms/IROutliner/illegal-landingpad.ll b/llvm/test/Transforms/IROutliner/illegal-landingpad.ll
index fbcc28c81fa5..e5060b5f2582 100644
--- a/llvm/test/Transforms/IROutliner/illegal-landingpad.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-landingpad.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that landingpad instructions are not outlined even if they
 ; in a similar section.  Dealing with exception handling inside of an outlined

diff  --git a/llvm/test/Transforms/IROutliner/illegal-memcpy.ll b/llvm/test/Transforms/IROutliner/illegal-memcpy.ll
index 3b55672a6a8a..6c242d7b5e84 100644
--- a/llvm/test/Transforms/IROutliner/illegal-memcpy.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-memcpy.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that we do not outline memcpy intrinsics since it may require
 ; extra address space checks.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-memmove.ll b/llvm/test/Transforms/IROutliner/illegal-memmove.ll
index f5d002f8b1e2..0a9216425455 100644
--- a/llvm/test/Transforms/IROutliner/illegal-memmove.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-memmove.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that we do not outline memcpy intrinsics since it may require
 ; extra address space checks.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-memset.ll b/llvm/test/Transforms/IROutliner/illegal-memset.ll
index 71f66c24a4af..4470d0c6d128 100644
--- a/llvm/test/Transforms/IROutliner/illegal-memset.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-memset.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that we do not outline memset intrinsics since it requires
 ; extra address space checks.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-phi-nodes.ll b/llvm/test/Transforms/IROutliner/illegal-phi-nodes.ll
index dc6746687c0c..f3cee80aec63 100644
--- a/llvm/test/Transforms/IROutliner/illegal-phi-nodes.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-phi-nodes.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; Show that we do not extract phi nodes as it would require extra label and
 ; control flow checking.

diff  --git a/llvm/test/Transforms/IROutliner/illegal-vaarg.ll b/llvm/test/Transforms/IROutliner/illegal-vaarg.ll
index 378f0cd25869..28a1e5994e70 100644
--- a/llvm/test/Transforms/IROutliner/illegal-vaarg.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-vaarg.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test ensures that we do not outline vararg instructions or intrinsics, as
 ; they may cause inconsistencies when outlining.

diff  --git a/llvm/test/Transforms/IROutliner/legal-debug.ll b/llvm/test/Transforms/IROutliner/legal-debug.ll
index 0a7ded9db19b..43d303606e55 100644
--- a/llvm/test/Transforms/IROutliner/legal-debug.ll
+++ b/llvm/test/Transforms/IROutliner/legal-debug.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test looks ahecks that debug info is extracted along with the other
 ; instructions.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-address-taken.ll b/llvm/test/Transforms/IROutliner/outlining-address-taken.ll
index 6f1d56f579ff..8af84fd519c2 100644
--- a/llvm/test/Transforms/IROutliner/outlining-address-taken.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-address-taken.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test shows that we do not outline from basic blocks with their address
 ; taken.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-commutative-fp.ll b/llvm/test/Transforms/IROutliner/outlining-commutative-fp.ll
index 35d8d27dab0f..a9d2a26fd096 100644
--- a/llvm/test/Transforms/IROutliner/outlining-commutative-fp.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-commutative-fp.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that floating point commutative instructions are not treated
 ; as commutative.  Even though an ffadd is technically commutative, the order

diff  --git a/llvm/test/Transforms/IROutliner/outlining-commutative.ll b/llvm/test/Transforms/IROutliner/outlining-commutative.ll
index c52792910cc5..5bd682c474dd 100644
--- a/llvm/test/Transforms/IROutliner/outlining-commutative.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-commutative.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test checks that commutative instructions where the operands are
 ; swapped are outlined as the same function.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-constants-vs-registers.ll b/llvm/test/Transforms/IROutliner/outlining-constants-vs-registers.ll
index 6809a396404d..093bb368c275 100644
--- a/llvm/test/Transforms/IROutliner/outlining-constants-vs-registers.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-constants-vs-registers.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test looks at instances of constants in the 
diff erent regions. If there
 ; is a register in the same place as a constant in a similar region of code, we

diff  --git a/llvm/test/Transforms/IROutliner/outlining-cost-model.ll b/llvm/test/Transforms/IROutliner/outlining-cost-model.ll
new file mode 100644
index 000000000000..3d47c2e7f0b1
--- /dev/null
+++ b/llvm/test/Transforms/IROutliner/outlining-cost-model.ll
@@ -0,0 +1,183 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s -check-prefix=NOCOST
+
+; This test checks that we have 
diff erent results from when the cost model
+; is on versus when it is off.  That is, if the number of instructions needed to
+; handle the arguments is greater than the number of instructions being added,
+; we do not outline.
+
+define void @function1() #0 {
+; CHECK-LABEL: @function1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
+; CHECK-NEXT:    ret void
+;
+; NOCOST-LABEL: @function1(
+; NOCOST-NEXT:  entry:
+; NOCOST-NEXT:    [[A:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[B:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
+; NOCOST-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %0 = load i32, i32* %a, align 4
+  %1 = load i32, i32* %b, align 4
+  %add = add i32 %0, %1
+  %mul = mul i32 %0, %1
+  %sub = sub i32 %0, %1
+  %div = sdiv i32 %0, %1
+  %add2 = add i32 %0, %1
+  %mul2 = mul i32 %0, %1
+  %sub2 = sub i32 %0, %1
+  %div2 = sdiv i32 %0, %1
+  ret void
+}
+
+define void @function2() #0 {
+; CHECK-LABEL: @function2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
+; CHECK-NEXT:    ret void
+;
+; NOCOST-LABEL: @function2(
+; NOCOST-NEXT:  entry:
+; NOCOST-NEXT:    [[A:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[B:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
+; NOCOST-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %0 = load i32, i32* %a, align 4
+  %1 = load i32, i32* %b, align 4
+  %add = add i32 %0, %1
+  %mul = mul i32 %0, %1
+  %sub = sub i32 %0, %1
+  %div = sdiv i32 %0, %1
+  %add2 = add i32 %0, %1
+  %mul2 = mul i32 %0, %1
+  %sub2 = sub i32 %0, %1
+  %div2 = sdiv i32 %0, %1
+  ret void
+}
+
+define void @function3() #0 {
+; CHECK-LABEL: @function3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    store i32 2, i32* [[A]], align 4
+; CHECK-NEXT:    store i32 3, i32* [[B]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[A]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B]], align 4
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    store i32 [[ADD]], i32* [[OUTPUT]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* [[OUTPUT]], align 4
+; CHECK-NEXT:    [[TMP3:%.*]] = load i32, i32* [[OUTPUT]], align 4
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[TMP2]], [[ADD]]
+; CHECK-NEXT:    store i32 [[MUL]], i32* [[RESULT]], align 4
+; CHECK-NEXT:    ret void
+;
+; NOCOST-LABEL: @function3(
+; NOCOST-NEXT:  entry:
+; NOCOST-NEXT:    [[DOTLOC:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[ADD_LOC:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[A:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[B:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[LT_CAST:%.*]] = bitcast i32* [[ADD_LOC]] to i8*
+; NOCOST-NEXT:    call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]])
+; NOCOST-NEXT:    [[LT_CAST1:%.*]] = bitcast i32* [[DOTLOC]] to i8*
+; NOCOST-NEXT:    call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST1]])
+; NOCOST-NEXT:    call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[OUTPUT]], i32* [[ADD_LOC]], i32* [[DOTLOC]])
+; NOCOST-NEXT:    [[ADD_RELOAD:%.*]] = load i32, i32* [[ADD_LOC]], align 4
+; NOCOST-NEXT:    [[DOTRELOAD:%.*]] = load i32, i32* [[DOTLOC]], align 4
+; NOCOST-NEXT:    call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
+; NOCOST-NEXT:    call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST1]])
+; NOCOST-NEXT:    [[TMP0:%.*]] = load i32, i32* [[OUTPUT]], align 4
+; NOCOST-NEXT:    call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], i32* [[RESULT]])
+; NOCOST-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %output = alloca i32, align 4
+  %result = alloca i32, align 4
+  store i32 2, i32* %a, align 4
+  store i32 3, i32* %b, align 4
+  %0 = load i32, i32* %a, align 4
+  %1 = load i32, i32* %b, align 4
+  %add = add i32 %0, %1
+  store i32 %add, i32* %output, align 4
+  %2 = load i32, i32* %output, align 4
+  %3 = load i32, i32* %output, align 4
+  %mul = mul i32 %2, %add
+  store i32 %mul, i32* %result, align 4
+  ret void
+}
+
+define void @function4() #0 {
+; CHECK-LABEL: @function4(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    store i32 2, i32* [[A]], align 4
+; CHECK-NEXT:    store i32 3, i32* [[B]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* [[A]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[B]], align 4
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT:    store i32 [[ADD]], i32* [[OUTPUT]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* [[OUTPUT]], align 4
+; CHECK-NEXT:    [[MUL:%.*]] = mul i32 [[TMP2]], [[ADD]]
+; CHECK-NEXT:    store i32 [[MUL]], i32* [[RESULT]], align 4
+; CHECK-NEXT:    ret void
+;
+; NOCOST-LABEL: @function4(
+; NOCOST-NEXT:  entry:
+; NOCOST-NEXT:    [[DOTLOC:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[ADD_LOC:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[A:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[B:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[OUTPUT:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[RESULT:%.*]] = alloca i32, align 4
+; NOCOST-NEXT:    [[LT_CAST:%.*]] = bitcast i32* [[ADD_LOC]] to i8*
+; NOCOST-NEXT:    call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST]])
+; NOCOST-NEXT:    [[LT_CAST1:%.*]] = bitcast i32* [[DOTLOC]] to i8*
+; NOCOST-NEXT:    call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[LT_CAST1]])
+; NOCOST-NEXT:    call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[OUTPUT]], i32* [[ADD_LOC]], i32* [[DOTLOC]])
+; NOCOST-NEXT:    [[ADD_RELOAD:%.*]] = load i32, i32* [[ADD_LOC]], align 4
+; NOCOST-NEXT:    [[DOTRELOAD:%.*]] = load i32, i32* [[DOTLOC]], align 4
+; NOCOST-NEXT:    call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST]])
+; NOCOST-NEXT:    call void @llvm.lifetime.end.p0i8(i64 -1, i8* [[LT_CAST1]])
+; NOCOST-NEXT:    call void @outlined_ir_func_2(i32 [[DOTRELOAD]], i32 [[ADD_RELOAD]], i32* [[RESULT]])
+; NOCOST-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %output = alloca i32, align 4
+  %result = alloca i32, align 4
+  store i32 2, i32* %a, align 4
+  store i32 3, i32* %b, align 4
+  %0 = load i32, i32* %a, align 4
+  %1 = load i32, i32* %b, align 4
+  %add = add i32 %0, %1
+  store i32 %add, i32* %output, align 4
+  %2 = load i32, i32* %output, align 4
+  %mul = mul i32 %2, %add
+  store i32 %mul, i32* %result, align 4
+  ret void
+}

diff  --git a/llvm/test/Transforms/IROutliner/outlining-debug-statements.ll b/llvm/test/Transforms/IROutliner/outlining-debug-statements.ll
new file mode 100644
index 000000000000..203d347ee5bb
--- /dev/null
+++ b/llvm/test/Transforms/IROutliner/outlining-debug-statements.ll
@@ -0,0 +1,71 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
+
+; This test makes sure that we do not include debug statements in outlined
+; functions.
+
+define void @outline_dbg1() {
+; CHECK-LABEL: @outline_dbg1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %c = alloca i32, align 4
+  store i32 2, i32* %a, align 4
+  store i32 3, i32* %b, align 4
+  call void @llvm.dbg.value(metadata i64 0, metadata !14, metadata !DIExpression()), !dbg !14
+  store i32 4, i32* %c, align 4
+  %al = load i32, i32* %a
+  %bl = load i32, i32* %b
+  %cl = load i32, i32* %c
+  ret void
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+define void @outline_dbg2() {
+; CHECK-LABEL: @outline_dbg2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[B:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    [[C:%.*]] = alloca i32, align 4
+; CHECK-NEXT:    call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %c = alloca i32, align 4
+  store i32 2, i32* %a, align 4
+  store i32 3, i32* %b, align 4
+  store i32 4, i32* %c, align 4
+  %al = load i32, i32* %a
+  %bl = load i32, i32* %b
+  %cl = load i32, i32* %c
+  ret void
+}
+
+; CHECK: define internal void @outlined_ir_func_0(i32* [[ARG0:%.*]], i32* [[ARG1:%.*]], i32* [[ARG2:%.*]]) #1 {
+; CHECK: entry_to_outline:
+; CHECK-NEXT:    store i32 2, i32* [[ARG0]], align 4
+; CHECK-NEXT:    store i32 3, i32* [[ARG1]], align 4
+; CHECK-NEXT:    store i32 4, i32* [[ARG2]], align 4
+; CHECK-NEXT:    [[AL:%.*]] = load i32, i32* [[ARG0]], align 4
+; CHECK-NEXT:    [[BL:%.*]] = load i32, i32* [[ARG1]], align 4
+; CHECK-NEXT:    [[CL:%.*]] = load i32, i32* [[ARG2]], align 4
+
+!0 = !DIFile(filename: "foo.c", directory: "/tmp")
+!1 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!5 = distinct !DICompileUnit(language: DW_LANG_C, file: !0, producer: "My Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !6, retainedTypes: !6, globals: !7)
+!6 = !{}
+!7 = !{}
+!11 = distinct !DISubprogram(name: "func_5", scope: !0, file: !0, line: 117, type: !12, isLocal: true, isDefinition: true, scopeLine: 118, isOptimized: false, unit: !5, retainedNodes: !6)
+!12 = !DISubroutineType(types: !13)
+!13 = !{}
+!14 = !DILocalVariable(name: "p_6", arg: 1, scope: !11, line: 117, type: !1)

diff  --git a/llvm/test/Transforms/IROutliner/outlining-
diff erent-constants.ll b/llvm/test/Transforms/IROutliner/outlining-
diff erent-constants.ll
index c81f7f62c38c..07a1ff75c584 100644
--- a/llvm/test/Transforms/IROutliner/outlining-
diff erent-constants.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-
diff erent-constants.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost< %s | FileCheck %s
 
 ; This test looks at the constants in the regions, and if it they are the
 ; 
diff erents it elevates the constants to arguments.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-
diff erent-globals.ll b/llvm/test/Transforms/IROutliner/outlining-
diff erent-globals.ll
index 4624bb53f230..ce7b53f46507 100644
--- a/llvm/test/Transforms/IROutliner/outlining-
diff erent-globals.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-
diff erent-globals.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test looks at the globals in the regions, and makes sure they are not
 ; outlined if they are 
diff erent values.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-
diff erent-output-blocks.ll b/llvm/test/Transforms/IROutliner/outlining-
diff erent-output-blocks.ll
index ddff51e8d115..20a58b97ee6e 100644
--- a/llvm/test/Transforms/IROutliner/outlining-
diff erent-output-blocks.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-
diff erent-output-blocks.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -iroutliner < %s | FileCheck %s
+; RUN: opt -S -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; These functions are constructed slightly 
diff erently so that they require
 ; 
diff erent output blocks for the values used outside of the region. We are

diff  --git a/llvm/test/Transforms/IROutliner/outlining-
diff erent-structure.ll b/llvm/test/Transforms/IROutliner/outlining-
diff erent-structure.ll
index ed978b20f73a..d0f18e655d15 100644
--- a/llvm/test/Transforms/IROutliner/outlining-
diff erent-structure.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-
diff erent-structure.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner --ir-outlining-no-cost < %s | FileCheck %s
 
 ; This is a negative case to show that when we have the same set of
 ; instructions, but in a 
diff erent order, they are not outlined in the same way.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-remapped-outputs.ll b/llvm/test/Transforms/IROutliner/outlining-remapped-outputs.ll
index 7d491a2b3099..ee74b85fc879 100644
--- a/llvm/test/Transforms/IROutliner/outlining-remapped-outputs.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-remapped-outputs.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -iroutliner < %s | FileCheck %s
+; RUN: opt -S -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test tests that inputs that are replaced with the output of an outlined
 ; function is still recognized as the same value.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-same-constants.ll b/llvm/test/Transforms/IROutliner/outlining-same-constants.ll
index b98ac2e06f7a..e9f4e7752643 100644
--- a/llvm/test/Transforms/IROutliner/outlining-same-constants.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-same-constants.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; This test looks at the constants in the regions, and if it they are the
 ; same it outlines them as constants rather than elevating them to arguments.

diff  --git a/llvm/test/Transforms/IROutliner/outlining-same-globals.ll b/llvm/test/Transforms/IROutliner/outlining-same-globals.ll
index b065eae58769..7d4700590758 100644
--- a/llvm/test/Transforms/IROutliner/outlining-same-globals.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-same-globals.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -verify -iroutliner < %s | FileCheck %s
+; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 @global1 = global i32 1, align 4
 @global2 = global i32 2, align 4

diff  --git a/llvm/test/Transforms/IROutliner/outlining-same-output-blocks.ll b/llvm/test/Transforms/IROutliner/outlining-same-output-blocks.ll
index fb2ce92c82e0..8f8a0eaabe79 100644
--- a/llvm/test/Transforms/IROutliner/outlining-same-output-blocks.ll
+++ b/llvm/test/Transforms/IROutliner/outlining-same-output-blocks.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -iroutliner < %s | FileCheck %s
+; RUN: opt -S -iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; These functions are constructed slightly 
diff erently so that they require
 ; the same output blocks for the values used outside of the region. We are


        


More information about the llvm-commits mailing list