void DataDependenceAnalysis::analyze(ir::IRKernel& kernel)
{
	auto dfg = static_cast<DataflowGraph*>(
		getAnalysis("DataflowGraphAnalysis"));

	report("Running data dependence analysis on kernel " << kernel.name);
	
	for(auto block = dfg->begin(); block != dfg->end(); ++block)
	{
		analyzeBlock(block, dfg, _nodes, _instructionToNodes);
	}
}
Пример #2
0
void SCCP::analyze() {
    // Queue the first block to start iteration.
    cfgwork.push(ir->begin);
    while (!cfgwork.empty()) {
        while (!cfgwork.empty())
            analyzeBlock(cfgwork.pop());
        while (!ssawork.empty())
            analyzeSSA(ssawork.pop());
    }
    // TODO own cmdline flag? something less intrusive
    // if ((enable_verbose || enable_printir) && ir->size() > 1000)
    //  printCounts(ir, eval_counts);
}
Пример #3
0
bool AllocaMerging::runOnFunction(Function& F)
{
	cheerp::PointerAnalyzer & PA = getAnalysis<cheerp::PointerAnalyzer>();
	cheerp::Registerize & registerize = getAnalysis<cheerp::Registerize>();
	cheerp::TypeSupport types(*F.getParent());
	AllocaInfos allocaInfos;
	// Gather all the allocas
	for(BasicBlock& BB: F)
		analyzeBlock(registerize, BB, allocaInfos);
	if (allocaInfos.size() < 2)
		return false;
	bool Changed = false;
	BasicBlock& entryBlock=F.getEntryBlock();
	// Look if we can merge allocas of the same type
	for(auto targetCandidate=allocaInfos.begin();targetCandidate!=allocaInfos.end();++targetCandidate)
	{
		AllocaInst* targetAlloca = targetCandidate->first;
		Type* targetType = targetAlloca->getAllocatedType();
		// The range storing the sum of all ranges merged into target
		cheerp::Registerize::LiveRange targetRange(targetCandidate->second);
		// If the range is empty, we have an alloca that we can't analyze
		if (targetRange.empty())
			continue;
		std::vector<AllocaInfos::iterator> mergeSet;
		auto sourceCandidate=targetCandidate;
		++sourceCandidate;
		for(;sourceCandidate!=allocaInfos.end();++sourceCandidate)
		{
			AllocaInst* sourceAlloca = sourceCandidate->first;
			Type* sourceType = sourceAlloca->getAllocatedType();
			// Bail out for non compatible types
			if(!areTypesEquivalent(types, PA, targetType, sourceType))
				continue;
			const cheerp::Registerize::LiveRange& sourceRange = sourceCandidate->second;
			// Bail out if this source candidate is not analyzable
			if(sourceRange.empty())
				continue;
			// Bail out if the allocas interfere
			if(targetRange.doesInterfere(sourceRange))
				continue;
			// Add the range to the target range and the source alloca to the mergeSet
			mergeSet.push_back(sourceCandidate);
			PA.invalidate(sourceAlloca);
			targetRange.merge(sourceRange);
		}

		// If the merge set is empty try another target
		if(mergeSet.empty())
			continue;

		PA.invalidate(targetAlloca);

		if(!Changed)
			registerize.invalidateLiveRangeForAllocas(F);

		// Make sure that this alloca is in the entry block
		if(targetAlloca->getParent()!=&entryBlock)
			targetAlloca->moveBefore(entryBlock.begin());
		// We can merge the allocas
		for(const AllocaInfos::iterator& it: mergeSet)
		{
			AllocaInst* allocaToMerge = it->first;
			Instruction* targetVal=targetAlloca;
			if(targetVal->getType()!=allocaToMerge->getType())
			{
				targetVal=new BitCastInst(targetVal, allocaToMerge->getType());
				targetVal->insertAfter(targetAlloca);
			}
			allocaToMerge->replaceAllUsesWith(targetVal);
			allocaToMerge->eraseFromParent();
			if(targetVal != targetAlloca)
				PA.getPointerKind(targetVal);
			allocaInfos.erase(it);
			NumAllocaMerged++;
		}
		PA.getPointerKind(targetAlloca);
		Changed = true;
	}
	if(Changed)
		registerize.computeLiveRangeForAllocas(F);
	return Changed;
}
Пример #4
0
bool AllocaArraysMerging::runOnFunction(Function& F)
{
	class ArraysToMerge
	{
	private:
		std::map<AllocaInst*, uint32_t> arraysToMerge;
		uint32_t currentOffset;
	public:
		ArraysToMerge():currentOffset(0)
		{
		}
		bool empty() const
		{
			return arraysToMerge.empty();
		}
		std::map<AllocaInst*, uint32_t>::iterator begin()
		{
			return arraysToMerge.begin();
		}
		std::map<AllocaInst*, uint32_t>::iterator end()
		{
			return arraysToMerge.end();
		}
		void add(AllocaInst* a)
		{
			arraysToMerge.insert(std::make_pair(a, currentOffset));
			currentOffset+=cast<ArrayType>(a->getAllocatedType())->getNumElements();
		}
		uint32_t getNewSize() const
		{
			return currentOffset;
		}
	};

	cheerp::PointerAnalyzer & PA = getAnalysis<cheerp::PointerAnalyzer>();
	cheerp::Registerize & registerize = getAnalysis<cheerp::Registerize>();
	cheerp::GlobalDepsAnalyzer & GDA = getAnalysis<cheerp::GlobalDepsAnalyzer>();
	std::list<std::pair<AllocaInst*, cheerp::Registerize::LiveRange>> allocaInfos;
	// Gather all the allocas
	for(BasicBlock& BB: F)
		analyzeBlock(registerize, BB, allocaInfos);
	if (allocaInfos.size() < 2)
		return false;
	bool Changed = false;
	// We can also try to merge arrays of the same type, if only pointers to values are passed around
	while(!allocaInfos.empty())
	{
		// Build a map of array to be merged and their offseet into the new array
		ArraysToMerge arraysToMerge;
		auto targetCandidate = allocaInfos.begin();
		AllocaInst* targetAlloca = targetCandidate->first;
		if(!targetAlloca->getAllocatedType()->isArrayTy() ||
			// Check target uses
			!checkUsesForArrayMerging(targetAlloca))
		{
				allocaInfos.erase(targetCandidate);
				continue;
		}
		Type* targetElementType = targetAlloca->getAllocatedType()->getSequentialElementType();
		auto sourceCandidate=targetCandidate;
		++sourceCandidate;
		// Now that we have computed the sourceCandidate we can invalidate the targetCandidate
		allocaInfos.erase(targetCandidate);
		while(sourceCandidate!=allocaInfos.end())
		{
			AllocaInst* sourceAlloca = sourceCandidate->first;
			// Check that allocas are arrays of the same type
			if(!sourceAlloca->getAllocatedType()->isArrayTy())
			{
				++sourceCandidate;
				continue;
			}
			// Both are arrays, check the types
			if(targetElementType != sourceAlloca->getAllocatedType()->getSequentialElementType())
			{
				++sourceCandidate;
				continue;
			}
			// Verify that the source candidate has supported uses
			if(!checkUsesForArrayMerging(sourceAlloca))
			{
				++sourceCandidate;
				continue;
			}
			// We can merge the source and the target
			// If the set is empty add the target as well
			if(arraysToMerge.empty())
				arraysToMerge.add(targetAlloca);
			arraysToMerge.add(sourceAlloca);
			auto oldCandidate = sourceCandidate;
			++sourceCandidate;
			// Now that we have moved to the next candidate, we can invalidate the old one
			allocaInfos.erase(oldCandidate);
		}
		// If we have a non-empty set of alloca merge them
		if (arraysToMerge.empty())
			continue;

		if(!Changed)
			registerize.invalidateLiveRangeForAllocas(F);
		// Build new alloca
		Type* newAllocaType = ArrayType::get(targetElementType, arraysToMerge.getNewSize());
		// Add the new struct type to the GlobalDepsAnalyzer, it may need the createArray helper
		GDA.visitType(newAllocaType, /*forceTypedArray*/ false);
		AllocaInst* newAlloca = new AllocaInst(newAllocaType, "mergedArray", &(*F.getEntryBlock().begin()));
		Type* indexType = IntegerType::get(newAllocaType->getContext(), 32);
		// Change every use of every merged array with an appropiate GEP
		for(auto it: arraysToMerge)
		{
			AllocaInst* allocaToMerge = it.first;
			uint32_t baseOffset = it.second;
			SmallVector<User*, 4> users(allocaToMerge->users());
			for(User* u: users)
			{
				if(GetElementPtrInst* oldGep = dyn_cast<GetElementPtrInst>(u))
				{
					// Build 2 GEPs, one to reach the first element in the merged array
					// and the other for the rest of the offsets
					SmallVector<Value*, 4> indices;
					// Dereference array
					indices.push_back(ConstantInt::get(indexType, 0));
					// Reach offset
					indices.push_back(ConstantInt::get(indexType, baseOffset));
					Value* gep1 = GetElementPtrInst::Create(newAlloca, indices, "", oldGep);
					// Apply all the old offsets but the first one using a new GEP
					indices.clear();
					indices.insert(indices.begin(), oldGep->idx_begin()+1, oldGep->idx_end());
					Value* gep2 = GetElementPtrInst::Create(gep1, indices, "", oldGep);
					// Replace all uses with gep2
					oldGep->replaceAllUsesWith(gep2);
					PA.invalidate(oldGep);
					oldGep->eraseFromParent();
				}
				else if(BitCastInst* BI=dyn_cast<BitCastInst>(u))
				{
					//Only used for lifetime intrinsics
					Value* newBitCast=new BitCastInst(newAlloca, BI->getType(), "", BI);
					BI->replaceAllUsesWith(newBitCast);
					PA.invalidate(BI);
					BI->eraseFromParent();
				}
				else
					assert(false && "Unexpected use while merging arrays");
			}
			// Kill the alloca itself now
			PA.invalidate(allocaToMerge);
			allocaToMerge->eraseFromParent();
			Changed = true;
		}
	}
	if(Changed)
		registerize.computeLiveRangeForAllocas(F);
	return Changed;
}