diff --git a/parser_library/src/context/ordinary_assembly/address.cpp b/parser_library/src/context/ordinary_assembly/address.cpp index 46cdbe521..9aee19222 100644 --- a/parser_library/src/context/ordinary_assembly/address.cpp +++ b/parser_library/src/context/ordinary_assembly/address.cpp @@ -16,13 +16,18 @@ #include #include +#include +#if __cpp_lib_polymorphic_allocator >= 201902L && __cpp_lib_memory_resource >= 201603L +# include +#endif #include -#include -#include +#include +#include #include #include "location_counter.h" #include "section.h" +#include "utils/merge_sorted.h" namespace hlasm_plugin::parser_library::context { @@ -77,33 +82,25 @@ void space::resolve(space_ptr this_space, space_ptr value) this_space->resolved_ = true; } -void space::resolve(space_ptr this_space, address value) +void space::resolve(space_ptr this_space, int length, std::vector unresolved) { if (this_space->resolved_) return; assert(this_space->kind == space_kind::LOCTR_UNKNOWN); - this_space->resolved_length = value.offset(); + this_space->resolved_length = length; - this_space->resolved_ptrs = std::move(value.spaces()); + this_space->resolved_ptrs = std::move(unresolved); this_space->resolved_ = true; } -void space::resolve(space_ptr this_space, std::variant value) -{ - if (std::holds_alternative(value)) - resolve(std::move(this_space), std::move(std::get(value))); - else - resolve(std::move(this_space), std::move(std::get
(value))); -} - const std::vector& address::bases() const { return bases_; } std::vector& address::bases() { return bases_; } -int get_space_offset(const std::vector& sp_vec) +int get_space_offset(std::span sp_vec) { return std::transform_reduce(sp_vec.begin(), sp_vec.end(), 0, std::plus<>(), [](const auto& v) { const auto& [sp, cnt] = v; @@ -111,55 +108,81 @@ int get_space_offset(const std::vector& sp_vec) }); } -int address::offset() const { return offset_ + get_space_offset(spaces_); } +int address::offset() const { return offset_ + get_space_offset(spaces_.spaces); } +int address::unresolved_offset() const { return offset_; } -std::vector& address::spaces() { return spaces_; } +enum class merge_op : bool +{ + add, + sub +}; -void insert(const address::space_entry& sp, - std::unordered_map& normalized_map, - std::vector& normalized_spaces) +struct normalization_helper { - if (auto it = normalized_map.find(sp.first.get()); it != normalized_map.end()) - normalized_spaces[it->second].second += sp.second; - else - { - normalized_spaces.push_back(sp); - normalized_map.emplace(sp.first.get(), normalized_spaces.size() - 1); - } -} + normalization_helper(const normalization_helper&) = delete; + normalization_helper(normalization_helper&&) = delete; + normalization_helper& operator=(const normalization_helper&) = delete; + normalization_helper& operator=(normalization_helper&&) = delete; +#if __cpp_lib_polymorphic_allocator >= 201902L && __cpp_lib_memory_resource >= 201603L + normalization_helper() + : buffer_resource(buffer.data(), buffer.size()) + , map(&buffer_resource) + {} + alignas(std::max_align_t) std::array buffer; + std::pmr::monotonic_buffer_resource buffer_resource; + std::pmr::unordered_map map; +#else + normalization_helper() = default; + std::unordered_map map; +#endif +}; -int get_unresolved_spaces(const std::vector& spaces, - std::unordered_map& normalized_map, - std::vector& normalized_spaces) +int get_unresolved_spaces(std::span spaces, + normalization_helper& helper, + std::vector& normalized_spaces, + int multiplier) { int offset = 0; - for (const auto& sp : spaces) + for (auto&& sp : spaces) { if (sp.first->resolved()) { - offset += sp.second - * (sp.first->resolved_length - + get_unresolved_spaces(sp.first->resolved_ptrs, normalized_map, normalized_spaces)); + offset += multiplier * sp.second * sp.first->resolved_length + + get_unresolved_spaces(sp.first->resolved_ptrs, helper, normalized_spaces, multiplier * sp.second); + // TODO: overflow check } + else if (auto [it, inserted] = helper.map.try_emplace(sp.first.get(), normalized_spaces.size()); inserted) + normalized_spaces.emplace_back(sp).second *= multiplier; else - insert(sp, normalized_map, normalized_spaces); + normalized_spaces[it->second].second += multiplier * sp.second; } return offset; } -const std::vector& address::spaces() const { return spaces_; } +void cleanup_spaces(std::vector& spaces) +{ + std::erase_if(spaces, [](const address::space_entry& e) { return e.second == 0; }); +} -std::vector address::normalized_spaces() const +std::pair, int> address::normalized_spaces(std::span spaces) { + if (spaces.empty()) + return {}; + std::vector res_spaces; - std::unordered_map tmp_map; + normalization_helper helper; - get_unresolved_spaces(spaces_, tmp_map, res_spaces); + int offset = get_unresolved_spaces(spaces, helper, res_spaces, 1); - std::erase_if(res_spaces, [](const space_entry& e) { return e.second == 0; }); + cleanup_spaces(res_spaces); - return res_spaces; + return { std::move(res_spaces), offset }; +} + +std::pair, int> address::normalized_spaces() const +{ + return normalized_spaces(spaces_.spaces); } address::address(base address_base, int offset, const space_storage& spaces) @@ -167,87 +190,174 @@ address::address(base address_base, int offset, const space_storage& spaces) { bases_.emplace_back(address_base, 1); - spaces_.reserve(spaces.size()); + if (spaces.empty()) + return; + + auto new_spaces = std::make_shared>(); + new_spaces->reserve(spaces.size()); for (auto& space : spaces) - { - spaces_.emplace_back(space, 1); - } - normalize(); -} + new_spaces->emplace_back(space, 1); -enum class op -{ - ADD, - SUB -}; + spaces_.spaces = *new_spaces; + spaces_.owner = std::move(new_spaces); +} -template -std::vector merge_entries(const std::vector& lhs, const std::vector& rhs, const op operation) +address::address(base address_base, int offset, space_storage&& spaces) + : offset_(offset) { - std::vector res; - std::vector prhs; + bases_.emplace_back(address_base, 1); - prhs.reserve(rhs.size()); - for (const auto& e : rhs) - prhs.push_back(&e); + if (spaces.empty()) + return; - for (auto& entry : lhs) - { - auto it = std::find_if(prhs.begin(), prhs.end(), [&](auto e) { return e ? entry.first == e->first : false; }); + auto new_spaces = std::make_shared>(); + new_spaces->reserve(spaces.size()); + for (auto& space : spaces) + new_spaces->emplace_back(std::move(space), 1); - if (it != prhs.end()) - { - int count; - if (operation == op::ADD) - count = entry.second + (*it)->second; // L + R - else - count = entry.second - (*it)->second; // L - R + spaces_.spaces = *new_spaces; + spaces_.owner = std::move(new_spaces); +} - if (count != 0) - res.emplace_back(entry.first, count); +template +std::vector merge_bases( + const std::vector& l, const std::vector& r) +{ + if (r.empty()) + return l; - *it = nullptr; - } - else + if constexpr (operation == merge_op::add) + { + if (l.empty()) + return r; + } + else + { + if (l.empty()) { - res.push_back(entry); + auto result = r; + for (auto& [_, cnt] : result) + cnt *= -1; + return result; } + if (l == r) + return {}; } - for (auto&& rest : prhs) - { - if (!rest) - continue; + std::vector result; - res.push_back(*rest); - if (operation == op::SUB) - res.back().second *= -1; + result.reserve(l.size() + r.size()); + + result = r; + if constexpr (operation == merge_op::sub) + { + for (auto& [_, cnt] : result) + cnt *= -1; } - return res; + std::sort(result.begin(), result.end(), [](const auto& l, const auto& r) { return l.first < r.first; }); + utils::merge_unsorted( + result, + l, + [](const auto& l, const auto& r) { return l.first <=> r.first; }, + [](auto& r, const auto& e) { r.second += e.second; }); + + std::erase_if(result, [](const auto& e) { return e.second == 0; }); + + return result; } address address::operator+(const address& addr) const { - return address(merge_entries(bases_, addr.bases_, op::ADD), - offset() + addr.offset(), - merge_entries(normalized_spaces(), addr.normalized_spaces(), op::ADD)); + if (!has_spaces() && !addr.has_spaces()) + return address(merge_bases(bases_, addr.bases_), offset_ + addr.offset_, space_list()); + + auto res_spaces = std::make_shared>(); + normalization_helper helper; + + int offset = 0; + offset += get_unresolved_spaces(spaces_.spaces, helper, *res_spaces, 1); + offset += get_unresolved_spaces(addr.spaces_.spaces, helper, *res_spaces, 1); + + cleanup_spaces(*res_spaces); + + return address(merge_bases(bases_, addr.bases_), + offset_ + addr.offset_ + offset, + space_list(std::move(res_spaces))); } address address::operator+(int offs) const { return address(bases_, offset_ + offs, spaces_); } +std::pair, std::span> trim_common( + std::span l, std::span r) +{ + if (l.data() == r.data()) + { + auto common = std::min(l.size(), r.size()); + return { l.subspan(common), r.subspan(common) }; + } + auto [le, re] = std::mismatch(l.begin(), l.end(), r.begin(), r.end()); + return { { le, l.end() }, { re, r.end() } }; +} + address address::operator-(const address& addr) const { - return address(merge_entries(bases_, addr.bases_, op::SUB), - offset() - addr.offset(), - merge_entries(normalized_spaces(), addr.normalized_spaces(), op::SUB)); + auto [lspaces, rspaces] = trim_common(spaces_.spaces, addr.spaces_.spaces); + if (lspaces.empty() && rspaces.empty()) + return address(merge_bases(bases_, addr.bases_), offset_ - addr.offset_, {}); + + normalization_helper helper; + + size_t l_processed = 0; + + if (rspaces.empty()) + { + for (const auto& [sp, cnt] : lspaces) + { + if (cnt == 0 || sp->resolved() + || !helper.map.try_emplace(sp.get(), l_processed).second) // requires normalization + break; + + ++l_processed; + } + if (l_processed == lspaces.size()) + return address(merge_bases(bases_, addr.bases_), + offset_ - addr.offset_, + space_list(lspaces, spaces_.owner)); + } + + auto res_spaces = std::make_shared>(); + + if (auto processed = lspaces.subspan(0, l_processed); !processed.empty()) + { + res_spaces->insert(res_spaces->end(), processed.begin(), processed.end()); + lspaces = lspaces.subspan(l_processed); + } + + int offset = 0; + offset += get_unresolved_spaces(lspaces, helper, *res_spaces, 1); + offset += get_unresolved_spaces(rspaces, helper, *res_spaces, -1); + + cleanup_spaces(*res_spaces); + + return address(merge_bases(bases_, addr.bases_), + offset_ - addr.offset_ + offset, + space_list(std::move(res_spaces))); } -address address::operator-(int offs) const { return address(bases_, offset() - offs, normalized_spaces()); } +address address::operator-(int offs) const { return address(bases_, offset_ - offs, spaces_); } address address::operator-() const { - return address(merge_entries({}, bases_, op::SUB), -offset(), merge_entries({}, normalized_spaces(), op::SUB)); + auto [spaces, off] = normalized_spaces(); + auto inv_bases = bases_; + for (auto& b : inv_bases) + b.second = -b.second; + for (auto& s : spaces) + s.second = -s.second; + return address(std::move(inv_bases), + -offset_ - off, + space_list(std::make_shared>(std::move(spaces)))); } bool address::is_complex() const { return bases_.size() > 1; } @@ -260,69 +370,52 @@ bool address::in_same_loctr(const address& addr) const if (addr.bases_[0].first != bases_[0].first) return false; - bool this_has_loctr_begin = spaces_.size() && spaces_[0].first->kind == space_kind::LOCTR_BEGIN; - bool addr_has_loctr_begin = addr.spaces_.size() && addr.spaces_[0].first->kind == space_kind::LOCTR_BEGIN; + auto [spaces, _] = normalized_spaces(); + auto [addr_spaces, __] = addr.normalized_spaces(); + + bool this_has_loctr_begin = spaces.size() && spaces[0].first->kind == space_kind::LOCTR_BEGIN; + bool addr_has_loctr_begin = addr_spaces.size() && addr_spaces[0].first->kind == space_kind::LOCTR_BEGIN; if (this_has_loctr_begin && addr_has_loctr_begin) - return addr.spaces_[0].first == spaces_[0].first; + return spaces[0].first == addr_spaces[0].first; else if (!this_has_loctr_begin && !addr_has_loctr_begin) return true; else { - if (addr.spaces_.size() && spaces_.size()) - return addr.spaces_.front().first->owner.name == spaces_.front().first->owner.name; + if (spaces.size() && addr_spaces.size()) + return spaces.front().first->owner.name == addr_spaces.front().first->owner.name; return false; } } bool address::is_simple() const { return bases_.size() == 1 && bases_[0].second == 1; } -bool has_unresolved_spaces(const space_ptr& sp) -{ - if (!sp->resolved()) - return true; - for (const auto& [s, _] : sp->resolved_ptrs) - if (has_unresolved_spaces(s)) - return true; - return false; -} - bool address::has_dependant_space() const { - for (size_t i = 0; i < spaces_.size(); i++) - { - if (i == 0 && spaces_[i].first->kind == space_kind::LOCTR_BEGIN) - continue; - if (has_unresolved_spaces(spaces_[i].first)) - return true; - } - return false; + if (!has_spaces() || spaces_.spaces.size() == 1 && spaces_.spaces.front().first->kind == space_kind::LOCTR_BEGIN) + return false; + auto [spaces, _] = normalized_spaces(); + if (spaces.empty() || spaces.size() == 1 && spaces.front().first->kind == space_kind::LOCTR_BEGIN) + return false; + return true; } bool address::has_unresolved_space() const { - for (const auto& [sp, _] : spaces_) - if (has_unresolved_spaces(sp)) - return true; - return false; + if (!has_spaces()) + return false; + + auto [spaces, _] = normalized_spaces(); + + return !spaces.empty(); } -address::address(std::vector bases_, int offset_, std::vector spaces_) +bool address::has_spaces() const { return !spaces_.empty(); } + +address::address(std::vector bases_, int offset_, space_list spaces) : bases_(std::move(bases_)) , offset_(offset_) - , spaces_(std::move(spaces_)) + , spaces_(std::move(spaces)) {} -void address::normalize() -{ - std::vector res_spaces; - std::unordered_map tmp_map; - - offset_ += get_unresolved_spaces(spaces_, tmp_map, res_spaces); - - std::erase_if(res_spaces, [](const space_entry& e) { return e.second == 0; }); - - spaces_ = std::move(res_spaces); -} - } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/address.h b/parser_library/src/context/ordinary_assembly/address.h index 6680fdd53..b2bd191a2 100644 --- a/parser_library/src/context/ordinary_assembly/address.h +++ b/parser_library/src/context/ordinary_assembly/address.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -44,19 +45,38 @@ struct address const section* owner = nullptr; id_index qualifier; - friend bool operator==(const base&, const base&) = default; + friend auto operator<=>(const base&, const base&) = default; }; using space_entry = std::pair; using base_entry = std::pair; + struct space_list + { + space_list() = default; + template + explicit space_list(std::shared_ptr ptr) + : spaces(*ptr) + , owner(std::move(ptr)) + {} + explicit space_list(std::span spaces, std::shared_ptr owner) + : spaces(spaces) + , owner(std::move(owner)) + {} + + std::span spaces; + std::shared_ptr owner; + + bool empty() const { return spaces.empty(); } + }; + private: // list of bases and their counts to which is the address relative std::vector bases_; // offset relative to bases int offset_ = 0; // list of spaces with their counts this address contains - std::vector spaces_; + space_list spaces_; public: // list of bases and their counts to which is the address relative @@ -64,13 +84,14 @@ struct address std::vector& bases(); // offset relative to bases int offset() const; + int unresolved_offset() const; // list of spaces with their counts this address contains - std::vector& spaces(); - const std::vector& spaces() const; - std::vector normalized_spaces() const; + static std::pair, int> normalized_spaces(std::span spaces); + std::pair, int> normalized_spaces() const; address() = default; address(base address_base, int offset, const space_storage& spaces); + address(base address_base, int offset, space_storage&& spaces); address operator+(const address& addr) const; address operator+(int offs) const; @@ -83,11 +104,13 @@ struct address bool is_simple() const; bool has_dependant_space() const; bool has_unresolved_space() const; - - void normalize(); + bool has_spaces() const; private: - address(std::vector bases, int offset, std::vector spaces); + address(std::vector bases, int offset, space_list spaces); + + friend struct address_resolver; + friend class location_counter; }; enum class space_kind @@ -125,9 +148,7 @@ struct space // replace space with another static void resolve(space_ptr this_space, space_ptr value); // fill space with the whole address - static void resolve(space_ptr this_space, address value); - // common resolver for 2 methods above - static void resolve(space_ptr this_space, std::variant value); + static void resolve(space_ptr this_space, int length, std::vector unresolved); bool resolved() const { return resolved_; } int resolved_length; diff --git a/parser_library/src/context/ordinary_assembly/address_resolver.cpp b/parser_library/src/context/ordinary_assembly/address_resolver.cpp index 1bea7ab46..ea2907226 100644 --- a/parser_library/src/context/ordinary_assembly/address_resolver.cpp +++ b/parser_library/src/context/ordinary_assembly/address_resolver.cpp @@ -21,15 +21,14 @@ using namespace hlasm_plugin::parser_library::context; -address_resolver::address_resolver(address dependency_address_) +address_resolver::address_resolver(address dependency_address_, size_t boundary) : dependency_address(std::move(dependency_address_)) -{ - cached_deps_.unresolved_address = extract_dep_address(dependency_address); -} + , boundary(boundary) +{} dependency_collector address_resolver::get_dependencies(dependency_solver&) const { - return extract_dep_address(dependency_address); + return extract_dep_address(dependency_address, boundary); } symbol_value address_resolver::resolve(dependency_solver&) const @@ -40,25 +39,22 @@ symbol_value address_resolver::resolve(dependency_solver&) const return dependency_address.offset(); } -address address_resolver::extract_dep_address(const address& addr) +address address_resolver::extract_dep_address(const address& addr, size_t boundary) { - address tmp(address::base {}, 0, {}); - auto spaces = addr.normalized_spaces(); - for (auto it = spaces.rbegin(); it != spaces.rend(); ++it) - { - tmp.spaces().push_back(*it); - if (it->first->kind == space_kind::ALIGNMENT || it->first->kind == space_kind::LOCTR_SET - || it->first->kind == space_kind::LOCTR_MAX) - break; - } - return tmp; + auto [spaces, _] = addr.normalized_spaces(); + auto enough = std::find_if(spaces.rbegin(), spaces.rend(), [boundary](const auto& e) { + return e.first->kind == space_kind::ALIGNMENT && e.first->align.boundary >= boundary + || e.first->kind == space_kind::LOCTR_SET || e.first->kind == space_kind::LOCTR_MAX; + }); + if (enough != spaces.rend()) + spaces.erase(spaces.begin(), std::prev(enough.base())); + return address({}, 0, address::space_list(std::make_shared>(std::move(spaces)))); } alignable_address_resolver::alignable_address_resolver( address dependency_address, std::vector
base_addrs, size_t boundary, int offset) - : address_resolver(std::move(dependency_address)) + : address_resolver(std::move(dependency_address), boundary) , base_addrs(std::move(base_addrs)) - , boundary(boundary) , offset(offset) {} @@ -70,15 +66,6 @@ symbol_value alignable_address_resolver::resolve(const address& addr) const return addr.offset() + (symbol_value::abs_value_t)al + offset; } -alignable_address_resolver::alignable_address_resolver( - address dependency_address_, std::vector
& base_addrs_, size_t boundary_, int offset_, bool) - : address_resolver(std::move(dependency_address_)) - , base_addrs(std::move(base_addrs_)) - , boundary(boundary_) - , offset(offset_) -{} - - alignable_address_abs_part_resolver::alignable_address_abs_part_resolver(const resolvable* dependency_source) : dependency_source_(dependency_source) {} @@ -101,7 +88,10 @@ symbol_value alignable_address_abs_part_resolver::resolve(dependency_solver& sol } aggregate_address_resolver::aggregate_address_resolver(std::vector
base_addrs, size_t boundary, int offset) - : alignable_address_resolver(base_addrs.back(), base_addrs, boundary, offset, false) + : last_base_addrs(base_addrs.size() - 1) + , base_addrs(std::move(base_addrs)) + , boundary(boundary) + , offset(offset) {} symbol_value aggregate_address_resolver::resolve(dependency_solver&) const @@ -117,5 +107,19 @@ symbol_value aggregate_address_resolver::resolve(dependency_solver&) const } } - return alignable_address_resolver::resolve(base_addrs[idx]); + auto al = boundary ? (boundary - base_addrs[idx].offset() % boundary) % boundary : 0; + return base_addrs[idx].offset() + (symbol_value::abs_value_t)al + offset; +} + +dependency_collector aggregate_address_resolver::get_dependencies(dependency_solver&) const +{ + while (last_base_addrs != -1) + { + auto addr = address_resolver::extract_dep_address(base_addrs[last_base_addrs], boundary); + if (addr.has_unresolved_space()) + return std::move(addr); + + --last_base_addrs; + } + return dependency_collector(); } diff --git a/parser_library/src/context/ordinary_assembly/address_resolver.h b/parser_library/src/context/ordinary_assembly/address_resolver.h index d613f6d01..362c15756 100644 --- a/parser_library/src/context/ordinary_assembly/address_resolver.h +++ b/parser_library/src/context/ordinary_assembly/address_resolver.h @@ -30,41 +30,47 @@ using addr_res_ptr = std::unique_ptr; // structure wrapping address providing resolvable interface to it struct address_resolver : public address_resolver_base { - explicit address_resolver(address dependency_address); + explicit address_resolver(address dependency_address, size_t boundary); dependency_collector get_dependencies(dependency_solver& solver) const override; symbol_value resolve(dependency_solver& solver) const override; + static address extract_dep_address(const address& addr, size_t boundary); + protected: address dependency_address; - dependency_collector cached_deps_; - static address extract_dep_address(const address& addr); + size_t boundary; }; // provides resolvable interface for address that require certain alignment -struct alignable_address_resolver : public address_resolver +struct alignable_address_resolver final : public address_resolver { alignable_address_resolver( address dependency_address, std::vector
base_addrs, size_t boundary, int offset); symbol_value resolve(dependency_solver& solver) const override; -protected: +private: std::vector
base_addrs; - size_t boundary; int offset; symbol_value resolve(const address& addr) const; - alignable_address_resolver( - address dependency_address, std::vector
& base_addrs, size_t boundary, int offset, bool); }; // provides resolvable interface for the agregate of addresses -struct aggregate_address_resolver final : public alignable_address_resolver +struct aggregate_address_resolver final : public address_resolver_base { aggregate_address_resolver(std::vector
base_addrs, size_t boundary, int offset); symbol_value resolve(dependency_solver& solver) const override; + + dependency_collector get_dependencies(dependency_solver& solver) const override; + +private: + mutable size_t last_base_addrs; + std::vector
base_addrs; + size_t boundary; + int offset; }; // provides resolvable interface for absolute part of the address diff --git a/parser_library/src/context/ordinary_assembly/dependency_collector.cpp b/parser_library/src/context/ordinary_assembly/dependency_collector.cpp index a6597a56d..5763d0b24 100644 --- a/parser_library/src/context/ordinary_assembly/dependency_collector.cpp +++ b/parser_library/src/context/ordinary_assembly/dependency_collector.cpp @@ -34,9 +34,7 @@ dependency_collector::dependency_collector(id_index undefined_symbol) dependency_collector::dependency_collector(address u_a) : unresolved_address(std::move(u_a)) -{ - unresolved_address->normalize(); -} +{} dependency_collector::dependency_collector(attr_ref attribute_reference) { @@ -110,7 +108,7 @@ dependency_collector& hlasm_plugin::parser_library::context::dependency_collecto if (unresolved_address) { - auto& spaces = unresolved_address->spaces(); + auto [spaces, _] = unresolved_address->normalized_spaces(); utils::merge_unsorted(unresolved_spaces, std::make_move_iterator(spaces.begin()), std::make_move_iterator(spaces.end()), @@ -121,8 +119,12 @@ dependency_collector& hlasm_plugin::parser_library::context::dependency_collecto if (dc.unresolved_address) { - utils::merge_unsorted( - unresolved_spaces, dc.unresolved_address->spaces(), merge_spaces_comparator(), merge_spaces()); + auto [spaces, _] = dc.unresolved_address->normalized_spaces(); + utils::merge_unsorted(unresolved_spaces, + std::make_move_iterator(spaces.begin()), + std::make_move_iterator(spaces.end()), + merge_spaces_comparator(), + merge_spaces()); } return *this; @@ -169,7 +171,6 @@ void dependency_collector::add_sub(const dependency_collector& holder, bool add) unresolved_address = *unresolved_address + (*holder.unresolved_address); else unresolved_address = *unresolved_address - (*holder.unresolved_address); - adjust_address(*unresolved_address); } else if (!unresolved_address && holder.unresolved_address) { @@ -187,20 +188,22 @@ void dependency_collector::div_mul(const dependency_collector& holder) else { if (unresolved_address) - utils::merge_unsorted( - unresolved_spaces, unresolved_address->spaces(), merge_spaces_comparator(), merge_spaces()); + { + auto [spaces, _] = unresolved_address->normalized_spaces(); + utils::merge_unsorted(unresolved_spaces, + std::make_move_iterator(spaces.begin()), + std::make_move_iterator(spaces.end()), + merge_spaces_comparator(), + merge_spaces()); + } if (holder.unresolved_address) - utils::merge_unsorted( - unresolved_spaces, holder.unresolved_address->spaces(), merge_spaces_comparator(), merge_spaces()); + { + auto [spaces, _] = holder.unresolved_address->normalized_spaces(); + utils::merge_unsorted(unresolved_spaces, + std::make_move_iterator(spaces.begin()), + std::make_move_iterator(spaces.end()), + merge_spaces_comparator(), + merge_spaces()); + } } } - -void dependency_collector::adjust_address(address& addr) -{ - auto known_spaces = std::partition(addr.spaces().begin(), addr.spaces().end(), [](auto& entry) { - return entry.first->kind == context::space_kind::LOCTR_UNKNOWN; - }); - - if (known_spaces != addr.spaces().begin()) - addr.spaces().erase(known_spaces, addr.spaces().end()); -} diff --git a/parser_library/src/context/ordinary_assembly/dependency_collector.h b/parser_library/src/context/ordinary_assembly/dependency_collector.h index f109bd683..095e67638 100644 --- a/parser_library/src/context/ordinary_assembly/dependency_collector.h +++ b/parser_library/src/context/ordinary_assembly/dependency_collector.h @@ -105,8 +105,6 @@ struct dependency_collector void add_sub(const dependency_collector& holder, bool add); void div_mul(const dependency_collector& holder); - - static void adjust_address(address& addr); }; } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/location_counter.cpp b/parser_library/src/context/ordinary_assembly/location_counter.cpp index 0b4f690eb..952e2a241 100644 --- a/parser_library/src/context/ordinary_assembly/location_counter.cpp +++ b/parser_library/src/context/ordinary_assembly/location_counter.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "section.h" @@ -41,7 +40,7 @@ location_counter::location_counter(id_index name, const section& owner, loctr_ki address location_counter::current_address() const { - return address({ &owner, id_index() }, curr_data().storage, curr_data().spaces()); + return address({ { { &owner, id_index() }, 1 } }, curr_data().storage, curr_data().spaces_for_address()); } address location_counter::current_address_for_alignment_evaluation(alignment align) const @@ -51,7 +50,7 @@ address location_counter::current_address_for_alignment_evaluation(alignment ali return up.unknown_space->align.boundary >= align.boundary; }).base(); if (it == spaces.begin()) - return address({ &owner, id_index() }, curr_data().storage, curr_data().spaces()); + return address({ { { &owner, id_index() }, 1 } }, curr_data().storage, curr_data().spaces_for_address()); space_storage alignment_spaces; alignment_spaces.reserve(std::distance(it, spaces.end())); @@ -81,7 +80,8 @@ aligned_addr location_counter::reserve_storage_area(size_t length, alignment a) check_available_value(); - return std::make_pair(address({ &owner, id_index() }, (int)curr_data().storage, curr_data().spaces()), sp); + return std::make_pair( + address({ { { &owner, id_index() }, 1 } }, (int)curr_data().storage, curr_data().spaces_for_address()), sp); } aligned_addr location_counter::align(alignment align) { return reserve_storage_area(0, align); } @@ -98,46 +98,41 @@ space_ptr location_counter::register_align_space(alignment align) bool location_counter::need_space_alignment(alignment align) const { return curr_data().need_space_alignment(align); } -space_ptr location_counter::set_value(const address& addr, size_t boundary, int offset, bool has_undefined_part) +std::pair location_counter::set_value(const address& addr, size_t boundary, int offset) { - int al = boundary ? (int)((boundary - (addr.offset() % boundary)) % boundary) : 0; - auto curr_addr = current_address(); - // checks whether addr is in this location counter and if it is well formed - if (!addr.in_same_loctr(curr_addr) || (!addr.has_dependant_space() && addr.offset() + al + offset < 0)) - throw std::runtime_error("set incompatible loctr value"); - - if (has_undefined_part) - { - // when address has undefined absolute part, register space - org_data_.emplace_back(); - return register_space(context::no_align, boundary, offset); - } + auto diff = curr_addr - addr; + auto diff_offset = diff.offset(); - if (curr_addr.spaces() != addr.spaces() || curr_data().storage - addr.offset() > curr_data().current_safe_area - || (boundary && curr_data().storage - addr.offset() > curr_data().current_safe_area + offset)) + if (!diff.bases().empty() || diff.has_spaces() || diff_offset > curr_data().current_safe_area + || (boundary && diff_offset > curr_data().current_safe_area + offset)) { // when addr is composed of different spaces or falls outside safe area, register space org_data_.emplace_back(); - return register_space(context::no_align, space_kind::LOCTR_SET); + return { std::move(curr_addr), register_space(context::no_align, space_kind::LOCTR_SET) }; } else { - int diff = addr.offset() - curr_data().storage; - if (diff < 0 && curr_data().kind == loctr_data_kind::POTENTIAL_MAX) + if (diff_offset > 0 && curr_data().kind == loctr_data_kind::POTENTIAL_MAX) { // when value of addr is lower than loctr's and current loctr value is at its maximum, create new loctr data // so that we can track new loctr value for later maximum retrieval (in method set_available_value) org_data_.emplace_back(curr_data()); curr_data().kind = loctr_data_kind::UNKNOWN_MAX; } - curr_data().append_storage(diff); + curr_data().append_storage(-diff_offset); check_available_value(); - return nullptr; + return { std::move(curr_addr), nullptr }; } } +space_ptr location_counter::set_value_undefined(size_t boundary, int offset) +{ + org_data_.emplace_back(); + return register_space(context::no_align, boundary, offset); +} + std::pair> location_counter::set_available_value() { // here we find the loctr data with the highest value @@ -157,25 +152,20 @@ std::pair> location_counter::set_available_value // and register space that will represent the highest loctr value std::vector
addr_arr; - - for (auto& entry : org_data_) - addr_arr.emplace_back(address::base { &owner, id_index() }, entry.storage, entry.spaces()); - space_ptr loctr_start = nullptr; if (kind == loctr_kind::NONSTARTING) { - loctr_start = addr_arr.front().spaces().front().first; + loctr_start = org_data_.front().fist_space(); assert(loctr_start->kind == space_kind::LOCTR_BEGIN); - for (auto& addr : addr_arr) - { - // make addresses (pseudo-)relative to current location counter - if (addr.spaces().front().first->kind == space_kind::LOCTR_BEGIN) - addr.spaces().erase(addr.spaces().begin()); - else if (addr.spaces().front().first->kind == space_kind::LOCTR_SET) - addr.spaces().emplace_back(loctr_start, -1); - else if (addr.spaces().front().first->kind == space_kind::LOCTR_UNKNOWN) - addr.spaces().emplace_back(loctr_start, -1); - } + } + + for (auto& entry : org_data_) + { + addr_arr.push_back({ + std::vector { { address::base { &owner, id_index() }, 1 } }, + entry.storage, + entry.pseudo_relative_spaces(loctr_start), + }); } org_data_.emplace_back(loctr_data_kind::POTENTIAL_MAX); @@ -211,8 +201,7 @@ bool location_counter::check_if_higher_value(size_t idx) const void location_counter::finish_layout(size_t offset) { - if (layuot_created_) - throw std::runtime_error("layout already created"); + assert(!layuot_created_); assert(!(kind == loctr_kind::STARTING) || offset == 0); // (STARTING => offset==0) <=> (!STARTING v offset==0) diff --git a/parser_library/src/context/ordinary_assembly/location_counter.h b/parser_library/src/context/ordinary_assembly/location_counter.h index 1a77985ff..7b4a5939f 100644 --- a/parser_library/src/context/ordinary_assembly/location_counter.h +++ b/parser_library/src/context/ordinary_assembly/location_counter.h @@ -66,7 +66,8 @@ class location_counter bool need_space_alignment(alignment align) const; // sets value of the location counter to the specified address (ORG instruction) - space_ptr set_value(const address& addr, size_t boundary, int offset, bool has_undefined_part); + std::pair set_value(const address& addr, size_t boundary, int offset); + space_ptr set_value_undefined(size_t boundary, int offset); // sets the location counter to the next available location (ORG with empty first param) std::pair> set_available_value(); diff --git a/parser_library/src/context/ordinary_assembly/location_counter_data.cpp b/parser_library/src/context/ordinary_assembly/location_counter_data.cpp index dd85c35a7..3dcae449c 100644 --- a/parser_library/src/context/ordinary_assembly/location_counter_data.cpp +++ b/parser_library/src/context/ordinary_assembly/location_counter_data.cpp @@ -15,8 +15,8 @@ #include "location_counter_data.h" #include -#include -#include +#include +#include using namespace hlasm_plugin::parser_library::context; @@ -33,7 +33,13 @@ location_counter_data::location_counter_data(loctr_data_kind kind) void location_counter_data::append_space(space_ptr sp) { + if (cached_spaces_for_address && cached_spaces_for_address->size() == cached_spaces_for_address->capacity()) + cached_spaces_for_address.reset(); + cached_pseudo_relative_spaces_for_address.reset(); + unknown_parts.emplace_back(space_storage_t { std::move(sp), 0 }); + if (cached_spaces_for_address) + cached_spaces_for_address->push_back({ unknown_parts.back().unknown_space, 1 }); current_safe_area = 0; } @@ -49,6 +55,9 @@ void location_counter_data::append_storage(int st) void location_counter_data::append_data(location_counter_data data) { + cached_spaces_for_address.reset(); + cached_pseudo_relative_spaces_for_address.reset(); + append_storage(data.unknown_parts.front().storage_after); data.unknown_parts.pop_front(); // the first unknown part is substitiuted by this data @@ -65,6 +74,9 @@ void location_counter_data::resolve_space(const space* sp, size_t length) if (match == unknown_parts.end()) return; + cached_spaces_for_address.reset(); + cached_pseudo_relative_spaces_for_address.reset(); + storage += length; if (match == unknown_parts.begin()) @@ -82,6 +94,8 @@ void location_counter_data::resolve_space(const space* sp, space_ptr new_space) if (match == unknown_parts.end()) return; + cached_spaces_for_address.reset(); + cached_pseudo_relative_spaces_for_address.reset(); match->unknown_space = std::move(new_space); } @@ -158,11 +172,48 @@ space_ptr location_counter_data::last_space() const return nullptr; } -space_storage location_counter_data::spaces() const +address::space_list location_counter_data::spaces_for_address() const { - space_storage res; - res.reserve(unknown_parts.size()); + if (cached_spaces_for_address) + return address::space_list(cached_spaces_for_address); + + auto result = std::make_shared>(); + result->reserve(std::bit_ceil(unknown_parts.size() + unknown_parts.size() / 2)); for (const auto& e : unknown_parts) - res.push_back(e.unknown_space); - return res; + result->push_back({ e.unknown_space, 1 }); + + cached_spaces_for_address = result; + + return address::space_list(result); +} + +address::space_list location_counter_data::pseudo_relative_spaces(space_ptr loctr_start) const +{ + if (cached_pseudo_relative_spaces_for_address) + return *cached_pseudo_relative_spaces_for_address; + + auto result = std::make_shared>(); + result->reserve(unknown_parts.size() + 1); + for (const auto& e : unknown_parts) + result->emplace_back(e.unknown_space, 1); + + const auto loctr_begin = loctr_start && result->front().first->kind == space_kind::LOCTR_BEGIN; + const auto loctr_set = loctr_start && result->front().first->kind == space_kind::LOCTR_SET; + const auto loctr_unknown = loctr_start && result->front().first->kind == space_kind::LOCTR_UNKNOWN; + + // make addresses (pseudo-)relative to current location counter + if (loctr_set) + result->push_back({ loctr_start, -1 }); + else if (loctr_unknown) + result->push_back({ loctr_start, -1 }); + + address::space_list result_list(std::move(result)); + + // make addresses (pseudo-)relative to current location counter + if (loctr_begin) + result_list.spaces = result_list.spaces.subspan(1); + + cached_pseudo_relative_spaces_for_address = result_list; + + return result_list; } diff --git a/parser_library/src/context/ordinary_assembly/location_counter_data.h b/parser_library/src/context/ordinary_assembly/location_counter_data.h index 7d7128bf5..927647924 100644 --- a/parser_library/src/context/ordinary_assembly/location_counter_data.h +++ b/parser_library/src/context/ordinary_assembly/location_counter_data.h @@ -16,6 +16,8 @@ #define CONTEXT_LOCATION_COUNTER_DATA_H #include +#include +#include #include "address.h" #include "alignment.h" @@ -90,6 +92,9 @@ struct location_counter_data int current_safe_area; loctr_data_kind kind; + mutable std::shared_ptr> cached_spaces_for_address; + mutable std::optional cached_pseudo_relative_spaces_for_address; + location_counter_data(); location_counter_data(loctr_data_kind kind); @@ -107,7 +112,8 @@ struct location_counter_data bool has_space() const; space_ptr fist_space() const; space_ptr last_space() const; - space_storage spaces() const; + address::space_list spaces_for_address() const; + address::space_list pseudo_relative_spaces(space_ptr loctr_start) const; }; } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp index 3c6561c6c..11e6bb581 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_context.cpp @@ -216,29 +216,29 @@ space_ptr ordinary_assembly_context::set_location_counter_value_space(const addr if (!curr_section_) create_private_section(); - address curr_addr = curr_section_->current_location_counter().current_address(); - auto sp = curr_section_->current_location_counter().set_value(addr, boundary, offset, undefined_address); - - if (sp) + if (undefined_address) { - if (!undefined_address) - symbol_dependencies.add_dependency(sp, - std::make_unique( - std::move(curr_addr), std::vector
{ addr }, boundary, offset), - dep_ctx, - li); - else - symbol_dependencies.add_dependency(sp, - std::make_unique(undefined_address), - dep_ctx, - li, - std::move(dependency_source)); + auto sp = curr_section_->current_location_counter().set_value_undefined(boundary, offset); + symbol_dependencies.add_dependency(sp, + std::make_unique(undefined_address), + dep_ctx, + li, + std::move(dependency_source)); return sp; } - else + + + if (auto [curr_addr, sp] = curr_section_->current_location_counter().set_value(addr, boundary, offset); sp) { - return reserve_storage_area_space(offset, alignment { 0, boundary ? boundary : 1 }, dep_ctx, li).second; + symbol_dependencies.add_dependency(sp, + std::make_unique( + std::move(curr_addr), std::vector
{ addr }, boundary, offset), + dep_ctx, + li); + return sp; } + + return reserve_storage_area_space(offset, alignment { 0, boundary ? boundary : 1 }, dep_ctx, li).second; } void ordinary_assembly_context::set_available_location_counter_value(const library_info& li) @@ -339,7 +339,7 @@ std::pair ordinary_assembly_context::reserve_storage_area_sp auto [ret_addr, sp] = curr_section_->current_location_counter().reserve_storage_area(length, align); assert(sp); - symbol_dependencies.add_dependency(sp, std::make_unique(addr), dep_ctx, li); + symbol_dependencies.add_dependency(sp, std::make_unique(addr, align.boundary), dep_ctx, li); return std::make_pair(ret_addr, sp); } return std::make_pair(curr_section_->current_location_counter().reserve_storage_area(length, align).first, nullptr); diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp index f943afd54..fbbbba80e 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.cpp @@ -37,7 +37,7 @@ id_index ordinary_assembly_dependency_solver::get_literal_id( } -dependency_evaluation_context ordinary_assembly_dependency_solver::derive_current_dependency_evaluation_context() const +dependency_evaluation_context ordinary_assembly_dependency_solver::derive_current_dependency_evaluation_context() const& { return dependency_evaluation_context { loctr_addr, @@ -48,6 +48,17 @@ dependency_evaluation_context ordinary_assembly_dependency_solver::derive_curren }; } +dependency_evaluation_context ordinary_assembly_dependency_solver::derive_current_dependency_evaluation_context() && +{ + return dependency_evaluation_context { + std::move(loctr_addr), + literal_pool_generation, + unique_id, + active_using, + opcode_gen, + }; +} + bool ordinary_assembly_dependency_solver::using_active(id_index label, const section* sect) const { return ord_context.using_label_active(active_using, label, sect); diff --git a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h index 90d3a30ca..d77b07dfc 100644 --- a/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h +++ b/parser_library/src/context/ordinary_assembly/ordinary_assembly_dependency_solver.h @@ -78,7 +78,8 @@ class ordinary_assembly_dependency_solver final : public dependency_solver std::variant get_symbol_candidate(id_index name) const override; std::string get_opcode_attr(id_index name) const override; - dependency_evaluation_context derive_current_dependency_evaluation_context() const; + dependency_evaluation_context derive_current_dependency_evaluation_context() const&; + dependency_evaluation_context derive_current_dependency_evaluation_context() &&; }; } // namespace hlasm_plugin::parser_library::context diff --git a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp index 8a690185e..4522dbbac 100644 --- a/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp +++ b/parser_library/src/context/ordinary_assembly/symbol_dependency_tables.cpp @@ -158,11 +158,11 @@ struct resolve_dependant_visitor const auto& addr = sym_val.get_reloc(); - if (auto spaces = addr.normalized_spaces(); + if (auto [spaces, _] = addr.normalized_spaces(); std::find_if(spaces.begin(), spaces.end(), [&sp](const auto& e) { return e.first == sp; }) != spaces.end()) add_diagnostic(diagnostic_op::error_E033); - auto tmp_loctr = sym_ctx.current_section()->current_location_counter(); + auto tmp_loctr_name = sym_ctx.current_section()->current_location_counter().name; sym_ctx.set_location_counter(sp->owner.name, location(), li); sym_ctx.current_section()->current_location_counter().switch_to_unresolved_value(sp); @@ -177,7 +177,7 @@ struct resolve_dependant_visitor add_diagnostic(diagnostic_op::error_A115_ORG_op_format); (void)sym_ctx.current_section()->current_location_counter().restore_from_unresolved_value(sp); - sym_ctx.set_location_counter(tmp_loctr.name, location(), li); + sym_ctx.set_location_counter(tmp_loctr_name, location(), li); return; } @@ -185,9 +185,17 @@ struct resolve_dependant_visitor addr, sp->previous_boundary, sp->previous_offset, nullptr, nullptr, dep_ctx, li); auto ret = sym_ctx.current_section()->current_location_counter().restore_from_unresolved_value(sp); - sym_ctx.set_location_counter(tmp_loctr.name, location(), li); + sym_ctx.set_location_counter(tmp_loctr_name, location(), li); - context::space::resolve(sp, std::move(ret)); + if (std::holds_alternative(ret)) + context::space::resolve(sp, std::move(std::get(ret))); + else + { + auto& new_addr = std::get
(ret); + auto pure_offset = new_addr.unresolved_offset(); + auto [space, offset_correction] = std::move(new_addr).normalized_spaces(); + context::space::resolve(sp, pure_offset + offset_correction, std::move(space)); + } if (!sym_ctx.symbol_dependencies.check_cycle(new_sp, li)) add_diagnostic(diagnostic_op::error_E033); @@ -293,6 +301,23 @@ const symbol_dependency_tables::dependency_value* symbol_dependency_tables::find return nullptr; } +void keep_unknown_loctr_only(auto& v) +{ + // assumes space_ptr only + assert(std::all_of(v.begin(), v.end(), [](const auto& e) { return std::holds_alternative(e); })); + + constexpr auto unknown_loctr = [](const auto& entry) { + return std::get(entry)->kind == context::space_kind::LOCTR_UNKNOWN; + }; + + auto known_spaces = std::partition(v.begin(), v.end(), unknown_loctr); + + if (known_spaces == v.begin()) + return; + + v.erase(known_spaces, v.end()); +} + std::vector symbol_dependency_tables::extract_dependencies( const resolvable* dependency_source, const dependency_evaluation_context& dep_ctx, const library_info& li) { @@ -307,13 +332,6 @@ std::vector symbol_dependency_tables::extract_dependencies( if (!ret.empty()) return ret; - ret.insert(ret.end(), - std::make_move_iterator(deps.unresolved_spaces.begin()), - std::make_move_iterator(deps.unresolved_spaces.end())); - - if (!ret.empty()) - return ret; - for (const auto& ref : deps.undefined_symbolics) { for (int i = 1; i < static_cast(data_attr_kind::max); ++i) @@ -321,13 +339,23 @@ std::vector symbol_dependency_tables::extract_dependencies( ret.emplace_back(attr_ref { static_cast(i), ref.name }); } - if (deps.unresolved_address) - for (auto& [space_id, count] : deps.unresolved_address->normalized_spaces()) + if (!ret.empty()) + return ret; + + ret.insert(ret.end(), + std::make_move_iterator(deps.unresolved_spaces.begin()), + std::make_move_iterator(deps.unresolved_spaces.end())); + + if (ret.empty() && deps.unresolved_address) + { + for (auto&& [space_id, count] : std::move(deps.unresolved_address)->normalized_spaces().first) { assert(count != 0); - ret.push_back(space_id); + ret.push_back(std::move(space_id)); } + } + keep_unknown_loctr_only(ret); return ret; } @@ -354,13 +382,16 @@ bool symbol_dependency_tables::update_dependencies(dependency_value& d, const li if (!d.m_last_dependencies.empty() || d.m_has_t_attr_dependency) return true; - for (const auto& sp : deps.unresolved_spaces) - d.m_last_dependencies.emplace_back(sp); + d.m_last_dependencies.insert(d.m_last_dependencies.end(), + std::make_move_iterator(deps.unresolved_spaces.begin()), + std::make_move_iterator(deps.unresolved_spaces.end())); if (deps.unresolved_address) - for (auto&& [sp, _] : deps.unresolved_address->normalized_spaces()) + for (auto&& [sp, _] : std::move(deps.unresolved_address)->normalized_spaces().first) d.m_last_dependencies.emplace_back(std::move(sp)); + keep_unknown_loctr_only(d.m_last_dependencies); + return !d.m_last_dependencies.empty(); } diff --git a/parser_library/src/expressions/mach_expr_term.cpp b/parser_library/src/expressions/mach_expr_term.cpp index 22efad2a0..af517bc17 100644 --- a/parser_library/src/expressions/mach_expr_term.cpp +++ b/parser_library/src/expressions/mach_expr_term.cpp @@ -113,7 +113,7 @@ context::dependency_collector mach_expr_symbol::get_dependencies(context::depend return context::dependency_collector::error(); reloc_value.bases().front().first.qualifier = qualifier; } - return reloc_value; + return std::move(reloc_value); } else return context::dependency_collector(); @@ -148,7 +148,7 @@ mach_expr_constant::value_t mach_expr_symbol::evaluate( { diags.add_diagnostic(diagnostic_op::error_ME006(get_range())); } - return reloc_value; + return std::move(reloc_value); } assert(false); @@ -186,7 +186,7 @@ context::dependency_collector mach_expr_location_counter::get_dependencies(conte if (!location_counter.has_value()) return context::dependency_collector::error(); else - return context::dependency_collector(*location_counter); + return context::dependency_collector(std::move(*location_counter)); } mach_expression::value_t mach_expr_location_counter::evaluate( @@ -196,7 +196,7 @@ mach_expression::value_t mach_expr_location_counter::evaluate( if (!location_counter.has_value()) return context::address(context::address::base {}, 0, {}); else - return *location_counter; + return std::move(*location_counter); } const mach_expression* mach_expr_location_counter::leftmost_term() const { return this; } diff --git a/parser_library/src/lsp/item_convertors.cpp b/parser_library/src/lsp/item_convertors.cpp index 15c3924ce..8b7ab8135 100644 --- a/parser_library/src/lsp/item_convertors.cpp +++ b/parser_library/src/lsp/item_convertors.cpp @@ -71,7 +71,13 @@ std::string hover_text(const context::symbol& sym) { bool first = true; const auto& reloc = sym.value().get_reloc(); - for (const auto& [base, d] : reloc.bases()) + auto bases = reloc.bases(); + std::sort(bases.begin(), bases.end(), [](const auto& l, const auto& r) { + if (auto c = l.first.owner->name <=> r.first.owner->name; c != 0) + return c < 0; + return l.first.qualifier < r.first.qualifier; + }); + for (const auto& [base, d] : bases) { if (base.owner->name.empty() || d == 0) continue; diff --git a/parser_library/src/processing/instruction_sets/asm_processor.cpp b/parser_library/src/processing/instruction_sets/asm_processor.cpp index 5ddf7f93b..14fa591fe 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.cpp +++ b/parser_library/src/processing/instruction_sets/asm_processor.cpp @@ -107,7 +107,7 @@ void asm_processor::process_sect(const context::section_kind kind, rebuilt_state context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -131,7 +131,7 @@ void asm_processor::process_LOCTR(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -223,61 +223,47 @@ void asm_processor::process_EQU(rebuilt_statement stmt) } // value operand - if (ops[0]->type == semantics::operand_type::ASM) + if (ops[0]->type != semantics::operand_type::ASM) + add_diagnostic(diagnostic_op::error_A132_EQU_value_format(ops[0]->operand_range)); + else if (auto expr_op = ops[0]->access_asm()->access_expr(); !expr_op) + add_diagnostic(diagnostic_op::error_A132_EQU_value_format(ops[0]->operand_range)); + else { - if (auto expr_op = ops[0]->access_asm()->access_expr(); expr_op) - { - auto holder(expr_op->expression->get_dependencies(dep_solver)); + auto holder(expr_op->expression->get_dependencies(dep_solver)); - if (length_attr == context::symbol_attributes::undef_length) + if (length_attr == context::symbol_attributes::undef_length) + { + auto l_term = expr_op->expression->leftmost_term(); + if (auto symbol_term = dynamic_cast(l_term)) { - auto l_term = expr_op->expression->leftmost_term(); - if (auto symbol_term = dynamic_cast(l_term)) - { - auto len_symbol = hlasm_ctx.ord_ctx.get_symbol(symbol_term->value); + auto len_symbol = hlasm_ctx.ord_ctx.get_symbol(symbol_term->value); - if (len_symbol != nullptr && len_symbol->kind() != context::symbol_value_kind::UNDEF) - length_attr = len_symbol->attributes().length(); - else - length_attr = 1; - } + if (len_symbol != nullptr && len_symbol->kind() != context::symbol_value_kind::UNDEF) + length_attr = len_symbol->attributes().length(); else length_attr = 1; } + else + length_attr = 1; + } - context::symbol_attributes attrs(context::symbol_origin::EQU, t_attr, length_attr); + context::symbol_attributes attrs(context::symbol_origin::EQU, t_attr, length_attr); - if (!holder.contains_dependencies()) - { - create_symbol( - stmt.stmt_range_ref(), symbol_name, expr_op->expression->evaluate(dep_solver, *this), attrs); - } - else - { - if (!holder.is_address() || !holder.unresolved_spaces.empty()) - { - const auto& stmt_range = stmt.stmt_range_ref(); - if (create_symbol(stmt_range, symbol_name, context::symbol_value(), attrs)) - { - if (!hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency(symbol_name, - expr_op->expression.get(), - std::make_unique( - std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), - lib_info)) - add_diagnostic(diagnostic_op::error_E033(stmt_range)); - } - } - else - create_symbol(stmt.stmt_range_ref(), symbol_name, *holder.unresolved_address, attrs); - } + if (!holder.contains_dependencies()) + create_symbol(stmt.stmt_range_ref(), symbol_name, expr_op->expression->evaluate(dep_solver, *this), attrs); + + else if (holder.is_address() && holder.unresolved_spaces.empty()) + create_symbol(stmt.stmt_range_ref(), symbol_name, *holder.unresolved_address, attrs); + else if (const auto& stmt_range = stmt.stmt_range_ref(); + create_symbol(stmt_range, symbol_name, context::symbol_value(), attrs)) + { + if (!hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency(symbol_name, + expr_op->expression.get(), + std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), + std::move(dep_solver).derive_current_dependency_evaluation_context(), + lib_info)) + add_diagnostic(diagnostic_op::error_E033(stmt_range)); } - else - add_diagnostic(diagnostic_op::error_A132_EQU_value_format(ops[0]->operand_range)); - } - else - { - add_diagnostic(diagnostic_op::error_A132_EQU_value_format(ops[0]->operand_range)); } } @@ -446,7 +432,7 @@ void asm_processor::process_data_instruction(rebuilt_statement stmt) const auto& deps = dep_stmt->get_dependencies(); auto adder = hlasm_ctx.ord_ctx.symbol_dependencies.add_dependencies( - std::move(dep_stmt), dep_solver.derive_current_dependency_evaluation_context(), lib_info); + std::move(dep_stmt), std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); adder.add_dependency(); bool cycle_ok = true; @@ -500,7 +486,7 @@ void asm_processor::process_COPY(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } } @@ -555,7 +541,7 @@ void asm_processor::process_external(rebuilt_statement stmt, external_type t) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -682,7 +668,7 @@ void asm_processor::process_ORG(rebuilt_statement stmt) offset, reloc_expr->expression.get(), std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); else hlasm_ctx.ord_ctx.set_location_counter_value(reloc_val, boundary, offset, lib_info); @@ -738,7 +724,7 @@ void asm_processor::process_OPSYN(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -770,7 +756,7 @@ void asm_processor::process(std::shared_ptr(std::move(rebuilt_stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } } @@ -978,7 +964,7 @@ void asm_processor::process_CCW(rebuilt_statement stmt) hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -1011,7 +997,7 @@ void asm_processor::process_CNOP(rebuilt_statement stmt) hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -1038,18 +1024,19 @@ void asm_processor::process_START(rebuilt_statement stmt) sym_loc.pos.column = 0; auto* section = hlasm_ctx.ord_ctx.set_section(sect_name, context::section_kind::EXECUTABLE, std::move(sym_loc), lib_info); - context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); const auto& ops = stmt.operands_ref().value; if (ops.size() != 1) { + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); return; } + context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); auto initial_offset = try_get_abs_value(ops.front().get(), dep_solver); if (!initial_offset.has_value()) { @@ -1097,7 +1084,7 @@ void asm_processor::process_END(rebuilt_statement stmt) hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); hlasm_ctx.end_reached(); @@ -1114,7 +1101,7 @@ void asm_processor::process_ALIAS(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } void asm_processor::process_LTORG(rebuilt_statement stmt) @@ -1141,7 +1128,7 @@ void asm_processor::process_LTORG(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -1222,7 +1209,7 @@ void asm_processor::process_USING(rebuilt_statement stmt) std::move(b), std::move(e), std::move(bases), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), hlasm_ctx.processing_stack()); } @@ -1265,8 +1252,9 @@ void asm_processor::process_DROP(rebuilt_statement stmt) } } - hlasm_ctx.using_remove( - std::move(bases), dep_solver.derive_current_dependency_evaluation_context(), hlasm_ctx.processing_stack()); + hlasm_ctx.using_remove(std::move(bases), + std::move(dep_solver).derive_current_dependency_evaluation_context(), + hlasm_ctx.processing_stack()); } namespace { @@ -1290,7 +1278,7 @@ void asm_processor::process_PUSH(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } @@ -1305,7 +1293,7 @@ void asm_processor::process_POP(rebuilt_statement stmt) context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, lib_info); hlasm_ctx.ord_ctx.symbol_dependencies.add_dependency( std::make_unique(std::move(stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); } diff --git a/parser_library/src/processing/instruction_sets/low_language_processor.cpp b/parser_library/src/processing/instruction_sets/low_language_processor.cpp index 2342c0e66..26c2d7de7 100644 --- a/parser_library/src/processing/instruction_sets/low_language_processor.cpp +++ b/parser_library/src/processing/instruction_sets/low_language_processor.cpp @@ -151,10 +151,12 @@ low_language_processor::preprocessed_part low_language_processor::preprocess_inn check_org_result hlasm_plugin::parser_library::processing::check_address_for_ORG( const context::address& addr_to_check, const context::address& curr_addr, size_t boundary, int offset) { - int al = boundary ? (int)((boundary - (addr_to_check.offset() % boundary)) % boundary) : 0; + int addr_to_check_offset = addr_to_check.offset(); - bool underflow = !addr_to_check.has_dependant_space() && addr_to_check.offset() + al + offset < 0; - if (!curr_addr.in_same_loctr(addr_to_check) || underflow) + int al = boundary ? (int)((boundary - (addr_to_check_offset % boundary)) % boundary) : 0; + + bool underflow = !addr_to_check.has_dependant_space() && addr_to_check_offset + al + offset < 0; + if (underflow || !curr_addr.in_same_loctr(addr_to_check)) return check_org_result::underflow; if (!addr_to_check.is_simple()) diff --git a/parser_library/src/processing/instruction_sets/mach_processor.cpp b/parser_library/src/processing/instruction_sets/mach_processor.cpp index 7449ea56d..cd3e6d951 100644 --- a/parser_library/src/processing/instruction_sets/mach_processor.cpp +++ b/parser_library/src/processing/instruction_sets/mach_processor.cpp @@ -68,7 +68,7 @@ void mach_processor::process(std::shared_ptr(std::move(rebuilt_stmt), hlasm_ctx.processing_stack()), - dep_solver.derive_current_dependency_evaluation_context(), + std::move(dep_solver).derive_current_dependency_evaluation_context(), lib_info); (void)hlasm_ctx.ord_ctx.reserve_storage_area(mach_instr.size_in_bits() / 8, context::halfword, lib_info); diff --git a/parser_library/test/context/address_test.cpp b/parser_library/test/context/address_test.cpp index 575659694..91d2826a1 100644 --- a/parser_library/test/context/address_test.cpp +++ b/parser_library/test/context/address_test.cpp @@ -25,19 +25,24 @@ TEST(address, normalized_spaces) hlasm_context ctx; ctx.ord_ctx.set_section(id_index("TEST"), section_kind::COMMON, location(), library_info_transitional::empty); - auto sp1 = ctx.ord_ctx.current_section()->current_location_counter().set_value( - ctx.ord_ctx.current_section()->current_location_counter().current_address(), 0, 0, true); + auto sp1 = ctx.ord_ctx.current_section()->current_location_counter().set_value_undefined(0, 0); auto sp2 = ctx.ord_ctx.current_section()->current_location_counter().register_ordinary_space(halfword); auto addr = ctx.ord_ctx.current_section()->current_location_counter().current_address(); space::resolve(sp1, sp2); - auto normalized = addr.normalized_spaces(); + auto [normalized, _] = addr.normalized_spaces(); ASSERT_EQ(normalized.size(), (size_t)1); EXPECT_EQ(normalized.front().first, sp2); EXPECT_EQ(normalized.front().second, (size_t)2); + + auto [normalized_move, __] = std::move(addr).normalized_spaces(); + + ASSERT_EQ(normalized_move.size(), (size_t)1); + EXPECT_EQ(normalized_move.front().first, sp2); + EXPECT_EQ(normalized_move.front().second, (size_t)2); } TEST(address, has_unresolved_spaces) @@ -45,8 +50,7 @@ TEST(address, has_unresolved_spaces) hlasm_context ctx; ctx.ord_ctx.set_section(id_index("TEST"), section_kind::COMMON, location(), library_info_transitional::empty); - auto sp1 = ctx.ord_ctx.current_section()->current_location_counter().set_value( - ctx.ord_ctx.current_section()->current_location_counter().current_address(), 0, 0, true); + auto sp1 = ctx.ord_ctx.current_section()->current_location_counter().set_value_undefined(0, 0); auto sp2 = ctx.ord_ctx.current_section()->current_location_counter().register_ordinary_space(halfword); auto addr = ctx.ord_ctx.current_section()->current_location_counter().current_address(); diff --git a/parser_library/test/lsp/lsp_context_ord_sym_test.cpp b/parser_library/test/lsp/lsp_context_ord_sym_test.cpp index 03d1c5e48..21377ef32 100644 --- a/parser_library/test/lsp/lsp_context_ord_sym_test.cpp +++ b/parser_library/test/lsp/lsp_context_ord_sym_test.cpp @@ -126,8 +126,8 @@ C1 CSECT C2 CSECT DS C A EQU 0-* -B EQU 0-*+C1 -C EQU C1-C0 +B EQU 0-C1+* +C EQU C0-C1 D EQU 0-C1-C1 )"; analyzer a(input); @@ -137,8 +137,8 @@ D EQU 0-C1-C1 EXPECT_TRUE(a.diags().empty()); EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 5, 0 }).starts_with("-C2 + X'FFFFFFFF' (-1)")); - EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 6, 0 }).starts_with("-C2 + C1 + X'FFFFFFFF' (-1)")); - EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 7, 0 }).starts_with("C1 - C0 + X'0' (0)")); + EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 6, 0 }).starts_with("-C1 + C2 + X'1' (1)")); + EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 7, 0 }).starts_with("C0 - C1 + X'0' (0)")); EXPECT_TRUE(a.context().lsp_ctx->hover(empty_loc, { 8, 0 }).starts_with("-2*C1 + X'0' (0)")); }