diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 65bbf30bb..366a2c46b 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -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 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, diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 7f2e207ed..d818480d5 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -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(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(env, "autogenerated-inspect-method-of-" + type->get_name()); + auto method_env = std::make_unique( + 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( + 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(std::vector{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 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(method_env->make_gpr(input->type()), input)); + + // add this function to the object file + auto fe = get_parent_env_of_type(env); + auto method = fe->alloc_val(m_ts.make_typespec("function")); + method->func = method_env.get(); + auto obj_env_inspect = get_parent_env_of_type(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(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(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(env); + Val* result = nullptr; + auto bitfield_info = m_ts.lookup_bitfield_info(type->get_name(), field_name); + result = fe->alloc_val(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: