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:
Tyler Wilding 2021-05-01 15:29:56 -04:00 committed by GitHub
parent 44fa183922
commit 7c182db7ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 12 deletions

View file

@ -113,6 +113,11 @@ class Compiler {
const std::string& field_name,
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);
void color_object_file(FileEnv* env);
std::vector<u8> codegen_object_file(FileEnv* env);
@ -262,7 +267,10 @@ class Compiler {
Env* env,
RegVal* reg,
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,
const TypeSpec& type,
const std::string& method_name,

View file

@ -169,18 +169,13 @@ void Compiler::generate_field_description(const goos::Object& form,
compile_format_string(form, env, str_template, format_args);
}
Val* Compiler::generate_inspector_for_type(const goos::Object& form, Env* env, Type* type) {
auto as_structure_type = dynamic_cast<StructureType*>(type);
if (!as_structure_type) { // generate the inspect method
return get_none();
}
StructureType* structured_type = as_structure_type;
Val* Compiler::generate_inspector_for_structured_type(const goos::Object& form,
Env* env,
StructureType* structured_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-" + type->get_name());
auto method_env = std::make_unique<FunctionEnv>(
env, "autogenerated-inspect-method-of-" + structured_type->get_name());
// put the method in the 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);
}
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)
*/
@ -260,7 +310,15 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res
}
// 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);
@ -439,6 +497,18 @@ Val* Compiler::get_field_of_structure(const StructureType* type,
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.
* This is kind of a mess because of the huge number of things you can do with this form: