mirror of
https://github.com/open-goal/jak-project
synced 2026-08-21 23:00:45 -04:00
[decompiler] ASM Branching Support (#677)
* basic example working in geometry * before updating offline' * clean up * temp * progress
This commit is contained in:
@@ -299,6 +299,8 @@ std::unique_ptr<AtomicOp> make_asm_op(const Instruction& i0, int idx) {
|
||||
case InstructionKind::MULAS:
|
||||
case InstructionKind::MADDAS:
|
||||
case InstructionKind::MADDS:
|
||||
case InstructionKind::MSUBAS:
|
||||
case InstructionKind::MSUBS:
|
||||
case InstructionKind::ADDAS:
|
||||
|
||||
// Moves / Loads / Stores
|
||||
@@ -361,6 +363,14 @@ std::unique_ptr<AtomicOp> make_asm_op(const Instruction& i0, int idx) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_1_allow_asm(const Instruction& i0, int idx) {
|
||||
auto as_normal = convert_1(i0, idx, false);
|
||||
if (as_normal) {
|
||||
return as_normal;
|
||||
}
|
||||
return make_asm_op(i0, idx);
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
// Branch Helpers
|
||||
////////////////////////
|
||||
@@ -407,7 +417,11 @@ std::unique_ptr<AtomicOp> make_branch(const IR2_Condition& condition,
|
||||
if (branch_delay.is_known()) {
|
||||
return std::make_unique<BranchOp>(likely, condition, dest_label, branch_delay, my_idx);
|
||||
} else {
|
||||
auto delay_op = std::shared_ptr<AtomicOp>(convert_1(delay, my_idx, false));
|
||||
auto delay_op = std::shared_ptr<AtomicOp>(convert_1_allow_asm(delay, my_idx));
|
||||
if (!delay_op) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Failed to convert branch delay slot instruction for branch at {}", my_idx));
|
||||
}
|
||||
return std::make_unique<AsmBranchOp>(likely, condition, dest_label, delay_op, my_idx);
|
||||
}
|
||||
}
|
||||
@@ -421,6 +435,14 @@ std::unique_ptr<AtomicOp> make_branch_no_delay(const IR2_Condition& condition,
|
||||
return std::make_unique<BranchOp>(likely, condition, dest_label, delay, my_idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> make_asm_branch_no_delay(const IR2_Condition& condition,
|
||||
bool likely,
|
||||
int dest_label,
|
||||
int my_idx) {
|
||||
assert(likely);
|
||||
return std::make_unique<AsmBranchOp>(likely, condition, dest_label, nullptr, my_idx);
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// OP 1 Conversions
|
||||
//////////////////////
|
||||
@@ -880,6 +902,23 @@ std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx, bool hint_in
|
||||
// OP 2 Conversions
|
||||
//////////////////////
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_fp_branch_asm(const Instruction& i0,
|
||||
const Instruction& i1,
|
||||
IR2_Condition::Kind kind,
|
||||
int idx) {
|
||||
if (i1.kind == InstructionKind::BC1TL || i1.kind == InstructionKind::BC1FL) {
|
||||
IR2_Condition condition(kind, make_src_atom(i0.get_src(0).get_reg(), idx),
|
||||
make_src_atom(i0.get_src(1).get_reg(), idx));
|
||||
if (i1.kind == InstructionKind::BC1FL) {
|
||||
condition.invert();
|
||||
}
|
||||
// return make_branch(condition, i2, false, i1.get_src(0).get_label(), idx);
|
||||
return make_asm_branch_no_delay(condition, true, i1.get_src(0).get_label(), idx);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_division_2(const Instruction& i0,
|
||||
const Instruction& i1,
|
||||
int idx,
|
||||
@@ -1071,6 +1110,8 @@ std::unique_ptr<AtomicOp> convert_2(const Instruction& i0, const Instruction& i1
|
||||
return convert_slt_2(i0, i1, idx, true);
|
||||
case InstructionKind::SLTU:
|
||||
return convert_slt_2(i0, i1, idx, false);
|
||||
case InstructionKind::CLTS:
|
||||
return convert_fp_branch_asm(i0, i1, IR2_Condition::Kind::FLOAT_LESS_THAN, idx);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1605,6 +1646,98 @@ std::unique_ptr<AtomicOp> convert_6(const Instruction& i0,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool is_lwc(const Instruction& instr, int offset) {
|
||||
return instr.kind == InstructionKind::LWC1 && instr.get_src(0).is_imm(offset);
|
||||
}
|
||||
|
||||
// 9 instructions
|
||||
std::unique_ptr<AtomicOp> convert_vector3_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, 0(v1)
|
||||
if (!is_lwc(instrs[3], 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto t3 = instrs[3].get_dst(0).get_reg();
|
||||
|
||||
// lwc1 f4, 4(v1)
|
||||
if (!is_lwc(instrs[4], 4)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto t4 = instrs[4].get_dst(0).get_reg();
|
||||
|
||||
// lwc1 f5, 8(v1)
|
||||
if (!is_lwc(instrs[5], 8)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto t5 = instrs[5].get_dst(0).get_reg();
|
||||
|
||||
auto src0 = instrs[0].get_src(1).get_reg();
|
||||
auto src1 = instrs[3].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[4].get_src(1).get_reg() != src1) {
|
||||
return nullptr;
|
||||
}
|
||||
if (instrs[5].get_src(1).get_reg() != src1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// mula.s f0, f3
|
||||
if (instrs[6].kind != InstructionKind::MULAS || instrs[6].get_src(0).get_reg() != t0 ||
|
||||
instrs[6].get_src(1).get_reg() != t3) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// madda.s f1, f4
|
||||
if (instrs[7].kind != InstructionKind::MADDAS || instrs[7].get_src(0).get_reg() != t1 ||
|
||||
instrs[7].get_src(1).get_reg() != t4) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// madd.s f0, f2, f5
|
||||
if (instrs[8].kind != InstructionKind::MADDS || instrs[8].get_src(0).get_reg() != t2 ||
|
||||
instrs[8].get_src(1).get_reg() != t5) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto dst = instrs[8].get_dst(0).get_reg();
|
||||
|
||||
return std::make_unique<SetVarOp>(
|
||||
make_dst_var(dst, idx),
|
||||
SimpleExpression(SimpleExpression::Kind::VECTOR_3_DOT, make_src_atom(src0, idx),
|
||||
make_src_atom(src1, idx)),
|
||||
idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_9(const Instruction* instrs, int idx) {
|
||||
auto as_vector3_dot = convert_vector3_dot(instrs, idx);
|
||||
if (as_vector3_dot) {
|
||||
return as_vector3_dot;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
@@ -1637,7 +1770,15 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
warnings.warn_sq_lq();
|
||||
}
|
||||
|
||||
if (n_instr >= 6) {
|
||||
if (n_instr >= 9) {
|
||||
op = convert_9(&instr[0], op_idx);
|
||||
if (op) {
|
||||
converted = true;
|
||||
length = 9;
|
||||
}
|
||||
}
|
||||
|
||||
if (!converted && 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) {
|
||||
@@ -1702,7 +1843,8 @@ int convert_block_to_atomic_ops(int begin_idx,
|
||||
|
||||
if (!converted) {
|
||||
// failed!
|
||||
throw std::runtime_error("Failed to convert " + instr->to_string(labels));
|
||||
throw std::runtime_error(
|
||||
fmt::format("Failed to convert ({} instrs) {}\n", n_instr, instr->to_string(labels)));
|
||||
// lg::die("Failed to convert instruction {} to an atomic op",
|
||||
// instr->to_string(labels));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user