mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-27 08:20:47 +00:00
[decompiler] Add tests and fixes for vector-h and math (#333)
* before messing with ssa stuff * fix ash * bounding box
This commit is contained in:
parent
0d8742241b
commit
99683c0dac
@ -574,18 +574,19 @@ void insertSpecialBreaks(NodePool& pool, PrettyPrinterNode* node) {
|
||||
}
|
||||
|
||||
if (name == "defun" || name == "defmethod" || name == "defun-debug" || name == "let" ||
|
||||
name == "let*") {
|
||||
name == "let*" || name == "rlet") {
|
||||
auto* first_list = getNextListOrEmptyListOnLine(node);
|
||||
if (first_list) {
|
||||
if (first_list->tok->kind == FormToken::TokenKind::EMPTY_PAIR) {
|
||||
insertNewlineAfter(pool, first_list, 0);
|
||||
breakList(pool, node->paren, first_list);
|
||||
} else {
|
||||
insertNewlineAfter(pool, first_list->paren, 0);
|
||||
breakList(pool, node->paren, first_list);
|
||||
}
|
||||
}
|
||||
|
||||
if ((name == "let" || name == "let*") && first_list) {
|
||||
if ((name == "let" || name == "let*" || name == "rlet") && first_list) {
|
||||
if (first_list->tok->kind == FormToken::TokenKind::OPEN_PAREN) {
|
||||
// we only want to break the variable list if it has multiple.
|
||||
bool single_var = false;
|
||||
|
@ -184,6 +184,16 @@ std::string Instruction::cop2_dest_to_char() const {
|
||||
return dest;
|
||||
}
|
||||
|
||||
int Instruction::cop2_dest_mask_intel() const {
|
||||
int mask = 0;
|
||||
for (int i = 0; i < 4; i++) { // x,y,z,w order
|
||||
if (cop2_dest & (1 << (3 - i))) { // set for ps2
|
||||
mask |= (1 << i);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert just the name of the opcode to a string, omitting src/dst, but including
|
||||
* suffixes (interlock, broadcasts and destination)
|
||||
|
@ -102,12 +102,14 @@ class Instruction {
|
||||
bool operator!=(const Instruction& other) const { return !((*this) == other); }
|
||||
|
||||
// extra fields for some COP2 instructions.
|
||||
// this is stored like in the PS2 instruction, which is different from intel
|
||||
uint8_t cop2_dest = 0xff; // 0xff indicates "don't print dest"
|
||||
uint8_t cop2_bc = 0xff; // 0xff indicates "don't print bc"
|
||||
uint8_t il = 0xff; // 0xff indicates "don't print il"
|
||||
|
||||
char cop2_bc_to_char() const;
|
||||
std::string cop2_dest_to_char() const;
|
||||
int cop2_dest_mask_intel() const;
|
||||
};
|
||||
} // namespace decompiler
|
||||
#endif // NEXT_INSTRUCTION_H
|
||||
|
@ -169,7 +169,6 @@ class Function {
|
||||
std::string debug_form_string;
|
||||
bool print_debug_forms = false;
|
||||
bool expressions_succeeded = false;
|
||||
bool types_succeeded = false;
|
||||
} ir2;
|
||||
|
||||
private:
|
||||
|
@ -125,6 +125,11 @@ TP_Type SimpleAtom::get_type(const TypeState& input,
|
||||
} else if ((label.offset & 7) == PAIR_OFFSET) {
|
||||
return TP_Type::make_from_ts(TypeSpec("pair"));
|
||||
}
|
||||
|
||||
auto hint_kv = env.label_types().find(label.name);
|
||||
if (hint_kv != env.label_types().end()) {
|
||||
return TP_Type::make_from_ts(dts.parse_type_spec(hint_kv->second.type_name));
|
||||
}
|
||||
// throw std::runtime_error("IR_StaticAddress couldn't figure out the type: " + label.name);
|
||||
lg::error("IR_StaticAddress doesn't know the type of {}", label.name);
|
||||
return TP_Type::make_from_ts("object");
|
||||
|
@ -102,64 +102,67 @@ goos::Object Env::get_variable_name_with_cast(Register reg, int atomic_idx, Acce
|
||||
lookup_name = remapped->second;
|
||||
}
|
||||
|
||||
// get the type of the variable. This is the type of thing if we do no casts.
|
||||
// first, get the type the decompiler found
|
||||
auto type_of_var = var_info.type.typespec();
|
||||
// and the user's type.
|
||||
auto retype_kv = m_var_retype.find(original_name);
|
||||
if (retype_kv != m_var_retype.end()) {
|
||||
type_of_var = retype_kv->second;
|
||||
}
|
||||
if (types_succeeded) {
|
||||
// get the type of the variable. This is the type of thing if we do no casts.
|
||||
// first, get the type the decompiler found
|
||||
auto type_of_var = var_info.type.typespec();
|
||||
// and the user's type.
|
||||
auto retype_kv = m_var_retype.find(original_name);
|
||||
if (retype_kv != m_var_retype.end()) {
|
||||
type_of_var = retype_kv->second;
|
||||
}
|
||||
|
||||
// next, we insert type casts that make enforce the user override.
|
||||
auto type_kv = m_typecasts.find(atomic_idx);
|
||||
if (type_kv != m_typecasts.end()) {
|
||||
for (auto& x : type_kv->second) {
|
||||
if (x.reg == reg) {
|
||||
// let's make sure the above claim is true
|
||||
TypeSpec type_in_reg;
|
||||
if (has_type_analysis() && mode == AccessMode::READ) {
|
||||
type_in_reg = get_types_for_op_mode(atomic_idx, AccessMode::READ).get(reg).typespec();
|
||||
if (type_in_reg.print() != x.type_name) {
|
||||
lg::error(
|
||||
"Decompiler type consistency error. There was a typecast for reg {} at idx {} "
|
||||
"(var {}) to type {}, but the actual type is {} ({})",
|
||||
reg.to_charp(), atomic_idx, lookup_name, x.type_name, type_in_reg.print(),
|
||||
type_in_reg.print());
|
||||
assert(false);
|
||||
// next, we insert type casts that make enforce the user override.
|
||||
auto type_kv = m_typecasts.find(atomic_idx);
|
||||
if (type_kv != m_typecasts.end()) {
|
||||
for (auto& x : type_kv->second) {
|
||||
if (x.reg == reg) {
|
||||
// let's make sure the above claim is true
|
||||
TypeSpec type_in_reg;
|
||||
if (has_type_analysis() && mode == AccessMode::READ) {
|
||||
type_in_reg = get_types_for_op_mode(atomic_idx, AccessMode::READ).get(reg).typespec();
|
||||
if (type_in_reg.print() != x.type_name) {
|
||||
lg::error(
|
||||
"Decompiler type consistency error. There was a typecast for reg {} at idx {} "
|
||||
"(var {}) to type {}, but the actual type is {} ({})",
|
||||
reg.to_charp(), atomic_idx, lookup_name, x.type_name, type_in_reg.print(),
|
||||
type_in_reg.print());
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type_of_var != type_in_reg) {
|
||||
// TODO - use the when possible?
|
||||
return pretty_print::build_list("the-as", x.type_name, lookup_name);
|
||||
if (type_of_var != type_in_reg) {
|
||||
// TODO - use the when possible?
|
||||
return pretty_print::build_list("the-as", x.type_name, lookup_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// type analysis stuff runs before variable types, so we insert casts that account
|
||||
// for the changing types due to the lca(uses) that is used to generate variable types.
|
||||
auto type_of_reg = get_types_for_op_mode(atomic_idx, mode).get(reg).typespec();
|
||||
if (mode == AccessMode::READ) {
|
||||
// note - this may be stricter than needed. but that's ok.
|
||||
// type analysis stuff runs before variable types, so we insert casts that account
|
||||
// for the changing types due to the lca(uses) that is used to generate variable types.
|
||||
auto type_of_reg = get_types_for_op_mode(atomic_idx, mode).get(reg).typespec();
|
||||
if (mode == AccessMode::READ) {
|
||||
// note - this may be stricter than needed. but that's ok.
|
||||
|
||||
if (type_of_var != type_of_reg) {
|
||||
// fmt::print("casting {} (reg {}, idx {}): reg type {} var type {} remapped var type
|
||||
// {}\n ",
|
||||
// lookup_name, reg.to_charp(), atomic_idx, type_of_reg.print(),
|
||||
// var_info.type.typespec().print(), type_of_var.print());
|
||||
return pretty_print::build_list("the-as", type_of_reg.print(), lookup_name);
|
||||
if (type_of_var != type_of_reg) {
|
||||
// fmt::print("casting {} (reg {}, idx {}): reg type {} var type {} remapped var
|
||||
// type
|
||||
// {}\n ",
|
||||
// lookup_name, reg.to_charp(), atomic_idx, type_of_reg.print(),
|
||||
// var_info.type.typespec().print(), type_of_var.print());
|
||||
return pretty_print::build_list("the-as", type_of_reg.print(), lookup_name);
|
||||
}
|
||||
} else {
|
||||
// if we're setting a variable, we are a little less strict.
|
||||
// let's leave this to set!'s for now. This is tricky with stuff like (if y x) where the
|
||||
// move is eliminated so the RegisterAccess points to the "wrong" place.
|
||||
// if (!dts->ts.tc(type_of_var, type_of_reg)) {
|
||||
// fmt::print("op {} reg {} type {}\n", atomic_idx, reg.to_charp(),
|
||||
// get_types_for_op_mode(atomic_idx, mode).get(reg).print()); return
|
||||
// pretty_print::build_list("the-as", type_of_reg.print(), lookup_name);
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
// if we're setting a variable, we are a little less strict.
|
||||
// let's leave this to set!'s for now. This is tricky with stuff like (if y x) where the move
|
||||
// is eliminated so the RegisterAccess points to the "wrong" place.
|
||||
// if (!dts->ts.tc(type_of_var, type_of_reg)) {
|
||||
// fmt::print("op {} reg {} type {}\n", atomic_idx, reg.to_charp(),
|
||||
// get_types_for_op_mode(atomic_idx, mode).get(reg).print()); return
|
||||
// pretty_print::build_list("the-as", type_of_reg.print(), lookup_name);
|
||||
// }
|
||||
}
|
||||
|
||||
return pretty_print::to_symbol(lookup_name);
|
||||
|
@ -24,6 +24,7 @@ struct FunctionAtomicOps;
|
||||
*/
|
||||
class Env {
|
||||
public:
|
||||
bool types_succeeded = false;
|
||||
bool has_local_vars() const { return m_has_local_vars; }
|
||||
bool has_type_analysis() const { return m_has_types; }
|
||||
bool has_reg_use() const { return m_has_reg_use; }
|
||||
|
@ -1205,7 +1205,7 @@ class LetElement : public FormElement {
|
||||
RegisterAccess dest;
|
||||
Form* src = nullptr;
|
||||
};
|
||||
std::vector<Entry> entries() { return m_entries; }
|
||||
std::vector<Entry>& entries() { return m_entries; }
|
||||
void add_entry(const Entry& e);
|
||||
bool is_star() const { return m_star; }
|
||||
|
||||
|
@ -141,8 +141,8 @@ void pop_helper(const std::vector<RegisterAccess>& vars,
|
||||
// fmt::print("Unsafe to pop {}: used {} times, def {} times, expected use {}\n",
|
||||
// var.to_string(env), use_def.use_count(), use_def.def_count(),
|
||||
// times);
|
||||
// if (var.to_string(env) == "v1-3") {
|
||||
// for (auto& use : use_def.defs) {
|
||||
// if (var.to_string(env) == "a3-0") {
|
||||
// for (auto& use : use_def.uses) {
|
||||
// if (!use.disabled) {
|
||||
// fmt::print(" at instruction {}\n", use.op_id);
|
||||
// }
|
||||
@ -1155,6 +1155,7 @@ Form* make_optional_cast(const std::optional<TypeSpec>& cast_type, Form* in, For
|
||||
void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
mark_popped();
|
||||
if (m_expr.is_var()) {
|
||||
// this matches the order in Compiler::compile_set
|
||||
auto vars = std::vector<RegisterAccess>({m_expr.var(), m_base_var});
|
||||
auto popped = pop_to_forms(vars, env, pool, stack, true);
|
||||
m_dst->set_base(make_optional_cast(m_dst_cast_type, popped.at(1), pool));
|
||||
|
@ -199,7 +199,8 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
|
||||
|
||||
// Handle destination masks
|
||||
if (func.allows_modifier(MOD::DEST_MASK) && instr.cop2_dest != 0xff && instr.cop2_dest != 15) {
|
||||
named_args.push_back(pretty_print::to_symbol(fmt::format(":mask #b{:b}", instr.cop2_dest)));
|
||||
named_args.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":mask #b{:b}", instr.cop2_dest_mask_intel())));
|
||||
}
|
||||
|
||||
// Some functions are configured, or its easiest to swap the source args
|
||||
|
@ -301,7 +301,7 @@ void ObjectFileDB::ir2_type_analysis_pass() {
|
||||
auto label_types = get_config().label_types[data.to_unique_name()];
|
||||
if (func.run_type_analysis_ir2(ts, dts, data.linked_data, hints, label_types)) {
|
||||
successful_functions++;
|
||||
func.ir2.types_succeeded = true;
|
||||
func.ir2.env.types_succeeded = true;
|
||||
} else {
|
||||
func.warnings.type_prop_warning("Type analysis failed");
|
||||
}
|
||||
@ -422,7 +422,8 @@ void ObjectFileDB::ir2_build_expressions() {
|
||||
(void)segment_id;
|
||||
(void)data;
|
||||
total++;
|
||||
if (func.ir2.top_form && func.ir2.env.has_type_analysis() && func.ir2.env.has_local_vars()) {
|
||||
if (func.ir2.top_form && func.ir2.env.has_type_analysis() && func.ir2.env.has_local_vars() &&
|
||||
func.ir2.env.types_succeeded) {
|
||||
attempted++;
|
||||
auto name = func.guessed_name.to_string();
|
||||
auto arg_config = get_config().function_arg_names.find(name);
|
||||
|
@ -1123,6 +1123,17 @@ Form* try_sc_as_ash(FormPool& pool, Function& f, const ShortCircuit* vtx) {
|
||||
// fix up reg info
|
||||
f.ir2.env.disable_use(delay->src().get_arg(0).var());
|
||||
|
||||
// fix up the other ones:
|
||||
f.ir2.env.disable_use(branch->op()->condition().src(0).var()); // bgezl X, L
|
||||
auto dsubu_var = dynamic_cast<SimpleExpressionElement*>(dsubu_set->src()->try_as_single_element())
|
||||
->expr()
|
||||
.get_arg(0)
|
||||
.var();
|
||||
f.ir2.env.disable_use(dsubu_var);
|
||||
|
||||
// and the def too
|
||||
f.ir2.env.disable_def(dsrav_set->dst());
|
||||
|
||||
return b0_c_ptr;
|
||||
}
|
||||
|
||||
|
@ -199,6 +199,66 @@ FormElement* fix_up_abs(LetElement* in, const Env& env, FormPool& pool) {
|
||||
src);
|
||||
}
|
||||
|
||||
FormElement* fix_up_abs_2(LetElement* in, const Env& env, FormPool& pool) {
|
||||
/*
|
||||
* (let ((result in))
|
||||
* (set! result (abs result))
|
||||
* ...
|
||||
* )
|
||||
*
|
||||
* -> should become.
|
||||
* (let ((result (abs in)))
|
||||
* )
|
||||
*/
|
||||
|
||||
if (in->entries().size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (in->body()->elts().empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// look for setting a temp.
|
||||
auto temp = in->entries().at(0).dest;
|
||||
auto temp_name = env.get_variable_name(temp);
|
||||
|
||||
Form* src = in->entries().at(0).src;
|
||||
|
||||
auto first_as_set = dynamic_cast<SetVarElement*>(in->body()->elts().front());
|
||||
if (!first_as_set) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto dest_var_name = env.get_variable_name(first_as_set->dst());
|
||||
if (dest_var_name != temp_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto matcher =
|
||||
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::ABS), {Matcher::any_reg(0)});
|
||||
|
||||
auto mr = match(matcher, first_as_set->src());
|
||||
if (!mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
assert(mr.maps.regs.at(0));
|
||||
|
||||
auto abs_var_name = env.get_variable_name(*mr.maps.regs.at(0));
|
||||
if (abs_var_name != temp_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// success!
|
||||
// modify the let entry:
|
||||
in->entries().at(0).src = pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr, GenericOperator::make_fixed(FixedOperatorKind::ABS), src);
|
||||
// remove the (set! x (abs x))
|
||||
in->body()->elts().erase(in->body()->elts().begin());
|
||||
return in;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr.
|
||||
*/
|
||||
@ -213,6 +273,11 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool) {
|
||||
return as_abs;
|
||||
}
|
||||
|
||||
auto as_abs_2 = fix_up_abs_2(in, env, pool);
|
||||
if (as_abs_2) {
|
||||
return as_abs_2;
|
||||
}
|
||||
|
||||
// nothing matched.
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -736,50 +736,9 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
|
||||
;; math
|
||||
(deftype random-generator (basic)
|
||||
((seed uint32 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
(define-extern truncate (function float float))
|
||||
(define-extern integral? (function float symbol))
|
||||
(define-extern fractional-part (function float float))
|
||||
(define-extern log2 (function int int))
|
||||
(define-extern seek (function float float float float))
|
||||
(define-extern lerp (function float float float float))
|
||||
(define-extern lerp-scale (function float float float float float float))
|
||||
(define-extern lerp-clamp (function float float float float))
|
||||
(define-extern seekl (function int int int int))
|
||||
(define-extern rand-vu-init (function float float))
|
||||
(define-extern rand-vu (function float))
|
||||
(define-extern rand-vu-nostep (function float))
|
||||
(define-extern rand-vu-float-range (function float float float))
|
||||
(define-extern rand-vu-percent? (function float symbol))
|
||||
(define-extern rand-vu-int-range (function int int int))
|
||||
(define-extern rand-vu-int-count (function int int))
|
||||
|
||||
; ;;(define-extern xyzwh object) ;; unknown type
|
||||
;
|
||||
;
|
||||
;
|
||||
; (define-extern lerp function)
|
||||
; (define-extern lerp-scale function)
|
||||
;
|
||||
|
||||
; ;;(define-extern random-generator object) ;; unknown type
|
||||
; (define-extern integral? function)
|
||||
; (define-extern rand-uint31-gen function)
|
||||
;
|
||||
; (define-extern fractional-part function)
|
||||
; (define-extern seek function)
|
||||
; ;;(define-extern xyzw object) ;; unknown type
|
||||
;
|
||||
(define-extern *random-generator* random-generator) ;; unknown type
|
||||
;
|
||||
|
||||
(deftype rgba (uint32)
|
||||
((r uint8 :offset 0)
|
||||
@ -802,6 +761,29 @@
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
(define-extern log2 (function int int))
|
||||
(define-extern seek (function float float float float))
|
||||
(define-extern lerp (function float float float float))
|
||||
(define-extern lerp-scale (function float float float float float float))
|
||||
(define-extern lerp-clamp (function float float float float))
|
||||
(define-extern seekl (function int int int int))
|
||||
(define-extern rand-vu-init (function float float))
|
||||
(define-extern rand-vu (function float))
|
||||
(define-extern rand-vu-nostep (function float))
|
||||
(define-extern rand-vu-float-range (function float float float))
|
||||
(define-extern rand-vu-percent? (function float symbol))
|
||||
(define-extern rand-vu-int-range (function int int int))
|
||||
(define-extern rand-vu-int-count (function int int))
|
||||
|
||||
(deftype random-generator (basic)
|
||||
((seed uint32 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
(define-extern *random-generator* random-generator)
|
||||
(define-extern rand-uint31-gen (function random-generator uint))
|
||||
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
@ -1180,13 +1162,13 @@
|
||||
:size-assert #x20
|
||||
:flag-assert #x1000000020
|
||||
(:methods
|
||||
(dummy-9 () none 9)
|
||||
(dummy-10 () none 10)
|
||||
(dummy-11 () none 11)
|
||||
(dummy-12 () none 12)
|
||||
(dummy-13 () none 13)
|
||||
(dummy-14 () none 14)
|
||||
(dummy-15 () none 15)
|
||||
(add-spheres! (_type_ (pointer sphere) int) int 9)
|
||||
(add-point! (_type_ vector3s) int 10)
|
||||
(set-from-point-offset! (_type_ vector3s vector3s) int 11)
|
||||
(set-from-point-offset-pad! (_type_ vector3s vector3s float) int 12)
|
||||
(set-from-sphere! (_type_ sphere) int 13)
|
||||
(set-from-spheres! (_type_ (pointer sphere) int) int 14)
|
||||
(add-box! (_type_ bounding-box) int 15)
|
||||
)
|
||||
)
|
||||
|
||||
@ -1247,6 +1229,7 @@
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
|
||||
(define-extern matrix-copy! (function matrix matrix matrix))
|
||||
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
@ -3572,6 +3555,7 @@
|
||||
:size-assert #x50
|
||||
:flag-assert #x900000050
|
||||
)
|
||||
|
||||
;; level-h
|
||||
(deftype level (basic)
|
||||
((name basic :offset-assert 4)
|
||||
@ -4225,6 +4209,7 @@
|
||||
)
|
||||
|
||||
(define-extern *dproc* process)
|
||||
(define-extern *display-strip-lines* int)
|
||||
|
||||
;;;;;;;;;;;;;;
|
||||
;; mspace-h
|
||||
@ -13638,6 +13623,12 @@
|
||||
:flag-assert #x900000014
|
||||
)
|
||||
|
||||
|
||||
;;;; level
|
||||
|
||||
(define-extern lookup-level-info (function symbol level-load-info))
|
||||
(define-extern remap-level-name (function level-load-info object))
|
||||
|
||||
; ;; text
|
||||
; (deftype game-text-info (basic)
|
||||
; ()
|
||||
@ -32501,7 +32492,7 @@
|
||||
;;(define-extern bounding-box4w object) ;; unknown type
|
||||
;;(define-extern bounding-box-both object) ;; unknown type
|
||||
;;(define-extern matrix4h object) ;; unknown type
|
||||
; (define-extern matrix-copy! function)
|
||||
|
||||
;;(define-extern matrix3 object) ;; unknown type
|
||||
;;(define-extern matrix object) ;; unknown type
|
||||
;;(define-extern *unity-quaternion* object) ;; unknown type
|
||||
@ -32889,7 +32880,7 @@
|
||||
;;(define-extern *display-cam-coll-marks* object) ;; unknown type
|
||||
;;(define-extern *display-ambient-hint-marks* object) ;; unknown type
|
||||
;;(define-extern *display-cam-los-debug* object) ;; unknown type
|
||||
;;(define-extern *display-strip-lines* object) ;; unknown type
|
||||
|
||||
;;(define-extern *display-process-anim* object) ;; unknown type
|
||||
;;(define-extern *display-actor-marks* object) ;; unknown type
|
||||
(define-extern *menu-hook* (function none))
|
||||
@ -34371,7 +34362,6 @@
|
||||
;;(define-extern save object) ;; unknown type
|
||||
;;(define-extern restore object) ;; unknown type
|
||||
;;(define-extern mc-unformat object) ;; unknown type
|
||||
(define-extern lookup-level-info function)
|
||||
;;(define-extern done object) ;; unknown type
|
||||
(define-extern get-aspect-ratio function)
|
||||
(define-extern progress-allowed? function)
|
||||
@ -34802,7 +34792,6 @@
|
||||
(define-extern load-vis-info function)
|
||||
(define-extern level-update-after-load function)
|
||||
(define-extern update-sound-banks function)
|
||||
(define-extern remap-level-name function)
|
||||
(define-extern add-bsp-drawable function)
|
||||
;;(define-extern *print-login* object) ;; unknown type
|
||||
;;(define-extern link-resume object) ;; unknown type
|
||||
|
@ -505,5 +505,5 @@
|
||||
],
|
||||
|
||||
"pair_functions_by_name":["ref", "last", "member", "nmember", "assoc", "assoce", "append!", "delete!", "delete-car!",
|
||||
"insert-cons!", "sort", "unload-package", "(method 4 pair)", "nassoc", "nassoce"]
|
||||
"insert-cons!", "sort", "unload-package", "(method 4 pair)", "nassoc", "nassoce", "lookup-level-info", "(method 21 level-group)"]
|
||||
}
|
@ -28,6 +28,16 @@
|
||||
["L35", "float", true]
|
||||
],
|
||||
|
||||
"vector-h": [
|
||||
["L32", "vector", true],
|
||||
["L31", "vector", true],
|
||||
["L30", "vector", true],
|
||||
["L29", "vector", true],
|
||||
["L28", "vector", true],
|
||||
["L27", "vector", true],
|
||||
["L26", "vector", true]
|
||||
],
|
||||
|
||||
"trigonometry": [
|
||||
["L143", "float", true],
|
||||
["L144", "float", true],
|
||||
|
@ -109,10 +109,22 @@
|
||||
[4, "s5", "string"]
|
||||
],
|
||||
|
||||
|
||||
// GSTATE
|
||||
"enter-state":[
|
||||
[68, "s0", "protect-frame"]
|
||||
],
|
||||
|
||||
// MATH
|
||||
"log2":[
|
||||
[3, "v1", "int"]
|
||||
],
|
||||
|
||||
// LEVEL
|
||||
"lookup-level-info":[
|
||||
[3, "a1", "symbol"],
|
||||
[4, "a1", "level-load-info"],
|
||||
[8, "a1", "level-load-info"],
|
||||
[12, "a1", "level-load-info"]
|
||||
]
|
||||
|
||||
}
|
||||
|
@ -617,9 +617,18 @@
|
||||
},
|
||||
"(method 11 touching-prims-entry-pool)":{
|
||||
"vars":{"a1-0":"current", "v1-0":"prev", "a2-0":"next"}
|
||||
},
|
||||
|
||||
// LEVEL
|
||||
"lookup-level-info":{
|
||||
"args":["name"],
|
||||
"vars":{"a1-1":["info", "level-load-info"], "v1-0":"rest", "a1-0":"current-sym"}
|
||||
},
|
||||
|
||||
"(method 21 level-group)":{
|
||||
"args":["obj", "name", "cmd-idx"],
|
||||
"vars":{"v1-1":"cmd-lst"}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -8,6 +8,9 @@
|
||||
;; Types related to bounding boxes.
|
||||
|
||||
;; floating point bounding box.
|
||||
;; min is the corner with lowest x,y,z values.
|
||||
;; max is the corner with highest x,y,z values.
|
||||
;; the w value should be 1 in both min and max.
|
||||
(deftype bounding-box (structure)
|
||||
((min vector :inline :offset-assert 0)
|
||||
(max vector :inline :offset-assert 16)
|
||||
@ -16,14 +19,14 @@
|
||||
:size-assert #x20
|
||||
:flag-assert #x1000000020
|
||||
(:methods
|
||||
(dummy-9 () none 9)
|
||||
(dummy-10 () none 10)
|
||||
(dummy-11 () none 11)
|
||||
(dummy-12 () none 12)
|
||||
(dummy-13 () none 13)
|
||||
(dummy-14 () none 14)
|
||||
(dummy-15 () none 15)
|
||||
)
|
||||
(add-spheres! (_type_ (pointer sphere) int) int 9)
|
||||
(add-point! (_type_ vector3s) int 10)
|
||||
(set-from-point-offset! (_type_ vector3s vector3s) int 11)
|
||||
(set-from-point-offset-pad! (_type_ vector3s vector3s float) int 12)
|
||||
(set-from-sphere! (_type_ sphere) int 13)
|
||||
(set-from-spheres! (_type_ (pointer sphere) int) int 14)
|
||||
(add-box! (_type_ bounding-box) int 15)
|
||||
)
|
||||
)
|
||||
|
||||
;; integer (word) bounding box.
|
||||
@ -44,4 +47,4 @@
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
)
|
||||
|
@ -28,3 +28,183 @@
|
||||
(>= (-> box max data 2) (-> pt data 2))
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 11 of type bounding-box
|
||||
(defmethod set-from-point-offset! bounding-box
|
||||
((obj bounding-box) (arg0 vector3s) (arg1 vector3s))
|
||||
"Set box to smallest containing the points arg0, (arg0 + arg1)"
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf3 arg1)
|
||||
(.lvf vf4 arg0)
|
||||
(.add.vf vf5 vf4 vf3)
|
||||
(.min.vf vf1 vf4 vf5)
|
||||
(.max.vf vf2 vf4 vf5)
|
||||
(.mov.vf vf1 vf0 :mask #b1000)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 10 of type bounding-box
|
||||
(defmethod add-point! bounding-box ((obj bounding-box) (arg0 vector3s))
|
||||
"Expand the box if needed to contain the given point"
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
)
|
||||
(.lvf vf1 obj)
|
||||
(.lvf vf2 obj :offset 16)
|
||||
(.lvf vf3 arg0)
|
||||
(.min.vf vf1 vf1 vf3)
|
||||
(.max.vf vf2 vf2 vf3)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 15 of type bounding-box
|
||||
(defmethod add-box! bounding-box ((obj bounding-box) (arg0 bounding-box))
|
||||
"Expand the box if needed to contain the given box"
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
)
|
||||
(.lvf vf1 obj)
|
||||
(.lvf vf2 obj :offset 16)
|
||||
(.lvf vf3 arg0)
|
||||
(.lvf vf4 arg0 :offset 16)
|
||||
(.min.vf vf1 vf1 vf3)
|
||||
(.max.vf vf2 vf2 vf4)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 12 of type bounding-box
|
||||
(defmethod set-from-point-offset-pad! bounding-box
|
||||
((obj bounding-box) (arg0 vector3s) (arg1 vector3s) (arg2 float))
|
||||
"Set the box size to contain pt, pt + offset, with some padding"
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
(vf6 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf4 arg1)
|
||||
(.lvf vf5 arg0)
|
||||
(.mov vf1 arg2)
|
||||
(.add.vf vf6 vf5 vf4)
|
||||
(.min.vf vf2 vf5 vf6)
|
||||
(.max.vf vf3 vf5 vf6)
|
||||
(.add.x.vf vf3 vf3 vf1 :mask #b111)
|
||||
(.sub.x.vf vf2 vf2 vf1 :mask #b111)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.mov.vf vf3 vf0 :mask #b1000)
|
||||
(.svf obj vf2)
|
||||
(.svf obj vf3 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 13 of type bounding-box
|
||||
(defmethod set-from-sphere! bounding-box ((obj bounding-box) (arg0 sphere))
|
||||
"Set the box size to contain the given sphere"
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf1 arg0)
|
||||
(.sub.w.vf vf2 vf1 vf1 :mask #b111)
|
||||
(.add.w.vf vf3 vf1 vf1 :mask #b111)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.mov.vf vf3 vf0 :mask #b1000)
|
||||
(.svf obj vf2)
|
||||
(.svf obj vf3 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod add-spheres! bounding-box ((obj bounding-box) (spheres (pointer sphere)) (count int))
|
||||
"Add count spheres."
|
||||
;; the PS2 implementation is very optimized
|
||||
;; It is unrolled and 'software pipelined' to do 4 at a time.
|
||||
;; This is slightly less optimized.
|
||||
(rlet ((current-min :class vf)
|
||||
(current-max :class vf)
|
||||
(sph-min :class vf)
|
||||
(sph-max :class vf)
|
||||
(sph :class vf))
|
||||
|
||||
(when (nonzero? count)
|
||||
;; load these outside the loop
|
||||
(.lvf current-min (-> obj min))
|
||||
(.lvf current-max (-> obj max))
|
||||
|
||||
(dotimes (i count)
|
||||
(.lvf sph (-> spheres i))
|
||||
(.sub.w.vf sph-min sph sph :mask #b111)
|
||||
(.add.w.vf sph-max sph sph :mask #b111)
|
||||
(.min.vf current-min current-min sph-min :mask #b111)
|
||||
(.max.vf current-max current-max sph-max :mask #b111)
|
||||
)
|
||||
|
||||
(.svf (-> obj min) current-min)
|
||||
(.svf (-> obj max) current-max)
|
||||
)
|
||||
)
|
||||
0
|
||||
)
|
||||
|
||||
(defmethod set-from-spheres! bounding-box ((obj bounding-box) (spheres (pointer sphere)) (count int))
|
||||
"Reset box to hold the given spheres. Note: this implementation could be optimized."
|
||||
;; This is also unrolled, but does 7 at a time.
|
||||
(rlet ((vf0 :class vf)
|
||||
(current-min :class vf)
|
||||
(current-max :class vf)
|
||||
(sph-min :class vf)
|
||||
(sph-max :class vf)
|
||||
(sph :class vf))
|
||||
;; init constant
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
;; init min/max. in the case we don't have any spheres, we should return (0,0,0,1) for min/max.
|
||||
(set! current-min vf0)
|
||||
(set! current-max vf0)
|
||||
|
||||
(dotimes (i count)
|
||||
(.lvf sph (-> spheres i))
|
||||
(.sub.w.vf sph-min sph sph :mask #b111)
|
||||
(.add.w.vf sph-max sph sph :mask #b111)
|
||||
(cond
|
||||
((zero? count)
|
||||
(set! current-min sph-min)
|
||||
(set! current-max sph-max)
|
||||
)
|
||||
(else
|
||||
(.min.vf current-min current-min sph-min :mask #b111)
|
||||
(.max.vf current-max current-max sph-max :mask #b111)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(.svf (-> obj min) current-min)
|
||||
(.svf (-> obj max) current-max)
|
||||
)
|
||||
0
|
||||
)
|
||||
|
@ -296,6 +296,6 @@
|
||||
)
|
||||
(set! result (shr (logand #xffffffff (shl result 1)) 1))
|
||||
(set! (-> gen seed) result)
|
||||
result
|
||||
(the uint result)
|
||||
)
|
||||
)
|
||||
|
@ -444,7 +444,6 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; vector-h
|
||||
(deftype vertical-planes (structure)
|
||||
((data uint128 4 :offset-assert 0) ;; probably wrong
|
||||
)
|
||||
|
@ -209,9 +209,8 @@ Val* Compiler::compile_set(const goos::Object& form, const goos::Object& rest, E
|
||||
va_check(form, args, {{}, {}}, {});
|
||||
|
||||
auto& destination = args.unnamed.at(0);
|
||||
// todo, I don't know if this is the correct order or not. Right now the value is computed
|
||||
// and to_reg'd first, then the destination is computed, if the destination requires math to
|
||||
// compute.
|
||||
// this is the order I'm using in the decompiler and it seems to be right.
|
||||
// see StorePlainDeref::push_to_stack for example
|
||||
auto source = compile_error_guard(args.unnamed.at(1), env);
|
||||
auto source_reg = source->to_reg(env);
|
||||
auto dest = compile_error_guard(destination, env);
|
||||
|
@ -152,6 +152,7 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var());
|
||||
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, casts, {}));
|
||||
test->func.ir2.env.types_succeeded = true;
|
||||
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
|
@ -80,4 +80,11 @@
|
||||
(define-extern throw (function symbol object int))
|
||||
(defmacro suspend()
|
||||
'(none)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; math
|
||||
(define-extern fabs (function float float))
|
||||
(define-extern abs (function int int))
|
||||
(define-extern rand-vu-init (function float none))
|
||||
(define-extern rand-vu (function float))
|
72
test/decompiler/reference/bounding-box-h_REF.gc
Normal file
72
test/decompiler/reference/bounding-box-h_REF.gc
Normal file
@ -0,0 +1,72 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition of type bounding-box
|
||||
(deftype bounding-box (structure)
|
||||
((min vector :inline :offset-assert 0)
|
||||
(max vector :inline :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 16
|
||||
:size-assert #x20
|
||||
:flag-assert #x1000000020
|
||||
(:methods
|
||||
(add-spheres! (_type_ (pointer sphere) int) int 9)
|
||||
(add-point! (_type_ vector3s) int 10)
|
||||
(set-from-point-offset! (_type_ vector3s vector3s) int 11)
|
||||
(set-from-point-offset-pad! (_type_ vector3s vector3s float) int 12)
|
||||
(set-from-sphere! (_type_ sphere) int 13)
|
||||
(set-from-spheres! (_type_ (pointer sphere) int) int 14)
|
||||
(add-box! (_type_ bounding-box) int 15)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 3 of type bounding-box
|
||||
(defmethod inspect bounding-box ((obj bounding-box))
|
||||
(format #t "[~8x] ~A~%" obj 'bounding-box)
|
||||
(format #t "~Tmin: ~`vector`P~%" (-> obj min))
|
||||
(format #t "~Tmax: ~`vector`P~%" (-> obj max))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type bounding-box4w
|
||||
(deftype bounding-box4w (structure)
|
||||
((min vector4w :inline :offset-assert 0)
|
||||
(max vector4w :inline :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
|
||||
;; definition for method 3 of type bounding-box4w
|
||||
(defmethod inspect bounding-box4w ((obj bounding-box4w))
|
||||
(format #t "[~8x] ~A~%" obj 'bounding-box4w)
|
||||
(format #t "~Tmin: ~`vector4w`P~%" (-> obj min))
|
||||
(format #t "~Tmax: ~`vector4w`P~%" (-> obj max))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition of type bounding-box-both
|
||||
(deftype bounding-box-both (structure)
|
||||
((box bounding-box :inline :offset-assert 0)
|
||||
(box4w bounding-box4w :inline :offset-assert 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
|
||||
;; definition for method 3 of type bounding-box-both
|
||||
(defmethod inspect bounding-box-both ((obj bounding-box-both))
|
||||
(format #t "[~8x] ~A~%" obj 'bounding-box-both)
|
||||
(format #t "~Tbox: #<bounding-box @ #x~X>~%" (-> obj box))
|
||||
(format #t "~Tbox4w: #<bounding-box4w @ #x~X>~%" (-> obj box4w))
|
||||
obj
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-3 0))
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(none)
|
146
test/decompiler/reference/bounding-box_REF.gc
Normal file
146
test/decompiler/reference/bounding-box_REF.gc
Normal file
@ -0,0 +1,146 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition for function box-vector-enside?
|
||||
(defun box-vector-enside? ((box bounding-box) (pt vector))
|
||||
(and
|
||||
(< (-> box min data 0) (-> pt data 0))
|
||||
(< (-> box min data 1) (-> pt data 1))
|
||||
(< (-> box min data 2) (-> pt data 2))
|
||||
(< (-> pt data 0) (-> box max data 0))
|
||||
(< (-> pt data 1) (-> box max data 1))
|
||||
(< (-> pt data 2) (-> box max data 2))
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function box-vector-inside?
|
||||
(defun box-vector-inside? ((box bounding-box) (pt vector))
|
||||
(and
|
||||
(>= (-> pt data 0) (-> box min data 0))
|
||||
(>= (-> pt data 1) (-> box min data 1))
|
||||
(>= (-> pt data 2) (-> box min data 2))
|
||||
(>= (-> box max data 0) (-> pt data 0))
|
||||
(>= (-> box max data 1) (-> pt data 1))
|
||||
(>= (-> box max data 2) (-> pt data 2))
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 11 of type bounding-box
|
||||
(defmethod
|
||||
set-from-point-offset!
|
||||
bounding-box
|
||||
((obj bounding-box) (arg0 vector3s) (arg1 vector3s))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf3 arg1)
|
||||
(.lvf vf4 arg0)
|
||||
(.add.vf vf5 vf4 vf3)
|
||||
(.min.vf vf1 vf4 vf5)
|
||||
(.max.vf vf2 vf4 vf5)
|
||||
(.mov.vf vf1 vf0 :mask #b1000)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 10 of type bounding-box
|
||||
(defmethod add-point! bounding-box ((obj bounding-box) (arg0 vector3s))
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
)
|
||||
(.lvf vf1 obj)
|
||||
(.lvf vf2 obj :offset 16)
|
||||
(.lvf vf3 arg0)
|
||||
(.min.vf vf1 vf1 vf3)
|
||||
(.max.vf vf2 vf2 vf3)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 15 of type bounding-box
|
||||
(defmethod add-box! bounding-box ((obj bounding-box) (arg0 bounding-box))
|
||||
(rlet ((vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
)
|
||||
(.lvf vf1 obj)
|
||||
(.lvf vf2 obj :offset 16)
|
||||
(.lvf vf3 arg0)
|
||||
(.lvf vf4 arg0 :offset 16)
|
||||
(.min.vf vf1 vf1 vf3)
|
||||
(.max.vf vf2 vf2 vf4)
|
||||
(.svf obj vf1)
|
||||
(.svf obj vf2 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 12 of type bounding-box
|
||||
(defmethod
|
||||
set-from-point-offset-pad!
|
||||
bounding-box
|
||||
((obj bounding-box) (arg0 vector3s) (arg1 vector3s) (arg2 float))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
(vf4 :class vf)
|
||||
(vf5 :class vf)
|
||||
(vf6 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf4 arg1)
|
||||
(.lvf vf5 arg0)
|
||||
(.mov vf1 arg2)
|
||||
(.add.vf vf6 vf5 vf4)
|
||||
(.min.vf vf2 vf5 vf6)
|
||||
(.max.vf vf3 vf5 vf6)
|
||||
(.add.x.vf vf3 vf3 vf1 :mask #b111)
|
||||
(.sub.x.vf vf2 vf2 vf1 :mask #b111)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.mov.vf vf3 vf0 :mask #b1000)
|
||||
(.svf obj vf2)
|
||||
(.svf obj vf3 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 13 of type bounding-box
|
||||
(defmethod set-from-sphere! bounding-box ((obj bounding-box) (arg0 sphere))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
(vf3 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(.lvf vf1 arg0)
|
||||
(.sub.w.vf vf2 vf1 vf1 :mask #b111)
|
||||
(.add.w.vf vf3 vf1 vf1 :mask #b111)
|
||||
(.mov.vf vf2 vf0 :mask #b1000)
|
||||
(.mov.vf vf3 vf0 :mask #b1000)
|
||||
(.svf obj vf2)
|
||||
(.svf obj vf3 :offset 16)
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for method 14 of type bounding-box
|
||||
;; ERROR: function was not converted to expressions. Cannot decompile.
|
||||
|
||||
;; definition for method 9 of type bounding-box
|
||||
;; ERROR: function was not converted to expressions. Cannot decompile.
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(none)
|
@ -208,12 +208,13 @@
|
||||
|
||||
;; definition for function remove-exit
|
||||
(defun remove-exit ()
|
||||
(local-vars (pp process)) (if (-> pp stack-frame-top)
|
||||
(let ((v0-0 (-> pp stack-frame-top next)))
|
||||
(set! (-> pp stack-frame-top) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
(local-vars (pp process))
|
||||
(if (-> pp stack-frame-top)
|
||||
(let ((v0-0 (-> pp stack-frame-top next)))
|
||||
(set! (-> pp stack-frame-top) v0-0)
|
||||
v0-0
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition (debug) for function stream<-process-mask
|
||||
@ -1506,11 +1507,9 @@
|
||||
(while s2-1
|
||||
(inspect-process-tree (-> s2-1 0) (+ arg1 1) (if (not (-> s2-1 0 brother))
|
||||
arg2
|
||||
(let* ((v1-7 1)
|
||||
(a2-4 (+ arg1 1))
|
||||
(v1-8 (ash v1-7 a2-4))
|
||||
)
|
||||
(logior arg2 v1-8)
|
||||
(logior
|
||||
arg2
|
||||
(ash 1 (+ arg1 1))
|
||||
)
|
||||
)
|
||||
arg3
|
||||
|
247
test/decompiler/reference/math_REF.gc
Normal file
247
test/decompiler/reference/math_REF.gc
Normal file
@ -0,0 +1,247 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition for function truncate
|
||||
(defun truncate ((arg0 float))
|
||||
(the float (the int arg0))
|
||||
)
|
||||
|
||||
;; definition for function integral?
|
||||
(defun integral? ((arg0 float))
|
||||
(= (the float (the int arg0)) arg0)
|
||||
)
|
||||
|
||||
;; definition for function fractional-part
|
||||
(defun fractional-part ((arg0 float))
|
||||
(- arg0 (the float (the int arg0)))
|
||||
)
|
||||
|
||||
;; definition of type rgba
|
||||
(deftype rgba (uint32)
|
||||
((r uint8 :offset 0 :size 8)
|
||||
(g uint8 :offset 8 :size 8)
|
||||
(b uint8 :offset 16 :size 8)
|
||||
(a uint8 :offset 24 :size 8)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
|
||||
;; definition of type xyzw
|
||||
(deftype xyzw (uint128)
|
||||
()
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
;; definition of type xyzwh
|
||||
(deftype xyzwh (uint128)
|
||||
()
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
;; definition for function log2
|
||||
(defun log2 ((arg0 int))
|
||||
(let ((arg0 (gpr->fpr arg0)))
|
||||
(+ (sar (the-as int (the float arg0)) 23) -127)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function seek
|
||||
(defun seek ((x float) (target float) (diff float))
|
||||
(let ((err (- target x)))
|
||||
(cond
|
||||
((>= diff (fabs err))
|
||||
target
|
||||
)
|
||||
((>= err 0.0)
|
||||
(+ x diff)
|
||||
)
|
||||
(else
|
||||
(- x diff)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function lerp
|
||||
(defun lerp ((minimum float) (maximum float) (amount float))
|
||||
(+ minimum (* amount (- maximum minimum)))
|
||||
)
|
||||
|
||||
;; definition for function lerp-scale
|
||||
(defun
|
||||
lerp-scale
|
||||
((min-out float) (max-out float) (in float) (min-in float) (max-in float))
|
||||
(let ((scale (fmax 0.0 (fmin 1.0 (/ (- in min-in) (- max-in min-in))))))
|
||||
(+ (* (- 1.0 scale) min-out) (* scale max-out))
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function lerp-clamp
|
||||
(defun lerp-clamp ((minimum float) (maximum float) (amount float))
|
||||
(cond
|
||||
((>= 0.0 amount)
|
||||
minimum
|
||||
)
|
||||
((>= amount 1.0)
|
||||
maximum
|
||||
)
|
||||
(else
|
||||
(+ (* (- 1.0 amount) minimum) (* amount maximum))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function seekl
|
||||
(defun seekl ((arg0 int) (arg1 int) (arg2 int))
|
||||
(let* ((v1-0 (- arg1 arg0))
|
||||
(a3-0 (abs v1-0))
|
||||
)
|
||||
(cond
|
||||
((>= arg2 a3-0)
|
||||
arg1
|
||||
)
|
||||
((>= v1-0 0)
|
||||
(+ arg0 arg2)
|
||||
)
|
||||
(else
|
||||
(- arg0 arg2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-init
|
||||
;; INFO: Return type mismatch int vs float.
|
||||
;; WARN: Unsupported inline assembly instruction kind - [56]
|
||||
;; WARN: Unsupported inline assembly instruction kind - [57]
|
||||
(defun rand-vu-init ((arg0 float))
|
||||
(local-vars (v0-0 int))
|
||||
(.ctc2.i vi_R arg0)
|
||||
(.cfc2.i v0-0 vi_R)
|
||||
(the-as float v0-0)
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(rand-vu-init 1.418091)
|
||||
|
||||
;; definition for function rand-vu
|
||||
;; INFO: Return type mismatch int vs float.
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VRGET]
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VRXOR]
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VRNEXT]
|
||||
(defun rand-vu ()
|
||||
(local-vars (v0-0 int))
|
||||
(rlet ((Q :class vf)
|
||||
(vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
(vf2 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(TODO.VRGET vf1)
|
||||
(.sqrt.vf Q vf1 :ftf #b0)
|
||||
(.add.vf vf2 vf0 Q :mask #b1)
|
||||
(TODO.VRXOR vf2)
|
||||
(TODO.VRNEXT vf1)
|
||||
(.sub.w.vf vf1 vf1 vf0)
|
||||
(.mov v0-0 vf1)
|
||||
(the-as float v0-0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-nostep
|
||||
;; INFO: Return type mismatch int vs float.
|
||||
;; WARN: Inline assembly instruction marked with TODO - [TODO.VRGET]
|
||||
(defun rand-vu-nostep ()
|
||||
(local-vars (v0-0 int))
|
||||
(rlet ((vf0 :class vf)
|
||||
(vf1 :class vf)
|
||||
)
|
||||
(.lvf vf0 (new 'static 'vector :x 0.0 :y 0.0 :z 0.0 :w 1.0))
|
||||
(TODO.VRGET vf1)
|
||||
(.sub.w.vf vf1 vf1 vf0)
|
||||
(.mov v0-0 vf1)
|
||||
(the-as float v0-0)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-float-range
|
||||
(defun rand-vu-float-range ((arg0 float) (arg1 float))
|
||||
(+ arg0 (* (rand-vu) (- arg1 arg0)))
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-percent?
|
||||
(defun rand-vu-percent? ((arg0 float))
|
||||
(>= arg0 (rand-vu))
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-int-range
|
||||
(defun rand-vu-int-range ((first int) (second int))
|
||||
(cond
|
||||
((< first second)
|
||||
(set! second (+ second 1))
|
||||
(let ((v1-1 second))
|
||||
)
|
||||
)
|
||||
(else
|
||||
(set! first (+ first 1))
|
||||
(let ((v1-3 first))
|
||||
)
|
||||
)
|
||||
)
|
||||
(let
|
||||
((float-in-range (rand-vu-float-range (the float first) (the float second))))
|
||||
(when (< float-in-range 0.0)
|
||||
(set! float-in-range (+ -1.0 float-in-range))
|
||||
(let ((v1-5 float-in-range))
|
||||
)
|
||||
)
|
||||
(the int float-in-range)
|
||||
)
|
||||
)
|
||||
|
||||
;; definition for function rand-vu-int-count
|
||||
(defun rand-vu-int-count ((arg0 int))
|
||||
(the int (* (rand-vu) (the float arg0)))
|
||||
)
|
||||
|
||||
;; definition of type random-generator
|
||||
(deftype random-generator (basic)
|
||||
((seed uint32 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; definition for method 3 of type random-generator
|
||||
(defmethod inspect random-generator ((obj random-generator))
|
||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||
(format #t "~Tseed: ~D~%" (-> obj seed))
|
||||
obj
|
||||
)
|
||||
|
||||
;; definition for symbol *random-generator*, type random-generator
|
||||
(define
|
||||
*random-generator*
|
||||
(the-as random-generator (new 'global 'random-generator))
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(set! (-> *random-generator* seed) (the-as uint #x666edd1e))
|
||||
|
||||
;; definition for function rand-uint31-gen
|
||||
;; ERROR: function was not converted to expressions. Cannot decompile.
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-6 0))
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(none)
|
||||
|
25
test/decompiler/reference/types-h_REF.gc
Normal file
25
test/decompiler/reference/types-h_REF.gc
Normal file
@ -0,0 +1,25 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; definition of type time-frame
|
||||
(deftype time-frame (int64)
|
||||
()
|
||||
:method-count-assert 9
|
||||
:size-assert #x8
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
;; definition of type part-id
|
||||
(deftype part-id (uint32)
|
||||
()
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-2 0))
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(none)
|
1033
test/decompiler/reference/vector-h_REF.gc
Normal file
1033
test/decompiler/reference/vector-h_REF.gc
Normal file
File diff suppressed because it is too large
Load Diff
9
test/decompiler/reference/vu1-macros_REF.gc
Normal file
9
test/decompiler/reference/vu1-macros_REF.gc
Normal file
@ -0,0 +1,9 @@
|
||||
;;-*-Lisp-*-
|
||||
(in-package goal)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(let ((v0-0 0))
|
||||
)
|
||||
|
||||
;; failed to figure out what this is:
|
||||
(none)
|
@ -2822,4 +2822,131 @@ TEST_F(FormRegressionTest, LoopingCode) {
|
||||
" (the-as symbol #f)\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
TEST_F(FormRegressionTest, AbsAsSideEffect) {
|
||||
std::string func =
|
||||
"sll r0, r0, 0\n"
|
||||
" dsubu v1, a1, a0\n"
|
||||
" or a3, v1, r0\n"
|
||||
" bltzl a3, L14\n"
|
||||
|
||||
" dsubu a3, r0, a3\n"
|
||||
|
||||
"L14:\n"
|
||||
" slt a3, a2, a3\n"
|
||||
" bne a3, r0, L15\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
" or v0, a1, r0\n"
|
||||
" beq r0, r0, L17\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
"L15:\n"
|
||||
" slt v1, v1, r0\n"
|
||||
" bne v1, r0, L16\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
" daddu v0, a0, a2\n"
|
||||
" beq r0, r0, L17\n"
|
||||
" sll r0, r0, 0\n"
|
||||
|
||||
"L16:\n"
|
||||
" dsubu v0, a0, a2\n"
|
||||
|
||||
"L17:\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function int int int int)";
|
||||
std::string expected =
|
||||
"(let* ((v1-0 (- arg1 arg0))\n"
|
||||
" (a3-0 (abs v1-0))\n" // modified
|
||||
" )\n"
|
||||
//" (set! a3-0 (abs a3-0))\n"
|
||||
" (cond\n"
|
||||
" ((>= arg2 a3-0)\n"
|
||||
" arg1\n"
|
||||
" )\n"
|
||||
" ((>= v1-0 0)\n"
|
||||
" (+ arg0 arg2)\n"
|
||||
" )\n"
|
||||
" (else\n"
|
||||
" (- arg0 arg2)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
// for github https://github.com/water111/jak-project/issues/332
|
||||
// method 11 bit-array
|
||||
TEST_F(FormRegressionTest, AshPropagation) {
|
||||
// (ash a2-0 a3-0)
|
||||
std::string func =
|
||||
"sll r0, r0, 0\n"
|
||||
" dsra v1, a1, 3\n"
|
||||
" daddu v1, v1, a0\n"
|
||||
" lbu v1, 8(v1)\n" // (-> arg0 bytes (sar arg1 3)) [LOAD]
|
||||
" addiu a2, r0, 1\n"
|
||||
" andi a3, a1, 7\n"
|
||||
" bgezl a3, L17\n" // use
|
||||
|
||||
" dsllv a2, a2, a3\n" // use, def
|
||||
|
||||
" dsubu a3, r0, a3\n" // use
|
||||
" dsrav a2, a2, a3\n" // (ash 1 (logand arg1 7)
|
||||
|
||||
"L17:\n"
|
||||
" or v1, v1, a2\n" // (logior (-> arg0 bytes (sar arg1 3)) (ash 1 (logand arg1 7)))
|
||||
" dsra a1, a1, 3\n" // compute source.
|
||||
" daddu a0, a1, a0\n"
|
||||
|
||||
" sb v1, 8(a0)\n"
|
||||
" or v0, r0, r0\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function bit-array int int)";
|
||||
std::string expected =
|
||||
"(begin\n"
|
||||
" (set!\n"
|
||||
" (-> arg0 bytes (sar arg1 3))\n"
|
||||
" (logior (-> arg0 bytes (sar arg1 3)) (the-as uint (ash 1 (logand arg1 7))))\n"
|
||||
" )\n"
|
||||
" 0\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
||||
|
||||
// for github https://github.com/water111/jak-project/issues/332
|
||||
// method 9 bit-array
|
||||
// also checks output prop.
|
||||
TEST_F(FormRegressionTest, AshPropagation2) {
|
||||
// (ash a2-0 a3-0)
|
||||
std::string func =
|
||||
"sll r0, r0, 0\n"
|
||||
"L20:\n"
|
||||
" dsra v1, a1, 3\n"
|
||||
" daddu v1, v1, a0\n"
|
||||
" lbu v1, 8(v1)\n"
|
||||
" daddiu v0, s7, 8\n"
|
||||
" addiu a0, r0, 1\n"
|
||||
" andi a1, a1, 7\n"
|
||||
" bgezl a1, L21\n"
|
||||
|
||||
" dsllv a0, a0, a1\n"
|
||||
|
||||
" dsubu a1, r0, a1\n"
|
||||
" dsrav a0, a0, a1\n"
|
||||
|
||||
"L21:\n"
|
||||
" and v1, v1, a0\n"
|
||||
" movz v0, s7, v1\n"
|
||||
" jr ra\n"
|
||||
" daddu sp, sp, r0";
|
||||
std::string type = "(function bit-array int symbol)";
|
||||
std::string expected =
|
||||
"(let ((v1-2 (-> arg0 bytes (sar arg1 3))))\n"
|
||||
" (nonzero? (logand v1-2 (the-as uint (ash 1 (logand arg1 7)))))\n"
|
||||
" )";
|
||||
test_with_expr(func, type, expected);
|
||||
}
|
@ -33,4 +33,15 @@ TEST(InstructionDecode, VSQRT) {
|
||||
LinkedWord vdiv_word(vdiv_test);
|
||||
auto instr = decode_instruction(vdiv_word, file, 0, 0);
|
||||
EXPECT_EQ(instr.to_string({}), "vsqrt Q, vf20.z");
|
||||
}
|
||||
|
||||
TEST(Instruction, IntelMaskMove) {
|
||||
init_opcode_info();
|
||||
LinkedObjectFile file;
|
||||
u32 vmove_instr = 0b010010'1'1100'00001'00010'01100111100;
|
||||
LinkedWord vmove_word(vmove_instr);
|
||||
auto instr = decode_instruction(vmove_word, file, 0, 0);
|
||||
EXPECT_EQ(instr.to_string({}), "vmove.xy vf1, vf2");
|
||||
// this should be flipped from the PS2...
|
||||
EXPECT_EQ(instr.cop2_dest_mask_intel(), 0b0011);
|
||||
}
|
@ -6,18 +6,29 @@
|
||||
#include "decompiler/config.h"
|
||||
#include "decompiler/ObjectFile/ObjectFileDB.h"
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "common/util/Timer.h"
|
||||
|
||||
namespace {
|
||||
// the object files to test
|
||||
const std::unordered_set<std::string> g_object_files_to_decompile = {
|
||||
"gcommon", "gstring-h", "gkernel-h", "gkernel", /*"pskernel",*/ "gstring", "dgo-h", "gstate",
|
||||
};
|
||||
const std::unordered_set<std::string> g_object_files_to_decompile = {"gcommon",
|
||||
"gstring-h",
|
||||
"gkernel-h",
|
||||
"gkernel",
|
||||
/*"pskernel",*/ "gstring",
|
||||
"dgo-h",
|
||||
"gstate",
|
||||
"types-h",
|
||||
"vu1-macros",
|
||||
"math",
|
||||
"vector-h",
|
||||
"bounding-box-h",
|
||||
/* gap */ "bounding-box"};
|
||||
|
||||
// the object files to check against a reference in test/decompiler/reference
|
||||
const std::vector<std::string> g_object_files_to_check_against_reference = {
|
||||
"gcommon", // NOTE: this file needs work, but adding it for now just to test the framework.
|
||||
"gstring-h", "gkernel-h", "gkernel", "gstring", "dgo-h", "gstate",
|
||||
};
|
||||
"gstring-h", "gkernel-h", "gkernel", "gstring", "dgo-h", "gstate",
|
||||
"types-h", "vu1-macros", "math", "vector-h", "bounding-box-h", /* gap */ "bounding-box"};
|
||||
|
||||
// the functions we expect the decompiler to skip
|
||||
const std::unordered_set<std::string> expected_skip_in_decompiler = {
|
||||
@ -39,14 +50,16 @@ const std::unordered_set<std::string> expected_skip_in_decompiler = {
|
||||
"kernel-check-hardwired-addresses", // ps2 ee kernel debug hook
|
||||
"kernel-read-function", // ps2 ee kernel debug hook
|
||||
"kernel-write-function", // ps2 ee kernel debug hook
|
||||
"kernel-copy-function" // ps2 ee kernel debug hook
|
||||
"kernel-copy-function", // ps2 ee kernel debug hook
|
||||
// math
|
||||
"rand-uint31-gen", // weird and terrible random generator
|
||||
// bounding-box
|
||||
"(method 9 bounding-box)", // handwritten asm loop
|
||||
"(method 14 bounding-box)", // handwritten asm loop
|
||||
};
|
||||
|
||||
const std::unordered_set<std::string> skip_in_compiling = {
|
||||
//////////////////////
|
||||
// GCOMMON
|
||||
//////////////////////
|
||||
|
||||
/// GCOMMON
|
||||
// these functions are not implemented by the compiler in OpenGOAL, but are in GOAL.
|
||||
"abs", "ash", "min", "max", "lognor",
|
||||
// weird PS2 specific debug registers:
|
||||
@ -60,23 +73,34 @@ const std::unordered_set<std::string> skip_in_compiling = {
|
||||
// inline assembly
|
||||
"valid?",
|
||||
|
||||
//////////////////////
|
||||
// GKERNEL-H
|
||||
//////////////////////
|
||||
/// GKERNEL-H
|
||||
// bitfields, possibly inline assembly
|
||||
"(method 2 handle)",
|
||||
|
||||
//////////////////////
|
||||
// GKERNEL
|
||||
//////////////////////
|
||||
/// GKERNEL
|
||||
// asm
|
||||
"(method 10 process)",
|
||||
|
||||
//////////////////////
|
||||
// GSTATE
|
||||
//////////////////////
|
||||
/// GSTATE
|
||||
"enter-state", // stack pointer asm
|
||||
|
||||
/// MATH
|
||||
"rand-vu-init", "rand-vu", "rand-vu-nostep", // random hardware
|
||||
"log2", // weird tricky int-as-float stuff
|
||||
|
||||
/// VECTOR-H
|
||||
"(method 3 vector4w)", // print quad
|
||||
"(method 3 vector8h)", // print quad
|
||||
"(method 3 vector16b)", // print quad
|
||||
"(method 3 vector)", // print quad
|
||||
"(method 3 rgbaf)", // print quad
|
||||
"(method 3 plane)", // print quad
|
||||
"(method 3 sphere)", // print quad
|
||||
"(method 3 qword)", // print quad
|
||||
"vector-zero!", // i128
|
||||
"vector-copy!", // i128
|
||||
"vector-dot", // fpu acc
|
||||
"vector4-dot", // fpu acc
|
||||
};
|
||||
|
||||
// default location for the data. It can be changed with a command line argument.
|
||||
@ -264,7 +288,7 @@ TEST_F(OfflineDecompilation, TypeAnalysis) {
|
||||
int failed_count = 0;
|
||||
db->for_each_function([&](decompiler::Function& func, int, decompiler::ObjectFileData&) {
|
||||
if (!func.suspected_asm) {
|
||||
if (!func.ir2.env.has_type_analysis() || !func.ir2.types_succeeded) {
|
||||
if (!func.ir2.env.has_type_analysis() || !func.ir2.env.types_succeeded) {
|
||||
lg::error("Function {} failed types", func.guessed_name.to_string());
|
||||
failed_count++;
|
||||
}
|
||||
@ -359,18 +383,36 @@ TEST_F(OfflineDecompilation, Reference) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
int line_count(const std::string& str) {
|
||||
int result = 0;
|
||||
for (auto& c : str) {
|
||||
if (c == '\n') {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(OfflineDecompilation, Compile) {
|
||||
Compiler compiler;
|
||||
|
||||
compiler.run_front_end_on_string(file_util::read_text_file(file_util::get_file_path(
|
||||
{"test", "decompiler", "reference", "all_forward_declarations.gc"})));
|
||||
|
||||
Timer timer;
|
||||
int total_lines = 0;
|
||||
for (auto& file : g_object_files_to_check_against_reference) {
|
||||
auto& obj_l = db->obj_files_by_name.at(file);
|
||||
ASSERT_EQ(obj_l.size(), 1);
|
||||
|
||||
std::string src = db->ir2_final_out(obj_l.at(0), skip_in_compiling);
|
||||
total_lines += line_count(src);
|
||||
|
||||
compiler.run_full_compiler_on_string_no_save(src);
|
||||
}
|
||||
auto time = timer.getSeconds();
|
||||
lg::info("Total Lines Compiled: {}. Lines/second: {:.1f}\n", total_lines,
|
||||
(float)total_lines / time);
|
||||
}
|
Loading…
Reference in New Issue
Block a user