diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index 1b617dcf12..c76e93a3d9 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -180,4 +180,5 @@ - Fields with type `(inline-array thing)` can now be set in statics. - `meters`, `degrees`, and `seconds` types have been added. - Bitfields with `symbol` fields used in an immediate `(new 'static ...)` can now define the symbol in the `new` form. -- Bitfields with `float` fields used in an immediate `(new 'static ...)` in code can use a non-constant floating point value. \ No newline at end of file +- Bitfields with `float` fields used in an immediate `(new 'static ...)` in code can use a non-constant floating point value. +- Multiple variables assigned to the same register using `:reg` in `rlet` (or overlapping with `self` in a behavior) will now be merged to a single variable instead of causing a compiler error. Variables will have their own type, but they will all be an alias of the same exact register. \ No newline at end of file diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index 718e838b8a..17f5016de8 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -302,6 +302,11 @@ StackVarAddrVal* FunctionEnv::allocate_aligned_stack_variable(const TypeSpec& ts return result; } +RegVal* FunctionEnv::push_reg_val(std::unique_ptr in) { + m_iregs.push_back(std::move(in)); + return m_iregs.back().get(); +} + /////////////////// // LexicalEnv /////////////////// diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index afc34a490a..90ad79ab77 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -208,6 +208,8 @@ class FunctionEnv : public DeclareEnv { const std::vector>& reg_vals() const { return m_iregs; } + RegVal* push_reg_val(std::unique_ptr in); + int segment = -1; std::string method_of_type_name = "#f"; bool is_asm_func = false; diff --git a/goalc/compiler/compilation/Asm.cpp b/goalc/compiler/compilation/Asm.cpp index a34a3fc0c3..8d3da868f2 100644 --- a/goalc/compiler/compilation/Asm.cpp +++ b/goalc/compiler/compilation/Asm.cpp @@ -75,21 +75,48 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest, } // alloc a register: - auto new_place_reg = env->make_ireg(ts, register_class); - new_place_reg->mark_as_settable(); - + RegVal* new_place_reg = nullptr; if (def_args.has_named("reg")) { - IRegConstraint constraint; - constraint.ireg = new_place_reg->ireg(); - constraint.contrain_everywhere = true; - constraint.desired_register = parse_register(def_args.named.at("reg")); - if (def_args.has_named("reset-here") && - get_true_or_false(form, def_args.get_named("reset-here"))) { - reset_regs.push_back(new_place_reg); + auto desired_register = parse_register(def_args.named.at("reg")); + // we want to see if we already created a variable for this register, and reuse it. + for (auto& constr : fenv->constraints()) { + if (constr.desired_register == desired_register && constr.contrain_everywhere) { + auto reg_val_ptr = std::make_unique(constr.ireg, ts); + new_place_reg = fenv->push_reg_val(std::move(reg_val_ptr)); + new_place_reg->mark_as_settable(); + break; + } } - new_place_reg->set_rlet_constraint(constraint.desired_register); - constraints.push_back(constraint); + if (!new_place_reg) { + for (auto& constr : constraints) { + if (constr.desired_register == desired_register && constr.contrain_everywhere) { + auto reg_val_ptr = std::make_unique(constr.ireg, ts); + new_place_reg = fenv->push_reg_val(std::move(reg_val_ptr)); + new_place_reg->mark_as_settable(); + break; + } + } + } + } + + if (!new_place_reg) { + new_place_reg = env->make_ireg(ts, register_class); + new_place_reg->mark_as_settable(); + + if (def_args.has_named("reg")) { + IRegConstraint constraint; + constraint.ireg = new_place_reg->ireg(); + constraint.contrain_everywhere = true; + constraint.desired_register = parse_register(def_args.named.at("reg")); + if (def_args.has_named("reset-here") && + get_true_or_false(form, def_args.get_named("reset-here"))) { + reset_regs.push_back(new_place_reg); + } + + new_place_reg->set_rlet_constraint(constraint.desired_register); + constraints.push_back(constraint); + } } lenv->vars[new_place_name.as_symbol()->name] = new_place_reg;