gl_shader_decompiler: Implement FMUL/FADD/FFMA immediate instructions.
This commit is contained in:
parent
8d4899d6ea
commit
5a28dce9eb
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
Reference in New Issue