Implemented IFE, LOOP instructions

Added operator- deduction
Fixed loading big ucode files
Minor fixes
This commit is contained in:
DH
2015-08-07 11:47:02 +03:00
parent e1ef4dc7d6
commit 2fc488f02a
8 changed files with 252 additions and 61 deletions
@@ -10,13 +10,15 @@
template<typename DecompilerType>
int process_ucode(const std::string& ipath, const std::string& opath)
{
if (auto &ifile_stream = std::ifstream{ ipath, std::ios::binary })
if (auto &ifile_stream = std::ifstream{ ipath, std::ios::binary | std::ios::ate })
{
if (auto &ofile_stream = std::ofstream{ opath })
{
u32 buffer[512 * 4];
u32 size = ifile_stream.read((char*)buffer, sizeof(buffer)).gcount();
auto info = DecompilerType{ buffer, size }.decompile();
std::vector<char> buffer(ifile_stream.tellg());
ifile_stream.seekg(0);
ifile_stream.read(buffer.data(), buffer.size());
auto info = DecompilerType{ buffer.data(), (u32)buffer.size() }.decompile();
ofile_stream << info.text;
return 0;
@@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode out.glsl</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>-fp_glsl fp_cg.ucode fp_out.glsl</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(SolutionDir)bin\</LocalDebuggerWorkingDirectory>
</PropertyGroup>
@@ -129,7 +129,7 @@ namespace rsx
using FENCB = instruction < opcode::FENCB, suffix_none >;
using BRK = instruction < opcode::BRK, suffix_none, arg<addr> >;
using CAL = instruction < opcode::CAL, suffix_none, arg<addr> >;
using IFE = instruction < opcode::IFE, H >;
using IFE = instruction < opcode::IFE, suffix_none, arg<cond> >;
using LOOP = instruction < opcode::LOOP, H >;
using REP = instruction < opcode::REP, H >;
using RET = instruction < opcode::RET, H >;
@@ -148,8 +148,7 @@ namespace rsx
template<typename decompiler_impl>
__forceinline static void function(decompiler<decompiler_impl>& decompiler)
{
if (id != opcode::FENCT && id != opcode::FENCT)
throw std::runtime_error("unimplemented instruction: " + instructions_names[(std::size_t)id]);
decompiler.nodest_instruction<id, flags>(decompiler.arg<args_type>()...);
}
};
@@ -220,6 +219,8 @@ namespace rsx
swizzle_y = src.swizzle_y;
swizzle_z = src.swizzle_z;
swizzle_w = src.swizzle_w;
variable.is_abs = src.abs;
variable.is_neg = src.neg;
};
switch (index)
@@ -317,7 +318,7 @@ namespace rsx
template<typename decompiler_impl>
__forceinline static program_variable impl(decompiler<decompiler_impl>& decompiler)
{
return decompiler.execution_condition();
return decompiler.execution_condition_register();
}
};
@@ -384,7 +385,7 @@ namespace rsx
return expand_arg_t<T>::impl(*this);
}
program_variable update_condition()
program_variable update_condition_register()
{
program_variable result = {};
@@ -396,7 +397,7 @@ namespace rsx
return info.vars.add(result);
}
program_variable execution_condition()
program_variable execution_condition_register(bool exclusive_channels_only = false)
{
program_variable result = {};
@@ -407,19 +408,37 @@ namespace rsx
static const std::string mask = "xyzw";
std::string swizzle;
swizzle += mask[ucode.src0.cond_swizzle_x];
swizzle += mask[ucode.src0.cond_swizzle_y];
swizzle += mask[ucode.src0.cond_swizzle_z];
swizzle += mask[ucode.src0.cond_swizzle_w];
if (exclusive_channels_only)
{
swizzle += mask[ucode.src0.cond_swizzle_x];
if (ucode.src0.cond_swizzle_x != ucode.src0.cond_swizzle_y)
swizzle += mask[ucode.src0.cond_swizzle_y];
if (ucode.src0.cond_swizzle_z != ucode.src0.cond_swizzle_x && ucode.src0.cond_swizzle_z != ucode.src0.cond_swizzle_y)
swizzle += mask[ucode.src0.cond_swizzle_z];
if (ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_x &&
ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_y &&
ucode.src0.cond_swizzle_w != ucode.src0.cond_swizzle_z)
swizzle += mask[ucode.src0.cond_swizzle_w];
}
else
{
swizzle += mask[ucode.src0.cond_swizzle_x];
swizzle += mask[ucode.src0.cond_swizzle_y];
swizzle += mask[ucode.src0.cond_swizzle_z];
swizzle += mask[ucode.src0.cond_swizzle_w];
}
result.mask.add(swizzle);
return info.vars.add(result);
}
void set_code_line(const std::string &code_line)
void set_code_line(const std::string &code_line, int tab_before = 0, int tab_after = 0, bool to_end = true)
{
program_decompiler_core::builder.add_code_block(ucode_index, code_line);
program_decompiler_core::builder.add_code_block(ucode_index, code_line, tab_before, tab_after, to_end);
}
template<opcode id, u32 flags, int count>
@@ -428,6 +447,15 @@ namespace rsx
set_code_line(decompiler_impl::set_dst<id, flags, count>(this, arg0, arg1, arg2));
}
template<opcode id, u32 flags>
void nodest_instruction(const program_variable& arg0 = {}, const program_variable& arg1 = {}, const program_variable& arg2 = {})
{
if (id != opcode::FENCT && id != opcode::FENCB)
{
decompiler_impl::nodest_instruction<id, flags>(this, arg0, arg1, arg2);
}
}
void unknown_instruction(opcode op)
{
throw std::runtime_error("unimplemented instruction '" + instructions_names[(std::size_t)op] + "' (" + std::to_string((std::size_t)op) + ") #"
@@ -122,6 +122,62 @@ namespace rsx
return "}";
}
__forceinline static std::string execution_condition(decompiler* dec)
{
if (dec->ucode.src0.exec_if_gr &&
dec->ucode.src0.exec_if_lt &&
dec->ucode.src0.exec_if_eq)
{
return{};
}
if (!dec->ucode.src0.exec_if_gr &&
!dec->ucode.src0.exec_if_lt &&
!dec->ucode.src0.exec_if_eq)
{
return "if (false) ";
}
program_variable execution_condition = dec->execution_condition_register(true);
if (execution_condition.mask.to_string().size() == 1)
{
std::string execution_condition_operation;
if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq)
execution_condition_operation = ">=";
else if (dec->ucode.src0.exec_if_lt && dec->ucode.src0.exec_if_eq)
execution_condition_operation = "<=";
else if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_lt)
execution_condition_operation = "!=";
else if (dec->ucode.src0.exec_if_gr)
execution_condition_operation = ">";
else if (dec->ucode.src0.exec_if_lt)
execution_condition_operation = "<";
else //if(dec->ucode.src0.exec_if_eq)
execution_condition_operation = "==";
return "if (" + execution_condition.to_string() + " " + execution_condition_operation + " 0.0f) ";
}
std::string execution_condition_function;
if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_eq)
execution_condition_function = "greaterThanEquals";
else if (dec->ucode.src0.exec_if_lt && dec->ucode.src0.exec_if_eq)
execution_condition_function = "lessThanEquals";
else if (dec->ucode.src0.exec_if_gr && dec->ucode.src0.exec_if_lt)
execution_condition_function = "notEquals";
else if (dec->ucode.src0.exec_if_gr)
execution_condition_function = "greaterThan";
else if (dec->ucode.src0.exec_if_lt)
execution_condition_function = "lessThan";
else //if(dec->ucode.src0.exec_if_eq)
execution_condition_function = "equals";
return "if (any(" + execution_condition_function + "(" + execution_condition.to_string() + ", " + " vec4(0.0f)))) ";
}
template<opcode id, u32 flags, int count>
__forceinline static std::string set_dst(decompiler* dec, const program_variable& arg0, const program_variable& arg1, const program_variable& arg2)
{
@@ -146,7 +202,7 @@ namespace rsx
"?", "?", "?", "?", "fma", "dot", "dot",
"distantion", "min", "max", "lessThan", "greaterThanEquals", "lessThanEqual", "greaterThan",
"notEqual", "equal", "fract", "floor", "?", "pk4", "up4",
"ddx", "ddy", "texture", "txp", "txd", "rcp", "rsq",
"dFdx", "dFdy", "texture", "txp", "txd", "rcp", "rsq",
"exp2", "log2", "lit", "lrp", "str", "sfl", "cos",
"sin", "pk2", "up2", "pow", "pkb", "upb", "pk16",
"up16", "bem", "pkg", "upg", "dpa2", "txl", "?",
@@ -161,7 +217,6 @@ namespace rsx
{
case opcode::MOV:
case opcode::MUL:
case opcode::ADD:
case opcode::DIV:
//operators
@@ -171,13 +226,28 @@ namespace rsx
if (!arg1.is_null())
{
value = "(" + value + " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1) + ")";
value += " " + std::string(1, operators[(std::size_t)id]) + " " + variable_to_string(arg1);
}
}
break;
case opcode::ADD:
{
value = variable_to_string(arg0);
std::string arg1_string = variable_to_string(arg1);
if (arg1_string[0] == '-')
{
value += " - " + arg1_string.substr(1);
}
else
{
value += " + " + arg1_string;
}
}
break;
case opcode::DIVSQ:
value = "(" + variable_to_string(arg0) + " / sqrt(" + variable_to_string(arg1) + "))";
value = variable_to_string(arg0) + " / sqrt(" + variable_to_string(arg1) + ")";
break;
case opcode::LIF:
@@ -218,6 +288,23 @@ namespace rsx
break;
}
program_variable dst = dec->dst<flags, count>();
if (id == opcode::SIN || id == opcode::COS)
{
std::string dst_mask = dst.mask.to_string();
if (dst_mask.size() != 1)
{
size_t size = 4;
if (!dst_mask.empty())
size = dst_mask.size();
value = "vec" + std::to_string(size) + "(" + value + ")";
}
}
if (flags & H)
{
switch (dec->ucode.dst.prec)
@@ -229,20 +316,21 @@ namespace rsx
value = "clamp(" + value + ", -65536, 65536)";
break;
case 2: //fixed point 12? let it be unimplemented, atm
value = "clamp(" + value + ", 0, 0)";
case 2: //fixed point 12?
value = "clamp(" + value + ", -1, 1)";
//throw std::runtime_error("fragment program decompiler: unimplemented precision.");
break;
}
switch (dec->ucode.src1.scale)
{
case 0: break;
case 1: value = "(" + value + " * 2.0)"; break;
case 2: value = "(" + value + " * 4.0)"; break;
case 3: value = "(" + value + " * 8.0)"; break;
case 5: value = "(" + value + " / 2.0)"; break;
case 6: value = "(" + value + " / 4.0)"; break;
case 7: value = "(" + value + " / 8.0)"; break;
case 1: value = mask_t::append_brackets_if_needed(value) + " * 2.0"; break;
case 2: value = mask_t::append_brackets_if_needed(value) + " * 4.0"; break;
case 3: value = mask_t::append_brackets_if_needed(value) + " * 8.0"; break;
case 5: value = mask_t::append_brackets_if_needed(value) + " / 2.0"; break;
case 6: value = mask_t::append_brackets_if_needed(value) + " / 4.0"; break;
case 7: value = mask_t::append_brackets_if_needed(value) + " / 8.0"; break;
default:
throw std::runtime_error("fragment program decompiler: unimplemented scale (" + std::to_string(dec->ucode.src1.scale) + "). ");
@@ -254,14 +342,13 @@ namespace rsx
}
}
std::string result;
program_variable dst = dec->dst<flags, count>();
program_variable update_condition;
std::string result;
bool do_update_condition = false;
if ((flags & C) && dec->ucode.dst.set_cond)
{
update_condition = dec->update_condition();
update_condition = dec->update_condition_register();
do_update_condition = !update_condition.is_null();
}
@@ -282,7 +369,7 @@ namespace rsx
}
else
{
program_variable execution_condition = dec->execution_condition();
program_variable execution_condition = dec->execution_condition_register();
mask_t update_mask;
update_mask
.add(execution_condition.mask.to_string())
@@ -306,26 +393,29 @@ namespace rsx
else //if(dec->ucode.src0.exec_if_eq)
execution_condition_operation = "==";
fmt::string update_mask_string = update_mask.to_string();
std::string update_mask_string = update_mask.to_string();
if (update_mask_string.empty())
update_mask_string = "xyzw";
std::string dst_mask = dst.mask.to_string();
if (dst_mask.empty())
dst_mask = "xyzw";
std::string last_condition_group;
std::string last_line;
for (char _mask : update_mask_string)
for (char _mask : std::string("xyzw").substr(0, update_mask_string.size()))
{
const std::string mask(1, _mask);
const std::string dot_mask = "." + mask;
const mask_t mask = mask_t{}.add(std::string(1, _mask));
auto channel_execution_condition = execution_condition;
std::string channel_execution_condition_mask = channel_execution_condition.mask.add(mask).to_string();
std::string channel_execution_condition_mask = channel_execution_condition.mask.add(mask.to_string()).to_string();
if (channel_execution_condition_mask != last_condition_group)
{
if (!last_condition_group.empty())
{
result += "}\n\n";
result += "}\n";
}
result += "if (" + channel_execution_condition.to_string() + " " + execution_condition_operation + " 0.0f)\n{\n";
@@ -338,31 +428,66 @@ namespace rsx
if (dst)
{
auto channel_dst = dst;
channel_dst.mask.add(mask);
channel_dst.mask = mask_t{}.add(dst_mask).add(mask.to_string());
channel_dst_string = channel_dst.to_string();
std::string line = "\t" + channel_dst_string + " = " + value + dot_mask + ";\n";
std::string line = "\t" + channel_dst_string + " = " + mask.apply_to(value) + ";\n";
if (last_line == line)
{
continue;
}
result += line;
last_line = line;
}
if (do_update_condition)
{
std::string cond_value = (dst ? channel_dst_string : value) + dot_mask;
std::string cond_value = mask.apply_to(dst ? channel_dst_string : value);
result += "\t" + update_condition.to_string() + dot_mask + " = " + cond_value + ";\n";
result += "\t" + mask.apply_to(update_condition.to_string()) + " = " + cond_value + ";\n";
}
}
if (!last_condition_group.empty())
result += "}\n\n";
result += "}\n";
}
return result;
}
template<opcode id, u32 flags>
static void nodest_instruction(decompiler* dec, const program_variable& arg0, const program_variable& arg1, const program_variable& arg2)
{
switch (id)
{
case opcode::LOOP:
dec->set_code_line(fmt::format("for (int i = %d; i < %d; i += %d)\n{",
dec->ucode.src1.init_counter, dec->ucode.src1.end_counter, dec->ucode.src1.increment), 0, 1);
dec->builder.add_code_block(dec->ucode.src2.end_offset >> 2, "}", -1, 0);
break;
case opcode::IFE:
dec->set_code_line(execution_condition(dec) + "\n{", 0, 1);
if (dec->ucode.src1.else_offset != dec->ucode.src2.end_offset)
dec->builder.add_code_block(dec->ucode.src1.else_offset >> 2, "}\nelse\n{", -1, 1);
dec->builder.add_code_block(dec->ucode.src2.end_offset >> 2, "}", -1, 0);
break;
case opcode::BRK:
{
dec->set_code_line(execution_condition(dec) + "break;");
}
break;
default:
//break;
throw std::runtime_error("unimplemented nodest instruction: " + instructions_names[(std::size_t)id]);
}
}
static std::string finalyze(decompiler *dec)
{
std::string result = "\nvoid main()\n{\n";
@@ -374,18 +499,12 @@ namespace rsx
bool is_need_declare;
};
struct source_info
const std::size_t color_source_registers[] =
{
std::size_t r_register;
std::size_t h_register;
};
const source_info color_source_registers[] =
{
{ 0, 0 },
{ 2, 4 },
{ 3, 6 },
{ 4, 8 }
{ 0 },
{ 2 },
{ 3 },
{ 4 }
};
program_variable color_variable{};
color_variable.type = program_variable_type::output;
@@ -394,7 +513,7 @@ namespace rsx
for (u32 i = 0; i < (u32)std::size(color_source_registers); ++i)
{
std::size_t color_register_index = dec->ctrl & 0x40 ? color_source_registers[i].r_register : color_source_registers[i].h_register;
std::size_t color_register_index = dec->ctrl & 0x40 ? color_source_registers[i] : color_source_registers[i] * 2;
std::string color_register = (dec->ctrl & 0x40 ? "R" : "H") + std::to_string(color_register_index);
if (dec->info.vars.exists(color_register))
{
@@ -1,5 +1,6 @@
#include "rsx_program_decompiler.h"
#include "fmt.h"
#include <cctype>
namespace rsx
{
@@ -82,9 +83,45 @@ namespace rsx
if (mask.empty())
return expr;
return expr + "." + mask;
return append_brackets_if_needed(expr) + "." + mask;
}
std::string mask_t::append_brackets_if_needed(const std::string& expr)
{
int opened_brackets = 0;
bool has_outside_brackets_op = false;
bool is_first_visible_char = false;
for (auto c : expr)
{
switch (c)
{
case '(': ++opened_brackets; break;
case ')': --opened_brackets; break;
case '-':
if (is_first_visible_char)
{
break;
}
case '+': case '*': case '/':
if (opened_brackets == 0)
{
has_outside_brackets_op = true;
}
break;
}
if (!is_first_visible_char && std::isgraph(c))
is_first_visible_char = false;
}
if (has_outside_brackets_op)
return "(" + expr + ")";
return expr;
};
std::string program_variable::to_string_impl() const
{
if (array_size)
@@ -29,7 +29,8 @@ namespace rsx
std::string to_string() const;
std::string to_string();
std::string apply_to(const std::string& std) const;
std::string apply_to(const std::string& expr) const;
static std::string append_brackets_if_needed(const std::string& expr);
};
@@ -210,6 +210,8 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="elf64.h" />
<ClInclude Include="endianness.h" />
<ClInclude Include="fmt.h" />
<ClInclude Include="rsx\rsx.h" />
<ClInclude Include="rsx\rsx_fragment_program.h" />
@@ -31,6 +31,8 @@
<Filter>rsx</Filter>
</ClInclude>
<ClInclude Include="fmt.h" />
<ClInclude Include="elf64.h" />
<ClInclude Include="endianness.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="rsx\rsx_program_decompiler.cpp">