mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 22:22:21 -04:00
[decompiler] Support accessing 128-bit bitfields (#514)
* support some 128-bit bitfield stuff * fix bug * support type stuff correctly
This commit is contained in:
@@ -43,7 +43,8 @@ InstructionParser::InstructionParser() {
|
||||
InstructionKind::BGTZ, InstructionKind::BLTZL, InstructionKind::BGTZL,
|
||||
InstructionKind::BGEZL, InstructionKind::MTC1, InstructionKind::MFC1,
|
||||
InstructionKind::MFLO, InstructionKind::MFHI, InstructionKind::MTLO1,
|
||||
InstructionKind::MFLO1, InstructionKind::SYNCL, InstructionKind::PCPYUD}) {
|
||||
InstructionKind::MFLO1, InstructionKind::SYNCL, InstructionKind::PCPYUD,
|
||||
InstructionKind::PEXTUW, InstructionKind::POR}) {
|
||||
auto& info = gOpcodeInfo[int(i)];
|
||||
if (info.defined) {
|
||||
m_opcode_name_lookup[info.name] = int(i);
|
||||
|
||||
@@ -289,7 +289,11 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
// this could be a bitfield access or a multiply.
|
||||
// we pick bitfield access if the parent is a bitfield.
|
||||
if (dynamic_cast<BitFieldType*>(dts.ts.lookup_type(arg0_type.typespec()))) {
|
||||
return TP_Type::make_from_left_shift_bitfield(arg0_type.typespec(), m_args[1].get_int());
|
||||
return TP_Type::make_from_left_shift_bitfield(arg0_type.typespec(), m_args[1].get_int(),
|
||||
false);
|
||||
} else if (arg0_type.kind == TP_Type::Kind::PCPYUD_BITFIELD) {
|
||||
return TP_Type::make_from_left_shift_bitfield(arg0_type.get_bitfield_type(),
|
||||
m_args[1].get_int(), true);
|
||||
} else {
|
||||
return TP_Type::make_from_product(1ull << m_args[1].get_int(), is_signed(dts, arg0_type));
|
||||
}
|
||||
@@ -307,6 +311,9 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
if (arg0_type.kind == TP_Type::Kind::LEFT_SHIFTED_BITFIELD && m_args[1].is_int()) {
|
||||
// second op in left/right shift combo
|
||||
int end_bit = 64 - arg0_type.get_left_shift();
|
||||
if (arg0_type.pcpyud()) {
|
||||
end_bit += 64;
|
||||
}
|
||||
|
||||
int size = 64 - m_args[1].get_int();
|
||||
int start_bit = end_bit - size;
|
||||
@@ -592,6 +599,35 @@ TypeState AsmOp::propagate_types_internal(const TypeState& input,
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_instr.kind == InstructionKind::PCPYUD) {
|
||||
if (m_src[1] && m_src[1]->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
assert(m_src[0]);
|
||||
auto& in_type = result.get(m_src[0]->reg());
|
||||
auto bf = dynamic_cast<BitFieldType*>(dts.ts.lookup_type(in_type.typespec()));
|
||||
if (bf) {
|
||||
assert(m_dst);
|
||||
result.get(m_dst->reg()) = TP_Type::make_from_pcpyud_bitfield(in_type.typespec());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pextuw t0, r0, gp
|
||||
if (m_instr.kind == InstructionKind::PEXTUW) {
|
||||
if (m_src[0] && m_src[0]->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
// sponge
|
||||
assert(m_src[1]);
|
||||
auto type = dts.ts.lookup_type(result.get(m_src[1]->reg()).typespec());
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
if (as_bitfield) {
|
||||
auto field = find_field(dts.ts, as_bitfield, 64, 32, true);
|
||||
assert(m_dst);
|
||||
result.get(m_dst->reg()) = TP_Type::make_from_ts(field.type());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dst.has_value()) {
|
||||
auto kind = m_dst->reg().get_kind();
|
||||
if (kind == Reg::FPR) {
|
||||
|
||||
@@ -1121,12 +1121,22 @@ void SimpleExpressionElement::update_from_stack_left_shift(const Env& env,
|
||||
} else {
|
||||
// try to turn this into a multiplication, if possible
|
||||
if (m_expr.get_arg(1).is_int()) {
|
||||
auto args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
|
||||
int sa = m_expr.get_arg(1).get_int();
|
||||
|
||||
auto as_ba = args.at(0)->try_as_element<BitfieldAccessElement>();
|
||||
if (as_ba) {
|
||||
BitfieldManip step(BitfieldManip::Kind::LEFT_SHIFT, m_expr.get_arg(1).get_int());
|
||||
auto other = as_ba->push_step(step, env.dts->ts, pool, env);
|
||||
assert(!other); // shouldn't be complete.
|
||||
result->push_back(as_ba);
|
||||
return;
|
||||
}
|
||||
|
||||
// somewhat arbitrary threshold to switch from multiplications to shift.
|
||||
if (sa < 10) {
|
||||
s64 multiplier = (s64(1) << sa);
|
||||
|
||||
auto args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::MULTIPLICATION), args.at(0),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
@@ -1134,6 +1144,33 @@ void SimpleExpressionElement::update_from_stack_left_shift(const Env& env,
|
||||
result->push_back(new_form);
|
||||
return;
|
||||
}
|
||||
|
||||
auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
auto arg0_u = is_uint_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
if (!arg0_i && !arg0_u) {
|
||||
auto bti = dynamic_cast<EnumType*>(env.dts->ts.lookup_type(arg0_type));
|
||||
if (bti) {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::SHL), args.at(0),
|
||||
cast_form(
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)),
|
||||
arg0_type, pool, env));
|
||||
result->push_back(new_form);
|
||||
} else {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::SHL),
|
||||
pool.alloc_single_element_form<CastElement>(nullptr, TypeSpec("int"), args.at(0)),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
|
||||
result->push_back(new_form);
|
||||
}
|
||||
} else {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::SHL), args.at(0),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
|
||||
result->push_back(new_form);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
update_from_stack_copy_first_int_2(env, FixedOperatorKind::SHL, pool, stack, result,
|
||||
@@ -1226,22 +1263,52 @@ void SimpleExpressionElement::update_from_stack_right_shift_arith(const Env& env
|
||||
assert(other); // should be a high field.
|
||||
result->push_back(other);
|
||||
} else {
|
||||
if (m_expr.get_arg(1).is_int() && m_expr.get_arg(1).get_int() < 10) {
|
||||
auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
auto arg =
|
||||
pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
int sa = m_expr.get_arg(1).get_int();
|
||||
if (m_expr.get_arg(1).is_int()) {
|
||||
if (m_expr.get_arg(1).get_int() < 10) {
|
||||
auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
auto arg =
|
||||
pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
int sa = m_expr.get_arg(1).get_int();
|
||||
|
||||
if (!arg0_i) {
|
||||
arg = cast_form(arg, TypeSpec("int"), pool, env);
|
||||
if (!arg0_i) {
|
||||
arg = cast_form(arg, TypeSpec("int"), pool, env);
|
||||
}
|
||||
s64 multiplier = (s64(1) << sa);
|
||||
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION), arg,
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(multiplier)));
|
||||
result->push_back(new_form);
|
||||
return;
|
||||
}
|
||||
|
||||
auto arg0_i = is_int_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
auto arg0_u = is_uint_type(env, m_my_idx, m_expr.get_arg(0).var());
|
||||
auto args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
|
||||
|
||||
auto as_ba = args.at(0)->try_as_element<BitfieldAccessElement>();
|
||||
if (as_ba) {
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_ARITH, m_expr.get_arg(1).get_int());
|
||||
auto other = as_ba->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should be a high field.
|
||||
result->push_back(other);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arg0_i && !arg0_u) {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::SAR),
|
||||
pool.alloc_single_element_form<CastElement>(nullptr, TypeSpec("int"), args.at(0)),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
|
||||
result->push_back(new_form);
|
||||
} else {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::SAR), args.at(0),
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
|
||||
result->push_back(new_form);
|
||||
}
|
||||
s64 multiplier = (s64(1) << sa);
|
||||
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(FixedOperatorKind::DIVISION), arg,
|
||||
pool.alloc_single_element_form<SimpleAtomElement>(
|
||||
nullptr, SimpleAtom::make_int_constant(multiplier)));
|
||||
result->push_back(new_form);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2728,7 +2795,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||
namespace {
|
||||
|
||||
void push_asm_srl_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
FormElement* /*form_elt*/,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack) {
|
||||
@@ -2754,6 +2821,123 @@ void push_asm_srl_to_stack(const AsmOp* op,
|
||||
assert(other); // should be a high field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
// stack.push_form_element(form_elt, true);
|
||||
auto src_var = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto as_ba = src_var->try_as_element<BitfieldAccessElement>();
|
||||
if (as_ba) {
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL_32BIT, integer);
|
||||
auto other = as_ba->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should immediately get a field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
throw std::runtime_error("Got invalid bitfield manip for srl");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push_asm_sllv_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack) {
|
||||
auto var = op->src(0);
|
||||
assert(var.has_value());
|
||||
|
||||
auto dst = op->dst();
|
||||
assert(dst.has_value());
|
||||
|
||||
auto sav = op->src(1);
|
||||
assert(sav.has_value());
|
||||
|
||||
auto arg0_type = env.get_variable_type(*var, true);
|
||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
if (sav->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
if (bitfield_info) {
|
||||
auto base = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::SLLV_SEXT, 0);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should immediately get a field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
auto src_var = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto as_ba = src_var->try_as_element<BitfieldAccessElement>();
|
||||
if (as_ba) {
|
||||
BitfieldManip step(BitfieldManip::Kind::SLLV_SEXT, 0);
|
||||
auto other = as_ba->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should immediately get a field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
throw std::runtime_error("Got invalid bitfield manip for sllv");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stack.push_form_element(form_elt, true);
|
||||
}
|
||||
}
|
||||
|
||||
void push_asm_pcpyud_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack) {
|
||||
// pcpyud v1, gp, r0 for example.
|
||||
|
||||
auto var = op->src(0);
|
||||
assert(var.has_value());
|
||||
|
||||
auto dst = op->dst();
|
||||
assert(dst.has_value());
|
||||
|
||||
auto possible_r0 = op->src(1);
|
||||
assert(possible_r0.has_value());
|
||||
|
||||
auto arg0_type = env.get_variable_type(*var, true);
|
||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
if (bitfield_info && possible_r0->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
auto base = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
read_elt->push_pcpyud();
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, read_elt), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
stack.push_form_element(form_elt, true);
|
||||
}
|
||||
}
|
||||
|
||||
void push_asm_pextuw_to_stack(const AsmOp* op,
|
||||
FormElement* form_elt,
|
||||
const Env& env,
|
||||
FormPool& pool,
|
||||
FormStack& stack) {
|
||||
// (.pextuw t0-0 r0-0 obj)
|
||||
|
||||
auto var = op->src(1);
|
||||
assert(var.has_value());
|
||||
|
||||
auto dst = op->dst();
|
||||
assert(dst.has_value());
|
||||
|
||||
auto possible_r0 = op->src(0);
|
||||
assert(possible_r0.has_value());
|
||||
|
||||
auto arg0_type = env.get_variable_type(*var, true);
|
||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||
if (bitfield_info && possible_r0->reg() == Register(Reg::GPR, Reg::R0)) {
|
||||
auto base = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::PEXTUW, 0);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should immediately get a field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
} else {
|
||||
stack.push_form_element(form_elt, true);
|
||||
}
|
||||
@@ -2768,6 +2952,15 @@ void push_asm_to_stack(const AsmOp* op,
|
||||
case InstructionKind::SRL:
|
||||
push_asm_srl_to_stack(op, form_elt, env, pool, stack);
|
||||
break;
|
||||
case InstructionKind::SLLV:
|
||||
push_asm_sllv_to_stack(op, form_elt, env, pool, stack);
|
||||
break;
|
||||
case InstructionKind::PCPYUD:
|
||||
push_asm_pcpyud_to_stack(op, form_elt, env, pool, stack);
|
||||
break;
|
||||
case InstructionKind::PEXTUW:
|
||||
push_asm_pextuw_to_stack(op, form_elt, env, pool, stack);
|
||||
break;
|
||||
default:
|
||||
stack.push_form_element(form_elt, true);
|
||||
break;
|
||||
|
||||
@@ -171,7 +171,9 @@ const BitField& find_field(const TypeSystem& ts,
|
||||
std::optional<bool> looking_for_unsigned) {
|
||||
for (auto& field : type->fields()) {
|
||||
if (field.size() == size && field.offset() == start_bit) {
|
||||
bool is_int = ts.tc(TypeSpec("integer"), field.type());
|
||||
// the GOAL compiler sign extended floats.
|
||||
bool is_int =
|
||||
ts.tc(TypeSpec("integer"), field.type()) || ts.tc(TypeSpec("float"), field.type());
|
||||
bool is_uint = ts.tc(TypeSpec("uinteger"), field.type());
|
||||
// allow sign match, or unsigned+not a number.
|
||||
|
||||
@@ -182,6 +184,12 @@ const BitField& find_field(const TypeSystem& ts,
|
||||
// matched!
|
||||
return field;
|
||||
}
|
||||
|
||||
// this is a hack to work around bad code where extracting the (pointer process)
|
||||
// would sign extend the address.
|
||||
if (!is_int && !is_uint && type->get_name() == "handle") {
|
||||
return field;
|
||||
}
|
||||
} else {
|
||||
return field;
|
||||
}
|
||||
@@ -286,6 +294,13 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||
|
||||
} // namespace
|
||||
|
||||
void BitfieldAccessElement::push_pcpyud() {
|
||||
if (!m_steps.empty()) {
|
||||
throw std::runtime_error("Unexpected pcpyud!");
|
||||
}
|
||||
m_got_pcpyud = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a step to the bitfield access. If this completes the access, returns a form representing the
|
||||
* access
|
||||
@@ -294,6 +309,8 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
const TypeSystem& ts,
|
||||
FormPool& pool,
|
||||
const Env& env) {
|
||||
int pcpyud_offset = m_got_pcpyud ? 64 : 0;
|
||||
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LEFT_SHIFT) {
|
||||
// for left/right shift combo to get a field.
|
||||
m_steps.push_back(step);
|
||||
@@ -305,7 +322,38 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
bool is_unsigned = step.right_shift_unsigned();
|
||||
int shift_size = step.get_shift_start_bit();
|
||||
int size = shift_size - step.amount;
|
||||
int start_bit = shift_size - size;
|
||||
int start_bit = pcpyud_offset + shift_size - size;
|
||||
auto type = ts.lookup_type(m_type);
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
auto field = find_field(ts, as_bitfield, start_bit, size, is_unsigned);
|
||||
auto result =
|
||||
pool.alloc_element<DerefElement>(m_base, false, DerefToken::make_field_name(field.name()));
|
||||
result->inline_nested();
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::SLLV_SEXT) {
|
||||
bool is_unsigned = false;
|
||||
int size = 32;
|
||||
int start_bit = 0 + pcpyud_offset;
|
||||
auto type = ts.lookup_type(m_type);
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
auto field = find_field(ts, as_bitfield, start_bit, size, is_unsigned);
|
||||
auto result =
|
||||
pool.alloc_element<DerefElement>(m_base, false, DerefToken::make_field_name(field.name()));
|
||||
result->inline_nested();
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::PEXTUW) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud PEXTUW sequence in bitfield");
|
||||
}
|
||||
bool is_unsigned = true;
|
||||
int size = 32;
|
||||
int start_bit = 64;
|
||||
auto type = ts.lookup_type(m_type);
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
@@ -318,7 +366,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LEFT_SHIFT) {
|
||||
// second op in left/right shift combo
|
||||
int end_bit = 64 - m_steps.at(0).amount;
|
||||
int end_bit = pcpyud_offset + 64 - m_steps.at(0).amount;
|
||||
if (!step.is_right_shift()) {
|
||||
throw std::runtime_error("Unexpected step 1");
|
||||
}
|
||||
@@ -342,12 +390,18 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
|
||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) {
|
||||
// and with mask
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGAND_WITH_CONSTANT_INT sequence in bitfield");
|
||||
}
|
||||
m_steps.push_back(step);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||
step.kind == BitfieldManip::Kind::NONZERO_COMPARE) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud NONZERO_COMPARE sequence in bitfield");
|
||||
}
|
||||
auto type = ts.lookup_type(m_type);
|
||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||
assert(as_bitfield);
|
||||
@@ -364,6 +418,9 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_CONSTANT_INT sequence in bitfield");
|
||||
}
|
||||
// this is setting a bitfield to a constant.
|
||||
// first, let's check that the mask is used properly:
|
||||
u64 mask = m_steps.at(0).amount;
|
||||
@@ -399,6 +456,9 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||
|
||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_FORM) {
|
||||
if (m_got_pcpyud) {
|
||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_FORM sequence in bitfield");
|
||||
}
|
||||
// this is setting a bitfield to a variable
|
||||
u64 mask = m_steps.at(0).amount;
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ struct BitfieldManip {
|
||||
LOGIOR_WITH_FORM,
|
||||
LOGAND_WITH_FORM,
|
||||
NONZERO_COMPARE,
|
||||
SLLV_SEXT, // sllv x, y, r0
|
||||
PEXTUW,
|
||||
INVALID
|
||||
} kind = Kind::INVALID;
|
||||
s64 amount = -1;
|
||||
@@ -72,6 +74,10 @@ struct BitfieldManip {
|
||||
return "logand-form";
|
||||
case Kind::NONZERO_COMPARE:
|
||||
return "nonzero-compare";
|
||||
case Kind::SLLV_SEXT:
|
||||
return "sllv-sext";
|
||||
case Kind::PEXTUW:
|
||||
return "pextuw";
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
assert(false);
|
||||
@@ -94,8 +100,10 @@ class BitfieldAccessElement : public FormElement {
|
||||
const TypeSystem& ts,
|
||||
FormPool& pool,
|
||||
const Env& env);
|
||||
void push_pcpyud();
|
||||
|
||||
private:
|
||||
bool m_got_pcpyud = false;
|
||||
Form* m_base = nullptr;
|
||||
TypeSpec m_type;
|
||||
std::vector<BitfieldManip> m_steps;
|
||||
|
||||
@@ -215,7 +215,6 @@ std::unique_ptr<AtomicOp> make_standard_store(const Instruction& i0,
|
||||
|
||||
std::unique_ptr<AtomicOp> make_asm_op(const Instruction& i0, int idx) {
|
||||
switch (i0.kind) {
|
||||
case InstructionKind::POR:
|
||||
case InstructionKind::SLLV: // goal will use dsllv
|
||||
case InstructionKind::SLL: // goal will use dsll
|
||||
case InstructionKind::PCPYUD:
|
||||
@@ -442,6 +441,14 @@ std::unique_ptr<AtomicOp> convert_or_1(const Instruction& i0, int idx) {
|
||||
return std::make_unique<SetVarOp>(dest, src, idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_por_1(const Instruction& i0, int idx) {
|
||||
if (is_gpr_3(i0, InstructionKind::POR, {}, {}, rr0())) {
|
||||
return std::make_unique<SetVarOp>(make_dst_var(i0, idx),
|
||||
make_src_atom(i0.get_src(0).get_reg(), idx).as_expr(), idx);
|
||||
}
|
||||
return std::make_unique<AsmOp>(i0, idx);
|
||||
}
|
||||
|
||||
std::unique_ptr<AtomicOp> convert_ori_1(const Instruction& i0, int idx) {
|
||||
auto dest = make_dst_var(i0, idx);
|
||||
SimpleExpression src;
|
||||
@@ -713,6 +720,8 @@ std::unique_ptr<AtomicOp> convert_1(const Instruction& i0, int idx, bool hint_in
|
||||
switch (i0.kind) {
|
||||
case InstructionKind::OR:
|
||||
return convert_or_1(i0, idx);
|
||||
case InstructionKind::POR:
|
||||
return convert_por_1(i0, idx);
|
||||
case InstructionKind::ORI:
|
||||
return convert_ori_1(i0, idx);
|
||||
case InstructionKind::AND:
|
||||
|
||||
@@ -381,15 +381,12 @@
|
||||
],
|
||||
|
||||
// RES
|
||||
"(method 4 res-tag)": [[12, "a0", "type"]],
|
||||
"(method 19 res-lump)": [
|
||||
[46, "t2", "(pointer uint64)"],
|
||||
[100, "t3", "(pointer uint64)"],
|
||||
[184, "t5", "(pointer uint64)"],
|
||||
[64, "t6", "(pointer uint64)"]
|
||||
],
|
||||
"(method 13 res-lump)": [[6, "a0", "res-tag"]],
|
||||
"(method 14 res-lump)": [[2, "a0", "res-tag"]],
|
||||
|
||||
// SHADOW-CPU-H
|
||||
"(method 10 shadow-control)": [[1, "v1", "int"]],
|
||||
|
||||
@@ -60,7 +60,13 @@ std::string TP_Type::print() const {
|
||||
case Kind::NON_VIRTUAL_METHOD:
|
||||
return fmt::format("<method {}>", m_ts.print());
|
||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||
return fmt::format("(<{}> << {})", m_ts.print(), m_int);
|
||||
if (m_pcpyud) {
|
||||
return fmt::format("(<{}> << {}) :u", m_ts.print(), m_int);
|
||||
} else {
|
||||
return fmt::format("(<{}> << {})", m_ts.print(), m_int);
|
||||
}
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return fmt::format("<pcpyud {}>", m_ts.print());
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
assert(false);
|
||||
@@ -108,7 +114,9 @@ bool TP_Type::operator==(const TP_Type& other) const {
|
||||
return m_int == other.m_int && m_ts == other.m_ts &&
|
||||
m_extra_multiplier == other.m_extra_multiplier;
|
||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||
return m_int == other.m_int && m_ts == other.m_ts;
|
||||
return m_int == other.m_int && m_ts == other.m_ts && m_pcpyud == other.m_pcpyud;
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
assert(false);
|
||||
@@ -163,6 +171,8 @@ TypeSpec TP_Type::typespec() const {
|
||||
return m_ts;
|
||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||
return TypeSpec("int"); // ideally this is never used.
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return TypeSpec("int");
|
||||
case Kind::INVALID:
|
||||
default:
|
||||
assert(false);
|
||||
|
||||
@@ -32,6 +32,7 @@ class TP_Type {
|
||||
DYNAMIC_METHOD_ACCESS, // partial access into a
|
||||
VIRTUAL_METHOD,
|
||||
NON_VIRTUAL_METHOD,
|
||||
PCPYUD_BITFIELD,
|
||||
LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant)
|
||||
INVALID
|
||||
} kind = Kind::UNINITIALIZED;
|
||||
@@ -59,6 +60,7 @@ class TP_Type {
|
||||
case Kind::VIRTUAL_METHOD:
|
||||
case Kind::NON_VIRTUAL_METHOD:
|
||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||
case Kind::PCPYUD_BITFIELD:
|
||||
return false;
|
||||
case Kind::UNINITIALIZED:
|
||||
case Kind::OBJECT_NEW_METHOD:
|
||||
@@ -211,11 +213,20 @@ class TP_Type {
|
||||
return result;
|
||||
}
|
||||
|
||||
static TP_Type make_from_left_shift_bitfield(const TypeSpec& ts, int amount) {
|
||||
static TP_Type make_from_left_shift_bitfield(const TypeSpec& ts, int amount, bool pcpyud) {
|
||||
TP_Type result;
|
||||
result.kind = Kind::LEFT_SHIFTED_BITFIELD;
|
||||
result.m_ts = ts;
|
||||
result.m_int = amount;
|
||||
result.m_pcpyud = pcpyud;
|
||||
return result;
|
||||
}
|
||||
|
||||
static TP_Type make_from_pcpyud_bitfield(const TypeSpec& ts) {
|
||||
TP_Type result;
|
||||
result.kind = Kind::PCPYUD_BITFIELD;
|
||||
result.m_ts = ts;
|
||||
result.m_pcpyud = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -265,14 +276,23 @@ class TP_Type {
|
||||
}
|
||||
|
||||
const TypeSpec& get_bitfield_type() const {
|
||||
assert(kind == Kind::LEFT_SHIFTED_BITFIELD);
|
||||
assert(kind == Kind::LEFT_SHIFTED_BITFIELD || kind == Kind::PCPYUD_BITFIELD);
|
||||
return m_ts;
|
||||
}
|
||||
|
||||
bool pcpyud() const {
|
||||
if (kind == Kind::LEFT_SHIFTED_BITFIELD) {
|
||||
return m_pcpyud;
|
||||
}
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
TypeSpec m_ts;
|
||||
std::string m_str;
|
||||
int64_t m_int = 0;
|
||||
bool m_pcpyud = false; // have we extracted the top doubleword of a bitfield?
|
||||
|
||||
int64_t m_extra_multiplier = 0;
|
||||
};
|
||||
|
||||
@@ -767,160 +767,31 @@
|
||||
|
||||
;; definition for method 3 of type gif-tag
|
||||
;; INFO: Return type mismatch object vs gif-tag.
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por gp, a0, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por a2, gp, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [srl a2, v1, 28]
|
||||
(defmethod inspect gif-tag ((obj gif-tag))
|
||||
(local-vars
|
||||
(r0-0 none)
|
||||
(v1-6 uint128)
|
||||
(v1-8 uint128)
|
||||
(v1-10 uint128)
|
||||
(v1-12 uint128)
|
||||
(v1-14 uint128)
|
||||
(v1-16 uint128)
|
||||
(v1-18 uint128)
|
||||
(v1-20 uint128)
|
||||
(v1-21 uint128)
|
||||
(v1-23 uint128)
|
||||
(v1-25 uint128)
|
||||
(v1-27 uint128)
|
||||
(v1-29 uint128)
|
||||
(v1-31 uint128)
|
||||
(v1-33 uint128)
|
||||
(v1-35 uint128)
|
||||
(a2-0 uint128)
|
||||
(a2-15 uint128)
|
||||
(gp-0 uint128)
|
||||
)
|
||||
(.por gp-0 obj r0-0)
|
||||
(let ((t9-0 format)
|
||||
(a0-1 #t)
|
||||
(a1-0 "[~8x] gif-tag~%")
|
||||
)
|
||||
(.por a2-0 gp-0 r0-0)
|
||||
(t9-0 a0-1 a1-0 a2-0)
|
||||
)
|
||||
(format #t "~Tnloop: ~4d~%" (shr (shl (the-as int gp-0) 49) 49))
|
||||
(format #t "~Teop : ~4d~%" (shr (shl (the-as int gp-0) 48) 63))
|
||||
(format #t "~Tid : ~4d~%" (shr (shl (the-as int gp-0) 18) 50))
|
||||
(format #t "~Tpre : ~4d~%" (shr (shl (the-as int gp-0) 17) 63))
|
||||
(format #t "~Tprim : ~4d~%" (shr (* gp-0 64) 53))
|
||||
(format #t "~Tflg : ~4d~%" (shr (* gp-0 16) 62))
|
||||
(format #t "~Tnreg : ~4d~%" (shr (the-as int gp-0) 60))
|
||||
(let ((t9-8 format)
|
||||
(a0-9 #t)
|
||||
(a1-8 "~Tregs0 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-6 gp-0 r0-0)
|
||||
(t9-8 a0-9 a1-8 (shr (shl (the-as int v1-6) 60) 60))
|
||||
)
|
||||
(let ((t9-9 format)
|
||||
(a0-10 #t)
|
||||
(a1-9 "~Tregs1 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-8 gp-0 r0-0)
|
||||
(t9-9 a0-10 a1-9 (shr (shl (the-as int v1-8) 56) 60))
|
||||
)
|
||||
(let ((t9-10 format)
|
||||
(a0-11 #t)
|
||||
(a1-10 "~Tregs2 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-10 gp-0 r0-0)
|
||||
(t9-10 a0-11 a1-10 (shr (shl (the-as int v1-10) 52) 60))
|
||||
)
|
||||
(let ((t9-11 format)
|
||||
(a0-12 #t)
|
||||
(a1-11 "~Tregs3 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-12 gp-0 r0-0)
|
||||
(t9-11 a0-12 a1-11 (shr (shl (the-as int v1-12) 48) 60))
|
||||
)
|
||||
(let ((t9-12 format)
|
||||
(a0-13 #t)
|
||||
(a1-12 "~Tregs4 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-14 gp-0 r0-0)
|
||||
(t9-12 a0-13 a1-12 (shr (shl (the-as int v1-14) 44) 60))
|
||||
)
|
||||
(let ((t9-13 format)
|
||||
(a0-14 #t)
|
||||
(a1-13 "~Tregs5 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-16 gp-0 r0-0)
|
||||
(t9-13 a0-14 a1-13 (shr (shl (the-as int v1-16) 40) 60))
|
||||
)
|
||||
(let ((t9-14 format)
|
||||
(a0-15 #t)
|
||||
(a1-14 "~Tregs6 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-18 gp-0 r0-0)
|
||||
(t9-14 a0-15 a1-14 (shr (shl (the-as int v1-18) 36) 60))
|
||||
)
|
||||
(let ((t9-15 format)
|
||||
(a0-16 #t)
|
||||
(a1-15 "~Tregs7 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-20 gp-0 r0-0)
|
||||
(.srl a2-15 v1-20 28)
|
||||
(t9-15 a0-16 a1-15 a2-15)
|
||||
)
|
||||
(let ((t9-16 format)
|
||||
(a0-17 #t)
|
||||
(a1-16 "~Tregs8 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-21 gp-0 r0-0)
|
||||
(t9-16 a0-17 a1-16 (shr (shl (the-as int v1-21) 28) 60))
|
||||
)
|
||||
(let ((t9-17 format)
|
||||
(a0-18 #t)
|
||||
(a1-17 "~Tregs9 : ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-23 gp-0 r0-0)
|
||||
(t9-17 a0-18 a1-17 (shr (shl (the-as int v1-23) 24) 60))
|
||||
)
|
||||
(let ((t9-18 format)
|
||||
(a0-19 #t)
|
||||
(a1-18 "~Tregs10: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-25 gp-0 r0-0)
|
||||
(t9-18 a0-19 a1-18 (shr (shl (the-as int v1-25) 20) 60))
|
||||
)
|
||||
(let ((t9-19 format)
|
||||
(a0-20 #t)
|
||||
(a1-19 "~Tregs11: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-27 gp-0 r0-0)
|
||||
(t9-19 a0-20 a1-19 (shr (shl (the-as int v1-27) 16) 60))
|
||||
)
|
||||
(let ((t9-20 format)
|
||||
(a0-21 #t)
|
||||
(a1-20 "~Tregs12: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-29 gp-0 r0-0)
|
||||
(t9-20 a0-21 a1-20 (shr (shl (the-as int v1-29) 12) 60))
|
||||
)
|
||||
(let ((t9-21 format)
|
||||
(a0-22 #t)
|
||||
(a1-21 "~Tregs13: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-31 gp-0 r0-0)
|
||||
(t9-21 a0-22 a1-21 (shr (* v1-31 256) 60))
|
||||
)
|
||||
(let ((t9-22 format)
|
||||
(a0-23 #t)
|
||||
(a1-22 "~Tregs14: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-33 gp-0 r0-0)
|
||||
(t9-22 a0-23 a1-22 (shr (* v1-33 16) 60))
|
||||
)
|
||||
(let ((t9-23 format)
|
||||
(a0-24 #t)
|
||||
(a1-23 "~Tregs15: ~4d~%")
|
||||
)
|
||||
(.pcpyud v1-35 gp-0 r0-0)
|
||||
(the-as gif-tag (t9-23 a0-24 a1-23 (shr (the-as int v1-35) 60)))
|
||||
)
|
||||
(format #t "[~8x] gif-tag~%" obj)
|
||||
(format #t "~Tnloop: ~4d~%" (-> obj nloop))
|
||||
(format #t "~Teop : ~4d~%" (-> obj eop))
|
||||
(format #t "~Tid : ~4d~%" (-> obj id))
|
||||
(format #t "~Tpre : ~4d~%" (-> obj pre))
|
||||
(format #t "~Tprim : ~4d~%" (-> obj prim))
|
||||
(format #t "~Tflg : ~4d~%" (-> obj flg))
|
||||
(format #t "~Tnreg : ~4d~%" (-> obj nreg))
|
||||
(format #t "~Tregs0 : ~4d~%" (-> obj regs0))
|
||||
(format #t "~Tregs1 : ~4d~%" (-> obj regs1))
|
||||
(format #t "~Tregs2 : ~4d~%" (-> obj regs2))
|
||||
(format #t "~Tregs3 : ~4d~%" (-> obj regs3))
|
||||
(format #t "~Tregs4 : ~4d~%" (-> obj regs4))
|
||||
(format #t "~Tregs5 : ~4d~%" (-> obj regs5))
|
||||
(format #t "~Tregs6 : ~4d~%" (-> obj regs6))
|
||||
(format #t "~Tregs7 : ~4d~%" (-> obj regs7))
|
||||
(format #t "~Tregs8 : ~4d~%" (-> obj regs8))
|
||||
(format #t "~Tregs9 : ~4d~%" (-> obj regs9))
|
||||
(format #t "~Tregs10: ~4d~%" (-> obj regs10))
|
||||
(format #t "~Tregs11: ~4d~%" (-> obj regs11))
|
||||
(format #t "~Tregs12: ~4d~%" (-> obj regs12))
|
||||
(format #t "~Tregs13: ~4d~%" (-> obj regs13))
|
||||
(format #t "~Tregs14: ~4d~%" (-> obj regs14))
|
||||
(the-as gif-tag (format #t "~Tregs15: ~4d~%" (-> obj regs15)))
|
||||
)
|
||||
|
||||
;; definition for symbol *fog-color*, type int
|
||||
|
||||
@@ -112,94 +112,27 @@
|
||||
)
|
||||
|
||||
;; definition for method 3 of type vec4s
|
||||
;; INFO: Return type mismatch uint128 vs vec4s.
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por gp, a0, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por a2, gp, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [sllv a2, gp, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [sllv a2, v1, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por v0, gp, r0]
|
||||
(defmethod inspect vec4s ((obj vec4s))
|
||||
(local-vars
|
||||
(r0-0 none)
|
||||
(v0-5 uint128)
|
||||
(v1-0 uint128)
|
||||
(v1-1 uint128)
|
||||
(a2-0 uint128)
|
||||
(a2-1 uint128)
|
||||
(a2-3 uint128)
|
||||
(gp-0 uint128)
|
||||
)
|
||||
(.por gp-0 obj r0-0)
|
||||
(let ((t9-0 format)
|
||||
(a0-1 #t)
|
||||
(a1-0 "[~8x] ~A~%")
|
||||
)
|
||||
(.por a2-0 gp-0 r0-0)
|
||||
(t9-0 a0-1 a1-0 a2-0 'vec4s)
|
||||
)
|
||||
(let ((t9-1 format)
|
||||
(a0-2 #t)
|
||||
(a1-1 "~Tx: ~f~%")
|
||||
)
|
||||
(.sllv a2-1 gp-0 r0-0)
|
||||
(t9-1 a0-2 a1-1 a2-1)
|
||||
)
|
||||
(format #t "~Ty: ~f~%" (sar (the-as int gp-0) 32))
|
||||
(let ((t9-3 format)
|
||||
(a0-4 #t)
|
||||
(a1-3 "~Tz: ~f~%")
|
||||
)
|
||||
(.pcpyud v1-0 gp-0 r0-0)
|
||||
(.sllv a2-3 v1-0 r0-0)
|
||||
(t9-3 a0-4 a1-3 a2-3)
|
||||
)
|
||||
(let ((t9-4 format)
|
||||
(a0-5 #t)
|
||||
(a1-4 "~Tw: ~f~%")
|
||||
)
|
||||
(.pcpyud v1-1 gp-0 r0-0)
|
||||
(t9-4 a0-5 a1-4 (sar (the-as int v1-1) 32))
|
||||
)
|
||||
(.por v0-5 gp-0 r0-0)
|
||||
(the-as vec4s v0-5)
|
||||
(format #t "[~8x] ~A~%" obj 'vec4s)
|
||||
(format #t "~Tx: ~f~%" (-> obj x))
|
||||
(format #t "~Ty: ~f~%" (-> obj y))
|
||||
(format #t "~Tz: ~f~%" (-> obj z))
|
||||
(format #t "~Tw: ~f~%" (-> obj w))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition for method 2 of type vec4s
|
||||
;; INFO: Return type mismatch uint128 vs vec4s.
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por gp, a0, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [sllv a2, gp, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [sllv t0, v1, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por t2, gp, r0]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [por v0, gp, r0]
|
||||
(defmethod print vec4s ((obj vec4s))
|
||||
(local-vars
|
||||
(r0-0 none)
|
||||
(v0-1 uint128)
|
||||
(v1-0 uint128)
|
||||
(v1-1 uint128)
|
||||
(a2-0 uint128)
|
||||
(t0-0 uint128)
|
||||
(t2-0 uint128)
|
||||
(gp-0 uint128)
|
||||
(format
|
||||
#t
|
||||
"#<vector ~F ~F ~F ~F @ #x~X>"
|
||||
(-> obj x)
|
||||
(-> obj y)
|
||||
(-> obj z)
|
||||
(-> obj w)
|
||||
obj
|
||||
)
|
||||
(.por gp-0 obj r0-0)
|
||||
(let ((t9-0 format)
|
||||
(a0-1 #t)
|
||||
(a1-0 "#<vector ~F ~F ~F ~F @ #x~X>")
|
||||
)
|
||||
(.sllv a2-0 gp-0 r0-0)
|
||||
(let ((a3-0 (sar (the-as int gp-0) 32)))
|
||||
(.pcpyud v1-0 gp-0 r0-0)
|
||||
(.sllv t0-0 v1-0 r0-0)
|
||||
(.pcpyud v1-1 gp-0 r0-0)
|
||||
(let ((t1-0 (sar (the-as int v1-1) 32)))
|
||||
(.por t2-0 gp-0 r0-0)
|
||||
(t9-0 a0-1 a1-0 a2-0 a3-0 t0-0 t1-0 t2-0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(.por v0-1 gp-0 r0-0)
|
||||
(the-as vec4s v0-1)
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type bfloat
|
||||
|
||||
@@ -286,9 +286,8 @@
|
||||
|
||||
;; definition for method 2 of type handle
|
||||
;; WARN: Unsupported inline assembly instruction kind - [subu a2, v1, s7]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [sllv a2, v1, r0]
|
||||
(defmethod print handle ((obj handle))
|
||||
(local-vars (r0-0 none) (a2-0 int) (a2-2 (pointer process)) (s7-0 none))
|
||||
(local-vars (a2-0 int) (s7-0 none))
|
||||
(cond
|
||||
((nonzero? obj)
|
||||
(let ((t9-0 format)
|
||||
@@ -297,15 +296,17 @@
|
||||
(v1-0 obj)
|
||||
)
|
||||
(.subu a2-0 v1-0 s7-0)
|
||||
(t9-0 a0-1 a1-0 (and (nonzero? a2-0) (begin
|
||||
(.sllv a2-2 v1-0 r0-0)
|
||||
(let ((a3-0 (-> a2-2 0)))
|
||||
(if (= (-> v1-0 pid) (-> a3-0 pid))
|
||||
a3-0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(t9-0
|
||||
a0-1
|
||||
a1-0
|
||||
(and
|
||||
(nonzero? a2-0)
|
||||
(let ((a3-0 (-> (the-as (pointer process) (-> v1-0 process)) 0)))
|
||||
(if (= (-> v1-0 pid) (-> a3-0 pid))
|
||||
a3-0
|
||||
)
|
||||
)
|
||||
)
|
||||
(-> obj pid)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1142,4 +1142,88 @@ TEST_F(FormRegressionTest, Method11FontContext) {
|
||||
" arg0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
// 128-bit bitfields, also type for pextuw
|
||||
TEST_F(FormRegressionTest, Method4ResTag) {
|
||||
std::string func =
|
||||
"sll r0, r0, 0\n"
|
||||
"L135:\n"
|
||||
" pcpyud v1, a0, r0\n"
|
||||
" dsrl32 v1, v1, 31\n"
|
||||
" bne v1, r0, L136\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
" pcpyud v1, a0, r0\n"
|
||||
" dsll v1, v1, 1\n"
|
||||
" dsrl32 v1, v1, 17\n"
|
||||
" dsll v0, v1, 2\n"
|
||||
" beq r0, r0, L137\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
"L136:\n"
|
||||
" pcpyud v1, a0, r0\n"
|
||||
" dsll v1, v1, 1\n"
|
||||
" dsrl32 v1, v1, 17\n"
|
||||
" pextuw a0, r0, a0\n"
|
||||
" lhu a0, 8(a0)\n"
|
||||
" multu3 v0, v1, a0\n"
|
||||
|
||||
"L137:\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function res-tag int)";
|
||||
std::string expected =
|
||||
"(the-as int (if (zero? (-> arg0 inlined?))\n"
|
||||
" (* (-> arg0 elt-count) 4)\n"
|
||||
" (* (the-as uint (-> arg0 elt-count)) (-> arg0 elt-type size))\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, Method2Vec4s) {
|
||||
std::string func =
|
||||
"sll r0, r0, 0\n"
|
||||
" daddiu sp, sp, -32\n"
|
||||
" sd ra, 0(sp)\n"
|
||||
" sd fp, 8(sp)\n"
|
||||
" or fp, t9, r0\n"
|
||||
" sq gp, 16(sp)\n"
|
||||
|
||||
" por gp, a0, r0\n"
|
||||
" lw t9, format(s7)\n"
|
||||
" daddiu a0, s7, #t\n"
|
||||
" daddiu a1, fp, L344\n"
|
||||
" sllv a2, gp, r0\n"
|
||||
" dsra32 a3, gp, 0\n"
|
||||
" pcpyud v1, gp, r0\n"
|
||||
" sllv t0, v1, r0\n"
|
||||
" pcpyud v1, gp, r0\n"
|
||||
" dsra32 t1, v1, 0\n"
|
||||
" por t2, gp, r0\n"
|
||||
" jalr ra, t9\n"
|
||||
" sll v0, ra, 0\n"
|
||||
|
||||
" por v0, gp, r0\n"
|
||||
" ld ra, 0(sp)\n"
|
||||
" ld fp, 8(sp)\n"
|
||||
" lq gp, 16(sp)\n"
|
||||
" jr ra\n"
|
||||
" daddiu sp, sp, 32";
|
||||
std::string type = "(function vec4s vec4s)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (format\n"
|
||||
" #t\n"
|
||||
" \"#<vector ~F ~F ~F ~F @ #x~X>\"\n"
|
||||
" (-> arg0 x)\n"
|
||||
" (-> arg0 y)\n"
|
||||
" (-> arg0 z)\n"
|
||||
" (-> arg0 w)\n"
|
||||
" arg0\n"
|
||||
" )\n"
|
||||
" arg0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected, false, "", {{"L344", "#<vector ~F ~F ~F ~F @ #x~X>"}});
|
||||
}
|
||||
@@ -75,8 +75,6 @@ const std::unordered_set<std::string> g_functions_to_skip_compiling = {
|
||||
"abs", "ash", "min", "max", "lognor",
|
||||
// weird PS2 specific debug registers:
|
||||
"breakpoint-range-set!",
|
||||
// int128 fancy stuff.
|
||||
"(method 3 vec4s)", "(method 2 vec4s)",
|
||||
// does weird stuff with the type system.
|
||||
"print", "printl", "inspect",
|
||||
// inline assembly
|
||||
@@ -119,9 +117,6 @@ const std::unordered_set<std::string> g_functions_to_skip_compiling = {
|
||||
// dma-disasm
|
||||
"disasm-dma-list", // missing a single cast :(
|
||||
|
||||
// gs
|
||||
"(method 3 gif-tag)", // inspect for a 128-bit type.
|
||||
|
||||
// math camera
|
||||
"transform-point-vector!", "transform-point-qword!", "transform-point-vector-scale!",
|
||||
|
||||
|
||||
Reference in New Issue
Block a user