mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +00:00 
			
		
		
		
	 12072dbac5
			
		
	
	
		12072dbac5
		
	
	
	
	
		
			
			It removes empty `BasicBlock`s with an unconditional jump continuation and then removes unreferenced blocks from the graph.
		
			
				
	
	
		
			85 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			85 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #include "Compiler/Passes/CFGSimplificationPass.h"
 | |
| #include "AST/AST.h"
 | |
| #include "Function.h"
 | |
| 
 | |
| namespace JSSpecCompiler {
 | |
| 
 | |
| void CFGSimplificationPass::process_function()
 | |
| {
 | |
|     auto& graph = *m_function->m_cfg;
 | |
| 
 | |
|     m_replacement.clear();
 | |
|     m_replacement.resize(graph.blocks_count());
 | |
|     m_state.clear();
 | |
|     m_state.resize(graph.blocks_count());
 | |
| 
 | |
|     for (auto const& block : graph.blocks) {
 | |
|         m_replacement[block->m_index] = block;
 | |
|         if (block->m_expressions.size() == 0)
 | |
|             if (auto jump = as<ControlFlowJump>(block->m_continuation); jump)
 | |
|                 m_replacement[block->m_index] = jump->m_block;
 | |
|     }
 | |
| 
 | |
|     for (size_t i = 0; i < graph.blocks_count(); ++i)
 | |
|         if (m_state[i] == State::NotUsed)
 | |
|             VERIFY(compute_replacement_block(i));
 | |
| 
 | |
|     // Fixing references
 | |
|     graph.start_block = m_replacement[graph.start_block->m_index];
 | |
|     for (auto const& block : graph.blocks) {
 | |
|         for (auto* next_block : block->m_continuation->references())
 | |
|             *next_block = m_replacement[(*next_block)->m_index];
 | |
|     }
 | |
| 
 | |
|     // Removing unused nodes
 | |
|     m_state.span().fill(State::NotUsed);
 | |
|     compute_referenced_blocks(graph.start_block);
 | |
| 
 | |
|     size_t j = 0;
 | |
|     for (size_t i = 0; i < graph.blocks_count(); ++i) {
 | |
|         if (m_state[graph.blocks[i]->m_index] == State::Used) {
 | |
|             graph.blocks[j] = graph.blocks[i];
 | |
|             graph.blocks[j]->m_index = j;
 | |
|             ++j;
 | |
|         }
 | |
|     }
 | |
|     graph.blocks.shrink(j);
 | |
| }
 | |
| 
 | |
| bool CFGSimplificationPass::compute_replacement_block(size_t i)
 | |
| {
 | |
|     if (m_state[i] == State::CurrentlyInside)
 | |
|         return false;
 | |
|     VERIFY(m_state[i] == State::NotUsed);
 | |
|     m_state[i] = State::CurrentlyInside;
 | |
| 
 | |
|     size_t j = m_replacement[i]->m_index;
 | |
| 
 | |
|     if (i == j)
 | |
|         return true;
 | |
|     if (m_state[j] == State::NotUsed)
 | |
|         if (!compute_replacement_block(j))
 | |
|             return false;
 | |
|     m_replacement[i] = m_replacement[j];
 | |
| 
 | |
|     m_state[i] = State::Used;
 | |
|     return true;
 | |
| }
 | |
| 
 | |
| void CFGSimplificationPass::compute_referenced_blocks(BasicBlockRef block)
 | |
| {
 | |
|     if (m_state[block->m_index] == State::Used)
 | |
|         return;
 | |
|     m_state[block->m_index] = State::Used;
 | |
| 
 | |
|     for (auto* next : block->m_continuation->references())
 | |
|         compute_referenced_blocks(*next);
 | |
| }
 | |
| 
 | |
| }
 |