Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Transforms/IPO/IROutliner.cpp
Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | struct OutlinableGroup { | ||||
/// The Function for the collective overall function. | /// The Function for the collective overall function. | ||||
Function *OutlinedFunction = nullptr; | Function *OutlinedFunction = nullptr; | ||||
/// Flag for whether we should not consider this group of OutlinableRegions | /// Flag for whether we should not consider this group of OutlinableRegions | ||||
/// for extraction. | /// for extraction. | ||||
bool IgnoreGroup = false; | bool IgnoreGroup = false; | ||||
/// Flag for whether the \ref ArgumentTypes have been defined after the | /// Flag for whether the \ref ArgumentTypes have been defined after the | ||||
/// exraction of the first region. | /// extraction of the first region. | ||||
bool InputTypesSet = false; | bool InputTypesSet = false; | ||||
/// The number of input values in \ref ArgumentTypes. Anything after this | /// The number of input values in \ref ArgumentTypes. Anything after this | ||||
/// index in ArgumentTypes is an output argument. | /// index in ArgumentTypes is an output argument. | ||||
unsigned NumAggregateInputs = 0; | unsigned NumAggregateInputs = 0; | ||||
/// For the \ref Regions, we look at every Value. If it is a constant, | /// For the \ref Regions, we look at every Value. If it is a constant, | ||||
/// we check whether it is the same in Region. | /// we check whether it is the same in Region. | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
/// \param NotSame - The set of global value numbers that do not have the same | /// \param NotSame - The set of global value numbers that do not have the same | ||||
/// constant in each region. | /// constant in each region. | ||||
/// \returns true if all Constants are the same in every use of a Constant in \p | /// \returns true if all Constants are the same in every use of a Constant in \p | ||||
/// Region and false if not | /// Region and false if not | ||||
static bool | static bool | ||||
collectRegionsConstants(OutlinableRegion &Region, | collectRegionsConstants(OutlinableRegion &Region, | ||||
DenseMap<unsigned, Constant *> &GVNToConstant, | DenseMap<unsigned, Constant *> &GVNToConstant, | ||||
DenseSet<unsigned> &NotSame) { | DenseSet<unsigned> &NotSame) { | ||||
bool ConstantsTheSame = true; | |||||
IRSimilarityCandidate &C = *Region.Candidate; | IRSimilarityCandidate &C = *Region.Candidate; | ||||
for (IRInstructionData &ID : C) { | for (IRInstructionData &ID : C) { | ||||
// Iterate over the operands in an instruction. If the global value number, | // Iterate over the operands in an instruction. If the global value number, | ||||
// assigned by the IRSimilarityCandidate, has been seen before, we check if | // assigned by the IRSimilarityCandidate, has been seen before, we check if | ||||
// the the number has been found to be not the same value in each instance. | // the the number has been found to be not the same value in each instance. | ||||
for (Value *V : ID.OperVals) { | for (Value *V : ID.OperVals) { | ||||
Optional<unsigned> GVNOpt = C.getGVN(V); | Optional<unsigned> GVNOpt = C.getGVN(V); | ||||
assert(GVNOpt.hasValue() && "Expected a GVN for operand?"); | assert(GVNOpt.hasValue() && "Expected a GVN for operand?"); | ||||
unsigned GVN = GVNOpt.getValue(); | unsigned GVN = GVNOpt.getValue(); | ||||
// If this global value has been found to not be the same, it could have | // Check if this global value has been found to not be the same already. | ||||
// just been a register, check that it is not a constant value. | |||||
if (NotSame.find(GVN) != NotSame.end()) { | if (NotSame.find(GVN) != NotSame.end()) { | ||||
if (isa<Constant>(V)) | if (isa<Constant>(V)) | ||||
return false; | ConstantsTheSame = false; | ||||
continue; | continue; | ||||
} | } | ||||
// If it has been the same so far, we check the value for if the | // If it has been the same so far, we check the value for if the | ||||
// associated Constant value match the previous instances of the same | // associated Constant value match the previous instances of the same | ||||
// global value number. If the global value does not map to a Constant, | // global value number. If the global value does not map to a Constant, | ||||
// it is considered to not be the same value. | // it is considered to not be the same value. | ||||
Optional<bool> ConstantMatches = constantMatches(V, GVN, GVNToConstant); | Optional<bool> ConstantMatches = constantMatches(V, GVN, GVNToConstant); | ||||
if (ConstantMatches.hasValue()) { | if (ConstantMatches.hasValue()) { | ||||
if (ConstantMatches.getValue()) | if (ConstantMatches.getValue()) | ||||
continue; | continue; | ||||
else | else | ||||
return false; | ConstantsTheSame = false; | ||||
} | } | ||||
// While this value is a register, it might not have been previously, | // While this value is a register, it might not have been previously, | ||||
// make sure we don't already have a constant mapped to this global value | // make sure we don't already have a constant mapped to this global value | ||||
// number. | // number. | ||||
if (GVNToConstant.find(GVN) != GVNToConstant.end()) | if (GVNToConstant.find(GVN) != GVNToConstant.end()) | ||||
return false; | ConstantsTheSame = false; | ||||
NotSame.insert(GVN); | NotSame.insert(GVN); | ||||
} | } | ||||
} | } | ||||
return true; | return ConstantsTheSame; | ||||
} | } | ||||
void OutlinableGroup::findSameConstants(DenseSet<unsigned> &NotSame) { | void OutlinableGroup::findSameConstants(DenseSet<unsigned> &NotSame) { | ||||
DenseMap<unsigned, Constant *> GVNToConstant; | DenseMap<unsigned, Constant *> GVNToConstant; | ||||
for (OutlinableRegion *Region : Regions) | for (OutlinableRegion *Region : Regions) | ||||
if (!collectRegionsConstants(*Region, GVNToConstant, NotSame)) { | collectRegionsConstants(*Region, GVNToConstant, NotSame); | ||||
IgnoreGroup = true; | |||||
return; | |||||
} | |||||
} | } | ||||
Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group, | Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group, | ||||
unsigned FunctionNameSuffix) { | unsigned FunctionNameSuffix) { | ||||
assert(!Group.OutlinedFunction && "Function is already defined!"); | assert(!Group.OutlinedFunction && "Function is already defined!"); | ||||
Group.OutlinedFunctionType = FunctionType::get( | Group.OutlinedFunctionType = FunctionType::get( | ||||
Type::getVoidTy(M.getContext()), Group.ArgumentTypes, false); | Type::getVoidTy(M.getContext()), Group.ArgumentTypes, false); | ||||
Show All 28 Lines | for (CurrBB = Old.begin(), FinalBB = Old.end(); CurrBB != FinalBB; | ||||
if (ReturnInst *RI = dyn_cast<ReturnInst>(I)) | if (ReturnInst *RI = dyn_cast<ReturnInst>(I)) | ||||
NewEnd = &(*CurrBB); | NewEnd = &(*CurrBB); | ||||
} | } | ||||
assert(NewEnd && "No return instruction for new function?"); | assert(NewEnd && "No return instruction for new function?"); | ||||
return NewEnd; | return NewEnd; | ||||
} | } | ||||
/// Find the GVN for the inputs that have been found by the CodeExtractor, | /// Find the the constants that will need to be lifted into arguments | ||||
/// excluding the ones that will be removed by llvm.assumes as these will be | /// as they are not the same in each instance of the region. | ||||
/// removed by the CodeExtractor. | /// | ||||
/// \param [in] C - The IRSimilarityCandidate containing the region we are | |||||
/// analyzing. | |||||
/// \param [in] NotSame - The set of global value numbers that do not have a | |||||
/// single Constant across all OutlinableRegions similar to \p C. | |||||
/// \param [out] Inputs - The list containing the global value numbers of the | |||||
/// arguments needed for the region of code. | |||||
static void findConstants(IRSimilarityCandidate &C, DenseSet<unsigned> &NotSame, | |||||
std::vector<unsigned> &Inputs) { | |||||
DenseSet<unsigned> InInput; | |||||
jroelofs: s/Seen/InInput/
might be a better name? | |||||
// Iterate over the instructions, and find what constants will need to be | |||||
// extracted into arguments. | |||||
for (IRInstructionDataList::iterator IDIt = C.begin(), EndIDIt = C.end(); | |||||
IDIt != EndIDIt; IDIt++) { | |||||
for (Value *V : (*IDIt).OperVals) { | |||||
// Since these are stored before any outlining, they will be in the | |||||
// global value numbering. | |||||
unsigned GVN = C.getGVN(V).getValue(); | |||||
if (Constant *CST = dyn_cast<Constant>(V)) | |||||
if (NotSame.find(GVN) != NotSame.end() && | |||||
InInput.find(GVN) == InInput.end()) { | |||||
Inputs.push_back(GVN); | |||||
InInput.insert(GVN); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/// Find the GVN for the inputs that have been found by the CodeExtractor. | |||||
/// | /// | ||||
/// \param [in] C - The IRSimilarityCandidate containing the region we are | /// \param [in] C - The IRSimilarityCandidate containing the region we are | ||||
/// analyzing. | /// analyzing. | ||||
/// \param [in] CurrentInputs - The set of inputs found by the | /// \param [in] CurrentInputs - The set of inputs found by the | ||||
/// CodeExtractor. | /// CodeExtractor. | ||||
/// \param [out] CurrentInputNumbers - The global value numbers for the | /// \param [out] EndInputNumbers - The global value numbers for the extracted | ||||
/// extracted arguments. | /// arguments. | ||||
static void mapInputsToGVNs(IRSimilarityCandidate &C, | static void mapInputsToGVNs(IRSimilarityCandidate &C, | ||||
SetVector<Value *> &CurrentInputs, | SetVector<Value *> &CurrentInputs, | ||||
std::vector<unsigned> &EndInputNumbers) { | std::vector<unsigned> &EndInputNumbers) { | ||||
// Get the global value number for each input. | // Get the global value number for each input. | ||||
for (Value *Input : CurrentInputs) { | for (Value *Input : CurrentInputs) { | ||||
assert(Input && "Have a nullptr as an input"); | assert(Input && "Have a nullptr as an input"); | ||||
assert(C.getGVN(Input).hasValue() && | assert(C.getGVN(Input).hasValue() && | ||||
"Could not find a numbering for the given input"); | "Could not find a numbering for the given input"); | ||||
EndInputNumbers.push_back(C.getGVN(Input).getValue()); | EndInputNumbers.push_back(C.getGVN(Input).getValue()); | ||||
} | } | ||||
} | } | ||||
/// Find the input GVNs and the output values for a region of Instructions. | /// Find the input GVNs and the output values for a region of Instructions. | ||||
/// Using the code extractor, we collect the inputs to the extracted function. | /// Using the code extractor, we collect the inputs to the extracted function. | ||||
/// | /// | ||||
/// The \p Region can be identifed as needing to be ignored in this function. | /// The \p Region can be identified as needing to be ignored in this function. | ||||
/// It should be checked whether it should be ignored after a call to this | /// It should be checked whether it should be ignored after a call to this | ||||
/// function. | /// function. | ||||
/// | /// | ||||
/// \param [in,out] Region - The region of code to be analyzed. | /// \param [in,out] Region - The region of code to be analyzed. | ||||
/// \param [out] Inputs - The global value numbers for the extracted arguments. | /// \param [out] Inputs - The global value numbers for the extracted arguments. | ||||
/// \param [in] NotSame - The global value numbers in the region that do not | |||||
/// have the same constant value in the regions structurally similar to | |||||
/// \p Region. | |||||
/// \param [out] ArgInputs - The values of the inputs to the extracted function. | /// \param [out] ArgInputs - The values of the inputs to the extracted function. | ||||
static void getCodeExtractorArguments(OutlinableRegion &Region, | static void getCodeExtractorArguments(OutlinableRegion &Region, | ||||
std::vector<unsigned> &InputGVNs, | std::vector<unsigned> &InputGVNs, | ||||
DenseSet<unsigned> &NotSame, | |||||
SetVector<Value *> &ArgInputs) { | SetVector<Value *> &ArgInputs) { | ||||
IRSimilarityCandidate &C = *Region.Candidate; | IRSimilarityCandidate &C = *Region.Candidate; | ||||
// OverallInputs are the inputs to the region found by the CodeExtractor, | // OverallInputs are the inputs to the region found by the CodeExtractor, | ||||
// SinkCands and HoistCands are used by the CodeExtractor to find sunken | // SinkCands and HoistCands are used by the CodeExtractor to find sunken | ||||
// allocas of values whose lifetimes are contained completely within the | // allocas of values whose lifetimes are contained completely within the | ||||
// outlined region. Outputs are values used outside of the outlined region | // outlined region. Outputs are values used outside of the outlined region | ||||
// found by the CodeExtractor. | // found by the CodeExtractor. | ||||
Show All 31 Lines | static void getCodeExtractorArguments(OutlinableRegion &Region, | ||||
// to be the same in every region, so we must elevate them all to arguments | // to be the same in every region, so we must elevate them all to arguments | ||||
// when they appear. If these values are not equal, it means there is some | // when they appear. If these values are not equal, it means there is some | ||||
// Input in OverallInputs that was removed for ArgInputs. | // Input in OverallInputs that was removed for ArgInputs. | ||||
if (ArgInputs.size() != OverallInputs.size()) { | if (ArgInputs.size() != OverallInputs.size()) { | ||||
Region.IgnoreRegion = true; | Region.IgnoreRegion = true; | ||||
return; | return; | ||||
} | } | ||||
findConstants(C, NotSame, InputGVNs); | |||||
mapInputsToGVNs(C, OverallInputs, InputGVNs); | mapInputsToGVNs(C, OverallInputs, InputGVNs); | ||||
// Sort the GVNs, since we now have constants included in the \ref InputGVNs | |||||
// we need to make sure they are in a deterministic order. | |||||
stable_sort(InputGVNs.begin(), InputGVNs.end()); | |||||
} | } | ||||
/// Look over the inputs and map each input argument to an argument in the | /// 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 | /// overall function for the OutlinableRegions. This creates a way to replace | ||||
/// arguments of the extracted function, with the arguments of the new overall | /// the arguments of the extracted function with the arguments of the new | ||||
/// function. | /// overall function. | ||||
/// | /// | ||||
/// \param [in,out] Region - The region of code to be analyzed. | /// \param [in,out] Region - The region of code to be analyzed. | ||||
/// \param [in] InputsGVNs - The global value numbering of the input values | /// \param [in] InputsGVNs - The global value numbering of the input values | ||||
/// collected. | /// collected. | ||||
/// \param [in] ArgInputs - The values of the arguments to the extracted | /// \param [in] ArgInputs - The values of the arguments to the extracted | ||||
/// function. | /// function. | ||||
static void | static void | ||||
findExtractedInputToOverallInputMapping(OutlinableRegion &Region, | findExtractedInputToOverallInputMapping(OutlinableRegion &Region, | ||||
std::vector<unsigned> InputGVNs, | std::vector<unsigned> InputGVNs, | ||||
SetVector<Value *> &ArgInputs) { | SetVector<Value *> &ArgInputs) { | ||||
IRSimilarityCandidate &C = *Region.Candidate; | IRSimilarityCandidate &C = *Region.Candidate; | ||||
OutlinableGroup &Group = *Region.Parent; | OutlinableGroup &Group = *Region.Parent; | ||||
// This counts the argument number in the overall function. | // This counts the argument number in the overall function. | ||||
unsigned TypeIndex = 0; | unsigned TypeIndex = 0; | ||||
// This counts the argument number in the extracted function. | // This counts the argument number in the extracted function. | ||||
unsigned OriginalIndex = 0; | unsigned OriginalIndex = 0; | ||||
// Find the mapping of the extracted arguments to the arguments for the | // Find the mapping of the extracted arguments to the arguments for the | ||||
// overall function. | // overall function. Since there may be extra arguments in the overall | ||||
// function to account for the extracted constants, we have two different | |||||
// counters as we find extracted arguments, and as we come across overall | |||||
// arguments. | |||||
for (unsigned InputVal : InputGVNs) { | for (unsigned InputVal : InputGVNs) { | ||||
Optional<Value *> InputOpt = C.fromGVN(InputVal); | Optional<Value *> InputOpt = C.fromGVN(InputVal); | ||||
assert(InputOpt.hasValue() && "Global value number not found?"); | assert(InputOpt.hasValue() && "Global value number not found?"); | ||||
Value *Input = InputOpt.getValue(); | Value *Input = InputOpt.getValue(); | ||||
if (!Group.InputTypesSet) | if (!Group.InputTypesSet) | ||||
Group.ArgumentTypes.push_back(Input->getType()); | Group.ArgumentTypes.push_back(Input->getType()); | ||||
// It is not a constant, check if it is a sunken alloca. If it is not, | // Check if we have a constant. If we do add it to the overall argument | ||||
// create the mapping from extracted to overall. If it is, create the | // number to Constant map for the region, and continue to the next input. | ||||
// mapping of the index to the value. | if (Constant *CST = dyn_cast<Constant>(Input)) { | ||||
Region.AggArgToConstant.insert(std::make_pair(TypeIndex, CST)); | |||||
TypeIndex++; | |||||
continue; | |||||
} | |||||
// It is not a constant, we create the mapping from extracted argument list | |||||
// to the overall argument list. | |||||
unsigned Found = ArgInputs.count(Input); | unsigned Found = ArgInputs.count(Input); | ||||
assert(Found && "Input cannot be found!"); | assert(Found && "Input cannot be found!"); | ||||
Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex)); | Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex)); | ||||
Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex)); | Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex)); | ||||
OriginalIndex++; | OriginalIndex++; | ||||
TypeIndex++; | TypeIndex++; | ||||
} | } | ||||
// If we do not have definitions for the OutlinableGroup holding the region, | // If the function type definitions for the OutlinableGroup holding the region | ||||
// set the length of the inputs here. We should have the same inputs for | // have not been set, set the length of the inputs here. We should have the | ||||
// all of the different regions contained in the OutlinableGroup since they | // same inputs for all of the different regions contained in the | ||||
// are all structurally similar to one another | // OutlinableGroup since they are all structurally similar to one another. | ||||
if (!Group.InputTypesSet) { | if (!Group.InputTypesSet) { | ||||
Group.NumAggregateInputs = TypeIndex; | Group.NumAggregateInputs = TypeIndex; | ||||
Group.InputTypesSet = true; | Group.InputTypesSet = true; | ||||
} | } | ||||
Region.NumExtractedInputs = OriginalIndex; | Region.NumExtractedInputs = OriginalIndex; | ||||
} | } | ||||
void IROutliner::findAddInputsOutputs(Module &M, OutlinableRegion &Region) { | void IROutliner::findAddInputsOutputs(Module &M, OutlinableRegion &Region, | ||||
DenseSet<unsigned> &NotSame) { | |||||
std::vector<unsigned> Inputs; | std::vector<unsigned> Inputs; | ||||
SetVector<Value *> ArgInputs; | SetVector<Value *> ArgInputs; | ||||
getCodeExtractorArguments(Region, Inputs, ArgInputs); | getCodeExtractorArguments(Region, Inputs, NotSame, ArgInputs); | ||||
if (Region.IgnoreRegion) | if (Region.IgnoreRegion) | ||||
return; | return; | ||||
// Map the inputs found by the CodeExtractor to the arguments found for | // Map the inputs found by the CodeExtractor to the arguments found for | ||||
// the overall function. | // the overall function. | ||||
findExtractedInputToOverallInputMapping(Region, Inputs, ArgInputs); | findExtractedInputToOverallInputMapping(Region, Inputs, ArgInputs); | ||||
} | } | ||||
Show All 15 Lines | CallInst *replaceCalledFunction(Module &M, OutlinableRegion &Region) { | ||||
CallInst *Call = Region.Call; | CallInst *Call = Region.Call; | ||||
assert(Call && "Call to replace is nullptr?"); | assert(Call && "Call to replace is nullptr?"); | ||||
Function *AggFunc = Group.OutlinedFunction; | Function *AggFunc = Group.OutlinedFunction; | ||||
assert(AggFunc && "Function to replace with is nullptr?"); | assert(AggFunc && "Function to replace with is nullptr?"); | ||||
// If the arguments are the same size, there are not values that need to be | // 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 | // made argument, or different output registers to handle. We can simply | ||||
// replace the called function in this case. | // replace the called function in this case. | ||||
assert(AggFunc->arg_size() == Call->arg_size() && | if (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 " | LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to " | ||||
<< *AggFunc << " with same number of arguments\n"); | << *AggFunc << " with same number of arguments\n"); | ||||
Call->setCalledFunction(AggFunc); | Call->setCalledFunction(AggFunc); | ||||
return Call; | return Call; | ||||
} | } | ||||
// We have a different number of arguments than the new function, so | |||||
// we need to use our previously mappings off extracted argument to overall | |||||
// function argument, and constants to overall function argument to create the | |||||
// new argument list. | |||||
for (unsigned AggArgIdx = 0; AggArgIdx < AggFunc->arg_size(); AggArgIdx++) { | |||||
ArgPair = Region.AggArgToExtracted.find(AggArgIdx); | |||||
if (ArgPair != Region.AggArgToExtracted.end()) { | |||||
Value *ArgumentValue = Call->getArgOperand(ArgPair->second); | |||||
// If we found the mapping from the extracted function to the overall | |||||
// function, we simply add it to the argument list. We use the same | |||||
// value, it just needs to honor the new order of arguments. | |||||
LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value " | |||||
<< *ArgumentValue << "\n"); | |||||
NewCallArgs.push_back(ArgumentValue); | |||||
continue; | |||||
} | |||||
// If it is a constant, we simply add it to the argument list as a value. | |||||
if (Region.AggArgToConstant.find(AggArgIdx) != | |||||
Region.AggArgToConstant.end()) { | |||||
Constant *CST = Region.AggArgToConstant.find(AggArgIdx)->second; | |||||
LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value " | |||||
<< *CST << "\n"); | |||||
NewCallArgs.push_back(CST); | |||||
continue; | |||||
} | |||||
// Add a nullptr value if the argument is not found in the extracted | |||||
// function. If we cannot find a value, it means it is not in use | |||||
// for the region, so we should not pass anything to it. | |||||
LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to nullptr\n"); | |||||
NewCallArgs.push_back(ConstantPointerNull::get( | |||||
static_cast<PointerType *>(AggFunc->getArg(AggArgIdx)->getType()))); | |||||
} | |||||
LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to " | |||||
<< *AggFunc << " with new set of arguments\n"); | |||||
// Create the new call instruction and erase the old one. | |||||
Call = CallInst::Create(AggFunc->getFunctionType(), AggFunc, NewCallArgs, "", | |||||
Call); | |||||
// It is possible that the call to the outlined function is either the first | |||||
// instruction in the new block, the last instruction, or both. If either of | |||||
// these is the case, we need to make sure that we replace the instruction in | |||||
// the IRInstructionData struct with the new call. | |||||
CallInst *OldCall = Region.Call; | |||||
if (Region.NewFront->Inst == OldCall) | |||||
Region.NewFront->Inst = Call; | |||||
if (Region.NewBack->Inst == OldCall) | |||||
Region.NewBack->Inst = Call; | |||||
// Transfer any debug information. | |||||
Call->setDebugLoc(Region.Call->getDebugLoc()); | |||||
// Remove the old instruction. | |||||
OldCall->eraseFromParent(); | |||||
jroelofsUnsubmitted Not Done ReplyInline ActionsI'd expect an RAUW... what if the call returns something? jroelofs: I'd expect an RAUW... what if the call returns something? | |||||
AndrewLittekenAuthorUnsubmitted The constructed functions do not return anything based on the CodeExtractor as they only contain single blocks. Additionally, this function only exists once since the extraction of a region only results in one function. After extraction we replace the different calls with a call to the aggregate function we created. AndrewLitteken: The constructed functions do not return anything based on the CodeExtractor as they only… | |||||
jroelofsUnsubmitted Oh, I see. This is only acting on synthesized calls, not pre-existing ones. jroelofs: Oh, I see. This is only acting on synthesized calls, not pre-existing ones. | |||||
Region.Call = Call; | |||||
return Call; | |||||
} | |||||
// Within an extracted function, replace the argument uses of the extracted | // Within an extracted function, replace the argument uses of the extracted | ||||
// region with the arguments of the function for an OutlinableGroup. | // region with the arguments of the function for an OutlinableGroup. | ||||
// | // | ||||
// \param OS [in] - The region of extracted code to be changed. | // \param OS [in] - The region of extracted code to be changed. | ||||
static void replaceArgumentUses(OutlinableRegion &Region) { | static void replaceArgumentUses(OutlinableRegion &Region) { | ||||
OutlinableGroup &Group = *Region.Parent; | OutlinableGroup &Group = *Region.Parent; | ||||
assert(Region.ExtractedFunction && "Region has no extracted function?"); | assert(Region.ExtractedFunction && "Region has no extracted function?"); | ||||
Show All 9 Lines | for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size(); | ||||
// argument value | // argument value | ||||
LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function " | LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function " | ||||
<< *Region.ExtractedFunction << " with " << *AggArg | << *Region.ExtractedFunction << " with " << *AggArg | ||||
<< " in function " << *Group.OutlinedFunction << "\n"); | << " in function " << *Group.OutlinedFunction << "\n"); | ||||
Arg->replaceAllUsesWith(AggArg); | Arg->replaceAllUsesWith(AggArg); | ||||
} | } | ||||
} | } | ||||
/// Within an extracted function, replace the constants that need to be lifted | |||||
/// into arguments with the actual argument. | |||||
/// | |||||
/// \param Region [in] - The region of extracted code to be changed. | |||||
void replaceConstants(OutlinableRegion &Region) { | |||||
OutlinableGroup &Group = *Region.Parent; | |||||
// Iterate over the constants that need to be elevated into arguments | |||||
for (std::pair<unsigned, Constant *> &Const : Region.AggArgToConstant) { | |||||
unsigned AggArgIdx = Const.first; | |||||
Function *OutlinedFunction = Group.OutlinedFunction; | |||||
assert(OutlinedFunction && "Overall Function is not defined?"); | |||||
Constant *CST = Const.second; | |||||
Argument *Arg = Group.OutlinedFunction->getArg(AggArgIdx); | |||||
// Identify the argument it will be elevated to, and replace instances of | |||||
// that constant in the function. | |||||
// TODO: If in the future constants do not have one global value number, | |||||
// i.e. a constant 1 could be mapped to several values, this check will | |||||
// have to be more strict. It cannot be using only replaceUsesWithIf. | |||||
LLVM_DEBUG(dbgs() << "Replacing uses of constant " << *CST | |||||
<< " in function " << *OutlinedFunction << " with " | |||||
<< *Arg << "\n"); | |||||
CST->replaceUsesWithIf(Arg, [OutlinedFunction](Use &U) { | |||||
if (Instruction *I = dyn_cast<Instruction>(U.getUser())) | |||||
return I->getFunction() == OutlinedFunction; | |||||
return false; | |||||
}); | |||||
} | |||||
} | |||||
/// Fill the new function that will serve as the replacement function for all of | /// 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 | /// 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 | /// list of regions. Replace this first region's extracted function with the | ||||
/// new overall function. | /// new overall function. | ||||
/// | /// | ||||
/// \param M [in] - The module we are outlining from. | /// \param M [in] - The module we are outlining from. | ||||
/// \param CurrentGroup [in] - The group of regions to be outlined. | /// \param CurrentGroup [in] - The group of regions to be outlined. | ||||
/// \param FuncsToRemove [in,out] - Extracted functions to erase from module | /// \param FuncsToRemove [in,out] - Extracted functions to erase from module | ||||
Show All 10 Lines | moveFunctionData(*CurrentOS->ExtractedFunction, | ||||
*CurrentGroup.OutlinedFunction); | *CurrentGroup.OutlinedFunction); | ||||
// Transfer the attributes | // Transfer the attributes | ||||
for (Attribute A : | for (Attribute A : | ||||
CurrentOS->ExtractedFunction->getAttributes().getFnAttributes()) | CurrentOS->ExtractedFunction->getAttributes().getFnAttributes()) | ||||
CurrentGroup.OutlinedFunction->addFnAttr(A); | CurrentGroup.OutlinedFunction->addFnAttr(A); | ||||
replaceArgumentUses(*CurrentOS); | replaceArgumentUses(*CurrentOS); | ||||
replaceConstants(*CurrentOS); | |||||
// Replace the call to the extracted function with the outlined function. | // Replace the call to the extracted function with the outlined function. | ||||
CurrentOS->Call = replaceCalledFunction(M, *CurrentOS); | CurrentOS->Call = replaceCalledFunction(M, *CurrentOS); | ||||
// We only delete the extracted funcitons at the end since we may need to | // We only delete the extracted funcitons at the end since we may need to | ||||
// reference instructions contained in them for mapping purposes. | // reference instructions contained in them for mapping purposes. | ||||
FuncsToRemove.push_back(CurrentOS->ExtractedFunction); | FuncsToRemove.push_back(CurrentOS->ExtractedFunction); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | for (SimilarityGroup &CandidateVec : SimilarityCandidates) { | ||||
for (OutlinableRegion *OS : CurrentGroup.Regions) { | for (OutlinableRegion *OS : CurrentGroup.Regions) { | ||||
// Break the outlinable region out of its parent BasicBlock into its own | // Break the outlinable region out of its parent BasicBlock into its own | ||||
// BasicBlocks (see function implementation). | // BasicBlocks (see function implementation). | ||||
OS->splitCandidate(); | OS->splitCandidate(); | ||||
std::vector<BasicBlock *> BE = {OS->StartBB}; | std::vector<BasicBlock *> BE = {OS->StartBB}; | ||||
OS->CE = new (OutlinerAllocator.Allocate<CodeExtractor>()) | OS->CE = new (OutlinerAllocator.Allocate<CodeExtractor>()) | ||||
CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false, | CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false, | ||||
false, "outlined"); | false, "outlined"); | ||||
findAddInputsOutputs(M, *OS); | findAddInputsOutputs(M, *OS, NotSame); | ||||
if (!OS->IgnoreRegion) | if (!OS->IgnoreRegion) | ||||
OutlinedRegions.push_back(OS); | OutlinedRegions.push_back(OS); | ||||
else | else | ||||
OS->reattachCandidate(); | OS->reattachCandidate(); | ||||
} | } | ||||
CurrentGroup.Regions = OutlinedRegions; | CurrentGroup.Regions = OutlinedRegions; | ||||
▲ Show 20 Lines • Show All 89 Lines • Show Last 20 Lines |
s/Seen/InInput/
might be a better name?