diff --git a/llvm/lib/Transforms/GenVISC/GenVISC.cpp b/llvm/lib/Transforms/GenVISC/GenVISC.cpp index 34d66354e574a5dae05132f6bbb8edbf176b4bb8..37e7f2e9a389ac6be095b1c4e7bddf4c19eabece 100644 --- a/llvm/lib/Transforms/GenVISC/GenVISC.cpp +++ b/llvm/lib/Transforms/GenVISC/GenVISC.cpp @@ -20,6 +20,9 @@ #include "llvm/SupportVISC/VISCHint.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Debug.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Transforms/Utils/Cloning.h" #define TIMER(X) do { if (VISCTimer) { X; } } while (0) @@ -161,6 +164,76 @@ static unsigned getNumericValue(Value* V) { return cast<ConstantInt>(V)->getZExtValue(); } +// Create new function F' as a copy of old function F with a new signature. +// The following two most used cases are handled by this function. +// 1. When some extra arguments need to be added to this function +// - Here we can map the old function arguments to +// new ones +// 2. When each pointer argument needs an additional size argument +// - Here, in the absence of VMap, we map the arguments in order, skipping +// over extra pointer arguments. +// The function returns the list of return instructions to the caller to fix in +// case the return type is also changed. +static Function* cloneFunction(Function* F, FunctionType* newFT, bool + isAddingPtrSizeArg, SmallVectorImpl<ReturnInst*> &Returns = NULL) { + + errs() << "Cloning Function: " << F->getName() << "\n"; + errs() << "Old Function Type: " << *F->getFunctionType() << "\n"; + errs() << "New Function Type: " << *newFT << "\n"; + + assert(F->getFunctionType()->getNumParams() <= newFT->getNumParams() + && "This function assumes that the new function has more arguments than the old function!"); + + // Create Function of specified type + Function* newF = Function::Create(newFT, F->getLinkage(), F->getName()+"_cloned", F->getParent()); + ValueToValueMapTy VMap; + errs() << "No value map provided. Creating default value map\n"; + errs() << "Old Function Type: " << *F->getType() << "\n"; + errs() << "New Function Type: " << *newF->getType() << "\n"; + if(isAddingPtrSizeArg) { + errs() << "Case 1: Pointer arg followed by a i64 size argument in new function\n"; + Function::arg_iterator new_ai = newF->arg_begin(); + for(Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); + ai != ae; ++ai) { + errs() << ai->getArgNo() << ". " << *ai << " : " << *new_ai << "\n"; + assert(ai->getType() == new_ai->getType() && "Arguments type do not match!"); + VMap[&*ai] = &*new_ai; + new_ai->takeName(&*ai); + if(ai->getType()->isPointerTy()) { + std::string oldName = new_ai->getName(); + // If the current argument is pointer type, the next argument in new + // function would be an i64 type containing the data size of this + // argument. Hence, skip the next arguement in new function. + ++new_ai; + new_ai->setName("bytes_"+oldName); + } + ++new_ai; + } + } + else { + errs() << "Case 2: Extra arguments are added at the end of old function\n"; + Function::arg_iterator new_ai = newF->arg_begin(); + for(Function::arg_iterator ai = F->arg_begin(), ae = F->arg_end(); + ai != ae; ++ai) { + assert(ai->getType() == new_ai->getType() && "Arguments type do not match!"); + VMap[&*ai] = &*new_ai; + if(ai->getType()->isPointerTy()) { + // If the current argument is pointer type, the next argument in new + // function would be an i64 type containing the data size of this + // argument. Hence, skip the next arguement in new function. + ++new_ai; + } + ++new_ai; + } + } + + // Clone function + CloneFunctionInto(newF, F, VMap, false, Returns); + errs() << *newF << "\n"; + + return newF; +} + // Add <numArgs> to the argument list of Function <F>. The names for these arguments // should be put in the string array <names>. Ideally the length of <names> // array should be numArgs. But, even when the length is not numArgs the @@ -168,13 +241,6 @@ static unsigned getNumericValue(Value* V) { // intuitive. static void addArgs(Function* F, unsigned numArgs, std::string names[]) { if(numArgs == 0) return; // Return if not arguments are to be added. - // Add the extra arguments to the Function argument list - for (unsigned i = 0; i < numArgs; ++i) { - new Argument(Type::getInt32Ty(F->getContext()), names[i%names->size()], F); - } - - // Now, we should change the type of the function F to reflect the added - // arguments. // Create the argument type list with added argument types std::vector<Type*> ArgTypes; @@ -185,11 +251,22 @@ static void addArgs(Function* F, unsigned numArgs, std::string names[]) { // Adding new arguments to the function argument list, would not change the // function type. We need to change the type of this function to reflect the // added arguments + for(int i = 0; i < numArgs; ++i) { + ArgTypes.push_back(Type::getInt32Ty(F->getContext())); + } FunctionType* FTy = FunctionType::get(F->getReturnType(), ArgTypes, F->isVarArg()); - PointerType* PTy = PointerType::get(FTy, cast<PointerType>(F->getType())->getAddressSpace()); // Change the function type - F->mutateType(PTy); + Function* newF = cloneFunction(F, newFT, false); + + // Add names to the extra arguments to the Function argument list + int numOldArgs = F->getFunctionType()->getNumParams(); + for(Function::arg_iterator ai = newF->arg_begin(), ae = newF->arg_end(); + ai != ae; ++ai) { + if (ai->getArgNo() < numOldArgs) + continue; + ai->setName(names[(ai->getArgNo() - numOldArgs) % names->size()]); + } } @@ -1366,33 +1443,19 @@ void GenVISC::genKernel(Function* KernelF, CallInst* CI, StructType* RetTy) { // Change arguments and types // Create the argument type list with added argument types - Function::ArgumentListType& argList = KernelF->getArgumentList(); + //Function::ArgumentListType& argList = KernelF->getArgumentList(); std::vector<Type*> argTypes; // Insert an i32 argument after every pointer argument. However adding an // argument does not change the attribute list of function and so the // arguments need to be shifted accordingly. - bool shiftAttr = false; + //bool shiftAttr = false; for(Function::arg_iterator ai = KernelF->arg_begin(), ae = KernelF->arg_end(); ai != ae; ++ai) { argTypes.push_back(ai->getType()); - DEBUG(errs() << "Adding Arguments" << *ai << "\n"); - if(shiftAttr) { - // If argument was added in the last iteration, shift the attributes to - // fix the mapping of arguments and attributes. Set the flag to false. - shiftAttr = false; - shiftAttributes(ai, 1, KernelF); - } if(ai->getType()->isPointerTy()) { - // If the current argument is a pointer argument, insert a i32 argument after - // it to denote the size of the pointer as required by visc - Argument* arg = new Argument(Type::getInt64Ty(KernelF->getContext()), - "bytes_"+ai->getName()); - argList.insertAfter(ai, arg); - // Set shiftAttr flag to true to denote that the argument was added and - // the attributes need to be shifted in the next iteration for correct - // mapping of arguments and their attributes. - shiftAttr = true; + // If it is a pointer argument, add an i64 type next + argTypes.push_back(Type::getInt64Ty(KernelF->getContext())); } } @@ -1403,7 +1466,7 @@ void GenVISC::genKernel(Function* KernelF, CallInst* CI, StructType* RetTy) { PointerType* PTy = PointerType::get(FTy, cast<PointerType>(KernelF->getType())->getAddressSpace()); // Change the function type - KernelF->mutateType(PTy); + KernelF = cloneFunction(KernelF, FTy, true); DEBUG(errs() << *KernelF << "\n"); // Replace ret void instruction with ret %RetTy undef @@ -1540,7 +1603,7 @@ static inline ConstantInt* getTimerID(Module& M, enum visc_TimerID timer) { return ConstantInt::get(Type::getInt32Ty(M.getContext()), timer); } -static void transformReturnTypeToStruct(Function* F) { +static Function* transformReturnTypeToStruct(Function* F) { // Currently only works for void return types DEBUG(errs() << "Transforming return type of function to Struct: " << F->getName() << "\n"); if(!F->getReturnType()->isVoidTy()) { @@ -1556,11 +1619,11 @@ static void transformReturnTypeToStruct(Function* F) { StructType* RetTy = StructType::create(F->getContext(), None, "emptyStruct", true); FunctionType* FTy = FunctionType::get(RetTy, ArgTypes, F->isVarArg()); - PointerType* PTy = FTy->getPointerTo(); - F->mutateType(PTy); + + SmallVector<ReturnInst*, 8> Returns; + Function* newF = cloneFunction(F, FTy, false, Returns); // Replace ret void instruction with ret %RetTy undef - for(auto& BB: F->getBasicBlockList()) { - if(ReturnInst* RI = dyn_cast<ReturnInst>(BB.getTerminator())) { + for(auto RI: Returns) { DEBUG(errs() << "Found return inst: "<< *RI << "\n"); ReturnInst* newRI = ReturnInst::Create(F->getContext(), UndefValue::get(RetTy)); ReplaceInstWithInst(RI, newRI);