From b58d9ec65de95fcbc0b24bb6075159a8b5bb0913 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Wed, 1 Sep 2021 10:02:20 -0400 Subject: [PATCH] support vector 4 (#803) --- decompiler/IR2/AtomicOp.cpp | 3 + decompiler/IR2/AtomicOp.h | 1 + decompiler/IR2/AtomicOpTypeAnalysis.cpp | 1 + decompiler/IR2/Form.cpp | 2 + decompiler/IR2/Form.h | 11 +- decompiler/IR2/FormExpressionAnalysis.cpp | 26 ++-- decompiler/IR2/IR2_common.h | 1 + decompiler/analysis/atomic_op_builder.cpp | 122 +++++++++++++++++- .../reference/engine/math/vector-h_REF.gc | 21 +-- 9 files changed, 152 insertions(+), 36 deletions(-) diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index 2e50275f94..62ce19abc0 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -304,6 +304,8 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) { return "subu-s7"; case SimpleExpression::Kind::VECTOR_3_DOT: return "vec3dot"; + case SimpleExpression::Kind::VECTOR_4_DOT: + return "vec4dot"; default: assert(false); return {}; @@ -363,6 +365,7 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) { case SimpleExpression::Kind::SUBU_L32_S7: return 1; case SimpleExpression::Kind::VECTOR_3_DOT: + case SimpleExpression::Kind::VECTOR_4_DOT: return 2; default: assert(false); diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index debee3b134..1b1ad95036 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -235,6 +235,7 @@ class SimpleExpression { VECTOR_CROSS, SUBU_L32_S7, // use SUBU X, src0, s7 to check if lower 32-bits are s7. VECTOR_3_DOT, + VECTOR_4_DOT }; // how many arguments? diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index 93db17a1f2..d130c9aa1d 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -228,6 +228,7 @@ TP_Type SimpleExpression::get_type(const TypeState& input, case Kind::SUBU_L32_S7: return TP_Type::make_from_ts("int"); case Kind::VECTOR_3_DOT: + case Kind::VECTOR_4_DOT: return TP_Type::make_from_ts("float"); default: throw std::runtime_error("Simple expression cannot get_type: " + diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index c22360a62b..7d942cafd3 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -1828,6 +1828,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) { return "l32-false-check"; case FixedOperatorKind::VECTOR_3_DOT: return "vector-dot"; + case FixedOperatorKind::VECTOR_4_DOT: + return "vector4-dot"; case FixedOperatorKind::PROCESS_TO_PPOINTER: return "process->ppointer"; case FixedOperatorKind::PPOINTER_TO_HANDLE: diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 82d0de7527..ec41851fc3 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -224,11 +224,12 @@ class SimpleExpressionElement : public FormElement { FormStack& stack, std::vector* result, bool allow_side_effects); - void update_from_stack_vector_3_dot(const Env& env, - FormPool& pool, - FormStack& stack, - std::vector* result, - bool allow_side_effects); + void update_from_stack_vector_dot(FixedOperatorKind kind, + const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects); const SimpleExpression& expr() const { return m_expr; } diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 720867044e..6e683a2eee 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -1321,11 +1321,12 @@ void SimpleExpressionElement::update_from_stack_vector_float_product( result->push_back(new_form); } -void SimpleExpressionElement::update_from_stack_vector_3_dot(const Env& env, - FormPool& pool, - FormStack& stack, - std::vector* result, - bool allow_side_effects) { +void SimpleExpressionElement::update_from_stack_vector_dot(FixedOperatorKind kind, + const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { std::vector popped_args = pop_to_forms({m_expr.get_arg(0).var(), m_expr.get_arg(1).var()}, env, pool, stack, allow_side_effects); @@ -1337,8 +1338,7 @@ void SimpleExpressionElement::update_from_stack_vector_3_dot(const Env& env, } auto new_form = pool.alloc_element( - GenericOperator::make_fixed(FixedOperatorKind::VECTOR_3_DOT), - std::vector{popped_args.at(0), popped_args.at(1)}); + GenericOperator::make_fixed(kind), std::vector{popped_args.at(0), popped_args.at(1)}); result->push_back(new_form); } @@ -2116,7 +2116,12 @@ void SimpleExpressionElement::update_from_stack(const Env& env, update_from_stack_subu_l32_s7(env, pool, stack, result, allow_side_effects); break; case SimpleExpression::Kind::VECTOR_3_DOT: - update_from_stack_vector_3_dot(env, pool, stack, result, allow_side_effects); + update_from_stack_vector_dot(FixedOperatorKind::VECTOR_3_DOT, env, pool, stack, result, + allow_side_effects); + break; + case SimpleExpression::Kind::VECTOR_4_DOT: + update_from_stack_vector_dot(FixedOperatorKind::VECTOR_4_DOT, env, pool, stack, result, + allow_side_effects); break; default: throw std::runtime_error( @@ -4290,8 +4295,9 @@ void push_asm_srl_to_stack(const AsmOp* op, stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true, env.get_variable_type(*dst, true)); } else { - throw std::runtime_error(fmt::format("Got invalid bitfield manip for srl: {} type was {}", - src_var->to_string(env), arg0_type.print())); + throw std::runtime_error( + fmt::format("Got invalid bitfield manip for srl at op {}: {} type was {}", op->op_id(), + src_var->to_string(env), arg0_type.print())); } } } diff --git a/decompiler/IR2/IR2_common.h b/decompiler/IR2/IR2_common.h index 735f761df0..b584f74bee 100644 --- a/decompiler/IR2/IR2_common.h +++ b/decompiler/IR2/IR2_common.h @@ -164,6 +164,7 @@ enum class FixedOperatorKind { PPOINTER_TO_HANDLE, PROCESS_TO_HANDLE, PPOINTER_TO_PROCESS, + VECTOR_4_DOT, INVALID }; diff --git a/decompiler/analysis/atomic_op_builder.cpp b/decompiler/analysis/atomic_op_builder.cpp index b6f8ea42c2..63b81b90a4 100644 --- a/decompiler/analysis/atomic_op_builder.cpp +++ b/decompiler/analysis/atomic_op_builder.cpp @@ -1888,6 +1888,110 @@ std::unique_ptr convert_vector3_dot(const Instruction* instrs, int idx idx); } +// 12 instructions +std::unique_ptr convert_vector4_dot(const Instruction* instrs, int idx) { + // lwc1 f0, 0(a0) + if (!is_lwc(instrs[0], 0)) { + return nullptr; + } + auto t0 = instrs[0].get_dst(0).get_reg(); + + // lwc1 f1, 4(a0) + if (!is_lwc(instrs[1], 4)) { + return nullptr; + } + auto t1 = instrs[1].get_dst(0).get_reg(); + + // lwc1 f2, 8(a0) + if (!is_lwc(instrs[2], 8)) { + return nullptr; + } + auto t2 = instrs[2].get_dst(0).get_reg(); + + // lwc1 f3, 12(a0) + if (!is_lwc(instrs[3], 12)) { + return nullptr; + } + auto t3 = instrs[3].get_dst(0).get_reg(); + + // lwc1 f3, 0(v1) + if (!is_lwc(instrs[4], 0)) { + return nullptr; + } + auto t4 = instrs[4].get_dst(0).get_reg(); + + // lwc1 f5, 4(v1) + if (!is_lwc(instrs[5], 4)) { + return nullptr; + } + auto t5 = instrs[5].get_dst(0).get_reg(); + + // lwc1 f5, 8(v1) + if (!is_lwc(instrs[6], 8)) { + return nullptr; + } + auto t6 = instrs[6].get_dst(0).get_reg(); + + // lwc1 f5, 12(v1) + if (!is_lwc(instrs[7], 12)) { + return nullptr; + } + auto t7 = instrs[7].get_dst(0).get_reg(); + + auto src0 = instrs[0].get_src(1).get_reg(); + auto src1 = instrs[4].get_src(1).get_reg(); + if (instrs[1].get_src(1).get_reg() != src0) { + return nullptr; + } + if (instrs[2].get_src(1).get_reg() != src0) { + return nullptr; + } + if (instrs[3].get_src(1).get_reg() != src0) { + return nullptr; + } + if (instrs[5].get_src(1).get_reg() != src1) { + return nullptr; + } + if (instrs[6].get_src(1).get_reg() != src1) { + return nullptr; + } + if (instrs[7].get_src(1).get_reg() != src1) { + return nullptr; + } + + // mula.s f0, f4 + if (instrs[8].kind != InstructionKind::MULAS || instrs[8].get_src(0).get_reg() != t0 || + instrs[8].get_src(1).get_reg() != t4) { + return nullptr; + } + + // madda.s f1, f5 + if (instrs[9].kind != InstructionKind::MADDAS || instrs[9].get_src(0).get_reg() != t1 || + instrs[9].get_src(1).get_reg() != t5) { + return nullptr; + } + + // madda.s f2, f6 + if (instrs[10].kind != InstructionKind::MADDAS || instrs[10].get_src(0).get_reg() != t2 || + instrs[10].get_src(1).get_reg() != t6) { + return nullptr; + } + + // madd.s f0, f3, f7 + if (instrs[11].kind != InstructionKind::MADDS || instrs[11].get_src(0).get_reg() != t3 || + instrs[11].get_src(1).get_reg() != t7) { + return nullptr; + } + + auto dst = instrs[11].get_dst(0).get_reg(); + + return std::make_unique( + make_dst_var(dst, idx), + SimpleExpression(SimpleExpression::Kind::VECTOR_4_DOT, make_src_atom(src0, idx), + make_src_atom(src1, idx)), + idx); +} + std::unique_ptr convert_9(const Instruction* instrs, int idx) { auto as_vector3_dot = convert_vector3_dot(instrs, idx); if (as_vector3_dot) { @@ -1896,6 +2000,14 @@ std::unique_ptr convert_9(const Instruction* instrs, int idx) { return nullptr; } +std::unique_ptr convert_12(const Instruction* instrs, int idx) { + auto as_vector4_dot = convert_vector4_dot(instrs, idx); + if (as_vector4_dot) { + return as_vector4_dot; + } + return nullptr; +} + } // namespace /*! @@ -1929,7 +2041,15 @@ int convert_block_to_atomic_ops(int begin_idx, warnings.warn_sq_lq(); } - if (n_instr >= 9) { + if (!converted && n_instr >= 12) { + op = convert_12(&instr[0], op_idx); + if (op) { + converted = true; + length = 12; + } + } + + if (!converted && n_instr >= 9) { op = convert_9(&instr[0], op_idx); if (op) { converted = true; diff --git a/test/decompiler/reference/engine/math/vector-h_REF.gc b/test/decompiler/reference/engine/math/vector-h_REF.gc index f2f75da579..179bf1d461 100644 --- a/test/decompiler/reference/engine/math/vector-h_REF.gc +++ b/test/decompiler/reference/engine/math/vector-h_REF.gc @@ -826,27 +826,8 @@ ) ;; definition for function vector4-dot -;; WARN: Unsupported inline assembly instruction kind - [mula.s f0, f4] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f1, f5] -;; WARN: Unsupported inline assembly instruction kind - [madda.s f2, f6] -;; WARN: Unsupported inline assembly instruction kind - [madd.s f0, f3, f7] (defun vector4-dot ((arg0 vector) (arg1 vector)) - (local-vars (f0-1 float)) - (let ((f0-0 (-> arg0 x)) - (f1-0 (-> arg0 y)) - (f2-0 (-> arg0 z)) - (f3-0 (-> arg0 w)) - (f4-0 (-> arg1 x)) - (f5-0 (-> arg1 y)) - (f6-0 (-> arg1 z)) - (f7-0 (-> arg1 w)) - ) - (.mula.s f0-0 f4-0) - (.madda.s f1-0 f5-0) - (.madda.s f2-0 f6-0) - (.madd.s f0-1 f3-0 f7-0) - ) - f0-1 + (vector4-dot arg0 arg1) ) ;; definition for function vector4-dot-vu