示例#1
0
void DuettoNativeRewriter::rewriteConstructorImplementation(Module& M, Function& F)
{
	//Copy the code in a function with the right signature
	Function* newFunc=getReturningConstructor(M, &F);
	if(!newFunc->empty())
		return;

	//Visit each instruction and take note of the ones that needs to be replaced
	Function::const_iterator B=F.begin();
	Function::const_iterator BE=F.end();
	ValueToValueMapTy valueMap;
	CallInst* lowerConstructor = NULL;
	const CallInst* oldLowerConstructor = NULL;
	for(;B!=BE;++B)
	{
		BasicBlock::const_iterator I=B->begin();
		BasicBlock::const_iterator IE=B->end();
		for(;I!=IE;++I)
		{
			if(I->getOpcode()!=Instruction::Call)
				continue;
			const CallInst* callInst=cast<CallInst>(&(*I));
			Function* f=callInst->getCalledFunction();
			if(!f)
				continue;
			const char* startOfType;
			const char* endOfType;
			if(!DuettoNativeRewriter::isBuiltinConstructor(f->getName().data(), startOfType, endOfType))
				continue;
			//Check that the constructor is for 'this'
			if(callInst->getOperand(0)!=F.arg_begin())
				continue;
			//If this is another constructor for the same type, change it to a
			//returning constructor and use it as the 'this' argument
			Function* newFunc = getReturningConstructor(M, f);
			llvm::SmallVector<Value*, 4> newArgs;
			for(unsigned i=1;i<callInst->getNumArgOperands();i++)
				newArgs.push_back(callInst->getArgOperand(i));
			lowerConstructor = CallInst::Create(newFunc, newArgs);
			oldLowerConstructor = callInst;
			break;
		}
		if(lowerConstructor)
			break;
	}

	//Clone the linkage first
	newFunc->setLinkage(F.getLinkage());
	Function::arg_iterator origArg=++F.arg_begin();
	Function::arg_iterator newArg=newFunc->arg_begin();
	valueMap.insert(make_pair(F.arg_begin(), lowerConstructor));

	for(unsigned i=1;i<F.arg_size();i++)
	{
		valueMap.insert(make_pair(&(*origArg), &(*newArg)));
		++origArg;
		++newArg;
	}
	SmallVector<ReturnInst*, 4> returns;
	CloneFunctionInto(newFunc, &F, valueMap, false, returns);

	//Find the right place to add the base construtor call
	assert(lowerConstructor->getNumArgOperands()<=1 && "Native constructors with multiple args are not supported");
	Instruction* callPred = NULL;
	if (lowerConstructor->getNumArgOperands()==1 && Instruction::classof(lowerConstructor->getArgOperand(0)))
	{
		//Switch the argument to the one in the new func
		lowerConstructor->setArgOperand(0, valueMap[lowerConstructor->getArgOperand(0)]);
		callPred = cast<Instruction>(lowerConstructor->getArgOperand(0));
	}
	else
		callPred = &newFunc->getEntryBlock().front();

	//Add add it
	lowerConstructor->insertAfter(callPred);

	//Override the returs values
	for(unsigned i=0;i<returns.size();i++)
	{
		Instruction* newInst = ReturnInst::Create(M.getContext(),lowerConstructor);
		newInst->insertBefore(returns[i]);
		returns[i]->removeFromParent();
	}
	//Recursively move all the users of the lower constructor after the call itself
	Instruction* insertPoint = lowerConstructor->getNextNode();
	SmallVector<Value*, 4> usersQueue(lowerConstructor->getNumUses());
	unsigned int i;
	Value::use_iterator it;
	for(i=usersQueue.size()-1,it=lowerConstructor->use_begin();it!=lowerConstructor->use_end();++it,i--)
		usersQueue[i]=it->getUser();

	SmallSet<Instruction*, 4> movedInstructions;
	while(!usersQueue.empty())
	{
		Instruction* cur=dyn_cast<Instruction>(usersQueue.pop_back_val());
		if(!cur)
			continue;
		if(movedInstructions.count(cur))
			continue;
		movedInstructions.insert(cur);
		cur->moveBefore(insertPoint);
		//Add users of this instrucution as well
		usersQueue.resize(usersQueue.size()+cur->getNumUses());
		for(i=usersQueue.size()-1,it=cur->use_begin();it!=cur->use_end();++it,i--)
			usersQueue[i]=it->getUser();
	}
	cast<Instruction>(valueMap[oldLowerConstructor])->eraseFromParent();
}
示例#2
0
// Replace "packW" and "unpackW" intrinsics by insert/extract operations and
// update the uses accordingly.
void
FunctionVectorizer::generatePackUnpackCode(Function*      f,
                                           const WFVInfo& info)
{
    assert (f);

    SmallVector<CallInst*, 16> eraseVec;

    for (auto &BB : *f)
    {
        Instruction* allocPos = BB.getFirstInsertionPt();
        for (auto &I : BB)
        {
            Instruction* inst = &I;

            if (isUnpackWFunctionCall(inst))
            {
                DEBUG_WFV( outs() << "generateUnpackCode(" << *inst << " )\n"; );

                CallInst* unpackCall = cast<CallInst>(inst);

                Value* value    = unpackCall->getArgOperand(0);
                Value* indexVal = unpackCall->getArgOperand(1);

                // Extract scalar values.
                Value* extract = generateHorizontalExtract(value,
                                                           indexVal,
                                                           unpackCall->getName(),
                                                           allocPos,
                                                           unpackCall,
                                                           info);

                // If the type only matches structurally, create an additional bitcast.
                Type* oldType = unpackCall->getType();
                Type* newType = extract->getType();
                if (oldType != newType)
                {
                    assert (newType->canLosslesslyBitCastTo(oldType) || WFV::typesMatch(oldType, newType));
                    Instruction* bc = new BitCastInst(extract, oldType, "", unpackCall);

                    // Copy properties from unpackCall.
                    WFV::copyMetadata(bc, *unpackCall);
                    extract = bc;
                }

                // Rewire the use.
                assert (unpackCall->getNumUses() == 1);
                Value* use = *unpackCall->use_begin();
                assert (isa<Instruction>(use));
                Instruction* scalarUse = cast<Instruction>(use);

                scalarUse->replaceUsesOfWith(unpackCall, extract);

                // Erase now unused unpack call.
                eraseVec.push_back(unpackCall);

                // If the returned extract operation is an alloca, we have to
                // make sure that all changes to that memory location are
                // correctly written back to the original memory from which
                // the sub-element was extracted.
                // This means we have to insert merge and store operations
                // after every use of this value (including "forwarded" uses
                // via casts, phis, and GEPs).
                // However, we must only merge back those values that were
                // modified. This is not only for efficiency, but also for
                // correctness, since there may be uninitialized pointers in
                // a structure, which we must not load/store from/to (see
                // test_struct_extra05 with all analyses disabled).
                if (isa<AllocaInst>(extract) ||
                    (isa<BitCastInst>(extract) &&
                     isa<AllocaInst>(cast<BitCastInst>(extract)->getOperand(0))))
                {
                    generateWriteBackOperations(cast<Instruction>(extract),
                                                cast<Instruction>(extract),
                                                value,
                                                indexVal,
                                                info);
                }
            }
            else if (isPackWFunctionCall(inst))
            {
                DEBUG_WFV( outs() << "generatePackCode(" << *inst << " )\n"; );

                CallInst* packCall = cast<CallInst>(inst);

                assert (WFV::isVectorizedType(*packCall->getType()) &&
                        "packCall should have vector return type after inst vectorization!");

                SmallVector<Value*, 8> scalarVals(info.mVectorizationFactor);

                // Get scalar results for merge.
                for (unsigned i=0; i<info.mVectorizationFactor; ++i)
                {
                    scalarVals[i] = packCall->getArgOperand(i);
                }

                // Merge scalar results.
                Instruction* merge = generateHorizontalMerge(scalarVals,
                                                             packCall->getType(),
                                                             "",
                                                             packCall,
                                                             info);

                // Rewire the uses.
                packCall->replaceAllUsesWith(merge);

                // Copy properties from packCall.
                WFV::copyMetadata(merge, *packCall);

                // Erase now unused pack call.
                eraseVec.push_back(packCall);
            }