mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
Compiler: Auto-generate inspect methods for bitfields (#407)
* goalc: Auto-generate inspect methods for bitfields * goalc: Don't generate inspect methods for 128-bit bitfields
This commit is contained in:
parent
44fa183922
commit
7c182db7ea
|
@ -113,6 +113,11 @@ class Compiler {
|
||||||
const std::string& field_name,
|
const std::string& field_name,
|
||||||
Env* env);
|
Env* env);
|
||||||
|
|
||||||
|
Val* get_field_of_bitfield(const BitFieldType* type,
|
||||||
|
Val* object,
|
||||||
|
const std::string& field_name,
|
||||||
|
Env* env);
|
||||||
|
|
||||||
SymbolVal* compile_get_sym_obj(const std::string& name, Env* env);
|
SymbolVal* compile_get_sym_obj(const std::string& name, Env* env);
|
||||||
void color_object_file(FileEnv* env);
|
void color_object_file(FileEnv* env);
|
||||||
std::vector<u8> codegen_object_file(FileEnv* env);
|
std::vector<u8> codegen_object_file(FileEnv* env);
|
||||||
|
@ -262,7 +267,10 @@ class Compiler {
|
||||||
Env* env,
|
Env* env,
|
||||||
RegVal* reg,
|
RegVal* reg,
|
||||||
const Field& f);
|
const Field& f);
|
||||||
Val* generate_inspector_for_type(const goos::Object& form, Env* env, Type* type);
|
Val* generate_inspector_for_structured_type(const goos::Object& form,
|
||||||
|
Env* env,
|
||||||
|
StructureType* type);
|
||||||
|
Val* generate_inspector_for_bitfield_type(const goos::Object& form, Env* env, BitFieldType* type);
|
||||||
RegVal* compile_get_method_of_type(const goos::Object& form,
|
RegVal* compile_get_method_of_type(const goos::Object& form,
|
||||||
const TypeSpec& type,
|
const TypeSpec& type,
|
||||||
const std::string& method_name,
|
const std::string& method_name,
|
||||||
|
|
|
@ -169,18 +169,13 @@ void Compiler::generate_field_description(const goos::Object& form,
|
||||||
compile_format_string(form, env, str_template, format_args);
|
compile_format_string(form, env, str_template, format_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, Type* type) {
|
Val* Compiler::generate_inspector_for_structured_type(const goos::Object& form,
|
||||||
auto as_structure_type = dynamic_cast<StructureType*>(type);
|
Env* env,
|
||||||
if (!as_structure_type) { // generate the inspect method
|
StructureType* structured_type) {
|
||||||
return get_none();
|
|
||||||
}
|
|
||||||
|
|
||||||
StructureType* structured_type = as_structure_type;
|
|
||||||
|
|
||||||
// Create a function environment to hold the code for the inspect method. The name is just for
|
// Create a function environment to hold the code for the inspect method. The name is just for
|
||||||
// debugging.
|
// debugging.
|
||||||
auto method_env =
|
auto method_env = std::make_unique<FunctionEnv>(
|
||||||
std::make_unique<FunctionEnv>(env, "autogenerated-inspect-method-of-" + type->get_name());
|
env, "autogenerated-inspect-method-of-" + structured_type->get_name());
|
||||||
// put the method in the debug segment.
|
// put the method in the debug segment.
|
||||||
method_env->set_segment(DEBUG_SEGMENT);
|
method_env->set_segment(DEBUG_SEGMENT);
|
||||||
|
|
||||||
|
@ -227,6 +222,61 @@ Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, T
|
||||||
env);
|
env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form,
|
||||||
|
Env* env,
|
||||||
|
BitFieldType* bitfield_type) {
|
||||||
|
// Create a function environment to hold the code for the inspect method. The name is just for
|
||||||
|
// debugging.
|
||||||
|
auto method_env = std::make_unique<FunctionEnv>(
|
||||||
|
env, "autogenerated-inspect-method-of-" + bitfield_type->get_name());
|
||||||
|
// put the method in the debug segment.
|
||||||
|
method_env->set_segment(DEBUG_SEGMENT);
|
||||||
|
|
||||||
|
// Create a register which will hold the input to the inspect method
|
||||||
|
auto input = method_env->make_gpr(bitfield_type->get_name());
|
||||||
|
// "Constrain" this register to be the register that the function argument is passed in
|
||||||
|
IRegConstraint constraint;
|
||||||
|
constraint.instr_idx = 0; // constraint at the start of the function
|
||||||
|
constraint.ireg = input->ireg(); // constrain this register
|
||||||
|
constraint.desired_register = emitter::gRegInfo.get_arg_reg(0); // to the first argument
|
||||||
|
method_env->constrain(constraint);
|
||||||
|
// Inform the compiler that `input`'s value will be written to `rdi` (first arg register)
|
||||||
|
method_env->emit(std::make_unique<IR_ValueReset>(std::vector<RegVal*>{input}));
|
||||||
|
|
||||||
|
RegVal* type_name =
|
||||||
|
compile_get_sym_obj(bitfield_type->get_name(), method_env.get())->to_gpr(method_env.get());
|
||||||
|
compile_format_string(form, method_env.get(), "[~8x] ~A~%", {input, type_name});
|
||||||
|
|
||||||
|
for (const BitField& bf : bitfield_type->fields()) {
|
||||||
|
std::string str_template;
|
||||||
|
std::vector<RegVal*> format_args = {};
|
||||||
|
str_template += fmt::format("~T{}: ~D | 0x~X | 0b~B~%", bf.name());
|
||||||
|
auto value = get_field_of_bitfield(bitfield_type, input, bf.name(), method_env.get())
|
||||||
|
->to_gpr(method_env.get());
|
||||||
|
format_args.push_back(value);
|
||||||
|
format_args.push_back(value);
|
||||||
|
format_args.push_back(value);
|
||||||
|
compile_format_string(form, method_env.get(), str_template, format_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
method_env->emit(std::make_unique<IR_Return>(method_env->make_gpr(input->type()), input));
|
||||||
|
|
||||||
|
// add this function to the object file
|
||||||
|
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
||||||
|
auto method = fe->alloc_val<LambdaVal>(m_ts.make_typespec("function"));
|
||||||
|
method->func = method_env.get();
|
||||||
|
auto obj_env_inspect = get_parent_env_of_type<FileEnv>(method_env.get());
|
||||||
|
obj_env_inspect->add_function(std::move(method_env));
|
||||||
|
|
||||||
|
// call method-set!
|
||||||
|
auto type_obj = compile_get_symbol_value(form, bitfield_type->get_name(), env)->to_gpr(env);
|
||||||
|
auto id_val = compile_integer(m_ts.lookup_method(bitfield_type->get_name(), "inspect").id, env)
|
||||||
|
->to_gpr(env);
|
||||||
|
auto method_set_val = compile_get_symbol_value(form, "method-set!", env)->to_gpr(env);
|
||||||
|
return compile_real_function_call(form, method_set_val, {type_obj, id_val, method->to_gpr(env)},
|
||||||
|
env);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Compile a (deftype ... form)
|
* Compile a (deftype ... form)
|
||||||
*/
|
*/
|
||||||
|
@ -260,7 +310,15 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-generate (inspect) method
|
// Auto-generate (inspect) method
|
||||||
generate_inspector_for_type(form, env, result.type_info);
|
auto as_structure_type = dynamic_cast<StructureType*>(result.type_info);
|
||||||
|
if (as_structure_type) { // generate the inspect method
|
||||||
|
generate_inspector_for_structured_type(form, env, as_structure_type);
|
||||||
|
} else {
|
||||||
|
auto as_bitfield_type = dynamic_cast<BitFieldType*>(result.type_info);
|
||||||
|
if (as_bitfield_type && as_bitfield_type->get_load_size() <= 8) { // Avoid 128-bit bitfields
|
||||||
|
generate_inspector_for_bitfield_type(form, env, as_bitfield_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_symbol_info.add_type(result.type.base_type(), form);
|
m_symbol_info.add_type(result.type.base_type(), form);
|
||||||
|
|
||||||
|
@ -439,6 +497,18 @@ Val* Compiler::get_field_of_structure(const StructureType* type,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Val* Compiler::get_field_of_bitfield(const BitFieldType* type,
|
||||||
|
Val* object,
|
||||||
|
const std::string& field_name,
|
||||||
|
Env* env) {
|
||||||
|
auto fe = get_parent_env_of_type<FunctionEnv>(env);
|
||||||
|
Val* result = nullptr;
|
||||||
|
auto bitfield_info = m_ts.lookup_bitfield_info(type->get_name(), field_name);
|
||||||
|
result = fe->alloc_val<BitFieldVal>(bitfield_info.result_type, object, bitfield_info.offset,
|
||||||
|
bitfield_info.size, bitfield_info.sign_extend);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Compile the (-> ...) form.
|
* Compile the (-> ...) form.
|
||||||
* This is kind of a mess because of the huge number of things you can do with this form:
|
* This is kind of a mess because of the huge number of things you can do with this form:
|
||||||
|
|
Loading…
Reference in a new issue