diff --git a/include/type.hpp b/include/type.hpp index 85d0ff7d..7ce29151 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -190,7 +190,9 @@ class RecordType : public Type { const noexcept = 0; /// @return The type offset in the record. virtual std::size_t offset( // NOLINT(readability-identifier-naming) - const std::string& id) const noexcept = 0; + const std::string& id) const = 0; + virtual std::size_t offset( // NOLINT(readability-identifier-naming) + const std::size_t id) const = 0; /// @brief Checks if `id` is a member of the record type. virtual bool IsMember(const std::string& id) const noexcept = 0; /// @return The type of a member in struct or union. The unknown type if the @@ -209,7 +211,9 @@ class StructType : public RecordType { std::string id() // NOLINT(readability-identifier-naming) const noexcept override; std::size_t offset( // NOLINT(readability-identifier-naming) - const std::string& id) const noexcept override; + const std::string& id) const override; + std::size_t offset( // NOLINT(readability-identifier-naming) + const std::size_t index) const override; bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( const std::string& id) const noexcept override; @@ -238,7 +242,9 @@ class UnionType : public RecordType { std::string id() // NOLINT(readability-identifier-naming) const noexcept override; std::size_t offset( // NOLINT(readability-identifier-naming) - const std::string& id) const noexcept override; + const std::string& id) const override; + std::size_t offset( // NOLINT(readability-identifier-naming) + const std::size_t index) const override; bool IsMember(const std::string& id) const noexcept override; std::unique_ptr MemberType( const std::string& id) const noexcept override; diff --git a/src/qbe_ir_generator.cpp b/src/qbe_ir_generator.cpp index 2e51028d..ff162f17 100644 --- a/src/qbe_ir_generator.cpp +++ b/src/qbe_ir_generator.cpp @@ -225,10 +225,18 @@ void QbeIrGenerator::Visit(const RecordVarDeclNode& record_var_decl) { init->Accept(*this); const auto init_num = num_recorder.NumOfPrevExpr(); + // NOTE: Every member shares the same starting memory location in union. + // Abort if initializing more than one element. + if (record_var_decl.type->IsUnion() && i > 0) { + break; + } + // res_addr = base_addr + offset const int res_addr_num = NextLocalNum(); + auto* record_type = dynamic_cast(record_var_decl.type.get()); + assert(record_type); WriteInstr_("{} =l add {}, {}", FuncScopeTemp{res_addr_num}, - FuncScopeTemp{base_addr}, i * init->type->size()); + FuncScopeTemp{base_addr}, record_type->offset(i)); WriteInstr_("storew {}, {}", FuncScopeTemp{init_num}, FuncScopeTemp{res_addr_num}); } diff --git a/src/type.cpp b/src/type.cpp index 426b7018..cff629a9 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -158,15 +158,32 @@ std::string StructType::id() const noexcept { return id_; } -std::size_t StructType::offset(const std::string& id) const noexcept { +std::size_t StructType::offset(const std::string& id) const { + std::size_t offset = 0; for (auto i = std::size_t{0}, e = fields_.size(); i < e; ++i) { const auto& field = fields_.at(i); if (field->id == id) { - return i * field->type->size(); + return offset; } + + offset += field->type->size(); } - return -1; + throw "member not found in struct!"; +} + +std::size_t StructType::offset(const std::size_t index) const { + std::size_t offset = 0; + for (auto i = std::size_t{0}, e = fields_.size(); i < e; ++i) { + const auto& field = fields_.at(i); + if (i == index) { + return offset; + } + + offset += field->type->size(); + } + + throw "member not found in struct!"; } bool StructType::IsMember(const std::string& id) const noexcept { @@ -231,7 +248,12 @@ std::unique_ptr StructType::Clone() const { return std::make_unique(id_, std::move(cloned_fields)); } -std::size_t UnionType::offset(const std::string& id) const noexcept { +std::size_t UnionType::offset(const std::string& id) const { + // Every member in union shares the same starting location. + return 0; +} + +std::size_t UnionType::offset(const std::size_t index) const { // Every member in union shares the same starting location. return 0; }