static bool canRemoveAliveOut(analysis::DataflowGraph& dfg,
	iterator block, const Register& aliveOut)
{
	for(BlockPointerSet::iterator successor = block->targets().begin();
		successor != block->targets().end(); ++successor)
	{
		for(RegisterSet::iterator aliveIn = (*successor)->aliveIn().begin();
			aliveIn != (*successor)->aliveIn().end(); ++aliveIn)
		{
			// A target successor uses the value
			if(aliveIn->id == aliveOut.id) return false;
		}
	}
	
	if(block->fallthrough() != dfg.end())
	{
		iterator successor = block->fallthrough();
		for(RegisterSet::iterator aliveIn = successor->aliveIn().begin();
			aliveIn != successor->aliveIn().end(); ++aliveIn)
		{
			// A fallthrough successor uses the value
			if(aliveIn->id == aliveOut.id) return false;
		}
	}
	
	// No successors use the value
	return true;
}
static void eliminateRedundantInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block)
{
	typedef std::vector<unsigned int> KillList;
	
	KillList killList;
	
	report("  Propagating constants through instructions in BB_" << block->id());
	unsigned int index = 0;
	for(auto instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		if(!propagateValueToSuccessors(dfg, blocks, instruction))
		{
			++index;
			continue;
		}
		
		if(canRemoveInstruction(block, instruction))
		{
			report("    value is not used, removed it.");
			killList.push_back(index);
			
			// schedule the block for more work
			// TODO: do this when we consider values in multiple blocks
		}
		else
		{
			++index;
		}
	}
	
	for(KillList::iterator killed = killList.begin();
		killed != killList.end(); ++killed)
	{
		dfg.erase(block, *killed);
	}
}
static void eliminateDeadInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block)
{
	typedef analysis::DataflowGraph::Block                Block;
	typedef analysis::DataflowGraph::RegisterSet   RegisterSet;
	typedef std::vector<unsigned int>                     KillList;
	typedef std::vector<PhiInstructionVector::iterator>   PhiKillList;
	typedef std::vector<RegisterSet::iterator>            AliveKillList;
	
	report(" Eliminating dead instructions from BB_" << block->id());
	
	report("  Removing dead alive out values");
	AliveKillList aliveOutKillList;
	for(RegisterSet::iterator aliveOut = block->aliveOut().begin();
		aliveOut != block->aliveOut().end(); ++aliveOut)
	{
		if(canRemoveAliveOut(dfg, block, *aliveOut))
		{
			report("   removed " << aliveOut->id);
			aliveOutKillList.push_back(aliveOut);
		}
	}
	
	for(AliveKillList::iterator killed = aliveOutKillList.begin();
		killed != aliveOutKillList.end(); ++killed)
	{
		block->aliveOut().erase(*killed);
	}
	
	KillList killList;
	
	report("  Removing dead instructions");
	unsigned int index = 0;
	for(InstructionVector::iterator instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		if(canRemoveInstruction(block, instruction))
		{
			report("   removed '" << instruction->i->toString() << "'");
			killList.push_back(index);
			
			// schedule the block for more work
			report("    scheduled this block again");
			blocks.insert(block);
		}
		else
		{
			++index;
		}
	}
	
	for(KillList::iterator killed = killList.begin();
		killed != killList.end(); ++killed)
	{
		dfg.erase(block, *killed);
	}
	
	PhiKillList phiKillList;
	
	report("  Removing dead phi instructions");
	for(PhiInstructionVector::iterator phi = block->phis().begin();
		phi != block->phis().end(); ++phi)
	{
		if(canRemovePhi(block, *phi))
		{
			report("   removed " << phi->d.id);
			phiKillList.push_back(phi);
		}
	}
	
	report("  Removing dead alive in values");
	AliveKillList aliveInKillList;
	for(RegisterSet::iterator aliveIn = block->aliveIn().begin();
		aliveIn != block->aliveIn().end(); ++aliveIn)
	{
		if(canRemoveAliveIn(block, *aliveIn))
		{
			report("   removed " << aliveIn->id);
			aliveInKillList.push_back(aliveIn);
			
			// schedule the predecessors for more work
			for(BlockPointerSet::iterator predecessor =
				block->predecessors().begin();
				predecessor != block->predecessors().end(); ++predecessor)
			{
				report("    scheduled predecessor BB_" << (*predecessor)->id());
				blocks.insert(*predecessor);
			}
		}
	}
	
	for(AliveKillList::iterator killed = aliveInKillList.begin();
		killed != aliveInKillList.end(); ++killed)
	{
		block->aliveIn().erase(*killed);
	}
}
	bool TestDataflowGraph::_verify( const analysis::DataflowGraph& graph )
	{
		for( analysis::DataflowGraph::const_iterator block = graph.begin(); 
			block != graph.end(); ++block )
		{
			analysis::DataflowGraph::Block::RegisterSet defined;
			
			report( " Alive in registers:" );
			for( analysis::DataflowGraph::Block::RegisterSet::const_iterator 
				reg = block->aliveIn().begin(); 
				reg != block->aliveIn().end(); ++reg )
			{
				report( "  " << reg->id );
				defined.insert( *reg );
			}
				
			if( !block->phis().empty() )
			{
				status << "  Block " << block->label() 
					<< " has " << block->phis().size() 
					<< " phi instructions." << std::endl;
				return false;			
			}
			
			for( analysis::DataflowGraph::InstructionVector::const_iterator 
				instruction = block->instructions().begin(); 
				instruction != block->instructions().end(); ++instruction )
			{
				report( " " << instruction->label << ":  " 
					<< hydrazine::toFormattedString( instruction->d.begin(), 
					instruction->d.end(), Double() ) << " <- " 
					<< hydrazine::toFormattedString( instruction->s.begin(), 
					instruction->s.end(), Double() ) );
					
				analysis::DataflowGraph::RegisterPointerVector::const_iterator
					reg = instruction->s.begin();
				for( ; reg != instruction->s.end(); ++reg )
				{
					if( !defined.count( *reg ) )
					{
						status << "  Register " << *reg->pointer 
							<< " in instruction " << instruction->label 
							<< " in block " << block->label() 
							<< " used uninitialized." << std::endl;
						return false;
					}
				}
				
				reg = instruction->d.begin();
					
				for( ; reg != instruction->d.end(); ++reg )
				{
					defined.insert( *reg );
				}
			}
			
			for( analysis::DataflowGraph::Block::RegisterSet::const_iterator 
				reg = block->aliveOut().begin(); 
				reg != block->aliveOut().end(); ++reg )
			{
				if( !defined.count( *reg ) )
				{
					status << "  Register " << reg->id 
						<< " out set of block " << block->label() 
						<< " used uninitialized." << std::endl;
					return false;
				}
			}			
		}
		return true;
	}
	bool TestDataflowGraph::_verifyIdentities( analysis::DataflowGraph& graph )
	{
		analysis::DataflowGraph::Block::RegisterSet global;
		analysis::InstructionConverter converter;

		analysis::DataflowGraph::iterator block1 = graph.begin();
		for( ; block1 != graph.end(); ++block1 ) {
			analysis::DataflowGraph::iterator block2 = graph.begin();
			for( ; block2 != graph.end(); ++block2 ) {

				if (block1 != block2) {
					analysis::DataflowGraph::InstructionVector::const_iterator inst1 = block1->instructions().begin();
					analysis::DataflowGraph::InstructionVector::const_iterator inst2 = block2->instructions().begin();

					while((inst1 != block1->instructions().end()) && (inst2 != block2->instructions().end())) {
						ir::PTXInstruction* ptxInst1 = static_cast< ir::PTXInstruction* >(inst1->i);
						ir::PTXInstruction* ptxInst2 = static_cast< ir::PTXInstruction* >(inst2->i);

						std::cout << ptxInst1->toString() << ": "
								<< hydrazine::toFormattedString( inst1->d.begin(), inst1->d.end(), Double() )
								<< " <- "
								<< hydrazine::toFormattedString( inst1->s.begin(), inst1->s.end(), Double() )
								<< "	|	";

						std::cout << ptxInst2->toString() << ": "
								<< hydrazine::toFormattedString( inst2->d.begin(), inst2->d.end(), Double() )
								<< " <- "
								<< hydrazine::toFormattedString( inst2->s.begin(), inst2->s.end(), Double() )
								<< std::endl;

						// try to match inst1 and inst2
						analysis::DataflowGraph::Instruction matchedInst1;
						analysis::DataflowGraph::Instruction matchedInst2;
						bool matched = converter.normalize(matchedInst1, matchedInst2, *inst1, *inst2);

						if (matched) {
							ir::PTXInstruction* matchedPtx1 = static_cast< ir::PTXInstruction* >(matchedInst1.i);
							ir::PTXInstruction* matchedPtx2 = static_cast< ir::PTXInstruction* >(matchedInst2.i);

							std::cout << "matched:" << std::endl;
							std::cout << matchedPtx1->toString() << ": "
									<< hydrazine::toFormattedString( matchedInst1.d.begin(), matchedInst1.d.end(), Double() )
									<< " <- "
									<< hydrazine::toFormattedString( matchedInst1.s.begin(), matchedInst1.s.end(), Double() )
									<< "	|	";

							std::cout << matchedPtx2->toString() << ": "
									<< hydrazine::toFormattedString( matchedInst2.d.begin(), matchedInst2.d.end(), Double() )
									<< " <- "
									<< hydrazine::toFormattedString( matchedInst2.s.begin(), matchedInst2.s.end(), Double() )
									<< std::endl;
						}

						std::cout << "-----------" << std::endl;

						++inst1;
						++inst2;
					} // while
				} // if

			} // for
		} // for

		return true;
	}
	bool TestDataflowGraph::_verifySsa( const analysis::DataflowGraph& graph )
	{
		analysis::DataflowGraph::Block::RegisterSet global;
		for( analysis::DataflowGraph::const_iterator block = graph.begin(); 
			block != graph.end(); ++block )
		{
			analysis::DataflowGraph::Block::RegisterSet defined;
			
			report( block->label() );
			report( " Alive in registers:" );
			for( analysis::DataflowGraph::Block::RegisterSet::const_iterator 
				reg = block->aliveIn().begin(); 
				reg != block->aliveIn().end(); ++reg )
			{
				report( "  " << reg->id );
				defined.insert( *reg );
			}
			
			for( analysis::DataflowGraph::PhiInstructionVector::const_iterator 
				phi = block->phis().begin(); 
				phi != block->phis().end(); ++phi )
			{
				report( " phi " << phi->d.id << " <- " 
					<< hydrazine::toFormattedString( phi->s.begin(), 
						phi->s.end(), ToId() ) );
				for( analysis::DataflowGraph::RegisterVector::const_iterator
					reg = phi->s.begin(); reg != phi->s.end(); ++reg )
				{
					if( !defined.count( *reg ) )
					{
						status << "  Register " << reg->id
							<< " in phi instruction " 
							<< std::distance( block->phis().begin(), phi )
							<< " in " << block->label() 
							<< " used uninitialized." << std::endl;
						return false;
					}
				}
				defined.insert( phi->d );
				if( !global.insert( phi->d ).second )
				{
					status << "  In " << block->label() 
						<< ", instruction phi " 
						<< std::distance( block->phis().begin(), phi )
						<< ", reg " << phi->d.id
						<< " already defined globally." << std::endl;
					return false;
				}
			}
			
			for( analysis::DataflowGraph::InstructionVector::const_iterator 
				instruction = block->instructions().begin(); 
				instruction != block->instructions().end(); ++instruction )
			{
				report( " " << instruction->label << ":  " 
					<< hydrazine::toFormattedString( instruction->d.begin(), 
					instruction->d.end(), Double() ) << " <- " 
					<< hydrazine::toFormattedString( instruction->s.begin(), 
					instruction->s.end(), Double() ) );
					
				analysis::DataflowGraph::RegisterPointerVector::const_iterator
					reg = instruction->s.begin();
				for( ; reg != instruction->s.end(); ++reg )
				{
					if( !defined.count( *reg ) )
					{
						status << "  Register " << *reg->pointer 
							<< " in instruction " << instruction->label 
							<< " in " << block->label() 
							<< " used uninitialized." << std::endl;
						return false;
					}
				}
				
				for( reg = instruction->d.begin(); 
					reg != instruction->d.end(); ++reg )
				{
					defined.insert( *reg );
					if( !global.insert( *reg ).second )
					{
						status << "  In " << block->label() 
							<< ", instruction " 
							<< instruction->label << ", reg " << *reg->pointer
							<< " already defined globally." << std::endl;
						return false;
					}
				}
			}
			
			for( analysis::DataflowGraph::Block::RegisterSet::const_iterator 
				reg = block->aliveOut().begin(); 
				reg != block->aliveOut().end(); ++reg )
			{
				if( !defined.count( *reg ) )
				{
					status << "  Register " << reg->id 
						<< " out set of block " << block->label() 
						<< " used uninitialized." << std::endl;
					return false;
				}
			}			
		}
		return true;
	}