[decompiler] clean up vector detection and add vector float product detection (#638)

* change

* recognize vector float product and update tests
This commit is contained in:
water111
2021-06-27 17:24:35 -04:00
committed by GitHub
parent bfb1fbe1fc
commit a6d5c4eda3
146 changed files with 1085 additions and 1653 deletions
+188 -1
View File
@@ -45,6 +45,10 @@ Register rsp() {
return make_gpr(Reg::SP);
}
Register make_vf(int idx) {
return Register(Reg::VF, idx);
}
/////////////////////////
// Variable Helpers
/////////////////////////
@@ -1393,6 +1397,100 @@ std::unique_ptr<AtomicOp> convert_4(const Instruction& i0,
// OP 5 Conversions
//////////////////////
std::unique_ptr<AtomicOp> convert_vector_plus(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
const Instruction& i3,
const Instruction& i4,
int idx) {
// vmove.w vf6, vf0
if (i0.kind != InstructionKind::VMOVE || i0.get_src(0).get_reg() != make_vf(0) ||
i0.get_dst(0).get_reg() != make_vf(6) || i0.cop2_dest != 1) {
return nullptr;
}
// lqc2 vf4, 0(a1) (src1)
if (i1.kind != InstructionKind::LQC2 || i1.get_dst(0).get_reg() != make_vf(4) ||
!i1.get_src(0).is_imm(0)) {
return nullptr;
}
Register src1 = i1.get_src(1).get_reg();
// lqc2 vf5, 0(a2) (src2)
if (i2.kind != InstructionKind::LQC2 || i2.get_dst(0).get_reg() != make_vf(5) ||
!i2.get_src(0).is_imm(0)) {
return nullptr;
}
Register src2 = i2.get_src(1).get_reg();
// vadd.xyz vf6, vf4, vf5
if (i3.kind != InstructionKind::VADD || i3.get_dst(0).get_reg() != make_vf(6) ||
i3.get_src(0).get_reg() != make_vf(4) || i3.get_src(1).get_reg() != make_vf(5) ||
i3.cop2_dest != 14) {
return nullptr;
}
// sqc2 vf6, 0(a0) (dst)
if (i4.kind != InstructionKind::SQC2 || i4.get_src(0).get_reg() != make_vf(6) ||
!i4.get_src(1).is_imm(0)) {
return nullptr;
}
Register dst = i4.get_src(2).get_reg();
return std::make_unique<SetVarOp>(
make_dst_var(dst, idx),
SimpleExpression(SimpleExpression::Kind::VECTOR_PLUS, make_src_atom(dst, idx),
make_src_atom(src1, idx), make_src_atom(src2, idx)),
idx);
}
std::unique_ptr<AtomicOp> convert_vector_minus(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
const Instruction& i3,
const Instruction& i4,
int idx) {
// lqc2 vf4, 0(a1) (src1)
if (i0.kind != InstructionKind::LQC2 || i0.get_dst(0).get_reg() != make_vf(4) ||
!i0.get_src(0).is_imm(0)) {
return nullptr;
}
Register src1 = i0.get_src(1).get_reg();
// lqc2 vf5, 0(a2) (src2)
if (i1.kind != InstructionKind::LQC2 || i1.get_dst(0).get_reg() != make_vf(5) ||
!i1.get_src(0).is_imm(0)) {
return nullptr;
}
Register src2 = i1.get_src(1).get_reg();
// vmove.w vf6, vf0
if (i2.kind != InstructionKind::VMOVE || i2.get_src(0).get_reg() != make_vf(0) ||
i2.get_dst(0).get_reg() != make_vf(6) || i2.cop2_dest != 1) {
return nullptr;
}
// vadd.xyz vf6, vf4, vf5
if (i3.kind != InstructionKind::VSUB || i3.get_dst(0).get_reg() != make_vf(6) ||
i3.get_src(0).get_reg() != make_vf(4) || i3.get_src(1).get_reg() != make_vf(5) ||
i3.cop2_dest != 14) {
return nullptr;
}
// sqc2 vf6, 0(a0) (dst)
if (i4.kind != InstructionKind::SQC2 || i4.get_src(0).get_reg() != make_vf(6) ||
!i4.get_src(1).is_imm(0)) {
return nullptr;
}
Register dst = i4.get_src(2).get_reg();
return std::make_unique<SetVarOp>(
make_dst_var(dst, idx),
SimpleExpression(SimpleExpression::Kind::VECTOR_MINUS, make_src_atom(dst, idx),
make_src_atom(src1, idx), make_src_atom(src2, idx)),
idx);
}
std::unique_ptr<AtomicOp> convert_5(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
@@ -1410,6 +1508,86 @@ std::unique_ptr<AtomicOp> convert_5(const Instruction& i0,
i3.get_src(0).is_reg(s6) && i4.kind == InstructionKind::MFLO1 && i4.get_dst(0).is_reg(s6)) {
return std::make_unique<SpecialOp>(SpecialOp::Kind::SUSPEND, idx);
}
auto as_vector_plus = convert_vector_plus(i0, i1, i2, i3, i4, idx);
if (as_vector_plus) {
return as_vector_plus;
}
auto as_vector_minus = convert_vector_minus(i0, i1, i2, i3, i4, idx);
if (as_vector_minus) {
return as_vector_minus;
}
return nullptr;
}
std::unique_ptr<AtomicOp> convert_vector_float_product(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
const Instruction& i3,
const Instruction& i4,
const Instruction& i5,
int idx) {
// lqc2 vf1, 0(vect_in)
if (i0.kind != InstructionKind::LQC2 || i0.get_dst(0).get_reg() != make_vf(1) ||
!i0.get_src(0).is_imm(0)) {
return nullptr;
}
Register vec_src = i0.get_src(1).get_reg();
// mfc1 gpr_temp, float_in
if (i1.kind != InstructionKind::MFC1) {
return nullptr;
}
Register gpr_temp = i1.get_dst(0).get_reg();
Register float_src = i1.get_src(0).get_reg();
// qmtc2.i vf2, gpr_temp
if (i2.kind != InstructionKind::QMTC2 || i2.get_dst(0).get_reg() != make_vf(2) ||
i2.get_src(0).get_reg() != gpr_temp) {
return nullptr;
}
// vaddx.w vf1, vf0, vf0
if (i3.kind != InstructionKind::VADD_BC || i3.get_dst(0).get_reg() != make_vf(1) ||
i3.get_src(0).get_reg() != make_vf(0) || i3.get_src(1).get_reg() != make_vf(0) ||
i3.cop2_bc != 0 || i3.cop2_dest != 1) {
return nullptr;
}
// vmulx.xyz vf1, vf1, vf2
if (i4.kind != InstructionKind::VMUL_BC || i4.get_dst(0).get_reg() != make_vf(1) ||
i4.get_src(0).get_reg() != make_vf(1) || i4.get_src(1).get_reg() != make_vf(2) ||
i4.cop2_dest != 14 || i4.cop2_bc != 0) {
return nullptr;
}
// sqc2 vf1, 0(gE)
if (i5.kind != InstructionKind::SQC2 || i5.get_src(0).get_reg() != make_vf(1) ||
!i5.get_src(1).is_imm(0)) {
return nullptr;
}
Register dst = i5.get_src(2).get_reg();
return std::make_unique<SetVarOp>(
make_dst_var(dst, idx),
SimpleExpression(SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT, make_src_atom(dst, idx),
make_src_atom(vec_src, idx), make_src_atom(float_src, idx)),
idx);
}
std::unique_ptr<AtomicOp> convert_6(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
const Instruction& i3,
const Instruction& i4,
const Instruction& i5,
int idx) {
auto as_vector_float_product = convert_vector_float_product(i0, i1, i2, i3, i4, i5, idx);
if (as_vector_float_product) {
return as_vector_float_product;
}
return nullptr;
}
@@ -1445,7 +1623,16 @@ int convert_block_to_atomic_ops(int begin_idx,
warnings.warn_sq_lq();
}
if (n_instr >= 5) {
if (n_instr >= 6) {
// try 6 instructions
op = convert_6(instr[0], instr[1], instr[2], instr[3], instr[4], instr[5], op_idx);
if (op) {
converted = true;
length = 6;
}
}
if (!converted && n_instr >= 5) {
// try 5 instructions
op = convert_5(instr[0], instr[1], instr[2], instr[3], instr[4], op_idx);
if (op) {