t6 dowhile fixes

This commit is contained in:
xensik 2022-02-22 12:19:05 +01:00
parent dbde03cc24
commit b9ecd1052f
4 changed files with 68 additions and 26 deletions

View File

@ -579,15 +579,14 @@ void compiler::emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt)
if (stmt->test == ast::kind::expr_not)
{
emit_expr(stmt->test.as_not->rvalue);
emit_opcode(opcode::OP_JumpOnTrue, break_loc);
emit_opcode(opcode::OP_JumpOnFalse, begin_loc);
}
else
{
emit_expr(stmt->test);
emit_opcode(opcode::OP_JumpOnFalse, break_loc);
emit_opcode(opcode::OP_JumpOnTrue, begin_loc);
}
emit_opcode(opcode::OP_Jump, begin_loc);
insert_label(break_loc);
can_break_ = old_break;

View File

@ -669,9 +669,18 @@ void decompiler::decompile_instruction(const instruction::ptr& inst, bool last)
auto lvalue = ast::expr(std::move(stack_.top()));
stack_.pop();
loc = lvalue.as_node->loc();
auto e_not = ast::expr(std::make_unique<ast::expr_not>(loc, std::move(lvalue)));
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(e_not), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
if (inst->index > resolve_label(inst->data[0]))
{
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(lvalue), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
}
else
{
auto e_not = ast::expr(std::make_unique<ast::expr_not>(loc, std::move(lvalue)));
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(e_not), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
}
}
break;
case opcode::OP_JumpOnFalse:
@ -679,8 +688,18 @@ void decompiler::decompile_instruction(const instruction::ptr& inst, bool last)
auto lvalue = ast::expr(std::move(stack_.top()));
stack_.pop();
loc = lvalue.as_node->loc();
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(lvalue), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
if (inst->index > resolve_label(inst->data[0]))
{
auto e_not = ast::expr(std::make_unique<ast::expr_not>(loc, std::move(lvalue)));
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(e_not), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
}
else
{
auto expr = std::make_unique<ast::asm_jump_cond>(loc, std::move(lvalue), inst->data[0]);
func_->stmt->list.push_back(ast::stmt(std::move(expr)));
}
}
break;
case opcode::OP_JumpOnTrueExpr:
@ -1166,7 +1185,13 @@ void decompiler::decompile_instruction(const instruction::ptr& inst, bool last)
break;
case opcode::OP_ProfileStart:
case opcode::OP_ProfileStop:
throw decomp_error("unhandled opcode " + resolver::opcode_name(inst->opcode));
case opcode::OP_SafeDecTop:
{
auto node = std::make_unique<ast::expr_undefined>(loc);
stack_.push(std::move(node));
}
break;
case opcode::OP_Nop:
case opcode::OP_Abort:
case opcode::OP_Object:
@ -1309,19 +1334,23 @@ void decompiler::decompile_loops(const ast::stmt_list::ptr& stmt)
if (entry == ast::kind::asm_jump_cond)
{
auto j = (entry.as_cond->value == blocks_.back().loc_end) ? (stmt->list.size() - 1) : (find_location_index(stmt, entry.as_cond->value) - 1);
auto j = (entry.as_cond->value == blocks_.back().loc_end) ? (stmt->list.size()) : (find_location_index(stmt, entry.as_cond->value));
if (j < i)
{
decompile_dowhile(stmt, j, i);
i = 0;
continue;
}
j -= 1;
if (stmt->list.at(j) == ast::kind::asm_jump)
{
if (stmt->list.at(j).as_node->loc().begin.line < std::stol(stmt->list.at(j).as_jump->value.substr(4), 0, 16))
continue;
if (j == i + 1 && (stmt->list.at(j).as_jump->value != blocks_.back().loc_continue))
{
decompile_dowhile(stmt, i, j);
i = 0;
}
else if (stmt->list.at(i).loc().label() == stmt->list.at(j).as_jump->value)
if (stmt->list.at(i).loc().label() == stmt->list.at(j).as_jump->value)
{
decompile_loop(stmt, i, j);
i = 0;
@ -1613,12 +1642,11 @@ void decompiler::decompile_loop(const ast::stmt_list::ptr& stmt, std::uint32_t s
return;
}
auto ref = stmt->list.at(end).loc().label();
auto ref2 = stmt->list.at(start).loc().label();
if (find_location_reference(stmt, start, end, ref))
if (find_location_reference(stmt, start, end, ref2))
{
// continue is at jumpback, not post-expr
// continue is at begin, not post-expr
decompile_while(stmt, start, end);
return;
}
@ -1673,17 +1701,14 @@ void decompiler::decompile_while(const ast::stmt_list::ptr& stmt, std::uint32_t
void decompiler::decompile_dowhile(const ast::stmt_list::ptr& stmt, std::uint32_t begin, std::uint32_t end)
{
block blk;
blk.loc_break = stmt->list.at(begin).as_cond->value;
blk.loc_end = stmt->list.at(begin).loc().label();
blk.loc_continue = stmt->list.at(begin).loc().label();
blk.loc_break = last_location_index(stmt, end) ? blocks_.back().loc_end : stmt->list.at(end + 1).loc().label();
blk.loc_end = stmt->list.at(end).loc().label();
blk.loc_continue = stmt->list.at(end).loc().label();
auto test = std::move(stmt->list.at(begin).as_cond->expr);
begin = find_location_index(stmt, stmt->list.at(end).as_jump->value);
auto test = std::move(stmt->list.at(end).as_cond->expr);
auto loc = stmt->list.at(begin).loc();
end--;
stmt->list.erase(stmt->list.begin() + end); // remove 'test'
stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback'
stmt->list.erase(stmt->list.begin() + end); // remove 'test jump'
auto while_stmt = std::make_unique<ast::stmt_list>(loc);
@ -2014,6 +2039,19 @@ auto decompiler::lvalues_match(const ast::stmt_assign::ptr& stmt1, const ast::st
return false;
}
auto decompiler::resolve_label(const std::string& name) -> std::int32_t
{
for (const auto& entry : labels_)
{
if (entry.second == name)
{
return entry.first;
}
}
throw decomp_error("Couldn't resolve label address of '" + name + "'!");
}
void decompiler::process_thread(const ast::decl_thread::ptr& thread)
{
process_stmt_list(thread->stmt);

View File

@ -51,6 +51,7 @@ private:
auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::uint32_t;
auto last_location_index(const ast::stmt_list::ptr& stmt, std::uint32_t index) -> bool;
auto lvalues_match(const ast::stmt_assign::ptr& stmt1, const ast::stmt_assign::ptr& stmt2) -> bool;
auto resolve_label(const std::string& name) -> std::int32_t;
void process_thread(const ast::decl_thread::ptr& thread);
void process_stmt(const ast::stmt& stmt);
void process_stmt_list(const ast::stmt_list::ptr& stmt);

View File

@ -31,6 +31,7 @@ auto node::is_special_stmt() -> bool
case kind::stmt_if:
case kind::stmt_ifelse:
case kind::stmt_while:
case kind::stmt_dowhile:
case kind::stmt_for:
case kind::stmt_foreach:
case kind::stmt_switch:
@ -48,6 +49,7 @@ auto node::is_special_stmt_dev() -> bool
case kind::stmt_if:
case kind::stmt_ifelse:
case kind::stmt_while:
case kind::stmt_dowhile:
case kind::stmt_for:
case kind::stmt_foreach:
case kind::stmt_switch:
@ -64,6 +66,7 @@ auto node::is_special_stmt_noif() -> bool
case kind::stmt_waittill:
case kind::stmt_waittillmatch:
case kind::stmt_while:
case kind::stmt_dowhile:
case kind::stmt_for:
case kind::stmt_foreach:
case kind::stmt_switch:
@ -79,6 +82,7 @@ auto node::is_special_stmt_dev_noif() -> bool
{
case kind::stmt_dev:
case kind::stmt_while:
case kind::stmt_dowhile:
case kind::stmt_for:
case kind::stmt_foreach:
case kind::stmt_switch: