gl_shader_decompiler: Implement FMUL/FADD/FFMA immediate instructions.

This commit is contained in:
bunnei 2018-04-15 20:45:56 -04:00
parent 8d4899d6ea
commit 5a28dce9eb
2 changed files with 53 additions and 12 deletions

View file

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <cstring>
#include <map> #include <map>
#include <string> #include <string>
#include "common/bit_field.h" #include "common/bit_field.h"
@ -289,6 +290,7 @@ enum class SubOp : u64 {
Lg2 = 0x3, Lg2 = 0x3,
Rcp = 0x4, Rcp = 0x4,
Rsq = 0x5, Rsq = 0x5,
Min = 0x8,
}; };
union Instruction { union Instruction {
@ -307,11 +309,22 @@ union Instruction {
BitField<39, 8, Register> gpr39; BitField<39, 8, Register> gpr39;
union { union {
BitField<20, 19, u64> imm20;
BitField<45, 1, u64> negate_b; BitField<45, 1, u64> negate_b;
BitField<46, 1, u64> abs_a; BitField<46, 1, u64> abs_a;
BitField<48, 1, u64> negate_a; BitField<48, 1, u64> negate_a;
BitField<49, 1, u64> abs_b; BitField<49, 1, u64> abs_b;
BitField<50, 1, u64> abs_d; BitField<50, 1, u64> abs_d;
BitField<56, 1, u64> negate_imm;
float GetImm20() const {
float result{};
u32 imm{static_cast<u32>(imm20)};
imm <<= 12;
imm |= negate_imm ? 0x80000000 : 0;
std::memcpy(&result, &imm, sizeof(imm));
return result;
}
} alu; } alu;
union { union {
@ -319,6 +332,7 @@ union Instruction {
BitField<49, 1, u64> negate_c; BitField<49, 1, u64> negate_c;
} ffma; } ffma;
BitField<61, 1, u64> is_b_imm;
BitField<60, 1, u64> is_b_gpr; BitField<60, 1, u64> is_b_gpr;
BitField<59, 1, u64> is_c_gpr; BitField<59, 1, u64> is_c_gpr;

View file

@ -190,6 +190,11 @@ private:
} }
} }
/// Generates code representing an immediate value
static std::string GetImmediate(const Instruction& instr) {
return std::to_string(instr.alu.GetImm20());
}
/// Generates code representing a temporary (GPR) register. /// Generates code representing a temporary (GPR) register.
std::string GetRegister(const Register& reg, unsigned elem = 0) { std::string GetRegister(const Register& reg, unsigned elem = 0) {
if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) { if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) {
@ -269,24 +274,32 @@ private:
} }
std::string op_b = instr.alu.negate_b ? "-" : ""; std::string op_b = instr.alu.negate_b ? "-" : "";
if (instr.is_b_imm) {
op_b += GetImmediate(instr);
} else {
if (instr.is_b_gpr) { if (instr.is_b_gpr) {
op_b += GetRegister(instr.gpr20); op_b += GetRegister(instr.gpr20);
} else { } else {
op_b += GetUniform(instr.uniform); op_b += GetUniform(instr.uniform);
} }
}
if (instr.alu.abs_b) { if (instr.alu.abs_b) {
op_b = "abs(" + op_b + ")"; op_b = "abs(" + op_b + ")";
} }
switch (instr.opcode.EffectiveOpCode()) { switch (instr.opcode.EffectiveOpCode()) {
case OpCode::Id::FMUL_C: case OpCode::Id::FMUL_C:
case OpCode::Id::FMUL_R: { case OpCode::Id::FMUL_R:
SetDest(0, dest, op_a + " * " + op_b, 1, 1); case OpCode::Id::FMUL_IMM: {
SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d);
break; break;
} }
case OpCode::Id::FADD_C: case OpCode::Id::FADD_C:
case OpCode::Id::FADD_R: { case OpCode::Id::FADD_R:
SetDest(0, dest, op_a + " + " + op_b, 1, 1); case OpCode::Id::FADD_IMM: {
SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d);
break; break;
} }
case OpCode::Id::MUFU: { case OpCode::Id::MUFU: {
@ -316,16 +329,28 @@ private:
std::string dest = GetRegister(instr.gpr0); std::string dest = GetRegister(instr.gpr0);
std::string op_a = GetRegister(instr.gpr8); std::string op_a = GetRegister(instr.gpr8);
std::string op_b = instr.ffma.negate_b ? "-" : ""; std::string op_b = instr.ffma.negate_b ? "-" : "";
op_b += GetUniform(instr.uniform);
std::string op_c = instr.ffma.negate_c ? "-" : ""; std::string op_c = instr.ffma.negate_c ? "-" : "";
op_c += GetRegister(instr.gpr39);
switch (instr.opcode.EffectiveOpCode()) { switch (instr.opcode.EffectiveOpCode()) {
case OpCode::Id::FFMA_CR: { case OpCode::Id::FFMA_CR: {
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); op_b += GetUniform(instr.uniform);
op_c += GetRegister(instr.gpr39);
break;
}
case OpCode::Id::FFMA_RR: {
op_b += GetRegister(instr.gpr20);
op_c += GetRegister(instr.gpr39);
break;
}
case OpCode::Id::FFMA_RC: {
op_b += GetRegister(instr.gpr39);
op_c += GetUniform(instr.uniform);
break;
}
case OpCode::Id::FFMA_IMM: {
op_b += GetImmediate(instr);
op_c += GetRegister(instr.gpr39);
break; break;
} }
default: { default: {
@ -336,6 +361,8 @@ private:
break; break;
} }
} }
SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1);
break; break;
} }
case OpCode::Type::Memory: { case OpCode::Type::Memory: {