mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[Compiler/Decompiler] Better support for Bitfield and Enum types (#374)
* compiler fixes, a decent amount of decompiler stuff is working too * more support in decompiler, fix some casts * decompile static data too
This commit is contained in:
parent
26accb8714
commit
060b125324
|
@ -1,16 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "common/common_types.h"
|
||||
#include "common/type_system/TypeSpec.h"
|
||||
|
||||
struct GoalEnum {
|
||||
std::string name;
|
||||
TypeSpec base_type;
|
||||
bool is_bitfield = false;
|
||||
std::unordered_map<std::string, s64> entries;
|
||||
|
||||
bool operator==(const GoalEnum& other) const;
|
||||
bool operator!=(const GoalEnum& other) const;
|
||||
};
|
|
@ -516,15 +516,6 @@ bool StructureType::operator==(const Type& other) const {
|
|||
// clang-format on
|
||||
}
|
||||
|
||||
bool BitFieldType::operator==(const Type& other) const {
|
||||
if (typeid(*this) != typeid(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* p_other = dynamic_cast<const BitFieldType*>(&other);
|
||||
return other.is_equal(*this) && m_fields == p_other->m_fields;
|
||||
}
|
||||
|
||||
int StructureType::get_size_in_memory() const {
|
||||
return m_size_in_mem;
|
||||
}
|
||||
|
@ -669,4 +660,44 @@ std::string BitFieldType::print() const {
|
|||
result += fmt::format("Mem size: {}, load size: {}, signed {}, align {}\n", get_size_in_memory(),
|
||||
get_load_size(), get_load_signed(), get_in_memory_alignment());
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BitFieldType::operator==(const Type& other) const {
|
||||
if (typeid(*this) != typeid(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* p_other = dynamic_cast<const BitFieldType*>(&other);
|
||||
return other.is_equal(*this) && m_fields == p_other->m_fields;
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// Enum
|
||||
/////////////////
|
||||
|
||||
EnumType::EnumType(const ValueType* parent,
|
||||
std::string name,
|
||||
bool is_bitfield,
|
||||
const std::unordered_map<std::string, s64>& entries)
|
||||
: ValueType(parent->get_name(),
|
||||
std::move(name),
|
||||
parent->is_boxed(),
|
||||
parent->get_load_size(),
|
||||
parent->get_load_signed(),
|
||||
parent->get_preferred_reg_class()),
|
||||
m_is_bitfield(is_bitfield),
|
||||
m_entries(entries) {}
|
||||
|
||||
std::string EnumType::print() const {
|
||||
return fmt::format("Enum Type {}", m_name);
|
||||
}
|
||||
|
||||
bool EnumType::operator==(const Type& other) const {
|
||||
if (typeid(*this) != typeid(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* p_other = dynamic_cast<const EnumType*>(&other);
|
||||
return other.is_equal(*this) && (m_entries == p_other->m_entries) &&
|
||||
(m_is_bitfield == p_other->m_is_bitfield);
|
||||
}
|
|
@ -5,11 +5,11 @@
|
|||
* Representation of a GOAL type in the type system.
|
||||
*/
|
||||
|
||||
#ifndef JAK_TYPE_H
|
||||
#define JAK_TYPE_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
#include "common/goal_constants.h"
|
||||
#include "TypeSpec.h"
|
||||
|
||||
|
@ -91,6 +91,8 @@ class Type {
|
|||
}
|
||||
}
|
||||
|
||||
bool is_boxed() const { return m_is_boxed; }
|
||||
|
||||
protected:
|
||||
Type(std::string parent, std::string name, bool is_boxed);
|
||||
|
||||
|
@ -312,4 +314,19 @@ class BitFieldType : public ValueType {
|
|||
std::vector<BitField> m_fields;
|
||||
};
|
||||
|
||||
#endif // JAK_TYPE_H
|
||||
class EnumType : public ValueType {
|
||||
public:
|
||||
EnumType(const ValueType* parent,
|
||||
std::string name,
|
||||
bool is_bitfield,
|
||||
const std::unordered_map<std::string, s64>& entries);
|
||||
std::string print() const override;
|
||||
bool operator==(const Type& other) const override;
|
||||
const std::unordered_map<std::string, s64>& entries() const { return m_entries; }
|
||||
bool is_bitfield() const { return m_is_bitfield; }
|
||||
|
||||
private:
|
||||
friend class TypeSystem;
|
||||
bool m_is_bitfield = false;
|
||||
std::unordered_map<std::string, s64> m_entries;
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <third-party/fmt/core.h>
|
||||
#include "TypeSystem.h"
|
||||
#include "common/util/math_util.h"
|
||||
#include "deftype.h"
|
||||
|
||||
TypeSystem::TypeSystem() {
|
||||
// the "none" and "_type_" types are included by default.
|
||||
|
@ -70,37 +69,6 @@ Type* TypeSystem::add_type(const std::string& name, std::unique_ptr<Type> type)
|
|||
return m_types[name].get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a new 'enum type'. This maps enum names to the their type's name, allowing the enum name to
|
||||
* be used as if it were a type name.
|
||||
*/
|
||||
Type* TypeSystem::add_enum_type(const std::string& name, const std::string& type) {
|
||||
auto kv = m_enum_types.find(name);
|
||||
if (kv != m_enum_types.end()) {
|
||||
// exists already
|
||||
|
||||
if (kv->second != type) {
|
||||
// exists, and we are trying to change it!
|
||||
fmt::print("[TypeSystem] Enum {} was originally\n{}\nand is redefined as\n{}\n", name,
|
||||
kv->second, type);
|
||||
|
||||
throw std::runtime_error("Enum type was redefined.");
|
||||
}
|
||||
} else {
|
||||
// an enum has been forward declared, which is only allowed for types
|
||||
if (m_forward_declared_types.find(name) != m_forward_declared_types.end()) {
|
||||
fmt::print("[TypeSystem] Enum {} was forward-declared, enums cannot be forward-declared\n",
|
||||
name);
|
||||
|
||||
throw std::runtime_error("Enum was forward-declared.");
|
||||
}
|
||||
|
||||
m_enum_types[name] = type;
|
||||
}
|
||||
|
||||
return lookup_type(m_enum_types[name]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Inform the type system that there will eventually be a type named "name".
|
||||
* This will allow the type system to generate TypeSpecs for this type, but not access detailed
|
||||
|
@ -216,9 +184,6 @@ TypeSpec TypeSystem::make_typespec(const std::string& name) const {
|
|||
if (m_types.find(name) != m_types.end() ||
|
||||
m_forward_declared_types.find(name) != m_forward_declared_types.end()) {
|
||||
return TypeSpec(name);
|
||||
} else if (m_enum_types.find(name) != m_enum_types.end()) {
|
||||
// simply return the enum's type instead
|
||||
return TypeSpec(m_enum_types.at(name));
|
||||
} else {
|
||||
fmt::print("[TypeSystem] The type {} is unknown.\n", name);
|
||||
throw std::runtime_error("make_typespec failed");
|
||||
|
@ -233,10 +198,6 @@ bool TypeSystem::partially_defined_type_exists(const std::string& name) const {
|
|||
return m_forward_declared_types.find(name) != m_forward_declared_types.end();
|
||||
}
|
||||
|
||||
bool TypeSystem::enum_type_exists(const std::string& name) const {
|
||||
return m_enum_types.find(name) != m_enum_types.end();
|
||||
}
|
||||
|
||||
TypeSpec TypeSystem::make_array_typespec(const TypeSpec& element_type) const {
|
||||
return TypeSpec("array", {element_type});
|
||||
}
|
||||
|
@ -359,17 +320,6 @@ MethodInfo TypeSystem::add_method(const std::string& type_name,
|
|||
return add_method(lookup_type(make_typespec(type_name)), method_name, ts, allow_new_method);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Return the type name of an enum. Throws if the enum does not exist.
|
||||
*/
|
||||
std::string TypeSystem::get_enum_type_name(const std::string& name) const {
|
||||
if (m_enum_types.find(name) != m_enum_types.end()) {
|
||||
return m_enum_types.at(name);
|
||||
} else {
|
||||
throw std::runtime_error("get_enum_type_name failed");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Add a method, if it doesn't exist. If the method already exists (possibly in a parent), checks to
|
||||
* see if this is an identical definition. If not, it's an error, and if so, nothing happens.
|
||||
|
@ -1152,6 +1102,18 @@ bool TypeSystem::typecheck_base_types(const std::string& expected,
|
|||
return false;
|
||||
}
|
||||
|
||||
EnumType* TypeSystem::try_enum_lookup(const std::string& type_name) const {
|
||||
auto it = m_types.find(type_name);
|
||||
if (it != m_types.end()) {
|
||||
return dynamic_cast<EnumType*>(it->second.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EnumType* TypeSystem::try_enum_lookup(const TypeSpec& type) const {
|
||||
return try_enum_lookup(type.base_type());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get a path from type to object.
|
||||
*/
|
||||
|
@ -1246,6 +1208,9 @@ TypeSpec TypeSystem::lowest_common_ancestor(const std::vector<TypeSpec>& types)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Converts a type in memory to the type you'll get in a register after loading it.
|
||||
*/
|
||||
TypeSpec coerce_to_reg_type(const TypeSpec& in) {
|
||||
if (in.arg_count() == 0) {
|
||||
if (in.base_type() == "int8" || in.base_type() == "int16" || in.base_type() == "int32" ||
|
||||
|
|
|
@ -91,7 +91,6 @@ class TypeSystem {
|
|||
TypeSystem();
|
||||
|
||||
Type* add_type(const std::string& name, std::unique_ptr<Type> type);
|
||||
Type* add_enum_type(const std::string& name, const std::string& type);
|
||||
void forward_declare_type(const std::string& name);
|
||||
void forward_declare_type_as_basic(const std::string& name);
|
||||
void forward_declare_type_as_structure(const std::string& name);
|
||||
|
@ -102,7 +101,6 @@ class TypeSystem {
|
|||
|
||||
bool fully_defined_type_exists(const std::string& name) const;
|
||||
bool partially_defined_type_exists(const std::string& name) const;
|
||||
bool enum_type_exists(const std::string& name) const;
|
||||
TypeSpec make_typespec(const std::string& name) const;
|
||||
TypeSpec make_array_typespec(const TypeSpec& element_type) const;
|
||||
TypeSpec make_function_typespec(const std::vector<std::string>& arg_types,
|
||||
|
@ -119,8 +117,6 @@ class TypeSystem {
|
|||
Type* lookup_type_allow_partial_def(const TypeSpec& ts) const;
|
||||
Type* lookup_type_allow_partial_def(const std::string& name) const;
|
||||
|
||||
std::string get_enum_type_name(const std::string& name) const;
|
||||
|
||||
MethodInfo add_method(const std::string& type_name,
|
||||
const std::string& method_name,
|
||||
const TypeSpec& ts,
|
||||
|
@ -187,6 +183,8 @@ class TypeSystem {
|
|||
return result;
|
||||
}
|
||||
|
||||
EnumType* try_enum_lookup(const std::string& type_name) const;
|
||||
EnumType* try_enum_lookup(const TypeSpec& type) const;
|
||||
TypeSpec lowest_common_ancestor(const TypeSpec& a, const TypeSpec& b) const;
|
||||
TypeSpec lowest_common_ancestor_reg(const TypeSpec& a, const TypeSpec& b) const;
|
||||
TypeSpec lowest_common_ancestor(const std::vector<TypeSpec>& types) const;
|
||||
|
@ -233,7 +231,6 @@ class TypeSystem {
|
|||
enum ForwardDeclareKind { TYPE, STRUCTURE, BASIC };
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<Type>> m_types;
|
||||
std::unordered_map<std::string, std::string> m_enum_types;
|
||||
std::unordered_map<std::string, ForwardDeclareKind> m_forward_declared_types;
|
||||
std::vector<std::unique_ptr<Type>> m_old_types;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This is used both in the compiler and in the decompiler for the type definition file.
|
||||
*/
|
||||
|
||||
#include "Enum.h"
|
||||
#include "common/goos/ParseHelpers.h"
|
||||
#include "defenum.h"
|
||||
#include "deftype.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
|
@ -58,20 +58,6 @@ bool integer_fits(s64 in, int size, bool is_signed) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void for_each_in_list(const goos::Object& list, T f) {
|
||||
const goos::Object* iter = &list;
|
||||
while (iter->is_pair()) {
|
||||
auto lap = iter->as_pair();
|
||||
f(lap->car);
|
||||
iter = &lap->cdr;
|
||||
}
|
||||
|
||||
if (!iter->is_empty_list()) {
|
||||
throw std::runtime_error("invalid list in for_each_in_list: " + list.print());
|
||||
}
|
||||
}
|
||||
|
||||
std::string symbol_string(const goos::Object& obj) {
|
||||
if (obj.is_symbol()) {
|
||||
return obj.as_symbol()->name;
|
||||
|
@ -81,10 +67,11 @@ std::string symbol_string(const goos::Object& obj) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalenum) {
|
||||
EnumType* parse_defenum(const goos::Object& defenum, TypeSystem* ts) {
|
||||
// default enum type will be int32.
|
||||
goalenum.base_type = ts->make_typespec("int32");
|
||||
goalenum.is_bitfield = false;
|
||||
TypeSpec base_type = ts->make_typespec("int32");
|
||||
bool is_bitfield = false;
|
||||
std::unordered_map<std::string, s64> entries;
|
||||
|
||||
auto iter = &defenum;
|
||||
|
||||
|
@ -94,7 +81,7 @@ void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalen
|
|||
if (!enum_name_obj.is_symbol()) {
|
||||
throw std::runtime_error("defenum must be given a symbol as its name");
|
||||
}
|
||||
goalenum.name = enum_name_obj.as_symbol()->name;
|
||||
std::string name = enum_name_obj.as_symbol()->name;
|
||||
|
||||
auto current = car(iter);
|
||||
while (current.is_symbol() && symbol_string(current).at(0) == ':') {
|
||||
|
@ -105,12 +92,12 @@ void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalen
|
|||
current = car(iter);
|
||||
|
||||
if (option_name == ":type") {
|
||||
goalenum.base_type = parse_typespec(ts, option_value);
|
||||
base_type = parse_typespec(ts, option_value);
|
||||
} else if (option_name == ":bitfield") {
|
||||
if (symbol_string(option_value) == "#t") {
|
||||
goalenum.is_bitfield = true;
|
||||
is_bitfield = true;
|
||||
} else if (symbol_string(option_value) == "#f") {
|
||||
goalenum.is_bitfield = false;
|
||||
is_bitfield = false;
|
||||
} else {
|
||||
fmt::print("Invalid option {} to :bitfield option.\n", option_value.print());
|
||||
throw std::runtime_error("invalid bitfield option");
|
||||
|
@ -121,10 +108,10 @@ void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalen
|
|||
}
|
||||
}
|
||||
|
||||
auto type = ts->lookup_type(goalenum.base_type);
|
||||
auto type = ts->lookup_type(base_type);
|
||||
while (!iter->is_empty_list()) {
|
||||
auto field = car(iter);
|
||||
auto name = symbol_string(car(&field));
|
||||
auto entry_name = symbol_string(car(&field));
|
||||
auto rest = cdr(&field);
|
||||
auto& value = car(rest);
|
||||
if (!value.is_int()) {
|
||||
|
@ -138,17 +125,20 @@ void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalen
|
|||
|
||||
rest = cdr(rest);
|
||||
if (!rest->is_empty_list()) {
|
||||
fmt::print("Got too many items in defenum {} entry {}\n", goalenum.name, name);
|
||||
fmt::print("Got too many items in defenum {} entry {}\n", name, entry_name);
|
||||
}
|
||||
|
||||
goalenum.entries[name] = entry_val;
|
||||
entries[entry_name] = entry_val;
|
||||
iter = cdr(iter);
|
||||
}
|
||||
|
||||
if (is_type("integer", goalenum.base_type, ts)) {
|
||||
ts->add_enum_type(goalenum.name, goalenum.base_type.base_type());
|
||||
if (is_type("integer", base_type, ts)) {
|
||||
auto parent = ts->get_type_of_type<ValueType>(base_type.base_type());
|
||||
auto new_type = std::make_unique<EnumType>(parent, name, is_bitfield, entries);
|
||||
new_type->set_runtime_type(parent->get_runtime_name());
|
||||
return dynamic_cast<EnumType*>(ts->add_type(name, std::move(new_type)));
|
||||
} else {
|
||||
throw std::runtime_error("Creating an enum with type " + goalenum.base_type.print() +
|
||||
throw std::runtime_error("Creating an enum with type " + base_type.print() +
|
||||
" is not allowed or not supported yet.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
#include "TypeSystem.h"
|
||||
#include "Enum.h"
|
||||
#include "common/goos/Object.h"
|
||||
|
||||
void parse_defenum(const goos::Object& defenum, TypeSystem* ts, GoalEnum& goalenum);
|
||||
EnumType* parse_defenum(const goos::Object& defenum, TypeSystem* ts);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* This is used both in the compiler and in the decompiler for the type definition file.
|
||||
*/
|
||||
|
||||
#include "common/goos/ParseHelpers.h"
|
||||
#include "deftype.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
|
||||
|
@ -56,20 +57,6 @@ bool is_type(const std::string& expected, const TypeSpec& actual, const TypeSyst
|
|||
return ts->tc(ts->make_typespec(expected), actual);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void for_each_in_list(const goos::Object& list, T f) {
|
||||
const goos::Object* iter = &list;
|
||||
while (iter->is_pair()) {
|
||||
auto lap = iter->as_pair();
|
||||
f(lap->car);
|
||||
iter = &lap->cdr;
|
||||
}
|
||||
|
||||
if (!iter->is_empty_list()) {
|
||||
throw std::runtime_error("invalid list in for_each_in_list: " + list.print());
|
||||
}
|
||||
}
|
||||
|
||||
std::string symbol_string(const goos::Object& obj) {
|
||||
if (obj.is_symbol()) {
|
||||
return obj.as_symbol()->name;
|
||||
|
@ -486,6 +473,7 @@ DeftypeResult parse_deftype(const goos::Object& deftype, TypeSystem* ts) {
|
|||
assert(pto);
|
||||
auto new_type = std::make_unique<BitFieldType>(
|
||||
parent_type_name, name, pto->get_size_in_memory(), pto->get_load_signed());
|
||||
new_type->set_runtime_type(pto->get_runtime_name());
|
||||
auto sr = parse_bitfield_type_def(new_type.get(), ts, field_list_obj, options_obj);
|
||||
result.flags = sr.flags;
|
||||
result.create_runtime_type = sr.generate_runtime_type;
|
||||
|
|
|
@ -216,6 +216,11 @@ Form* cast_form(Form* in, const TypeSpec& new_type, FormPool& pool, const Env& e
|
|||
return cast_to_bitfield(bitfield_info, new_type, pool, env, in);
|
||||
}
|
||||
|
||||
auto enum_info = dynamic_cast<EnumType*>(type_info);
|
||||
if (enum_info && enum_info->is_bitfield()) {
|
||||
return cast_to_bitfield_enum(enum_info, new_type, pool, env, in);
|
||||
}
|
||||
|
||||
return pool.alloc_single_element_form<CastElement>(nullptr, new_type, in);
|
||||
}
|
||||
|
||||
|
@ -843,17 +848,27 @@ void SimpleExpressionElement::update_from_stack_copy_first_int_2(const Env& env,
|
|||
FormStack& stack,
|
||||
std::vector<FormElement*>* result,
|
||||
bool allow_side_effects) {
|
||||
auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true);
|
||||
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 (!m_expr.get_arg(1).is_var()) {
|
||||
auto args = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects);
|
||||
|
||||
if (!arg0_i && !arg0_u) {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(kind),
|
||||
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);
|
||||
auto bti = dynamic_cast<EnumType*>(env.dts->ts.lookup_type(arg0_type));
|
||||
if (bti) {
|
||||
auto new_form = pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_fixed(kind), 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(kind),
|
||||
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(kind), args.at(0),
|
||||
|
@ -993,8 +1008,38 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
|||
auto new_form = pool.alloc_element<GenericElement>(GenericOperator::make_fixed(kind),
|
||||
args.at(0), args.at(1));
|
||||
result->push_back(new_form);
|
||||
} else {
|
||||
// types bad, insert cast.
|
||||
} else {
|
||||
// this is an ugly hack to make (logand (lognot (enum-bitfield xxxx)) work.
|
||||
// I have only one example for this, so I think this unlikely to work in all cases.
|
||||
if (m_expr.get_arg(1).is_var()) {
|
||||
auto arg1_type = env.get_variable_type(m_expr.get_arg(1).var(), true);
|
||||
auto eti = env.dts->ts.try_enum_lookup(arg1_type.base_type());
|
||||
if (eti) {
|
||||
auto integer = get_goal_integer_constant(args.at(0), env);
|
||||
if (integer && ((s64)*integer) < 0) {
|
||||
// clearing a bitfield.
|
||||
auto elts = decompile_bitfield_enum_from_int(arg1_type, env.dts->ts, ~*integer);
|
||||
auto oper =
|
||||
GenericOperator::make_function(pool.alloc_single_element_form<ConstantTokenElement>(
|
||||
nullptr, arg1_type.base_type()));
|
||||
std::vector<Form*> form_elts;
|
||||
for (auto& x : elts) {
|
||||
form_elts.push_back(pool.alloc_single_element_form<ConstantTokenElement>(nullptr, x));
|
||||
}
|
||||
auto inverted =
|
||||
pool.alloc_single_element_form<GenericElement>(nullptr, oper, form_elts);
|
||||
auto normal = pool.alloc_single_element_form<GenericElement>(
|
||||
nullptr, GenericOperator::make_fixed(FixedOperatorKind::LOGNOT), inverted);
|
||||
auto new_form = pool.alloc_element<GenericElement>(GenericOperator::make_fixed(kind),
|
||||
normal, args.at(1));
|
||||
result->push_back(new_form);
|
||||
// assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto cast = pool.alloc_single_element_form<CastElement>(
|
||||
nullptr, TypeSpec(arg0_i ? "int" : "uint"), args.at(1));
|
||||
auto new_form =
|
||||
|
|
|
@ -380,9 +380,10 @@ std::vector<Form*> compact_nested_logiors(GenericElement* input, const Env&) {
|
|||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
* If this could be an integer constant, figure out what the value is.
|
||||
* TODO move this somewhere more general.
|
||||
*/
|
||||
std::optional<u64> get_goal_integer_constant(Form* in, const Env&) {
|
||||
auto as_atom = form_as_atom(in);
|
||||
|
@ -405,8 +406,6 @@ std::optional<u64> get_goal_integer_constant(Form* in, const Env&) {
|
|||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BitFieldDef BitFieldDef::from_constant(const BitFieldConstantDef& constant, FormPool& pool) {
|
||||
BitFieldDef bfd;
|
||||
bfd.field_name = constant.field_name;
|
||||
|
@ -474,4 +473,26 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
|||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||
}
|
||||
|
||||
Form* cast_to_bitfield_enum(const EnumType* type_info,
|
||||
const TypeSpec& typespec,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
Form* in) {
|
||||
auto integer = get_goal_integer_constant(strip_int_or_uint_cast(in), env);
|
||||
if (integer) {
|
||||
auto elts =
|
||||
decompile_bitfield_enum_from_int(TypeSpec(type_info->get_name()), env.dts->ts, *integer);
|
||||
auto oper = GenericOperator::make_function(
|
||||
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, type_info->get_name()));
|
||||
std::vector<Form*> form_elts;
|
||||
for (auto& x : elts) {
|
||||
form_elts.push_back(pool.alloc_single_element_form<ConstantTokenElement>(nullptr, x));
|
||||
}
|
||||
return pool.alloc_single_element_form<GenericElement>(nullptr, oper, form_elts);
|
||||
} else {
|
||||
// all failed, just return whatever.
|
||||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
|
@ -138,4 +138,11 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
|||
const Env& env,
|
||||
Form* in);
|
||||
|
||||
Form* cast_to_bitfield_enum(const EnumType* type_info,
|
||||
const TypeSpec& typespec,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
Form* in);
|
||||
|
||||
std::optional<u64> get_goal_integer_constant(Form* in, const Env&);
|
||||
} // namespace decompiler
|
||||
|
|
|
@ -183,19 +183,48 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
|
||||
(defenum process-mask
|
||||
:bitfield #t :type uint32
|
||||
(execute 0) ;; 1
|
||||
(draw 1) ;; 2
|
||||
(pause 2) ;; 4
|
||||
(menu 3) ;; 8
|
||||
(progress 4) ;; 16
|
||||
(actor-pause 5) ;; 32
|
||||
(sleep 6) ;; 64
|
||||
(sleep-code 7) ;; 128
|
||||
(process-tree 8) ;; 256 not an actual process, just a "tree node" for organization
|
||||
(heap-shrunk 9) ;; 512
|
||||
(going 10) ;; 1024
|
||||
(movie 11) ;; 2048
|
||||
(movie-subject 12) ;; 4096
|
||||
(target 13) ;; 8192
|
||||
(sidekick 14) ;; 16384
|
||||
(crate 15) ;; 32768
|
||||
(collectable 16) ;; 65536
|
||||
(enemy 17) ;; 131072
|
||||
(camera 18) ;; 262144
|
||||
(platform 19) ;; 524288
|
||||
(ambient 20) ;; 1048576
|
||||
(entity 21) ;; 2097152
|
||||
(projectile 22) ;; 4194304
|
||||
(attackable 23) ;; 8388608
|
||||
(death 24) ;; 16777216
|
||||
)
|
||||
|
||||
;; gkernel-h
|
||||
(deftype kernel-context (basic)
|
||||
((prevent-from-run uint32 :offset-assert 4)
|
||||
(require-for-run uint32 :offset-assert 8)
|
||||
(allow-to-run uint32 :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
((prevent-from-run process-mask :offset-assert 4)
|
||||
(require-for-run process-mask :offset-assert 8)
|
||||
(allow-to-run process-mask :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x30
|
||||
|
@ -258,7 +287,7 @@
|
|||
;; gkernel-h
|
||||
(deftype process-tree (basic)
|
||||
((name basic :offset-assert 4)
|
||||
(mask uint32 :offset-assert 8)
|
||||
(mask process-mask :offset-assert 8)
|
||||
(parent (pointer process-tree) :offset-assert 12)
|
||||
(brother (pointer process-tree) :offset-assert 16)
|
||||
(child (pointer process-tree) :offset-assert 20)
|
||||
|
@ -2933,6 +2962,7 @@
|
|||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
||||
(defenum gs-prim-type
|
||||
:type uint8
|
||||
(point 0)
|
||||
|
@ -2947,14 +2977,14 @@
|
|||
;; initializes the contents of the vertex queue.
|
||||
(deftype gs-prim (uint64)
|
||||
((prim gs-prim-type :offset 0 :size 3)
|
||||
(iip uint8 :offset 3 :size 1)
|
||||
(tme uint8 :offset 4 :size 1)
|
||||
(fge uint8 :offset 5 :size 1)
|
||||
(abe uint8 :offset 6 :size 1)
|
||||
(aa1 uint8 :offset 7 :size 1)
|
||||
(fst uint8 :offset 8 :size 1)
|
||||
(ctxt uint8 :offset 9 :size 1)
|
||||
(fix uint8 :offset 10 :size 1)
|
||||
(iip uint8 :offset 3 :size 1)
|
||||
(tme uint8 :offset 4 :size 1)
|
||||
(fge uint8 :offset 5 :size 1)
|
||||
(abe uint8 :offset 6 :size 1)
|
||||
(aa1 uint8 :offset 7 :size 1)
|
||||
(fst uint8 :offset 8 :size 1)
|
||||
(ctxt uint8 :offset 9 :size 1)
|
||||
(fix uint8 :offset 10 :size 1)
|
||||
)
|
||||
:flag-assert #x900000008
|
||||
)
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"STR/GRSOBBB.STR","STR/SA3INTRO.STR"
|
||||
],
|
||||
"str_file_names_":[],
|
||||
"allowed_objects":["gcommon"],
|
||||
"allowed_objects":["gstate"],
|
||||
|
||||
"type_casts_file":"decompiler/config/jak1_ntsc_black_label/type_casts.jsonc",
|
||||
"anonymous_function_types_file":"decompiler/config/jak1_ntsc_black_label/anonymous_function_types.jsonc",
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "common/type_system/defenum.h"
|
||||
#include "common/type_system/deftype.h"
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "common/type_system/Enum.h"
|
||||
#include "common/log/log.h"
|
||||
#include "TP_Type.h"
|
||||
|
||||
|
@ -63,7 +62,10 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
|||
|
||||
} else if (car(o).as_symbol()->name == "deftype") {
|
||||
auto dtr = parse_deftype(cdr(o), &ts);
|
||||
add_symbol(dtr.type.base_type(), "type");
|
||||
if (dtr.create_runtime_type) {
|
||||
add_symbol(dtr.type.base_type(), "type");
|
||||
}
|
||||
|
||||
} else if (car(o).as_symbol()->name == "declare-type") {
|
||||
auto* rest = &cdr(o);
|
||||
auto type_name = car(*rest);
|
||||
|
@ -80,9 +82,8 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
|||
throw std::runtime_error("bad declare-type");
|
||||
}
|
||||
} else if (car(o).as_symbol()->name == "defenum") {
|
||||
GoalEnum new_enum;
|
||||
parse_defenum(cdr(o), &ts, new_enum);
|
||||
// TODO we do nothing with the enum for now
|
||||
parse_defenum(cdr(o), &ts);
|
||||
// so far, enums are never runtime types so there's no symbol for them.
|
||||
} else {
|
||||
throw std::runtime_error("Decompiler cannot parse " + car(o).print());
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "data_decompile.h"
|
||||
#include "third-party/fmt/core.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
|
@ -511,8 +513,6 @@ goos::Object decompile_structure(const TypeSpec& type,
|
|||
|
||||
std::vector<goos::Object> result_def = {
|
||||
pretty_print::to_symbol(fmt::format("new 'static '{}", actual_type.print()))};
|
||||
// pretty_print::to_symbol("new"), pretty_print::to_symbol("'static"),
|
||||
// pretty_print::to_symbol(fmt::format("'{}", actual_type.print()))};
|
||||
for (auto& f : field_defs_out) {
|
||||
auto str = f.second.print();
|
||||
if (str.length() < 40) {
|
||||
|
@ -529,6 +529,20 @@ goos::Object decompile_structure(const TypeSpec& type,
|
|||
goos::Object decompile_value(const TypeSpec& type,
|
||||
const std::vector<u8>& bytes,
|
||||
const TypeSystem& ts) {
|
||||
auto bitfield_enum = ts.try_enum_lookup(type);
|
||||
if (bitfield_enum) {
|
||||
assert((int)bytes.size() == bitfield_enum->get_load_size());
|
||||
assert(bytes.size() <= 8);
|
||||
u64 value = 0;
|
||||
memcpy(&value, bytes.data(), bytes.size());
|
||||
auto defs = decompile_bitfield_enum_from_int(type, ts, value);
|
||||
std::vector<goos::Object> result_def = {pretty_print::to_symbol(type.print())};
|
||||
for (auto& x : defs) {
|
||||
result_def.push_back(pretty_print::to_symbol(x));
|
||||
}
|
||||
return pretty_print::build_list(result_def);
|
||||
}
|
||||
|
||||
// try as common integer types:
|
||||
if (ts.tc(TypeSpec("uint32"), type)) {
|
||||
assert(bytes.size() == 4);
|
||||
|
@ -849,4 +863,35 @@ std::vector<BitFieldConstantDef> decompile_bitfield_from_int(const TypeSpec& typ
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> decompile_bitfield_enum_from_int(const TypeSpec& type,
|
||||
const TypeSystem& ts,
|
||||
u64 value) {
|
||||
u64 reconstructed = 0;
|
||||
std::vector<std::string> result;
|
||||
auto type_info = ts.try_enum_lookup(type.base_type());
|
||||
assert(type_info);
|
||||
assert(type_info->is_bitfield());
|
||||
|
||||
for (auto& field : type_info->entries()) {
|
||||
u64 mask = ((u64)1) << field.second;
|
||||
if (value & mask) {
|
||||
reconstructed |= mask;
|
||||
result.push_back(field.first);
|
||||
}
|
||||
}
|
||||
|
||||
if (reconstructed != value) {
|
||||
throw std::runtime_error(
|
||||
fmt::format("Failed to decompile bitfield enum. Original value is 0x{:x} but we could only "
|
||||
"make 0x{:x} using the available fields.",
|
||||
value, reconstructed));
|
||||
}
|
||||
|
||||
// unordered map will give us these fields in a weird order, let's order them explicitly.
|
||||
std::sort(result.begin(), result.end(), [&](const std::string& a, const std::string& b) {
|
||||
return type_info->entries().at(a) < type_info->entries().at(b);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
|
@ -76,4 +76,8 @@ std::vector<BitFieldConstantDef> decompile_bitfield_from_int(const TypeSpec& typ
|
|||
const TypeSystem& ts,
|
||||
u64 value);
|
||||
|
||||
std::vector<std::string> decompile_bitfield_enum_from_int(const TypeSpec& type,
|
||||
const TypeSystem& ts,
|
||||
u64 value);
|
||||
|
||||
} // namespace decompiler
|
||||
|
|
|
@ -169,9 +169,38 @@
|
|||
;; - not set up in GOAL code
|
||||
;; So these deftypes generate no code.
|
||||
|
||||
(defenum process-mask
|
||||
:bitfield #t :type uint32
|
||||
(execute 0) ;; 1
|
||||
(draw 1) ;; 2
|
||||
(pause 2) ;; 4
|
||||
(menu 3) ;; 8
|
||||
(progress 4) ;; 16
|
||||
(actor-pause 5) ;; 32
|
||||
(sleep 6) ;; 64
|
||||
(sleep-code 7) ;; 128
|
||||
(process-tree 8) ;; 256 not an actual process, just a "tree node" for organization
|
||||
(heap-shrunk 9) ;; 512
|
||||
(going 10) ;; 1024
|
||||
(movie 11) ;; 2048
|
||||
(movie-subject 12) ;; 4096
|
||||
(target 13) ;; 8192
|
||||
(sidekick 14) ;; 16384
|
||||
(crate 15) ;; 32768
|
||||
(collectable 16) ;; 65536
|
||||
(enemy 17) ;; 131072
|
||||
(camera 18) ;; 262144
|
||||
(platform 19) ;; 524288
|
||||
(ambient 20) ;; 1048576
|
||||
(entity 21) ;; 2097152
|
||||
(projectile 22) ;; 4194304
|
||||
(attackable 23) ;; 8388608
|
||||
(death 24) ;; 16777216
|
||||
)
|
||||
|
||||
(deftype process-tree (basic)
|
||||
((name basic :offset-assert 4)
|
||||
(mask uint32 :offset-assert 8)
|
||||
(mask process-mask :offset-assert 8)
|
||||
(parent (pointer process-tree) :offset-assert 12)
|
||||
(brother (pointer process-tree) :offset-assert 16)
|
||||
(child (pointer process-tree) :offset-assert 20)
|
||||
|
@ -193,6 +222,7 @@
|
|||
:no-runtime-type ;; already defined by kscheme. Don't do it again.
|
||||
)
|
||||
|
||||
|
||||
(deftype stack-frame (basic)
|
||||
((name basic :offset 4)
|
||||
(next stack-frame :offset 8) ;; which way does this point?
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
;; bitfield enum to indicate proprties about a process-tree
|
||||
(defenum process-mask
|
||||
:bitfield #t :type int32
|
||||
:bitfield #t :type uint32
|
||||
(execute 0) ;; 1
|
||||
(draw 1) ;; 2
|
||||
(pause 2) ;; 4
|
||||
|
@ -112,17 +112,17 @@
|
|||
|
||||
;; this stores the current state of the kernel.
|
||||
(deftype kernel-context (basic)
|
||||
((prevent-from-run uint32 :offset-assert 4)
|
||||
(require-for-run uint32 :offset-assert 8)
|
||||
(allow-to-run uint32 :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
((prevent-from-run process-mask :offset-assert 4)
|
||||
(require-for-run process-mask :offset-assert 8)
|
||||
(allow-to-run process-mask :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
)
|
||||
|
||||
:size-assert #x30
|
||||
|
@ -199,7 +199,7 @@
|
|||
;; (except GOAL is old and it looks like they called them left-child right-brother trees back then)
|
||||
(deftype process-tree (basic)
|
||||
((name basic :offset-assert 4)
|
||||
(mask uint32 :offset-assert 8)
|
||||
(mask process-mask :offset-assert 8)
|
||||
(parent (pointer process-tree) :offset-assert 12)
|
||||
(brother (pointer process-tree) :offset-assert 16)
|
||||
(child (pointer process-tree) :offset-assert 20)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef JAK_COMPILER_H
|
||||
#define JAK_COMPILER_H
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include "common/type_system/TypeSystem.h"
|
||||
|
@ -17,7 +14,6 @@
|
|||
#include "third-party/fmt/color.h"
|
||||
#include "CompilerException.h"
|
||||
#include "goalc/compiler/SymbolInfo.h"
|
||||
#include "common/type_system/Enum.h"
|
||||
#include "common/goos/ReplUtils.h"
|
||||
|
||||
enum MathMode { MATH_INT, MATH_BINT, MATH_FLOAT, MATH_INVALID };
|
||||
|
@ -216,7 +212,6 @@ class Compiler {
|
|||
Debugger m_debugger;
|
||||
goos::Interpreter m_goos;
|
||||
std::unordered_map<std::string, TypeSpec> m_symbol_types;
|
||||
std::unordered_map<std::string, GoalEnum> m_enums;
|
||||
std::unordered_map<std::shared_ptr<goos::SymbolObject>, goos::Object> m_global_constants;
|
||||
std::unordered_map<std::shared_ptr<goos::SymbolObject>, LambdaVal*> m_inlineable_functions;
|
||||
CompilerSettings m_settings;
|
||||
|
@ -237,12 +232,12 @@ class Compiler {
|
|||
bool is_none(Val* in);
|
||||
emitter::Register parse_register(const goos::Object& code);
|
||||
u64 enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const EnumType* e,
|
||||
const goos::Object& rest,
|
||||
bool throw_on_error,
|
||||
bool* success);
|
||||
Val* compile_enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const EnumType* e,
|
||||
const goos::Object& rest,
|
||||
Env* env);
|
||||
|
||||
|
@ -547,5 +542,3 @@ extern const std::unordered_map<
|
|||
std::string,
|
||||
Val* (Compiler::*)(const goos::Object& form, const goos::Object& rest, Env* env)>
|
||||
g_goal_forms;
|
||||
|
||||
#endif // JAK_COMPILER_H
|
||||
|
|
|
@ -205,10 +205,10 @@ bool Compiler::try_getting_constant_integer(const goos::Object& in, int64_t* out
|
|||
auto head = in.as_pair()->car;
|
||||
if (head.is_symbol()) {
|
||||
auto head_sym = head.as_symbol();
|
||||
auto enum_kv = m_enums.find(head_sym->name);
|
||||
if (enum_kv != m_enums.end()) {
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym->name);
|
||||
if (enum_type) {
|
||||
bool success;
|
||||
u64 as_enum = enum_lookup(in, enum_kv->second, in.as_pair()->cdr, false, &success);
|
||||
u64 as_enum = enum_lookup(in, enum_type, in.as_pair()->cdr, false, &success);
|
||||
if (success) {
|
||||
*out = as_enum;
|
||||
return true;
|
||||
|
|
|
@ -272,9 +272,10 @@ Val* Compiler::compile_pair(const goos::Object& code, Env* env) {
|
|||
return compile_goos_macro(code, macro_obj, rest, env);
|
||||
}
|
||||
|
||||
auto enum_kv = m_enums.find(head_sym->name);
|
||||
if (enum_kv != m_enums.end()) {
|
||||
return compile_enum_lookup(code, enum_kv->second, rest, env);
|
||||
// next try as an enum
|
||||
auto enum_type = m_ts.try_enum_lookup(head_sym->name);
|
||||
if (enum_type) {
|
||||
return compile_enum_lookup(code, enum_type, rest, env);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -718,7 +718,8 @@ StaticResult Compiler::fill_static_array(const goos::Object& form,
|
|||
// 8 - 12 allocated length
|
||||
memcpy(obj->data.data() + 8, &length, 4);
|
||||
// 12 - 16 content type
|
||||
obj->add_type_record(content_type.base_type(), 12);
|
||||
auto runtime_type = m_ts.lookup_type(content_type.base_type())->get_runtime_name();
|
||||
obj->add_type_record(runtime_type, 12);
|
||||
}
|
||||
|
||||
// now add arguments:
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "third-party/fmt/core.h"
|
||||
#include "common/type_system/defenum.h"
|
||||
#include "common/type_system/deftype.h"
|
||||
#include "common/type_system/Enum.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -995,34 +994,24 @@ Val* Compiler::compile_none(const goos::Object& form, const goos::Object& rest,
|
|||
}
|
||||
|
||||
Val* Compiler::compile_defenum(const goos::Object& form, const goos::Object& rest, Env* env) {
|
||||
// format is (defenum name [options] [entries])
|
||||
(void)form;
|
||||
(void)env;
|
||||
|
||||
GoalEnum new_enum;
|
||||
parse_defenum(rest, &m_ts, new_enum);
|
||||
|
||||
auto existing_kv = m_enums.find(new_enum.name);
|
||||
if (existing_kv != m_enums.end() && existing_kv->second != new_enum) {
|
||||
print_compiler_warning("defenum changes the definition of existing enum {}",
|
||||
new_enum.name.c_str());
|
||||
}
|
||||
m_enums[new_enum.name] = new_enum;
|
||||
|
||||
parse_defenum(rest, &m_ts);
|
||||
return get_none();
|
||||
}
|
||||
|
||||
u64 Compiler::enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const EnumType* e,
|
||||
const goos::Object& rest,
|
||||
bool throw_on_error,
|
||||
bool* success) {
|
||||
*success = true;
|
||||
if (e.is_bitfield) {
|
||||
if (e->is_bitfield()) {
|
||||
uint64_t value = 0;
|
||||
for_each_in_list(rest, [&](const goos::Object& o) {
|
||||
auto kv = e.entries.find(symbol_string(o));
|
||||
if (kv == e.entries.end()) {
|
||||
auto kv = e->entries().find(symbol_string(o));
|
||||
if (kv == e->entries().end()) {
|
||||
if (throw_on_error) {
|
||||
throw_compiler_error(form, "The value {} was not found in enum.", o.print());
|
||||
} else {
|
||||
|
@ -1046,8 +1035,8 @@ u64 Compiler::enum_lookup(const goos::Object& form,
|
|||
return;
|
||||
}
|
||||
}
|
||||
auto kv = e.entries.find(symbol_string(o));
|
||||
if (kv == e.entries.end()) {
|
||||
auto kv = e->entries().find(symbol_string(o));
|
||||
if (kv == e->entries().end()) {
|
||||
if (throw_on_error) {
|
||||
throw_compiler_error(form, "The value {} was not found in enum.", o.print());
|
||||
} else {
|
||||
|
@ -1072,34 +1061,22 @@ u64 Compiler::enum_lookup(const goos::Object& form,
|
|||
}
|
||||
|
||||
Val* Compiler::compile_enum_lookup(const goos::Object& form,
|
||||
const GoalEnum& e,
|
||||
const EnumType* e,
|
||||
const goos::Object& rest,
|
||||
Env* env) {
|
||||
bool success;
|
||||
u64 value = enum_lookup(form, e, rest, true, &success);
|
||||
assert(success);
|
||||
auto result = compile_integer(value, env);
|
||||
result->set_type(e.base_type);
|
||||
result->set_type(TypeSpec(e->get_name()));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GoalEnum::operator==(const GoalEnum& other) const {
|
||||
return base_type == other.base_type && is_bitfield == other.is_bitfield &&
|
||||
entries == other.entries;
|
||||
}
|
||||
|
||||
bool GoalEnum::operator!=(const GoalEnum& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
int Compiler::get_size_for_size_of(const goos::Object& form, const goos::Object& rest) {
|
||||
auto args = get_va(form, rest);
|
||||
va_check(form, args, {goos::ObjectType::SYMBOL}, {});
|
||||
|
||||
auto type_to_look_for = args.unnamed.at(0).as_symbol()->name;
|
||||
if (m_ts.enum_type_exists(type_to_look_for)) {
|
||||
type_to_look_for = m_ts.get_enum_type_name(type_to_look_for);
|
||||
}
|
||||
|
||||
if (!m_ts.fully_defined_type_exists(type_to_look_for)) {
|
||||
throw_compiler_error(
|
||||
|
|
|
@ -122,6 +122,13 @@
|
|||
`(none))
|
||||
|
||||
;; timer-h
|
||||
(defenum timer-clock-selection
|
||||
:type uint8
|
||||
(busclk 0)
|
||||
(busclk/16 1)
|
||||
(busclk/256 2)
|
||||
(hblank 3)
|
||||
)
|
||||
(declare-type dma-buffer basic)
|
||||
|
||||
;; display-h
|
||||
|
|
|
@ -3,17 +3,17 @@
|
|||
|
||||
;; definition of type kernel-context
|
||||
(deftype kernel-context (basic)
|
||||
((prevent-from-run uint32 :offset-assert 4)
|
||||
(require-for-run uint32 :offset-assert 8)
|
||||
(allow-to-run uint32 :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
((prevent-from-run process-mask :offset-assert 4)
|
||||
(require-for-run process-mask :offset-assert 8)
|
||||
(allow-to-run process-mask :offset-assert 12)
|
||||
(next-pid int32 :offset-assert 16)
|
||||
(fast-stack-top pointer :offset-assert 20)
|
||||
(current-process basic :offset-assert 24)
|
||||
(relocating-process basic :offset-assert 28)
|
||||
(relocating-min int32 :offset-assert 32)
|
||||
(relocating-max int32 :offset-assert 36)
|
||||
(relocating-offset int32 :offset-assert 40)
|
||||
(low-memory-message basic :offset-assert 44)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x30
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
(define
|
||||
*kernel-context*
|
||||
(new 'static 'kernel-context
|
||||
:prevent-from-run #x41
|
||||
:prevent-from-run (process-mask execute sleep)
|
||||
:next-pid 2
|
||||
:current-process #f
|
||||
:relocating-process #f
|
||||
|
@ -317,7 +317,7 @@
|
|||
)
|
||||
)
|
||||
(set! (-> v0-0 name) arg0)
|
||||
(set! (-> v0-0 mask) (the-as uint 256))
|
||||
(set! (-> v0-0 mask) (process-mask process-tree))
|
||||
(set! (-> v0-0 parent) (the-as (pointer process-tree) #f))
|
||||
(set! (-> v0-0 brother) (the-as (pointer process-tree) #f))
|
||||
(set! (-> v0-0 child) (the-as (pointer process-tree) #f))
|
||||
|
@ -551,7 +551,7 @@
|
|||
)
|
||||
)
|
||||
(set! (-> s3-0 name) arg2)
|
||||
(set! (-> s3-0 mask) (the-as uint 256))
|
||||
(set! (-> s3-0 mask) (process-mask process-tree))
|
||||
(set! (-> s3-0 parent) (the-as (pointer process-tree) #f))
|
||||
(set! (-> s3-0 brother) (the-as (pointer process-tree) #f))
|
||||
(set! (-> s3-0 child) (the-as (pointer process-tree) #f))
|
||||
|
@ -658,7 +658,7 @@
|
|||
)
|
||||
)
|
||||
(set! (-> obj name) arg0)
|
||||
(set! (-> obj mask) (the-as uint 256))
|
||||
(set! (-> obj mask) (process-mask process-tree))
|
||||
(set! (-> obj allocated-length) arg1)
|
||||
(set! (-> obj parent) (the-as (pointer process-tree) #f))
|
||||
(set! (-> obj brother) (the-as (pointer process-tree) #f))
|
||||
|
@ -979,7 +979,7 @@
|
|||
)
|
||||
(set! (-> s5-1 1 parent) (the-as (pointer process-tree) (-> s5-1 2)))
|
||||
(if (-> s5-1 2)
|
||||
(set! (-> s5-1 2 mask) (the-as uint (-> s5-1 1)))
|
||||
(set! (-> s5-1 2 mask) (the-as process-mask (-> s5-1 1)))
|
||||
(set! (-> obj alive-list prev) (the-as dead-pool-heap-rec (-> s5-1 1)))
|
||||
)
|
||||
(set! (-> s5-1 2) (the-as process-tree (-> obj dead-list next)))
|
||||
|
@ -998,7 +998,7 @@
|
|||
(when
|
||||
(not
|
||||
(or
|
||||
(nonzero? (logand (-> arg0 mask) 512))
|
||||
(nonzero? (logand (-> arg0 mask) (process-mask heap-shrunk)))
|
||||
(and (not (-> arg0 next-state)) (not (-> arg0 state)))
|
||||
)
|
||||
)
|
||||
|
@ -1011,7 +1011,7 @@
|
|||
(< (the-as int arg0) (the-as int (gap-location obj (-> obj first-gap))))
|
||||
(set! (-> obj first-gap) (find-gap obj (the-as dead-pool-heap-rec s5-0)))
|
||||
)
|
||||
(set! (-> arg0 mask) (logior (-> arg0 mask) 512))
|
||||
(set! (-> arg0 mask) (logior (-> arg0 mask) (process-mask heap-shrunk)))
|
||||
)
|
||||
(if (= (-> obj first-shrink) s5-0)
|
||||
(set! (-> obj first-shrink) (the-as dead-pool-heap-rec (-> s5-0 2)))
|
||||
|
@ -1256,7 +1256,14 @@
|
|||
(defun
|
||||
iterate-process-tree
|
||||
((arg0 process-tree) (arg1 (function object object)) (arg2 kernel-context))
|
||||
(let ((s4-0 (or (nonzero? (logand (-> arg0 mask) 256)) (arg1 arg0))))
|
||||
(let
|
||||
((s4-0
|
||||
(or
|
||||
(nonzero? (logand (-> arg0 mask) (process-mask process-tree)))
|
||||
(arg1 arg0)
|
||||
)
|
||||
)
|
||||
)
|
||||
(cond
|
||||
((= s4-0 'dead)
|
||||
)
|
||||
|
@ -1282,10 +1289,10 @@
|
|||
(let
|
||||
((s3-0
|
||||
(or
|
||||
(nonzero? (logand (-> arg0 mask) 256))
|
||||
(nonzero? (logand (-> arg0 mask) (process-mask process-tree)))
|
||||
(not
|
||||
(and
|
||||
(zero? (logand (-> arg2 prevent-from-run) (-> arg0 mask)))
|
||||
(zero? (logand (-> arg2 prevent-from-run) (the-as uint (-> arg0 mask))))
|
||||
(run-logic? arg0)
|
||||
)
|
||||
)
|
||||
|
@ -1316,7 +1323,7 @@
|
|||
(defun
|
||||
search-process-tree
|
||||
((arg0 process-tree) (arg1 (function process-tree object)))
|
||||
(if (zero? (logand (-> arg0 mask) 256))
|
||||
(if (zero? (logand (-> arg0 mask) (process-mask process-tree)))
|
||||
(if (arg1 arg0)
|
||||
(return arg0)
|
||||
)
|
||||
|
@ -1361,7 +1368,9 @@
|
|||
((or (= v1-0 'waiting-to-run) (= v1-0 'suspended))
|
||||
(set! (-> s5-0 current-process) a0-0)
|
||||
(cond
|
||||
((nonzero? (logand (-> a0-0 mask) 4))
|
||||
((nonzero?
|
||||
(logand (-> a0-0 mask) (process-mask pause))
|
||||
)
|
||||
(set! *stdcon* *stdcon1*)
|
||||
(set! *debug-draw-pauseable* #t)
|
||||
)
|
||||
|
@ -1399,7 +1408,13 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
(if (nonzero? (logand (-> a0-0 mask) 128))
|
||||
(if
|
||||
(nonzero?
|
||||
(logand
|
||||
(-> a0-0 mask)
|
||||
(process-mask sleep-code)
|
||||
)
|
||||
)
|
||||
(set! (-> a0-0 status) 'suspended)
|
||||
((-> a0-0 main-thread resume-hook)
|
||||
(-> a0-0 main-thread)
|
||||
|
@ -1700,7 +1715,13 @@
|
|||
activate
|
||||
process
|
||||
((obj process) (arg0 process-tree) (arg1 basic) (arg2 pointer))
|
||||
(set! (-> obj mask) (logand -961 (the-as int (-> arg0 mask))))
|
||||
(set!
|
||||
(-> obj mask)
|
||||
(logand
|
||||
(lognot (process-mask sleep sleep-code process-tree heap-shrunk))
|
||||
(-> arg0 mask)
|
||||
)
|
||||
)
|
||||
(set! (-> obj status) 'ready)
|
||||
(let ((v1-4 (-> *kernel-context* next-pid)))
|
||||
(set! (-> obj pid) v1-4)
|
||||
|
@ -1721,7 +1742,7 @@
|
|||
(set! (-> obj state) #f)
|
||||
(set! (-> obj next-state) #f)
|
||||
(cond
|
||||
((nonzero? (logand (-> arg0 mask) 256))
|
||||
((nonzero? (logand (-> arg0 mask) (process-mask process-tree)))
|
||||
(set! (-> obj entity) #f)
|
||||
)
|
||||
(else
|
||||
|
@ -1952,7 +1973,7 @@
|
|||
(let ((gp-2 change-parent)
|
||||
(a0-57 (new 'global 'process-tree 'camera-pool))
|
||||
)
|
||||
(set! (-> a0-57 mask) (the-as uint #x4011c))
|
||||
(set! (-> a0-57 mask) (process-mask pause menu progress process-tree camera))
|
||||
(set! *camera-pool* a0-57)
|
||||
(gp-2 a0-57 *active-pool*)
|
||||
)
|
||||
|
@ -1961,7 +1982,7 @@
|
|||
(let ((gp-3 change-parent)
|
||||
(a0-59 (new 'global 'process-tree 'target-pool))
|
||||
)
|
||||
(set! (-> a0-59 mask) (the-as uint 284))
|
||||
(set! (-> a0-59 mask) (process-mask pause menu progress process-tree))
|
||||
(set! *target-pool* a0-59)
|
||||
(gp-3 a0-59 *active-pool*)
|
||||
)
|
||||
|
@ -1970,7 +1991,7 @@
|
|||
(let ((gp-4 change-parent)
|
||||
(a0-61 (new 'global 'process-tree 'entity-pool))
|
||||
)
|
||||
(set! (-> a0-61 mask) (the-as uint #x20011c))
|
||||
(set! (-> a0-61 mask) (process-mask pause menu progress process-tree entity))
|
||||
(set! *entity-pool* a0-61)
|
||||
(gp-4 a0-61 *active-pool*)
|
||||
)
|
||||
|
@ -1979,7 +2000,7 @@
|
|||
(let ((gp-5 change-parent)
|
||||
(a0-63 (new 'global 'process-tree 'default-pool))
|
||||
)
|
||||
(set! (-> a0-63 mask) (the-as uint 284))
|
||||
(set! (-> a0-63 mask) (process-mask pause menu progress process-tree))
|
||||
(set! *default-pool* a0-63)
|
||||
(gp-5 a0-63 *active-pool*)
|
||||
)
|
||||
|
|
|
@ -63,8 +63,11 @@
|
|||
(arg5 object)
|
||||
)
|
||||
(local-vars (pp process) (s7-0 none) (sp-0 none) (sp-1 int) (ra-0 int))
|
||||
(set! (-> pp mask) (logand -193 (the-as int (-> pp mask))))
|
||||
(set! (-> pp mask) (logior (-> pp mask) 1024))
|
||||
(set!
|
||||
(-> pp mask)
|
||||
(logand (lognot (process-mask sleep sleep-code)) (-> pp mask))
|
||||
)
|
||||
(set! (-> pp mask) (logior (-> pp mask) (process-mask going)))
|
||||
(cond
|
||||
((= (-> pp status) 'initialize)
|
||||
(set! (-> pp trans-hook) #f)
|
||||
|
@ -93,7 +96,7 @@
|
|||
(set! s0-1 (-> s0-1 next))
|
||||
)
|
||||
)
|
||||
(set! (-> pp mask) (logand -1025 (the-as int (-> pp mask))))
|
||||
(set! (-> pp mask) (logand (lognot (process-mask going)) (-> pp mask)))
|
||||
(let ((s0-2 (-> pp state)))
|
||||
(set! (-> pp event-hook) (-> s0-2 event))
|
||||
(cond
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
;; definition of type timer-mode
|
||||
(deftype timer-mode (uint32)
|
||||
((clks uint8 :offset 0 :size 2)
|
||||
(gate uint8 :offset 2 :size 1)
|
||||
(gats uint8 :offset 3 :size 1)
|
||||
(gatm uint8 :offset 4 :size 2)
|
||||
(zret uint8 :offset 6 :size 1)
|
||||
(cue uint8 :offset 7 :size 1)
|
||||
(cmpe uint8 :offset 8 :size 1)
|
||||
(ovfe uint8 :offset 9 :size 1)
|
||||
(equf uint8 :offset 10 :size 1)
|
||||
(ovff uint8 :offset 11 :size 1)
|
||||
((clks timer-clock-selection :offset 0 :size 2)
|
||||
(gate uint8 :offset 2 :size 1)
|
||||
(gats uint8 :offset 3 :size 1)
|
||||
(gatm uint8 :offset 4 :size 2)
|
||||
(zret uint8 :offset 6 :size 1)
|
||||
(cue uint8 :offset 7 :size 1)
|
||||
(cmpe uint8 :offset 8 :size 1)
|
||||
(ovfe uint8 :offset 9 :size 1)
|
||||
(equf uint8 :offset 10 :size 1)
|
||||
(ovff uint8 :offset 11 :size 1)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
|
|
|
@ -20,7 +20,7 @@ class DataDecompTest : public ::testing::Test {
|
|||
|
||||
static void TearDownTestCase() { dts.reset(); }
|
||||
|
||||
void check_forms_equal(const std::string& expected, const std::string& actual) {
|
||||
void check_forms_equal(const std::string& actual, const std::string& expected) {
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
auto actual_form =
|
||||
|
@ -356,4 +356,31 @@ TEST_F(DataDecompTest, Bitfield) {
|
|||
auto decomp =
|
||||
decompile_bitfield(typespec, info, parsed.label("L80"), parsed.labels, {parsed.words}, ts);
|
||||
check_forms_equal(decomp.print(), "(new 'static 'rgba :r #x40 :b #x40 :a #x80)");
|
||||
}
|
||||
|
||||
TEST_F(DataDecompTest, KernelContext) {
|
||||
std::string input =
|
||||
" .type kernel-context\n"
|
||||
"L345:\n"
|
||||
" .word 0x41\n"
|
||||
" .word 0x0\n"
|
||||
" .word 0x0\n"
|
||||
" .word 0x2\n"
|
||||
" .word 0x0\n"
|
||||
" .symbol #f\n"
|
||||
" .symbol #f\n"
|
||||
" .word 0x0\n"
|
||||
" .word 0x0\n"
|
||||
" .word 0x0\n"
|
||||
" .symbol #t\n";
|
||||
auto parsed = parse_data(input);
|
||||
auto decomp =
|
||||
decompile_at_label_guess_type(parsed.label("L345"), parsed.labels, {parsed.words}, dts->ts);
|
||||
check_forms_equal(decomp.print(),
|
||||
"(new 'static 'kernel-context\n"
|
||||
" :prevent-from-run (process-mask execute sleep)\n"
|
||||
" :next-pid 2\n"
|
||||
" :current-process #f\n"
|
||||
" :relocating-process #f\n"
|
||||
" :low-memory-message #t)\n");
|
||||
}
|
|
@ -307,7 +307,8 @@ TEST_F(FormRegressionTest, IterateProcessTree) {
|
|||
" daddiu sp, sp, 80";
|
||||
std::string type = "(function process-tree (function object object) kernel-context object)";
|
||||
std::string expected =
|
||||
"(let ((s4-0 (or (nonzero? (logand (-> arg0 mask) 256)) (arg1 arg0))))\n"
|
||||
"(let ((s4-0 (or (nonzero? (logand (-> arg0 mask) (process-mask process-tree))) (arg1 "
|
||||
"arg0))))\n"
|
||||
" (cond\n"
|
||||
" ((= s4-0 (quote dead))\n"
|
||||
" )\n"
|
||||
|
|
|
@ -452,7 +452,7 @@ TEST_F(FormRegressionTest, RemoveMethod0ProcessTree) {
|
|||
"(let\n"
|
||||
" ((v0-0 (object-new arg0 arg1 (the-as int (-> arg1 size)))))\n"
|
||||
" (set! (-> v0-0 name) arg2)\n"
|
||||
" (set! (-> v0-0 mask) (the-as uint 256))\n"
|
||||
" (set! (-> v0-0 mask) (process-mask process-tree))\n"
|
||||
" (set! (-> v0-0 parent) (the-as (pointer process-tree) #f))\n"
|
||||
" (set! (-> v0-0 brother) (the-as (pointer process-tree) #f))\n"
|
||||
" (set! (-> v0-0 child) (the-as (pointer process-tree) #f))\n"
|
||||
|
@ -948,7 +948,7 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPool) {
|
|||
"(let\n"
|
||||
" ((s3-0 (object-new arg0 arg1 (the-as int (-> arg1 size)))))\n"
|
||||
" (set! (-> s3-0 name) arg4)\n"
|
||||
" (set! (-> s3-0 mask) (the-as uint 256))\n"
|
||||
" (set! (-> s3-0 mask) (process-mask process-tree))\n"
|
||||
" (set! (-> s3-0 parent) (the-as (pointer process-tree) #f))\n"
|
||||
" (set! (-> s3-0 brother) (the-as (pointer process-tree) #f))\n"
|
||||
" (set! (-> s3-0 child) (the-as (pointer process-tree) #f))\n"
|
||||
|
@ -1263,7 +1263,7 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) {
|
|||
" )\n"
|
||||
" )\n"
|
||||
" (set! (-> obj name) arg2)\n"
|
||||
" (set! (-> obj mask) (the-as uint 256))\n"
|
||||
" (set! (-> obj mask) (process-mask process-tree))\n"
|
||||
" (set! (-> obj allocated-length) arg3)\n"
|
||||
" (set! (-> obj parent) (the-as (pointer process-tree) #f))\n"
|
||||
" (set! (-> obj brother) (the-as (pointer process-tree) #f))\n"
|
||||
|
@ -2241,7 +2241,7 @@ TEST_F(FormRegressionTest, ExprMethod15DeadPoolHeap) {
|
|||
" )\n"
|
||||
" (set! (-> s5-1 1 parent) (the-as (pointer process-tree) (-> s5-1 2)))\n"
|
||||
" (if (-> s5-1 2)\n"
|
||||
" (set! (-> s5-1 2 mask) (the-as uint (-> s5-1 1)))\n"
|
||||
" (set! (-> s5-1 2 mask) (the-as process-mask (-> s5-1 1)))\n"
|
||||
" (set! (-> arg0 alive-list prev) (the-as dead-pool-heap-rec (-> s5-1 1)))\n"
|
||||
" )\n"
|
||||
" (set! (-> s5-1 2) (the-as process-tree (-> arg0 dead-list next)))\n"
|
||||
|
@ -2352,7 +2352,7 @@ TEST_F(FormRegressionTest, ExprMethod17DeadPoolHeap) {
|
|||
" (when\n"
|
||||
" (not\n"
|
||||
" (or\n"
|
||||
" (nonzero? (logand (-> arg1 mask) 512))\n"
|
||||
" (nonzero? (logand (-> arg1 mask) (process-mask heap-shrunk)))\n"
|
||||
" (and (not (-> arg1 next-state)) (not (-> arg1 state)))\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
|
@ -2371,7 +2371,7 @@ TEST_F(FormRegressionTest, ExprMethod17DeadPoolHeap) {
|
|||
" )\n"
|
||||
" (set! (-> arg0 first-gap) (find-gap arg0 (the-as dead-pool-heap-rec s5-0)))\n"
|
||||
" )\n"
|
||||
" (set! (-> arg1 mask) (logior (-> arg1 mask) 512))\n"
|
||||
" (set! (-> arg1 mask) (logior (-> arg1 mask) (process-mask heap-shrunk)))\n"
|
||||
" )\n"
|
||||
" (if (= (-> arg0 first-shrink) s5-0)\n"
|
||||
" (set!\n"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(defenum test-bitfield :bitfield #t
|
||||
(defenum test-bitfield2 :bitfield #t
|
||||
(four 2)
|
||||
(one 0)
|
||||
(two 1)
|
||||
|
@ -6,11 +6,11 @@
|
|||
|
||||
(deftype type-with-bitfield (basic)
|
||||
((name basic)
|
||||
(thing int32)
|
||||
(thing test-bitfield2)
|
||||
)
|
||||
)
|
||||
|
||||
(let ((obj (new 'global 'type-with-bitfield)))
|
||||
(set! (-> obj thing) (test-bitfield one four))
|
||||
(set! (-> obj thing) (test-bitfield2 one four))
|
||||
(the uint (-> obj thing))
|
||||
)
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
(deftype type-with-bitfield2 (basic)
|
||||
((name basic)
|
||||
(thing1 int32)
|
||||
(thing2 int32)
|
||||
(thing1 test-int-enum)
|
||||
(thing2 test-int-enum)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
(defenum test-enum
|
||||
:bitfield #f
|
||||
:type uint16
|
||||
(one 1)
|
||||
(two 2)
|
||||
)
|
||||
|
||||
(deftype test-bitfield (uint16)
|
||||
((f1 uint8 :size 1 :offset 0)
|
||||
(f2 uint8 :size 7 :offset 1))
|
||||
)
|
||||
|
||||
|
||||
(defun print-test-bitfield ((obj test-bitfield))
|
||||
(format #t "f1: ~d~%" (-> obj f1))
|
||||
(format #t "f2: ~d~%" (-> obj f2))
|
||||
obj
|
||||
)
|
||||
|
||||
(defun print-int ((obj int))
|
||||
(format #t "int: ~d~%" obj)
|
||||
obj)
|
||||
|
||||
(let ((test-arr (new 'static 'boxed-array test-bitfield 12)))
|
||||
(format #t "content type: ~A~%" (-> test-arr content-type))
|
||||
)
|
||||
|
||||
(let ((test-arr (new 'static 'boxed-array test-enum 12)))
|
||||
(format #t "content type: ~A~%" (-> test-arr content-type))
|
||||
)
|
||||
|
||||
(deftype enum-bitfield-test-type (structure)
|
||||
((bf0 test-bitfield)
|
||||
(bf1 test-bitfield)
|
||||
(en0 test-enum)
|
||||
(en1 test-enum)
|
||||
(bfs test-bitfield 12)
|
||||
(ens test-enum 12))
|
||||
)
|
||||
|
||||
(let ((obj (new 'stack 'enum-bitfield-test-type)))
|
||||
(format #t "bitfield spacing: ~d~%" (&- (&-> obj bf1) (&-> obj bf0)))
|
||||
(format #t "enum spacing: ~d~%" (&- (&-> obj en1) (&-> obj en0)))
|
||||
(format #t "bitfield array spacing: ~d~%" (&- (&-> obj bfs 1) (&-> obj bfs 0)))
|
||||
(format #t "enum array spacing: ~d~%" (&- (&-> obj ens 1) (&-> obj ens 0)))
|
||||
)
|
||||
|
||||
(defun function-enum-test ((x test-enum))
|
||||
(let ((obj (new 'stack 'enum-bitfield-test-type)))
|
||||
(set! (-> obj en0) x)
|
||||
(set! (-> obj ens 1) x)
|
||||
)
|
||||
(test-enum one)
|
||||
)
|
||||
|
||||
(defun function-bitfield-test ((x test-bitfield))
|
||||
(let ((obj (new 'stack 'enum-bitfield-test-type)))
|
||||
(set! (-> obj bf0) x)
|
||||
(set! (-> obj bfs 1) x)
|
||||
)
|
||||
(new 'static 'test-bitfield :f1 1)
|
||||
)
|
||||
|
||||
(let ((obj (new 'stack 'enum-bitfield-test-type))
|
||||
(mem (new 'stack 'array 'uint8 12))
|
||||
)
|
||||
(set! (-> obj bf0) (function-bitfield-test (new 'static 'test-bitfield :f1 1)))
|
||||
(set! (-> obj bf0) (function-bitfield-test (the test-bitfield 1)))
|
||||
(set! (-> obj en0) (function-enum-test (test-enum one)))
|
||||
(set! (-> obj en0) (function-enum-test (the test-enum 1)))
|
||||
(set! (-> mem 2) 4)
|
||||
(set! (-> mem 3) 5)
|
||||
|
||||
(set! (-> (the (pointer test-enum) mem)) (test-enum one))
|
||||
(set! (-> (the (pointer test-bitfield) mem)) (new 'static 'test-bitfield :f1 1))
|
||||
(format #t "~d~%" (+ (-> mem 2) (-> mem 3)))
|
||||
|
||||
)
|
||||
|
||||
(format #t "sizes: ~d ~d~%" (size-of test-enum) (size-of test-bitfield))
|
|
@ -401,6 +401,19 @@ TEST_F(WithGameTests, SizeOf) {
|
|||
"size of stack array is 16\n0\n"});
|
||||
}
|
||||
|
||||
TEST_F(WithGameTests, EnumAndBitfieldTypes) {
|
||||
runner.run_static_test(env, testCategory, "test-bitfield-and-enum-types.gc",
|
||||
{"content type: uint16\n" // runtime type is u16
|
||||
"content type: uint16\n"
|
||||
"bitfield spacing: 2\n" // u16 spacing
|
||||
"enum spacing: 2\n" // u16 spacing
|
||||
"bitfield array spacing: 2\n" // u16 spacing
|
||||
"enum array spacing: 2\n" // u16 spacing
|
||||
"9\n" // 4 + 5
|
||||
"sizes: 2 2\n" // size-of should work
|
||||
"0\n"});
|
||||
}
|
||||
|
||||
TEST_F(WithGameTests, Trig) {
|
||||
runner.run_static_test(env, testCategory, "test-trig.gc",
|
||||
{"2.0000\n" // 2 deg
|
||||
|
|
Loading…
Reference in a new issue