IRInstructionData *NewFront = nullptr;
IRInstructionData *NewBack = nullptr;
+ /// The number of extracted inputs from the CodeExtractor.
+ unsigned NumExtractedInputs;
+
+ /// Mapping the extracted argument number to the argument number in the
+ /// overall function. Since there will be inputs, such as elevated constants
+ /// that are not the same in each region in a SimilarityGroup, or values that
+ /// cannot be sunk into the extracted section in every region, we must keep
+ /// track of which extracted argument maps to which overall argument.
+ DenseMap<unsigned, unsigned> ExtractedArgToAgg;
+ DenseMap<unsigned, unsigned> AggArgToExtracted;
+
/// Used to create an outlined function.
CodeExtractor *CE = nullptr;
pruneIncompatibleRegions(std::vector<IRSimilarityCandidate> &CandidateVec,
OutlinableGroup &CurrentGroup);
+ /// Create the function based on the overall types found in the current
+ /// regions being outlined.
+ ///
+ /// \param M - The module to outline from.
+ /// \param [in,out] CG - The OutlinableGroup for the regions to be outlined.
+ /// \param [in] FunctionNameSuffix - How many functions have we previously
+ /// created.
+ /// \returns the newly created function.
+ Function *createFunction(Module &M, OutlinableGroup &CG,
+ unsigned FunctionNameSuffix);
+
/// Identify the needed extracted inputs in a section, and add to the overall
/// function if needed.
///
/// \returns True if it was successfully outlined.
bool extractSection(OutlinableRegion &Region);
+ /// For the similarities found, and the extracted sections, create a single
+ /// outlined function with appropriate output blocks as necessary.
+ ///
+ /// \param [in] M - The module to outline from
+ /// \param [in] CurrentGroup - The set of extracted sections to consolidate.
+ /// \param [in,out] FuncsToRemove - List of functions to remove from the
+ /// module after outlining is completed.
+ /// \param [in,out] OutlinedFunctionNum - the number of new outlined
+ /// functions.
+ void deduplicateExtractedSections(Module &M, OutlinableGroup &CurrentGroup,
+ std::vector<Function *> &FuncsToRemove,
+ unsigned &OutlinedFunctionNum);
+
/// The set of outlined Instructions, identified by their location in the
/// sequential ordering of instructions in a Module.
DenseSet<unsigned> Outlined;
/// The sections that could be outlined
std::vector<OutlinableRegion *> Regions;
+ /// The argument types for the function created as the overall function to
+ /// replace the extracted function for each region.
+ std::vector<Type *> ArgumentTypes;
+ /// The FunctionType for the overall function.
+ FunctionType *OutlinedFunctionType = nullptr;
+ /// The Function for the collective overall function.
+ Function *OutlinedFunction = nullptr;
+
/// Flag for whether we should not consider this group of OutlinableRegions
/// for extraction.
bool IgnoreGroup = false;
+ /// Flag for whether the \ref ArgumentTypes have been defined after the
+ /// extraction of the first region.
+ bool InputTypesSet = false;
+
+ /// The number of input values in \ref ArgumentTypes. Anything after this
+ /// index in ArgumentTypes is an output argument.
+ unsigned NumAggregateInputs = 0;
+
/// For the \ref Regions, we look at every Value. If it is a constant,
/// we check whether it is the same in Region.
///
return false;
}
-/// Find whether \p Region matches the global value numbering to Constant mapping
-/// found so far.
+/// Find whether \p Region matches the global value numbering to Constant
+/// mapping found so far.
///
/// \param Region - The OutlinableRegion we are checking for constants
+/// \param GVNToConstant - The mapping of global value number to Constants.
/// \param NotSame - The set of global value numbers that do not have the same
/// constant in each region.
/// \returns true if all Constants are the same in every use of a Constant in \p
/// Region and false if not
static bool
collectRegionsConstants(OutlinableRegion &Region,
- DenseMap<unsigned, Constant *> &GVNToConstant,
- DenseSet<unsigned> &NotSame) {
+ DenseMap<unsigned, Constant *> &GVNToConstant,
+ DenseSet<unsigned> &NotSame) {
IRSimilarityCandidate &C = *Region.Candidate;
for (IRInstructionData &ID : C) {
}
}
+Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group,
+ unsigned FunctionNameSuffix) {
+ assert(!Group.OutlinedFunction && "Function is already defined!");
+
+ Group.OutlinedFunctionType = FunctionType::get(
+ Type::getVoidTy(M.getContext()), Group.ArgumentTypes, false);
+
+ // These functions will only be called from within the same module, so
+ // we can set an internal linkage.
+ Group.OutlinedFunction = Function::Create(
+ Group.OutlinedFunctionType, GlobalValue::InternalLinkage,
+ "outlined_ir_func_" + std::to_string(FunctionNameSuffix), M);
+
+ Group.OutlinedFunction->addFnAttr(Attribute::OptimizeForSize);
+ Group.OutlinedFunction->addFnAttr(Attribute::MinSize);
+
+ return Group.OutlinedFunction;
+}
+
+/// Move each BasicBlock in \p Old to \p New.
+///
+/// \param [in] Old - the function to move the basic blocks from.
+/// \param [in] New - The function to move the basic blocks to.
+/// \returns the first return block for the function in New.
+static BasicBlock *moveFunctionData(Function &Old, Function &New) {
+ Function::iterator CurrBB, NextBB, FinalBB;
+ BasicBlock *NewEnd = nullptr;
+ std::vector<Instruction *> DebugInsts;
+ for (CurrBB = Old.begin(), FinalBB = Old.end(); CurrBB != FinalBB;
+ CurrBB = NextBB) {
+ NextBB = std::next(CurrBB);
+ CurrBB->removeFromParent();
+ CurrBB->insertInto(&New);
+ Instruction *I = CurrBB->getTerminator();
+ if (ReturnInst *RI = dyn_cast<ReturnInst>(I))
+ NewEnd = &(*CurrBB);
+ }
+
+ assert(NewEnd && "No return instruction for new function?");
+ return NewEnd;
+}
+
/// Find the GVN for the inputs that have been found by the CodeExtractor,
/// excluding the ones that will be removed by llvm.assumes as these will be
/// removed by the CodeExtractor.
/// analyzing.
/// \param [in] CurrentInputs - The set of inputs found by the
/// CodeExtractor.
-/// \param [out] CurrentInputNumbers - The global value numbers for the extracted
-/// arguments.
+/// \param [out] CurrentInputNumbers - The global value numbers for the
+/// extracted arguments.
static void mapInputsToGVNs(IRSimilarityCandidate &C,
SetVector<Value *> &CurrentInputs,
std::vector<unsigned> &EndInputNumbers) {
/// function.
///
/// \param [in,out] Region - The region of code to be analyzed.
-/// \param [out] Inputs - The global value numbers for the extracted arguments.
+/// \param [out] InputGVNs - The global value numbers for the extracted
+/// arguments.
/// \param [out] ArgInputs - The values of the inputs to the extracted function.
static void getCodeExtractorArguments(OutlinableRegion &Region,
std::vector<unsigned> &InputGVNs,
mapInputsToGVNs(C, OverallInputs, InputGVNs);
}
-void IROutliner::findAddInputsOutputs(
- Module &M, OutlinableRegion &Region) {
+/// Look over the inputs and map each input argument to an argument in the
+/// overall function for the regions. This creates a way to replace the
+/// arguments of the extracted function, with the arguments of the new overall
+/// function.
+///
+/// \param [in,out] Region - The region of code to be analyzed.
+/// \param [in] InputsGVNs - The global value numbering of the input values
+/// collected.
+/// \param [in] ArgInputs - The values of the arguments to the extracted
+/// function.
+static void
+findExtractedInputToOverallInputMapping(OutlinableRegion &Region,
+ std::vector<unsigned> InputGVNs,
+ SetVector<Value *> &ArgInputs) {
+
+ IRSimilarityCandidate &C = *Region.Candidate;
+ OutlinableGroup &Group = *Region.Parent;
+
+ // This counts the argument number in the overall function.
+ unsigned TypeIndex = 0;
+
+ // This counts the argument number in the extracted function.
+ unsigned OriginalIndex = 0;
+
+ // Find the mapping of the extracted arguments to the arguments for the
+ // overall function.
+ for (unsigned InputVal : InputGVNs) {
+ Optional<Value *> InputOpt = C.fromGVN(InputVal);
+ assert(InputOpt.hasValue() && "Global value number not found?");
+ Value *Input = InputOpt.getValue();
+
+ if (!Group.InputTypesSet)
+ Group.ArgumentTypes.push_back(Input->getType());
+
+ // It is not a constant, check if it is a sunken alloca. If it is not,
+ // create the mapping from extracted to overall. If it is, create the
+ // mapping of the index to the value.
+ unsigned Found = ArgInputs.count(Input);
+ assert(Found && "Input cannot be found!");
+
+ Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex));
+ Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex));
+ OriginalIndex++;
+ TypeIndex++;
+ }
+
+ // If we do not have definitions for the OutlinableGroup holding the region,
+ // set the length of the inputs here. We should have the same inputs for
+ // all of the different regions contained in the OutlinableGroup since they
+ // are all structurally similar to one another
+ if (!Group.InputTypesSet) {
+ Group.NumAggregateInputs = TypeIndex;
+ Group.InputTypesSet = true;
+ }
+
+ Region.NumExtractedInputs = OriginalIndex;
+}
+
+void IROutliner::findAddInputsOutputs(Module &M, OutlinableRegion &Region) {
std::vector<unsigned> Inputs;
SetVector<Value *> ArgInputs;
if (Region.IgnoreRegion)
return;
+
+ // Map the inputs found by the CodeExtractor to the arguments found for
+ // the overall function.
+ findExtractedInputToOverallInputMapping(Region, Inputs, ArgInputs);
+}
+
+/// Replace the extracted function in the Region with a call to the overall
+/// function constructed from the deduplicated similar regions, replacing and
+/// remapping the values passed to the extracted function as arguments to the
+/// new arguments of the overall function.
+///
+/// \param [in] M - The module to outline from.
+/// \param [in] Region - The regions of extracted code to be replaced with a new
+/// function.
+/// \returns a call instruction with the replaced function.
+CallInst *replaceCalledFunction(Module &M, OutlinableRegion &Region) {
+ std::vector<Value *> NewCallArgs;
+ DenseMap<unsigned, unsigned>::iterator ArgPair;
+
+ OutlinableGroup &Group = *Region.Parent;
+ CallInst *Call = Region.Call;
+ assert(Call && "Call to replace is nullptr?");
+ Function *AggFunc = Group.OutlinedFunction;
+ assert(AggFunc && "Function to replace with is nullptr?");
+
+ // If the arguments are the same size, there are not values that need to be
+ // made argument, or different output registers to handle. We can simply
+ // replace the called function in this case.
+ assert(AggFunc->arg_size() == Call->arg_size() &&
+ "Can only replace calls with the same number of arguments!");
+
+ LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to "
+ << *AggFunc << " with same number of arguments\n");
+ Call->setCalledFunction(AggFunc);
+ return Call;
+}
+
+// Within an extracted function, replace the argument uses of the extracted
+// region with the arguments of the function for an OutlinableGroup.
+//
+// \param OS [in] - The region of extracted code to be changed.
+static void replaceArgumentUses(OutlinableRegion &Region) {
+ OutlinableGroup &Group = *Region.Parent;
+ assert(Region.ExtractedFunction && "Region has no extracted function?");
+
+ for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size();
+ ArgIdx++) {
+ assert(Region.ExtractedArgToAgg.find(ArgIdx) !=
+ Region.ExtractedArgToAgg.end() &&
+ "No mapping from extracted to outlined?");
+ unsigned AggArgIdx = Region.ExtractedArgToAgg.find(ArgIdx)->second;
+ Argument *AggArg = Group.OutlinedFunction->getArg(AggArgIdx);
+ Argument *Arg = Region.ExtractedFunction->getArg(ArgIdx);
+ // The argument is an input, so we can simply replace it with the overall
+ // argument value
+ LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function "
+ << *Region.ExtractedFunction << " with " << *AggArg
+ << " in function " << *Group.OutlinedFunction << "\n");
+ Arg->replaceAllUsesWith(AggArg);
+ }
+}
+
+/// Fill the new function that will serve as the replacement function for all of
+/// the extracted regions of a certain structure from the first region in the
+/// list of regions. Replace this first region's extracted function with the
+/// new overall function.
+///
+/// \param M [in] - The module we are outlining from.
+/// \param CurrentGroup [in] - The group of regions to be outlined.
+/// \param FuncsToRemove [in,out] - Extracted functions to erase from module
+/// once outlining is complete.
+static void fillOverallFunction(Module &M, OutlinableGroup &CurrentGroup,
+ std::vector<Function *> &FuncsToRemove) {
+ OutlinableRegion *CurrentOS = CurrentGroup.Regions[0];
+
+ // Move first extracted function's instructions into new function
+ LLVM_DEBUG(dbgs() << "Move instructions from "
+ << *CurrentOS->ExtractedFunction << " to instruction "
+ << *CurrentGroup.OutlinedFunction << "\n");
+ moveFunctionData(*CurrentOS->ExtractedFunction,
+ *CurrentGroup.OutlinedFunction);
+
+ // Transfer the attributes
+ for (Attribute A :
+ CurrentOS->ExtractedFunction->getAttributes().getFnAttributes())
+ CurrentGroup.OutlinedFunction->addFnAttr(A);
+
+ replaceArgumentUses(*CurrentOS);
+
+ // Replace the call to the extracted function with the outlined function.
+ CurrentOS->Call = replaceCalledFunction(M, *CurrentOS);
+
+ // We only delete the extracted funcitons at the end since we may need to
+ // reference instructions contained in them for mapping purposes.
+ FuncsToRemove.push_back(CurrentOS->ExtractedFunction);
+}
+
+void IROutliner::deduplicateExtractedSections(
+ Module &M, OutlinableGroup &CurrentGroup,
+ std::vector<Function *> &FuncsToRemove, unsigned &OutlinedFunctionNum) {
+ createFunction(M, CurrentGroup, OutlinedFunctionNum);
+
+ std::vector<BasicBlock *> OutputStoreBBs;
+
+ OutlinableRegion *CurrentOS;
+
+ fillOverallFunction(M, CurrentGroup, FuncsToRemove);
+
+ // Do the same for the other extracted functions
+ for (unsigned Idx = 1; Idx < CurrentGroup.Regions.size(); Idx++) {
+ CurrentOS = CurrentGroup.Regions[Idx];
+
+ replaceArgumentUses(*CurrentOS);
+ CurrentOS->Call = replaceCalledFunction(M, *CurrentOS);
+ FuncsToRemove.push_back(CurrentOS->ExtractedFunction);
+ }
+
+ OutlinedFunctionNum++;
}
void IROutliner::pruneIncompatibleRegions(
});
DenseSet<unsigned> NotSame;
+ std::vector<Function *> FuncsToRemove;
// Iterate over the possible sets of similarity.
for (SimilarityGroup &CandidateVec : SimilarityCandidates) {
OutlinableGroup CurrentGroup;
// Create functions out of all the sections, and mark them as outlined.
OutlinedRegions.clear();
for (OutlinableRegion *OS : CurrentGroup.Regions) {
- OutlinedFunctionNum++;
bool FunctionOutlined = extractSection(*OS);
if (FunctionOutlined) {
unsigned StartIdx = OS->Candidate->getStartIdx();
}
CurrentGroup.Regions = std::move(OutlinedRegions);
+
+ if (CurrentGroup.Regions.empty())
+ continue;
+
+ deduplicateExtractedSections(M, CurrentGroup, FuncsToRemove,
+ OutlinedFunctionNum);
}
+ for (Function *F : FuncsToRemove)
+ F->eraseFromParent();
+
return OutlinedFunctionNum;
}
; 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 @extract1.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
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 @extract2.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
; 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: call void @extract_outs1.outlined(i32 [[TMP2]], i32 [[ADD]], i32* [[RESULT]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[TMP2]], i32 [[ADD]], i32* [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
; 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: call void @extract_outs2.outlined(i32 [[TMP2]], i32 [[ADD]], i32* [[RESULT]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32 [[TMP2]], i32 [[ADD]], i32* [[RESULT]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: store i1 true, i1* [[D]], align 4
; CHECK-NEXT: [[DL:%.*]] = load i1, i1* [[D]], align 1
; CHECK-NEXT: [[SPLIT_INST:%.*]] = sub i1 [[DL]], [[DL]]
-; CHECK-NEXT: call void @outline_assumes.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL]])
-; CHECK-NEXT: call void @outline_assumes.outlined.1(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: [[D:%.*]] = alloca i1, align 4
; CHECK-NEXT: store i1 false, i1* [[D]], align 4
; CHECK-NEXT: [[DL:%.*]] = load i1, i1* [[D]], align 1
-; CHECK-NEXT: call void @outline_assumes2.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL]])
-; CHECK-NEXT: call void @outline_assumes2.outlined.2(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: store i1 true, i1* [[D]], align 4
; CHECK-NEXT: [[DL:%.*]] = load i1, i1* [[D]], align 1
; CHECK-NEXT: [[SPLIT_INST:%.*]] = add i1 [[DL]], [[DL]]
-; CHECK-NEXT: call void @outline_assumes3.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL]])
-; CHECK-NEXT: call void @outline_assumes3.outlined.3(i32* [[A]])
+; CHECK-NEXT: call void @outlined_ir_func_2(i32* [[A]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: store i1 false, i1* [[D]], align 4
; CHECK-NEXT: [[DL:%.*]] = load i1, i1* [[D]], align 1
; CHECK-NEXT: [[SPLIT_INST:%.*]] = add i1 [[DL]], [[DL]]
-; CHECK-NEXT: call void @outline_assumes4.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @llvm.assume(i1 [[DL]])
-; CHECK-NEXT: call void @outline_assumes4.outlined.4(i32* [[A]])
+; CHECK-NEXT: call void @outlined_ir_func_2(i32* [[A]])
; CHECK-NEXT: ret void
;
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 @function1.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret void
; 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 @function2.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: br label [[NEXT:%.*]]
; CHECK: next:
; CHECK-NEXT: ret void
; CHECK-LABEL: @function1(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], 4
-; CHECK-NEXT: call void @function1.outlined(i32 [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B:%.*]])
; CHECK-NEXT: callbr void asm "xorl $0, $0
; CHECK-NEXT: to label [[NORMAL:%.*]] [label %fail1]
; CHECK: normal:
-; CHECK-NEXT: call void @function1.outlined.1(i32 [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
; CHECK: fail1:
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B]], 1
; CHECK-LABEL: @function2(
; CHECK-NEXT: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], 4
-; CHECK-NEXT: call void @function2.outlined(i32 [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B:%.*]])
; CHECK-NEXT: callbr void asm "xorl $0, $0
; CHECK-NEXT: to label [[NORMAL:%.*]] [label %fail1]
; CHECK: normal:
-; CHECK-NEXT: call void @function2.outlined.2(i32 [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32 [[B]])
; CHECK-NEXT: ret i32 0
; CHECK: fail1:
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[B]], 1
; 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 @outline_constants1.outlined.1(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @f1(i32* [[A]], i32* [[B]])
-; CHECK-NEXT: call void @outline_constants1.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
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 @outline_constants2.outlined.2(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_1(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: call void @f1(i32* [[A]], i32* [[B]])
-; CHECK-NEXT: call void @outline_constants2.outlined(i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catchpad1] unwind to caller
; CHECK: catchpad1:
; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] []
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK-NEXT: [[CS1:%.*]] = catchswitch within none [label %catchpad1] unwind to caller
; CHECK: catchpad1:
; CHECK-NEXT: [[TMP0:%.*]] = catchpad within [[CS1]] []
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none []
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: [[CLEAN:%.*]] = cleanuppad within none []
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[C:%.*]] = freeze i32* [[A:%.*]]
-; CHECK-NEXT: call void @function1.outlined(i32* [[C]], i32* [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[C]], i32* [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[C:%.*]] = freeze i32* [[A:%.*]]
-; CHECK-NEXT: call void @function2.outlined(i32* [[C]], i32* [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[C]], i32* [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S:%.*]], i64 1
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[S]], i64 [[T:%.*]]
; CHECK-NEXT: ret void
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_ST:%.*]], %struct.ST* [[S:%.*]], i64 1
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_ST]], %struct.ST* [[S]], i64 [[T:%.*]]
; CHECK-NEXT: ret void
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: invoke void @llvm.donothing()
; CHECK-NEXT: to label [[NORMAL:%.*]] unwind label [[EXCEPTION:%.*]]
; CHECK: exception:
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK: exception:
; CHECK-NEXT: [[CLEANUP:%.*]] = landingpad i8
; CHECK-NEXT: cleanup
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]])
; CHECK-NEXT: br label [[NORMAL]]
; CHECK: normal:
; CHECK-NEXT: ret void
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: [[TMP:%.*]] = bitcast [59 x i64]* [[POOL]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP]], i8 0, i64 236, i1 false)
-; CHECK-NEXT: call void @function1.outlined(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
entry:
; CHECK-NEXT: [[POOL:%.*]] = alloca [59 x i64], align 4
; CHECK-NEXT: [[TMP:%.*]] = bitcast [59 x i64]* [[POOL]] to i8*
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP]], i8 0, i64 236, i1 false)
-; CHECK-NEXT: call void @function2.outlined(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i64 [[N:%.*]], i64 [[X:%.*]], i64 [[Z:%.*]])
; CHECK-NEXT: ret i64 0
;
entry:
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 3, [[NEXT:%.*]] ]
-; CHECK-NEXT: call void @function1.outlined(i32* [[A:%.*]], i32* [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A:%.*]], i32* [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
; CHECK-NEXT: br label [[FIRST:%.*]]
; CHECK: first:
; CHECK-NEXT: [[TMP0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 3, [[NEXT:%.*]] ]
-; CHECK-NEXT: call void @function2.outlined(i32* [[A:%.*]], i32* [[B:%.*]])
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A:%.*]], i32* [[B:%.*]])
; CHECK-NEXT: ret void
; CHECK: next:
; CHECK-NEXT: br label [[FIRST]]
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32* [[B]], [[META11:metadata !.*]], metadata !DIExpression()), [[DBG18]]
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4, [[DBG19:!dbg !.*]]
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32* [[C]], [[META12:metadata !.*]], metadata !DIExpression()), [[DBG19]]
-; CHECK-NEXT: call void @function1.outlined(i32* [[A]], i32* [[B]], i32* [[C]]), [[DBG20:!dbg !.*]]
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]]), [[DBG20:!dbg !.*]]
; CHECK-NEXT: ret void, [[DBG21:!dbg !.*]]
;
entry:
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32* [[B]], [[META25:metadata !.*]], metadata !DIExpression()), [[DBG31]]
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4, [[DBG32:!dbg !.*]]
; CHECK-NEXT: call void @llvm.dbg.value(metadata i32* [[C]], [[META26:metadata !.*]], metadata !DIExpression()), [[DBG32]]
-; CHECK-NEXT: call void @function2.outlined(i32* [[A]], i32* [[B]], i32* [[C]]), [[DBG33:!dbg !.*]]
+; CHECK-NEXT: call void @outlined_ir_func_0(i32* [[A]], i32* [[B]], i32* [[C]]), [[DBG33:!dbg !.*]]
; CHECK-NEXT: ret void, [[DBG34:!dbg !.*]]
;
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 @[[FUNCTION_2:.*]](i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @[[FUNCTION_1]](i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
ret void
}
-; CHECK: define internal void @[[FUNCTION_2]](i32* [[ARG0:%.*]], i32* [[ARG1:%.*]], i32* [[ARG2:%.*]])
+; CHECK: define internal void @[[FUNCTION_1]](i32* [[ARG0:%.*]], i32* [[ARG1:%.*]], i32* [[ARG2:%.*]])
; 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 2, i32* [[A]], align 4
; CHECK-NEXT: store i32 3, i32* [[B]], align 4
; CHECK-NEXT: store i32 4, i32* [[C]], align 4
-; CHECK-NEXT: call void @[[FUNCTION_1:.*]](i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @[[FUNCTION_0]](i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
; CHECK-NEXT: store i32 2, i32* [[A]], align 4
; CHECK-NEXT: store i32 3, i32* [[B]], align 4
; CHECK-NEXT: store i32 4, i32* [[C]], align 4
-; CHECK-NEXT: call void @[[FUNCTION_1:.*]](i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @[[FUNCTION_0]](i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
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 @[[FUNCTION_1:.*]](i32* [[A]], i32* [[B]], i32* [[C]])
+; CHECK-NEXT: call void @[[FUNCTION_0]](i32* [[A]], i32* [[B]], i32* [[C]])
; CHECK-NEXT: ret void
;
entry:
define void @outline_globals1() {
; CHECK-LABEL: @outline_globals1(
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @[[FUNCTION_0:.*]]()
+; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: ret void
;
entry:
define void @outline_globals2() {
; CHECK-LABEL: @outline_globals2(
; CHECK-NEXT: entry:
-; CHECK-NEXT: call void @[[FUNCTION_1:.*]]()
+; CHECK-NEXT: call void @outlined_ir_func_0()
; CHECK-NEXT: ret void
;
entry:
ret void
}
-; CHECK: define internal void @[[FUNCTION_0]]()
-; CHECK: entry_to_outline:
-; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @global1, align 4
-; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @global2, align 4
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[TMP1]], [[TMP2]]
-
-
-; CHECK: define internal void @[[FUNCTION_1]]()
+; CHECK: define internal void @outlined_ir_func_0()
; CHECK: entry_to_outline:
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @global1, align 4
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @global2, align 4