Shader_IR: add the ability to amend code in the shader ir.
This commit introduces a mechanism by which shader IR code can be amended and extended. This useful for track algorithms where certain information can derived from before the track such as indexes to array samplers.
This commit is contained in:
parent
f846e3d6d0
commit
b3371ed09e
|
@ -751,6 +751,11 @@ private:
|
||||||
|
|
||||||
Expression Visit(const Node& node) {
|
Expression Visit(const Node& node) {
|
||||||
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
||||||
|
auto amend_index = operation->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
Visit(amend_node).CheckVoid();
|
||||||
|
}
|
||||||
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
|
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
|
||||||
if (operation_index >= operation_decompilers.size()) {
|
if (operation_index >= operation_decompilers.size()) {
|
||||||
UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
|
UNREACHABLE_MSG("Out of bounds operation: {}", operation_index);
|
||||||
|
@ -872,6 +877,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
||||||
|
auto amend_index = conditional->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
Visit(amend_node).CheckVoid();
|
||||||
|
}
|
||||||
// It's invalid to call conditional on nested nodes, use an operation instead
|
// It's invalid to call conditional on nested nodes, use an operation instead
|
||||||
code.AddLine("if ({}) {{", Visit(conditional->GetCondition()).AsBool());
|
code.AddLine("if ({}) {{", Visit(conditional->GetCondition()).AsBool());
|
||||||
++code.scope;
|
++code.scope;
|
||||||
|
@ -884,6 +894,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
||||||
|
auto amend_index = comment->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
Visit(amend_node).CheckVoid();
|
||||||
|
}
|
||||||
code.AddLine("// " + comment->GetText());
|
code.AddLine("// " + comment->GetText());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -954,6 +954,12 @@ private:
|
||||||
|
|
||||||
Expression Visit(const Node& node) {
|
Expression Visit(const Node& node) {
|
||||||
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
if (const auto operation = std::get_if<OperationNode>(&*node)) {
|
||||||
|
auto amend_index = operation->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
[[maybe_unused]] const Type type = Visit(amend_node).type;
|
||||||
|
ASSERT(type == Type::Void);
|
||||||
|
}
|
||||||
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
|
const auto operation_index = static_cast<std::size_t>(operation->GetCode());
|
||||||
const auto decompiler = operation_decompilers[operation_index];
|
const auto decompiler = operation_decompilers[operation_index];
|
||||||
if (decompiler == nullptr) {
|
if (decompiler == nullptr) {
|
||||||
|
@ -1142,6 +1148,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
|
||||||
|
auto amend_index = conditional->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
[[maybe_unused]] const Type type = Visit(amend_node).type;
|
||||||
|
ASSERT(type == Type::Void);
|
||||||
|
}
|
||||||
// It's invalid to call conditional on nested nodes, use an operation instead
|
// It's invalid to call conditional on nested nodes, use an operation instead
|
||||||
const Id true_label = OpLabel();
|
const Id true_label = OpLabel();
|
||||||
const Id skip_label = OpLabel();
|
const Id skip_label = OpLabel();
|
||||||
|
@ -1164,6 +1176,12 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
if (const auto comment = std::get_if<CommentNode>(&*node)) {
|
||||||
|
auto amend_index = comment->GetAmendIndex();
|
||||||
|
if (amend_index) {
|
||||||
|
const Node& amend_node = ir.GetAmendNode(*amend_index);
|
||||||
|
[[maybe_unused]] const Type type = Visit(amend_node).type;
|
||||||
|
ASSERT(type == Type::Void);
|
||||||
|
}
|
||||||
Name(OpUndef(t_void), comment->GetText());
|
Name(OpUndef(t_void), comment->GetText());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -392,8 +392,30 @@ struct MetaImage {
|
||||||
using Meta =
|
using Meta =
|
||||||
std::variant<MetaArithmetic, MetaTexture, MetaImage, MetaStackClass, Tegra::Shader::HalfType>;
|
std::variant<MetaArithmetic, MetaTexture, MetaImage, MetaStackClass, Tegra::Shader::HalfType>;
|
||||||
|
|
||||||
|
class AmendNode {
|
||||||
|
public:
|
||||||
|
std::optional<u32> GetAmendIndex() const {
|
||||||
|
if (amend_index == amend_null_index) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
return {amend_index};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAmendIndex(u32 index) {
|
||||||
|
amend_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearAmend() {
|
||||||
|
amend_index = amend_null_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr u32 amend_null_index = 0xFFFFFFFF;
|
||||||
|
u32 amend_index{amend_null_index};
|
||||||
|
};
|
||||||
|
|
||||||
/// Holds any kind of operation that can be done in the IR
|
/// Holds any kind of operation that can be done in the IR
|
||||||
class OperationNode final {
|
class OperationNode final : public AmendNode {
|
||||||
public:
|
public:
|
||||||
explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
|
explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
|
||||||
|
|
||||||
|
@ -433,7 +455,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Encloses inside any kind of node that returns a boolean conditionally-executed code
|
/// Encloses inside any kind of node that returns a boolean conditionally-executed code
|
||||||
class ConditionalNode final {
|
class ConditionalNode final : public AmendNode {
|
||||||
public:
|
public:
|
||||||
explicit ConditionalNode(Node condition, std::vector<Node>&& code)
|
explicit ConditionalNode(Node condition, std::vector<Node>&& code)
|
||||||
: condition{std::move(condition)}, code{std::move(code)} {}
|
: condition{std::move(condition)}, code{std::move(code)} {}
|
||||||
|
@ -630,7 +652,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Commentary, can be dropped
|
/// Commentary, can be dropped
|
||||||
class CommentNode final {
|
class CommentNode final : public AmendNode {
|
||||||
public:
|
public:
|
||||||
explicit CommentNode(std::string text) : text{std::move(text)} {}
|
explicit CommentNode(std::string text) : text{std::move(text)} {}
|
||||||
|
|
||||||
|
|
|
@ -446,4 +446,10 @@ Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
|
||||||
Immediate(bits));
|
Immediate(bits));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 ShaderIR::DeclareAmend(Node new_amend) {
|
||||||
|
const u32 id = static_cast<u32>(amend_code.size());
|
||||||
|
amend_code.push_back(new_amend);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace VideoCommon::Shader
|
} // namespace VideoCommon::Shader
|
||||||
|
|
|
@ -176,6 +176,10 @@ public:
|
||||||
/// Returns a condition code evaluated from internal flags
|
/// Returns a condition code evaluated from internal flags
|
||||||
Node GetConditionCode(Tegra::Shader::ConditionCode cc) const;
|
Node GetConditionCode(Tegra::Shader::ConditionCode cc) const;
|
||||||
|
|
||||||
|
const Node& GetAmendNode(u32 index) const {
|
||||||
|
return amend_code[index];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ASTDecoder;
|
friend class ASTDecoder;
|
||||||
|
|
||||||
|
@ -392,6 +396,9 @@ private:
|
||||||
Tegra::Shader::Instruction instr,
|
Tegra::Shader::Instruction instr,
|
||||||
bool is_write);
|
bool is_write);
|
||||||
|
|
||||||
|
/// Amends
|
||||||
|
u32 DeclareAmend(Node new_amend);
|
||||||
|
|
||||||
const ProgramCode& program_code;
|
const ProgramCode& program_code;
|
||||||
const u32 main_offset;
|
const u32 main_offset;
|
||||||
const CompilerSettings settings;
|
const CompilerSettings settings;
|
||||||
|
@ -406,6 +413,7 @@ private:
|
||||||
std::map<u32, NodeBlock> basic_blocks;
|
std::map<u32, NodeBlock> basic_blocks;
|
||||||
NodeBlock global_code;
|
NodeBlock global_code;
|
||||||
ASTManager program_manager{true, true};
|
ASTManager program_manager{true, true};
|
||||||
|
NodeBlock amend_code;
|
||||||
|
|
||||||
std::set<u32> used_registers;
|
std::set<u32> used_registers;
|
||||||
std::set<Tegra::Shader::Pred> used_predicates;
|
std::set<Tegra::Shader::Pred> used_predicates;
|
||||||
|
|
Reference in New Issue