mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-02 07:22:24 +00:00
Subprogram creation
This commit is contained in:
parent
920efdf37c
commit
0f6912cf18
@ -778,6 +778,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/recompiler.cpp
|
src/shader_recompiler/recompiler.cpp
|
||||||
src/shader_recompiler/recompiler.h
|
src/shader_recompiler/recompiler.h
|
||||||
src/shader_recompiler/info.h
|
src/shader_recompiler/info.h
|
||||||
|
src/shader_recompiler/pools.h
|
||||||
src/shader_recompiler/params.h
|
src/shader_recompiler/params.h
|
||||||
src/shader_recompiler/runtime_info.h
|
src/shader_recompiler/runtime_info.h
|
||||||
src/shader_recompiler/specialization.h
|
src/shader_recompiler/specialization.h
|
||||||
@ -863,8 +864,11 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||||||
src/shader_recompiler/ir/post_order.h
|
src/shader_recompiler/ir/post_order.h
|
||||||
src/shader_recompiler/ir/program.cpp
|
src/shader_recompiler/ir/program.cpp
|
||||||
src/shader_recompiler/ir/program.h
|
src/shader_recompiler/ir/program.h
|
||||||
src/shader_recompiler/ir/reinterpret.h
|
|
||||||
src/shader_recompiler/ir/reg.h
|
src/shader_recompiler/ir/reg.h
|
||||||
|
src/shader_recompiler/ir/reinterpret.h
|
||||||
|
src/shader_recompiler/ir/srt_gvn_table.h
|
||||||
|
src/shader_recompiler/ir/subprogram.cpp
|
||||||
|
src/shader_recompiler/ir/subprogram.h
|
||||||
src/shader_recompiler/ir/type.cpp
|
src/shader_recompiler/ir/type.cpp
|
||||||
src/shader_recompiler/ir/type.h
|
src/shader_recompiler/ir/type.h
|
||||||
src/shader_recompiler/ir/value.cpp
|
src/shader_recompiler/ir/value.cpp
|
||||||
|
@ -20,7 +20,7 @@ namespace Shader::IR {
|
|||||||
class Block {
|
class Block {
|
||||||
public:
|
public:
|
||||||
struct ConditionalData {
|
struct ConditionalData {
|
||||||
std::uint32_t depth;
|
u32 depth;
|
||||||
const ConditionalData* parent;
|
const ConditionalData* parent;
|
||||||
const AbstractSyntaxNode* asl_node;
|
const AbstractSyntaxNode* asl_node;
|
||||||
};
|
};
|
||||||
@ -71,6 +71,14 @@ public:
|
|||||||
[[nodiscard]] std::span<Block* const> ImmSuccessors() const noexcept {
|
[[nodiscard]] std::span<Block* const> ImmSuccessors() const noexcept {
|
||||||
return imm_successors;
|
return imm_successors;
|
||||||
}
|
}
|
||||||
|
// Returns if the block has a given immediate predecessor.
|
||||||
|
[[nodiscard]] bool HasImmPredecessor(const Block* block) const noexcept {
|
||||||
|
return std::ranges::find(imm_predecessors, block) != imm_predecessors.end();
|
||||||
|
}
|
||||||
|
// Returns if the block has a given immediate successor.
|
||||||
|
[[nodiscard]] bool HasImmSuccessor(const Block* block) const noexcept {
|
||||||
|
return std::ranges::find(imm_successors, block) != imm_successors.end();
|
||||||
|
}
|
||||||
|
|
||||||
// Set the conditional data for this block.
|
// Set the conditional data for this block.
|
||||||
void SetConditionalData(const ConditionalData& data) {
|
void SetConditionalData(const ConditionalData& data) {
|
||||||
|
225
src/shader_recompiler/ir/subprogram.cpp
Normal file
225
src/shader_recompiler/ir/subprogram.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/container/flat_set.hpp>
|
||||||
|
#include "shader_recompiler/ir/conditional_tree.h"
|
||||||
|
#include "shader_recompiler/ir/subprogram.h"
|
||||||
|
#include "shader_recompiler/ir/post_order.h"
|
||||||
|
|
||||||
|
namespace Shader::IR {
|
||||||
|
|
||||||
|
SubProgram::SubProgram(Program* super_program, Pools& pools) : super_program(super_program), pools(pools) {}
|
||||||
|
|
||||||
|
Block* SubProgram::AddBlock(Block* orig_block) {
|
||||||
|
auto it = orig_block_to_block.find(orig_block);
|
||||||
|
if (it != orig_block_to_block.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
auto block = pools.block_pool.Create(pools.inst_pool);
|
||||||
|
orig_block_to_block[orig_block] = block;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst* SubProgram::AddInst(Inst* orig_inst) {
|
||||||
|
auto it = orig_inst_to_inst.find(orig_inst);
|
||||||
|
if (it != orig_inst_to_inst.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
Block* block = AddBlock(orig_inst->GetParent());
|
||||||
|
Inst inst(orig_inst->GetOpcode(), orig_inst->Flags<u32>());
|
||||||
|
if (orig_inst->GetOpcode() == Opcode::Phi) {
|
||||||
|
AddPhi(orig_inst, &inst);
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < orig_inst->NumArgs(); ++i) {
|
||||||
|
SetArg(&inst, i, orig_inst->Arg(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto insertion_point = block->end();
|
||||||
|
if (block->back().GetOpcode() == Opcode::ConditionRef) {
|
||||||
|
--insertion_point;
|
||||||
|
}
|
||||||
|
return &(*block->PrependNewInst(insertion_point, inst));
|
||||||
|
}
|
||||||
|
|
||||||
|
Block* SubProgram::GetBlock(Block* orig_block) {
|
||||||
|
auto it = orig_block_to_block.find(orig_block);
|
||||||
|
if (it != orig_block_to_block.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst* SubProgram::GetInst(Inst* orig_inst) {
|
||||||
|
auto it = orig_inst_to_inst.find(orig_inst);
|
||||||
|
if (it != orig_inst_to_inst.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program SubProgram::GetSubProgram() {
|
||||||
|
Program sub_program(super_program->info);
|
||||||
|
BuildBlockListAndASL(sub_program);
|
||||||
|
sub_program.post_order_blocks = PostOrder(sub_program.syntax_list.front());
|
||||||
|
AddConditionalTreeFromASL(sub_program.syntax_list);
|
||||||
|
for (Block* block : sub_program.blocks) {
|
||||||
|
block->SsaSeal();
|
||||||
|
}
|
||||||
|
return sub_program;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubProgram::AddPhi(Inst* orig_phi, Inst* phi) {
|
||||||
|
// Current IR only has Phis with 2 arguments.
|
||||||
|
ASSERT(orig_phi->NumArgs() == 2);
|
||||||
|
Block* orig_block0 = orig_phi->PhiBlock(0);
|
||||||
|
Block* orig_block1 = orig_phi->PhiBlock(1);
|
||||||
|
Block* block0 = AddBlock(orig_block0);
|
||||||
|
Block* block1 = AddBlock(orig_block1);
|
||||||
|
const Value& arg0 = orig_phi->Arg(0);
|
||||||
|
const Value& arg1 = orig_phi->Arg(1);
|
||||||
|
AddPhiOperand(phi, block0, arg0);
|
||||||
|
AddPhiOperand(phi, block1, arg1);
|
||||||
|
const auto get_conds = [orig_block0, orig_block1]() -> std::pair<const Block::ConditionalData&, const Block::ConditionalData&> {
|
||||||
|
const Block::ConditionalData& cond0 = orig_block0->CondData();
|
||||||
|
const Block::ConditionalData& cond1 = orig_block1->CondData();
|
||||||
|
if (cond0.depth > cond1.depth) {
|
||||||
|
return {cond0, cond1};
|
||||||
|
}
|
||||||
|
return {cond1, cond0};
|
||||||
|
};
|
||||||
|
const auto& [start_cond, target_cond] = get_conds();
|
||||||
|
const Block::ConditionalData* cond = &start_cond;
|
||||||
|
while (cond->depth > target_cond.depth) {
|
||||||
|
if (cond->asl_node->type == AbstractSyntaxNode::Type::If) {
|
||||||
|
AddInst(cond->asl_node->data.if_node.cond.InstRecursive());
|
||||||
|
} else if (cond->asl_node->type == AbstractSyntaxNode::Type::Loop) {
|
||||||
|
AddInst(&cond->asl_node->data.loop.continue_block->back());
|
||||||
|
}
|
||||||
|
if (orig_phi->GetParent()->CondData().asl_node == cond->asl_node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cond = cond->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubProgram::SetArg(Inst* inst, size_t index, const Value& arg) {
|
||||||
|
if (arg.IsImmediate()) {
|
||||||
|
inst->SetArg(index, arg);
|
||||||
|
} else {
|
||||||
|
inst->SetArg(index, Value(AddInst(arg.InstRecursive())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubProgram::AddPhiOperand(Inst* phi, Block* block, const Value& arg) {
|
||||||
|
if (arg.IsImmediate()) {
|
||||||
|
phi->AddPhiOperand(block, arg);
|
||||||
|
} else {
|
||||||
|
phi->AddPhiOperand(block, Value(AddInst(arg.InstRecursive())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubProgram::BuildBlockListAndASL(Program& sub_program) {
|
||||||
|
boost::container::flat_set<Block*> filter_blocks;
|
||||||
|
for (const AbstractSyntaxNode& orig_asl_node : super_program->syntax_list) {
|
||||||
|
AbstractSyntaxNode asl_node;
|
||||||
|
asl_node.type = orig_asl_node.type;
|
||||||
|
Block* orig_block = orig_asl_node.data.block;
|
||||||
|
switch (orig_asl_node.type) {
|
||||||
|
case AbstractSyntaxNode::Type::Block: {
|
||||||
|
Block* block = GetBlock(orig_block);
|
||||||
|
if (!block) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!sub_program.syntax_list.empty()) {
|
||||||
|
Block* last_block = sub_program.blocks.back();
|
||||||
|
if (!last_block->HasImmSuccessor(block)) {
|
||||||
|
last_block->AddBranch(block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
asl_node.data.block = block;
|
||||||
|
sub_program.blocks.push_back(block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::If: {
|
||||||
|
Inst* cond = GetInst(orig_asl_node.data.if_node.cond.InstRecursive());
|
||||||
|
if (!cond) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Block* block = cond->GetParent();
|
||||||
|
Block* merge_block = AddBlock(orig_asl_node.data.if_node.merge);
|
||||||
|
Block* body_block = AddBlock(orig_asl_node.data.if_node.body);
|
||||||
|
asl_node.data.if_node.cond = U1(Value(cond));
|
||||||
|
asl_node.data.if_node.body = body_block;
|
||||||
|
asl_node.data.if_node.merge = merge_block;
|
||||||
|
block->AddBranch(merge_block);
|
||||||
|
block->AddBranch(body_block);
|
||||||
|
filter_blocks.insert(merge_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::EndIf: {
|
||||||
|
Block* merge_block = GetBlock(orig_asl_node.data.end_if.merge);
|
||||||
|
if (!filter_blocks.contains(merge_block)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
asl_node.data.end_if.merge = merge_block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::Loop: {
|
||||||
|
Block* continue_block = GetBlock(orig_asl_node.data.loop.continue_block);
|
||||||
|
if (!continue_block) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (continue_block->back().GetOpcode() != Opcode::ConditionRef) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Block* merge_block = AddBlock(orig_asl_node.data.loop.merge);
|
||||||
|
asl_node.data.loop.body = AddBlock(orig_asl_node.data.loop.body);
|
||||||
|
asl_node.data.loop.continue_block = continue_block;
|
||||||
|
asl_node.data.loop.merge = merge_block;
|
||||||
|
filter_blocks.insert(merge_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::Repeat: {
|
||||||
|
Inst* cond = GetInst(orig_asl_node.data.repeat.cond.InstRecursive());
|
||||||
|
if (!cond) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Block* block = cond->GetParent();
|
||||||
|
Block* merge_block = AddBlock(orig_asl_node.data.repeat.merge);
|
||||||
|
Block* loop_header_block = AddBlock(orig_asl_node.data.repeat.loop_header);
|
||||||
|
asl_node.data.repeat.cond = U1(Value(cond));
|
||||||
|
asl_node.data.repeat.loop_header = loop_header_block;
|
||||||
|
asl_node.data.repeat.merge = merge_block;
|
||||||
|
block->AddBranch(loop_header_block);
|
||||||
|
block->AddBranch(merge_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::Break: {
|
||||||
|
Inst* cond = GetInst(orig_asl_node.data.break_node.cond.InstRecursive());
|
||||||
|
if (!cond) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Block* block = cond->GetParent();
|
||||||
|
Block* merge_block = AddBlock(orig_asl_node.data.break_node.merge);
|
||||||
|
Block* skip_block = AddBlock(orig_asl_node.data.break_node.skip);
|
||||||
|
asl_node.data.break_node.cond = U1(Value(&block->back()));
|
||||||
|
asl_node.data.break_node.merge = merge_block;
|
||||||
|
asl_node.data.break_node.skip = skip_block;
|
||||||
|
block->AddBranch(merge_block);
|
||||||
|
block->AddBranch(skip_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AbstractSyntaxNode::Type::Unreachable:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sub_program.syntax_list.push_back(asl_node);
|
||||||
|
}
|
||||||
|
for (Block* block : sub_program.blocks) {
|
||||||
|
block->has_multiple_predecessors = block->ImmPredecessors().size() > 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Shader::IR
|
37
src/shader_recompiler/ir/subprogram.h
Normal file
37
src/shader_recompiler/ir/subprogram.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/container/flat_map.hpp>
|
||||||
|
#include "shader_recompiler/pools.h"
|
||||||
|
#include "shader_recompiler/ir/basic_block.h"
|
||||||
|
#include "shader_recompiler/ir/program.h"
|
||||||
|
|
||||||
|
namespace Shader::IR {
|
||||||
|
|
||||||
|
struct SubProgram {
|
||||||
|
SubProgram(Program* super_program, Pools& pools);
|
||||||
|
|
||||||
|
Block* AddBlock(Block* orig_block);
|
||||||
|
Inst* AddInst(Inst* orig_inst);
|
||||||
|
|
||||||
|
Block* GetBlock(Block* orig_block);
|
||||||
|
Inst* GetInst(Inst* orig_inst);
|
||||||
|
|
||||||
|
Program GetSubProgram();
|
||||||
|
private:
|
||||||
|
void AddPhi(Inst* orig_phi, Inst* phi);
|
||||||
|
|
||||||
|
void SetArg(Inst* inst, size_t index, const Value& arg);
|
||||||
|
void AddPhiOperand(Inst* phi, Block* block, const Value& arg);
|
||||||
|
|
||||||
|
void BuildBlockListAndASL(Program& sub_program);
|
||||||
|
|
||||||
|
Program* super_program;
|
||||||
|
Pools& pools;
|
||||||
|
boost::container::flat_map<Block*, Block*> orig_block_to_block;
|
||||||
|
boost::container::flat_map<Inst*, Inst*> orig_inst_to_inst;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Shader::IR
|
26
src/shader_recompiler/pools.h
Normal file
26
src/shader_recompiler/pools.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/object_pool.h"
|
||||||
|
#include "shader_recompiler/ir/basic_block.h"
|
||||||
|
|
||||||
|
namespace Shader {
|
||||||
|
|
||||||
|
struct Pools {
|
||||||
|
static constexpr u32 InstPoolSize = 8192;
|
||||||
|
static constexpr u32 BlockPoolSize = 32;
|
||||||
|
|
||||||
|
Common::ObjectPool<IR::Inst> inst_pool;
|
||||||
|
Common::ObjectPool<IR::Block> block_pool;
|
||||||
|
|
||||||
|
explicit Pools() : inst_pool{InstPoolSize}, block_pool{BlockPoolSize} {}
|
||||||
|
|
||||||
|
void ReleaseContents() {
|
||||||
|
inst_pool.ReleaseContents();
|
||||||
|
block_pool.ReleaseContents();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Shader
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/object_pool.h"
|
#include "shader_recompiler/pools.h"
|
||||||
#include "shader_recompiler/ir/basic_block.h"
|
#include "shader_recompiler/ir/basic_block.h"
|
||||||
#include "shader_recompiler/ir/program.h"
|
#include "shader_recompiler/ir/program.h"
|
||||||
|
|
||||||
@ -12,21 +12,6 @@ namespace Shader {
|
|||||||
struct Profile;
|
struct Profile;
|
||||||
struct RuntimeInfo;
|
struct RuntimeInfo;
|
||||||
|
|
||||||
struct Pools {
|
|
||||||
static constexpr u32 InstPoolSize = 8192;
|
|
||||||
static constexpr u32 BlockPoolSize = 32;
|
|
||||||
|
|
||||||
Common::ObjectPool<IR::Inst> inst_pool;
|
|
||||||
Common::ObjectPool<IR::Block> block_pool;
|
|
||||||
|
|
||||||
explicit Pools() : inst_pool{InstPoolSize}, block_pool{BlockPoolSize} {}
|
|
||||||
|
|
||||||
void ReleaseContents() {
|
|
||||||
inst_pool.ReleaseContents();
|
|
||||||
block_pool.ReleaseContents();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info,
|
[[nodiscard]] IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info,
|
||||||
RuntimeInfo& runtime_info, const Profile& profile);
|
RuntimeInfo& runtime_info, const Profile& profile);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user