shader: Support SSA loops on IR
This commit is contained in:
		@@ -12,6 +12,7 @@ namespace Shader::IR {
 | 
			
		||||
 | 
			
		||||
struct Function {
 | 
			
		||||
    BlockList blocks;
 | 
			
		||||
    BlockList post_order_blocks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Shader::IR
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								src/shader_recompiler/frontend/ir/post_order.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/shader_recompiler/frontend/ir/post_order.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
// Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <boost/container/flat_set.hpp>
 | 
			
		||||
#include <boost/container/small_vector.hpp>
 | 
			
		||||
 | 
			
		||||
#include "shader_recompiler/frontend/ir/basic_block.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/post_order.h"
 | 
			
		||||
 | 
			
		||||
namespace Shader::IR {
 | 
			
		||||
 | 
			
		||||
BlockList PostOrder(const BlockList& blocks) {
 | 
			
		||||
    boost::container::small_vector<Block*, 16> block_stack;
 | 
			
		||||
    boost::container::flat_set<Block*> visited;
 | 
			
		||||
 | 
			
		||||
    BlockList post_order_blocks;
 | 
			
		||||
    post_order_blocks.reserve(blocks.size());
 | 
			
		||||
 | 
			
		||||
    Block* const first_block{blocks.front()};
 | 
			
		||||
    visited.insert(first_block);
 | 
			
		||||
    block_stack.push_back(first_block);
 | 
			
		||||
 | 
			
		||||
    const auto visit_branch = [&](Block* block, Block* branch) {
 | 
			
		||||
        if (!branch) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!visited.insert(branch).second) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        // Calling push_back twice is faster than insert on msvc
 | 
			
		||||
        block_stack.push_back(block);
 | 
			
		||||
        block_stack.push_back(branch);
 | 
			
		||||
        return true;
 | 
			
		||||
    };
 | 
			
		||||
    while (!block_stack.empty()) {
 | 
			
		||||
        Block* const block{block_stack.back()};
 | 
			
		||||
        block_stack.pop_back();
 | 
			
		||||
 | 
			
		||||
        if (!visit_branch(block, block->TrueBranch()) &&
 | 
			
		||||
            !visit_branch(block, block->FalseBranch())) {
 | 
			
		||||
            post_order_blocks.push_back(block);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return post_order_blocks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Shader::IR
 | 
			
		||||
							
								
								
									
										13
									
								
								src/shader_recompiler/frontend/ir/post_order.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/shader_recompiler/frontend/ir/post_order.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
// Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "shader_recompiler/frontend/ir/basic_block.h"
 | 
			
		||||
 | 
			
		||||
namespace Shader::IR {
 | 
			
		||||
 | 
			
		||||
BlockList PostOrder(const BlockList& blocks);
 | 
			
		||||
 | 
			
		||||
} // namespace Shader::IR
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "shader_recompiler/frontend/ir/basic_block.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/post_order.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/structured_control_flow.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/program.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/translate/translate.h"
 | 
			
		||||
@@ -56,11 +57,14 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fmt::print(stdout, "No optimizations: {}", IR::DumpProgram(program));
 | 
			
		||||
    std::ranges::for_each(functions, Optimization::SsaRewritePass);
 | 
			
		||||
    for (IR::Function& function : functions) {
 | 
			
		||||
        Optimization::Invoke(Optimization::GlobalMemoryToStorageBufferPass, function);
 | 
			
		||||
        Optimization::Invoke(Optimization::ConstantPropagationPass, function);
 | 
			
		||||
        Optimization::Invoke(Optimization::DeadCodeEliminationPass, function);
 | 
			
		||||
        function.post_order_blocks = PostOrder(function.blocks);
 | 
			
		||||
        Optimization::SsaRewritePass(function.post_order_blocks);
 | 
			
		||||
    }
 | 
			
		||||
    for (IR::Function& function : functions) {
 | 
			
		||||
        Optimization::PostOrderInvoke(Optimization::GlobalMemoryToStorageBufferPass, function);
 | 
			
		||||
        Optimization::PostOrderInvoke(Optimization::ConstantPropagationPass, function);
 | 
			
		||||
        Optimization::PostOrderInvoke(Optimization::DeadCodeEliminationPass, function);
 | 
			
		||||
        Optimization::IdentityRemovalPass(function);
 | 
			
		||||
        Optimization::VerificationPass(function);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user