ocelot/ocelot/transforms/implementation/SubkernelFormationPass.cpp
void SubkernelFormationPass::ExtractKernelsPass::runOnKernel(ir::IRKernel& k)
{
	typedef std::vector<ir::ControlFlowGraph::iterator> BlockQueue;
	
	report(" Splitting kernel '" << k.name << "' into sub-kernel regions.");
	report("  - expected region size: " << _expectedRegionSize);
	
	BlockQueue queue;
	KernelVector splitKernels;
	BlockSet region;
	BlockSet encountered;
	BlockSet alreadyAdded;
	BlockSet inEdges;
	BlockSet savedBlocks;
	IdToSubkernelMap idToKernelMap;

	unsigned int currentRegionSize = 0;
	unsigned int kernelId = 0;
	unsigned int spillRegionSize = 0;
		
	std::string originalName = k.name;
	
	ir::PTXKernel& ptx = static_cast<ir::PTXKernel&>(k);

	analysis::DataflowGraph::IteratorMap cfgToDfgMap = _dfg().getCFGtoDFGMap();
	
	// This is the new kernel entry point
	splitKernels.push_back(new ir::PTXKernel(k.name, false, k.module));

	ir::PTXKernel* newKernel = splitKernels.back();

	report(" New kernel name is " << newKernel->name);

	// Start at the entry block	
	ir::ControlFlowGraph::iterator entry = ptx.cfg()->get_entry_block();
	queue.push_back(entry);
	
	while(true)
	{
		// The front of the queue becomes part of the region
		ir::ControlFlowGraph::iterator block = queue.back();
		queue.pop_back();

		// Remove this block from the entering list (if it exists)
		inEdges.erase(block);
		
		// Keep track of all blocks entering the region
		for(ir::ControlFlowGraph::const_edge_pointer_iterator 
			edge = block->in_edges.begin(); 
			edge != block->in_edges.end(); ++edge)
		{
			// skip the entry block
			if((*edge)->head == ptx.cfg()->get_entry_block()) continue;

			// skip the current block
			if((*edge)->head == block) continue;

			// skip blocks in the region
			if(region.count((*edge)->head)) continue;
			
			inEdges.insert((*edge)->head);
		}
		
		// Edges leaving the region become candidates for the next subkernel
		for(ir::ControlFlowGraph::const_edge_pointer_iterator 
			edge = block->out_edges.begin(); 
			edge != block->out_edges.end(); ++edge)
		{
			ir::ControlFlowGraph::iterator tail = (*edge)->tail;

			// skip the exit block
			if(tail == ptx.cfg()->get_exit_block()) continue;
			
			// skip blocks that have already been added
			if(alreadyAdded.count(tail) != 0) continue;
			
			// skip already encountered blocks
			if(!encountered.insert(tail).second) continue;
			
			// push successor blocks
			report("  Queuing up sucessor of block " 
				<< block->id << ", block " << tail->id);
			queue.push_back(tail);
		}

		// Add the block to the new kernel (skip the entry)
		if(block == entry) continue;

		currentRegionSize += block->instructions.size();
		region.insert(block);
		report("  Adding block with id " << block->id 
			<< " to kernel " << newKernel->name);
		idToKernelMap.insert(std::make_pair(block->id,
			KernelAndId(kernelId, newKernel)));
		
		// create a new region if there are enough blocks
		if(currentRegionSize < _expectedRegionSize && !queue.empty()) continue;
		
		entry = createRegion(*newKernel, spillRegionSize, ptx, region,
			inEdges, entry, cfgToDfgMap, alreadyAdded, savedBlocks, _dfg());
		alreadyAdded.insert(region.begin(), region.end());
		
		createScheduler(*newKernel, ptx, savedBlocks, _dfg());

		// restart with a new kernel if there are any blocks left
		if(entry == ptx.cfg()->get_exit_block()) break;
	
		std::stringstream name;
		name << originalName << "_split_" << kernelId++;

		splitKernels.push_back(new ir::PTXKernel(name.str(), true, k.module));
		encountered.clear();
		inEdges.clear();
		region.clear();
		queue.clear();
		savedBlocks.clear();
		queue.push_back(entry);
		currentRegionSize = 0;
		
		newKernel = splitKernels.back();
		report(" New kernel name is " << newKernel->name);
	}

	// Add variables
	for(KernelVector::iterator kernel = splitKernels.begin();
		kernel != splitKernels.end(); ++kernel)
	{
		addVariables(**kernel, k, spillRegionSize, splitKernels.size() > 1);
	}
	
	// Rename 
	updateTailCallTargets(splitKernels, idToKernelMap);

	kernels.insert(std::make_pair(splitKernels.front(),
		std::move(splitKernels)));
}
/* algorithm
    1) start at a kernel entry point that dominates all remaining blocks
    2) create a strongly connected subgraph with N instructions and no barriers
      a) This is a new kernel
    3) For all edges leaving the graph
      a) save all live registers
      b) save the target block's id
      c) create a new scheduler block includes an indirect branch to each 
         of the targets
      d) redirect each edge to the kernel exit point
      e) create a new kernel rooted in the new scheduler block, goto 1
*/
algorithm
1) start at a kernel entry point that dominates all remaining blocks
2) create a strongly connected subgraph with N instructions and no barriers
a) This is a new kernel
3) For all edges leaving the graph
a) save all live registers
b) save the target block's id
c) create a new scheduler block includes an indirect branch to each
of the targets
d) redirect each edge to the kernel exit point
e) create a new kernel rooted in the new scheduler block, goto 1
algorithm 1 ) start at a kernel entry point that dominates all remaining blocks 2 ) create a strongly connected subgraph with N instructions and no barriers a ) This is a new kernel 3 ) For all edges leaving the graph a ) save all live registers b ) save the target block ' s id c ) create a new scheduler block includes an indirect branch to each of the targets d ) redirect each edge to the kernel exit point e ) create a new kernel rooted in the new scheduler block goto 1
void SubkernelFormationPass::ExtractKernelsPass::runOnKernel(ir::IRKernel& k)
{
	typedef std::vector<ir::ControlFlowGraph::iterator> BlockQueue;
	report(" Splitting kernel '" << k.name << "' into sub-kernel regions.");
	report("  - expected region size: " << _expectedRegionSize);
	BlockQueue queue;
	KernelVector splitKernels;
	BlockSet region;
	BlockSet encountered;
	BlockSet alreadyAdded;
	BlockSet inEdges;
	BlockSet savedBlocks;
	IdToSubkernelMap idToKernelMap;
	unsigned int currentRegionSize = 0;
	unsigned int kernelId = 0;
	unsigned int spillRegionSize = 0;
	std::string originalName = k.name;
	ir::PTXKernel& ptx = static_cast<ir::PTXKernel&>(k);
	analysis::DataflowGraph::IteratorMap cfgToDfgMap = _dfg().getCFGtoDFGMap();
	splitKernels.push_back(new ir::PTXKernel(k.name, false, k.module));
	ir::PTXKernel* newKernel = splitKernels.back();
	report(" New kernel name is " << newKernel->name);
	ir::ControlFlowGraph::iterator entry = ptx.cfg()->get_entry_block();
	queue.push_back(entry);
	while(true)
	{
		ir::ControlFlowGraph::iterator block = queue.back();
		queue.pop_back();
		inEdges.erase(block);
		for(ir::ControlFlowGraph::const_edge_pointer_iterator 
			edge = block->in_edges.begin(); 
			edge != block->in_edges.end(); ++edge)
		{
			if((*edge)->head == ptx.cfg()->get_entry_block()) continue;
			if((*edge)->head == block) continue;
			if(region.count((*edge)->head)) continue;
			inEdges.insert((*edge)->head);
		}
		for(ir::ControlFlowGraph::const_edge_pointer_iterator 
			edge = block->out_edges.begin(); 
			edge != block->out_edges.end(); ++edge)
		{
			ir::ControlFlowGraph::iterator tail = (*edge)->tail;
			if(tail == ptx.cfg()->get_exit_block()) continue;
			if(alreadyAdded.count(tail) != 0) continue;
			if(!encountered.insert(tail).second) continue;
			report("  Queuing up sucessor of block " 
				<< block->id << ", block " << tail->id);
			queue.push_back(tail);
		}
		if(block == entry) continue;
		currentRegionSize += block->instructions.size();
		region.insert(block);
		report("  Adding block with id " << block->id 
			<< " to kernel " << newKernel->name);
		idToKernelMap.insert(std::make_pair(block->id,
			KernelAndId(kernelId, newKernel)));
		if(currentRegionSize < _expectedRegionSize && !queue.empty()) continue;
		entry = createRegion(*newKernel, spillRegionSize, ptx, region,
			inEdges, entry, cfgToDfgMap, alreadyAdded, savedBlocks, _dfg());
		alreadyAdded.insert(region.begin(), region.end());
		createScheduler(*newKernel, ptx, savedBlocks, _dfg());
		if(entry == ptx.cfg()->get_exit_block()) break;
		std::stringstream name;
		name << originalName << "_split_" << kernelId++;
		splitKernels.push_back(new ir::PTXKernel(name.str(), true, k.module));
		encountered.clear();
		inEdges.clear();
		region.clear();
		queue.clear();
		savedBlocks.clear();
		queue.push_back(entry);
		currentRegionSize = 0;
		newKernel = splitKernels.back();
		report(" New kernel name is " << newKernel->name);
	}
	for(KernelVector::iterator kernel = splitKernels.begin();
		kernel != splitKernels.end(); ++kernel)
	{
		addVariables(**kernel, k, spillRegionSize, splitKernels.size() > 1);
	}
	updateTailCallTargets(splitKernels, idToKernelMap);
	kernels.insert(std::make_pair(splitKernels.front(),
		std::move(splitKernels)));
}
void SubkernelFormationPass :: ExtractKernelsPass :: runOnKernel ( ir :: IRKernel & k ) { typedef std :: vector < ir :: ControlFlowGraph :: iterator > BlockQueue ; report ( " " << k . name << " " ) ; report ( " " << _expectedRegionSize ) ; BlockQueue queue ; KernelVector splitKernels ; BlockSet region ; BlockSet encountered ; BlockSet alreadyAdded ; BlockSet inEdges ; BlockSet savedBlocks ; IdToSubkernelMap idToKernelMap ; unsigned int currentRegionSize = 0 ; unsigned int kernelId = 0 ; unsigned int spillRegionSize = 0 ; std :: string originalName = k . name ; ir :: PTXKernel & ptx = static_cast < ir :: PTXKernel & > ( k ) ; analysis :: DataflowGraph :: IteratorMap cfgToDfgMap = _dfg ( ) . getCFGtoDFGMap ( ) ; splitKernels . push_back ( new ir :: PTXKernel ( k . name , false , k . module ) ) ; ir :: PTXKernel * newKernel = splitKernels . back ( ) ; report ( " " << newKernel -> name ) ; ir :: ControlFlowGraph :: iterator entry = ptx . cfg ( ) -> get_entry_block ( ) ; queue . push_back ( entry ) ; while ( true ) { ir :: ControlFlowGraph :: iterator block = queue . back ( ) ; queue . pop_back ( ) ; inEdges . erase ( block ) ; for ( ir :: ControlFlowGraph :: const_edge_pointer_iterator edge = block -> in_edges . begin ( ) ; edge != block -> in_edges . end ( ) ; ++ edge ) { if ( ( * edge ) -> head == ptx . cfg ( ) -> get_entry_block ( ) ) continue ; if ( ( * edge ) -> head == block ) continue ; if ( region . count ( ( * edge ) -> head ) ) continue ; inEdges . insert ( ( * edge ) -> head ) ; } for ( ir :: ControlFlowGraph :: const_edge_pointer_iterator edge = block -> out_edges . begin ( ) ; edge != block -> out_edges . end ( ) ; ++ edge ) { ir :: ControlFlowGraph :: iterator tail = ( * edge ) -> tail ; if ( tail == ptx . cfg ( ) -> get_exit_block ( ) ) continue ; if ( alreadyAdded . count ( tail ) != 0 ) continue ; if ( ! encountered . insert ( tail ) . second ) continue ; report ( " " << block -> id << " " << tail -> id ) ; queue . push_back ( tail ) ; } if ( block == entry ) continue ; currentRegionSize += block -> instructions . size ( ) ; region . insert ( block ) ; report ( " " << block -> id << " " << newKernel -> name ) ; idToKernelMap . insert ( std :: make_pair ( block -> id , KernelAndId ( kernelId , newKernel ) ) ) ; if ( currentRegionSize < _expectedRegionSize && ! queue . empty ( ) ) continue ; entry = createRegion ( * newKernel , spillRegionSize , ptx , region , inEdges , entry , cfgToDfgMap , alreadyAdded , savedBlocks , _dfg ( ) ) ; alreadyAdded . insert ( region . begin ( ) , region . end ( ) ) ; createScheduler ( * newKernel , ptx , savedBlocks , _dfg ( ) ) ; if ( entry == ptx . cfg ( ) -> get_exit_block ( ) ) break ; std :: stringstream name ; name << originalName << " " << kernelId ++ ; splitKernels . push_back ( new ir :: PTXKernel ( name . str ( ) , true , k . module ) ) ; encountered . clear ( ) ; inEdges . clear ( ) ; region . clear ( ) ; queue . clear ( ) ; savedBlocks . clear ( ) ; queue . push_back ( entry ) ; currentRegionSize = 0 ; newKernel = splitKernels . back ( ) ; report ( " " << newKernel -> name ) ; } for ( KernelVector :: iterator kernel = splitKernels . begin ( ) ; kernel != splitKernels . end ( ) ; ++ kernel ) { addVariables ( * * kernel , k , spillRegionSize , splitKernels . size ( ) > 1 ) ; } updateTailCallTargets ( splitKernels , idToKernelMap ) ; kernels . insert ( std :: make_pair ( splitKernels . front ( ) , std :: move ( splitKernels ) ) ) ; }
algorithm
1) start at a kernel entry point that dominates all remaining blocks
2) create a strongly connected subgraph with N instructions and no barriers
a) This is a new kernel
3) For all edges leaving the graph
a) save all live registers
b) save the target block's id
c) create a new scheduler block includes an indirect branch to each
of the targets
d) redirect each edge to the kernel exit point
e) create a new kernel rooted in the new scheduler block, goto 1
algorithm 1 ) start at a kernel entry point that dominates all remaining blocks 2 ) create a strongly connected subgraph with N instructions and no barriers a ) This is a new kernel 3 ) For all edges leaving the graph a ) save all live registers b ) save the target block ' s id c ) create a new scheduler block includes an indirect branch to each of the targets d ) redirect each edge to the kernel exit point e ) create a new kernel rooted in the new scheduler block goto 1
// This is the new kernel entry point // Start at the entry block	 // The front of the queue becomes part of the region // Remove this block from the entering list (if it exists) // Keep track of all blocks entering the region // skip the entry block // skip the current block // skip blocks in the region // Edges leaving the region become candidates for the next subkernel // skip the exit block // skip blocks that have already been added // skip already encountered blocks // push successor blocks // Add the block to the new kernel (skip the entry) // create a new region if there are enough blocks // restart with a new kernel if there are any blocks left // Add variables // Rename 