mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-03-21 17:49:58 -05:00
Merge pull request #14317 from JosJuice/jit-cache-macro-loop
Jit: Use RangeSet for physical_addresses
This commit is contained in:
commit
f898d75bf3
|
|
@ -761,8 +761,6 @@ include_directories(Externals/picojson)
|
|||
|
||||
add_subdirectory(Externals/expr)
|
||||
|
||||
add_subdirectory(Externals/rangeset)
|
||||
|
||||
add_subdirectory(Externals/FatFs)
|
||||
|
||||
if (USE_RETRO_ACHIEVEMENTS)
|
||||
|
|
|
|||
2
Externals/licenses.md
vendored
2
Externals/licenses.md
vendored
|
|
@ -64,8 +64,6 @@ Dolphin includes or links code of the following third-party software projects:
|
|||
[LGPLv2.1+](http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/LICENSE)
|
||||
- [Qt5](http://qt-project.org/):
|
||||
[LGPLv3 and other licenses](http://doc.qt.io/qt-5/licensing.html)
|
||||
- [rangeset](https://github.com/AdmiralCurtiss/rangeset)
|
||||
[zlib license](https://github.com/AdmiralCurtiss/rangeset/blob/master/LICENSE)
|
||||
- [SDL](https://www.libsdl.org/):
|
||||
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
|
||||
- [SFML](http://www.sfml-dev.org/):
|
||||
|
|
|
|||
4
Externals/rangeset/CMakeLists.txt
vendored
4
Externals/rangeset/CMakeLists.txt
vendored
|
|
@ -1,4 +0,0 @@
|
|||
add_library(RangeSet::RangeSet INTERFACE IMPORTED GLOBAL)
|
||||
set_target_properties(RangeSet::RangeSet PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/include
|
||||
)
|
||||
17
Externals/rangeset/LICENSE
vendored
17
Externals/rangeset/LICENSE
vendored
|
|
@ -1,17 +0,0 @@
|
|||
Copyright (c) 2020 Admiral H. Curtiss
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
|
@ -127,6 +127,8 @@ add_library(common
|
|||
QoSSession.h
|
||||
Random.cpp
|
||||
Random.h
|
||||
RangeSet.h
|
||||
RangeSizeSet.h
|
||||
ScopeGuard.h
|
||||
SDCardUtil.cpp
|
||||
SDCardUtil.h
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright 2020 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
|
@ -5,51 +8,53 @@
|
|||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace HyoutaUtilities {
|
||||
template <typename T> class RangeSet {
|
||||
namespace Common
|
||||
{
|
||||
template <typename T>
|
||||
class RangeSet
|
||||
{
|
||||
private:
|
||||
using MapT = std::map<T, T>;
|
||||
|
||||
public:
|
||||
struct const_iterator {
|
||||
struct const_iterator
|
||||
{
|
||||
public:
|
||||
const T& from() const {
|
||||
return It->first;
|
||||
}
|
||||
const T& from() const { return It->first; }
|
||||
|
||||
const T& to() const {
|
||||
return It->second;
|
||||
}
|
||||
const T& to() const { return It->second; }
|
||||
|
||||
const_iterator& operator++() {
|
||||
std::pair<T, T> operator*() { return {from(), to()}; }
|
||||
|
||||
const_iterator& operator++()
|
||||
{
|
||||
++It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator++(int) {
|
||||
const_iterator operator++(int)
|
||||
{
|
||||
const_iterator old = *this;
|
||||
++It;
|
||||
return old;
|
||||
}
|
||||
|
||||
const_iterator& operator--() {
|
||||
const_iterator& operator--()
|
||||
{
|
||||
--It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator--(int) {
|
||||
const_iterator operator--(int)
|
||||
{
|
||||
const_iterator old = *this;
|
||||
--It;
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator& rhs) const {
|
||||
return this->It == rhs.It;
|
||||
}
|
||||
bool operator==(const const_iterator& rhs) const { return this->It == rhs.It; }
|
||||
|
||||
bool operator!=(const const_iterator& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
bool operator!=(const const_iterator& rhs) const { return !operator==(rhs); }
|
||||
|
||||
private:
|
||||
typename MapT::const_iterator It;
|
||||
|
|
@ -57,7 +62,8 @@ public:
|
|||
friend class RangeSet;
|
||||
};
|
||||
|
||||
void insert(T from, T to) {
|
||||
void insert(T from, T to)
|
||||
{
|
||||
if (from >= to)
|
||||
return;
|
||||
|
||||
|
|
@ -65,18 +71,21 @@ public:
|
|||
// upper_bound() returns the closest range whose starting position
|
||||
// is greater than 'from'.
|
||||
auto bound = Map.upper_bound(from);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// There is no range that starts greater than the given one.
|
||||
// This means we have three options:
|
||||
// - 1. No range exists yet, this is the first range.
|
||||
if (Map.empty()) {
|
||||
if (Map.empty())
|
||||
{
|
||||
insert_range(from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
// - 2. The given range does not overlap the last range.
|
||||
--bound;
|
||||
if (from > get_to(bound)) {
|
||||
if (from > get_to(bound))
|
||||
{
|
||||
insert_range(from, to);
|
||||
return;
|
||||
}
|
||||
|
|
@ -86,7 +95,8 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (bound == Map.begin()) {
|
||||
if (bound == Map.begin())
|
||||
{
|
||||
// The given range starts before any of the existing ones.
|
||||
// We must insert this as a new range even if we potentially overlap
|
||||
// an existing one as we can't modify a key in a std::map.
|
||||
|
|
@ -101,7 +111,8 @@ public:
|
|||
// could possibly be affected.
|
||||
|
||||
// If 'bound' overlaps with given range, update bounds object.
|
||||
if (get_to(bound) >= from) {
|
||||
if (get_to(bound) >= from)
|
||||
{
|
||||
maybe_expand_to(bound, to);
|
||||
auto inserted = bound;
|
||||
++bound;
|
||||
|
|
@ -112,7 +123,8 @@ public:
|
|||
// 'bound' *doesn't* overlap with given range, check next range.
|
||||
|
||||
// If this range overlaps with given range,
|
||||
if (get_from(abound) <= to) {
|
||||
if (get_from(abound) <= to)
|
||||
{
|
||||
// insert new range
|
||||
auto inserted = insert_range(from, to >= get_to(abound) ? to : get_to(abound));
|
||||
// and delete overlaps
|
||||
|
|
@ -126,49 +138,61 @@ public:
|
|||
insert_range(from, to);
|
||||
}
|
||||
|
||||
void erase(T from, T to) {
|
||||
void erase(T from, T to)
|
||||
{
|
||||
if (from >= to)
|
||||
return;
|
||||
|
||||
// Like insert(), we use upper_bound to find the closest range.
|
||||
auto bound = Map.upper_bound(from);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// There is no range that starts greater than the given one.
|
||||
if (Map.empty()) {
|
||||
if (Map.empty())
|
||||
{
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
--bound;
|
||||
// 'bound' now points at the last range.
|
||||
if (from >= get_to(bound)) {
|
||||
if (from >= get_to(bound))
|
||||
{
|
||||
// Given range is larger than any range that exists, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (to >= get_to(bound)) {
|
||||
if (from == get_from(bound)) {
|
||||
if (to >= get_to(bound))
|
||||
{
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Given range fully overlaps last range, erase it.
|
||||
erase_range(bound);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Given range overlaps end of last range, reduce it.
|
||||
reduce_to(bound, from);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (from == get_from(bound)) {
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Given range overlaps begin of last range, reduce it.
|
||||
reduce_from(bound, to);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Given range overlaps middle of last range, bisect it.
|
||||
bisect_range(bound, from, to);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (bound == Map.begin()) {
|
||||
if (bound == Map.begin())
|
||||
{
|
||||
// If we found the first range that means 'from' is before any stored range.
|
||||
// This means we can just erase from start until 'to' and be done with it.
|
||||
erase_from_iterator_to_value(bound, to);
|
||||
|
|
@ -178,7 +202,8 @@ public:
|
|||
// check previous range
|
||||
auto abound = bound--;
|
||||
|
||||
if (from == get_from(bound)) {
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Similarly, if the previous range starts with the given one, just erase until 'to'.
|
||||
erase_from_iterator_to_value(bound, to);
|
||||
return;
|
||||
|
|
@ -187,12 +212,16 @@ public:
|
|||
// If we come here, the given range may or may not overlap part of the current 'bound'
|
||||
// (but never the full range), which means we may need to update the end position of it,
|
||||
// or possibly even split it into two.
|
||||
if (from < get_to(bound)) {
|
||||
if (to < get_to(bound)) {
|
||||
if (from < get_to(bound))
|
||||
{
|
||||
if (to < get_to(bound))
|
||||
{
|
||||
// need to split in two
|
||||
bisect_range(bound, from, to);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// just update end
|
||||
reduce_to(bound, from);
|
||||
}
|
||||
|
|
@ -203,15 +232,12 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
const_iterator erase(const_iterator it) {
|
||||
return const_iterator(erase_range(it.It));
|
||||
}
|
||||
const_iterator erase(const_iterator it) { return const_iterator(erase_range(it.It)); }
|
||||
|
||||
void clear() {
|
||||
Map.clear();
|
||||
}
|
||||
void clear() { Map.clear(); }
|
||||
|
||||
bool contains(T value) const {
|
||||
bool contains(T value) const
|
||||
{
|
||||
auto it = Map.upper_bound(value);
|
||||
if (it == Map.begin())
|
||||
return false;
|
||||
|
|
@ -219,49 +245,45 @@ public:
|
|||
return get_from(it) <= value && value < get_to(it);
|
||||
}
|
||||
|
||||
std::size_t size() const {
|
||||
return Map.size();
|
||||
bool overlaps(T from, T to) const
|
||||
{
|
||||
if (from >= to)
|
||||
return false;
|
||||
|
||||
auto it = Map.lower_bound(to);
|
||||
if (it == Map.begin())
|
||||
return false;
|
||||
--it;
|
||||
return get_from(it) < to && from < get_to(it);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return Map.empty();
|
||||
}
|
||||
std::size_t size() const { return Map.size(); }
|
||||
|
||||
void swap(RangeSet<T>& other) {
|
||||
Map.swap(other.Map);
|
||||
}
|
||||
bool empty() const { return Map.empty(); }
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(Map.begin());
|
||||
}
|
||||
void swap(RangeSet<T>& other) { Map.swap(other.Map); }
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(Map.end());
|
||||
}
|
||||
const_iterator begin() const { return const_iterator(Map.begin()); }
|
||||
|
||||
const_iterator cbegin() const {
|
||||
return const_iterator(Map.cbegin());
|
||||
}
|
||||
const_iterator end() const { return const_iterator(Map.end()); }
|
||||
|
||||
const_iterator cend() const {
|
||||
return const_iterator(Map.cend());
|
||||
}
|
||||
const_iterator cbegin() const { return const_iterator(Map.cbegin()); }
|
||||
|
||||
bool operator==(const RangeSet<T>& other) const {
|
||||
return this->Map == other.Map;
|
||||
}
|
||||
const_iterator cend() const { return const_iterator(Map.cend()); }
|
||||
|
||||
bool operator!=(const RangeSet<T>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool operator==(const RangeSet<T>& other) const { return this->Map == other.Map; }
|
||||
|
||||
bool operator!=(const RangeSet<T>& other) const { return !(*this == other); }
|
||||
|
||||
// Get free size and fragmentation ratio
|
||||
std::pair<std::size_t, double> get_stats() const {
|
||||
std::pair<std::size_t, double> get_stats() const
|
||||
{
|
||||
std::size_t free_total = 0;
|
||||
if (begin() == end())
|
||||
return {free_total, 1.0};
|
||||
std::size_t largest_size = 0;
|
||||
for (auto iter = begin(); iter != end(); ++iter) {
|
||||
for (auto iter = begin(); iter != end(); ++iter)
|
||||
{
|
||||
const std::size_t size = calc_size(iter.from(), iter.to());
|
||||
if (size > largest_size)
|
||||
largest_size = size;
|
||||
|
|
@ -271,11 +293,15 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
static std::size_t calc_size(T from, T to) {
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
static std::size_t calc_size(T from, T to)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
// For pointers we don't want pointer arithmetic here, else void* breaks.
|
||||
return reinterpret_cast<std::size_t>(to) - reinterpret_cast<std::size_t>(from);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<std::size_t>(to - from);
|
||||
}
|
||||
}
|
||||
|
|
@ -289,35 +315,25 @@ private:
|
|||
// - Stored ranges never overlap.
|
||||
MapT Map;
|
||||
|
||||
T get_from(typename MapT::iterator it) const {
|
||||
return it->first;
|
||||
}
|
||||
T get_from(typename MapT::iterator it) const { return it->first; }
|
||||
|
||||
T get_to(typename MapT::iterator it) const {
|
||||
return it->second;
|
||||
}
|
||||
T get_to(typename MapT::iterator it) const { return it->second; }
|
||||
|
||||
T get_from(typename MapT::const_iterator it) const {
|
||||
return it->first;
|
||||
}
|
||||
T get_from(typename MapT::const_iterator it) const { return it->first; }
|
||||
|
||||
T get_to(typename MapT::const_iterator it) const {
|
||||
return it->second;
|
||||
}
|
||||
T get_to(typename MapT::const_iterator it) const { return it->second; }
|
||||
|
||||
typename MapT::iterator insert_range(T from, T to) {
|
||||
return Map.emplace(from, to).first;
|
||||
}
|
||||
typename MapT::iterator insert_range(T from, T to) { return Map.emplace(from, to).first; }
|
||||
|
||||
typename MapT::iterator erase_range(typename MapT::iterator it) {
|
||||
typename MapT::iterator erase_range(typename MapT::iterator it) { return Map.erase(it); }
|
||||
|
||||
typename MapT::const_iterator erase_range(typename MapT::const_iterator it)
|
||||
{
|
||||
return Map.erase(it);
|
||||
}
|
||||
|
||||
typename MapT::const_iterator erase_range(typename MapT::const_iterator it) {
|
||||
return Map.erase(it);
|
||||
}
|
||||
|
||||
void bisect_range(typename MapT::iterator it, T from, T to) {
|
||||
void bisect_range(typename MapT::iterator it, T from, T to)
|
||||
{
|
||||
assert(get_from(it) < from);
|
||||
assert(get_from(it) < to);
|
||||
assert(get_to(it) > from);
|
||||
|
|
@ -328,54 +344,66 @@ private:
|
|||
insert_range(to, itto);
|
||||
}
|
||||
|
||||
typename MapT::iterator reduce_from(typename MapT::iterator it, T from) {
|
||||
typename MapT::iterator reduce_from(typename MapT::iterator it, T from)
|
||||
{
|
||||
assert(get_from(it) < from);
|
||||
T itto = get_to(it);
|
||||
erase_range(it);
|
||||
return insert_range(from, itto);
|
||||
}
|
||||
|
||||
void maybe_expand_to(typename MapT::iterator it, T to) {
|
||||
void maybe_expand_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
if (to <= get_to(it))
|
||||
return;
|
||||
|
||||
expand_to(it, to);
|
||||
}
|
||||
|
||||
void expand_to(typename MapT::iterator it, T to) {
|
||||
void expand_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
assert(get_to(it) < to);
|
||||
it->second = to;
|
||||
}
|
||||
|
||||
void reduce_to(typename MapT::iterator it, T to) {
|
||||
void reduce_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
assert(get_to(it) > to);
|
||||
it->second = to;
|
||||
}
|
||||
|
||||
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound, T to) {
|
||||
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound,
|
||||
T to)
|
||||
{
|
||||
// Erase all ranges that overlap the inserted while updating the upper end.
|
||||
while (bound != Map.end() && get_from(bound) <= to) {
|
||||
while (bound != Map.end() && get_from(bound) <= to)
|
||||
{
|
||||
maybe_expand_to(inserted, get_to(bound));
|
||||
bound = erase_range(bound);
|
||||
}
|
||||
}
|
||||
|
||||
void erase_from_iterator_to_value(typename MapT::iterator bound, T to) {
|
||||
void erase_from_iterator_to_value(typename MapT::iterator bound, T to)
|
||||
{
|
||||
// Assumption: Given bound starts at or after the 'from' value of the range to erase.
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
// Given range starts before stored range.
|
||||
if (to <= get_from(bound)) {
|
||||
if (to <= get_from(bound))
|
||||
{
|
||||
// Range ends before this range too, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (to < get_to(bound)) {
|
||||
if (to < get_to(bound))
|
||||
{
|
||||
// Range ends in the middle of current range, reduce current.
|
||||
reduce_from(bound, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == get_to(bound)) {
|
||||
if (to == get_to(bound))
|
||||
{
|
||||
// Range ends exactly with current range, erase current.
|
||||
erase_range(bound);
|
||||
return;
|
||||
|
|
@ -384,11 +412,12 @@ private:
|
|||
// Range ends later than current range.
|
||||
// First erase current, then loop to check the range(s) after this one too.
|
||||
bound = erase_range(bound);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// Unless that was the last range, in which case there's nothing else to do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace HyoutaUtilities
|
||||
} // namespace Common
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
// Copyright 2020 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
|
|
@ -6,42 +9,51 @@
|
|||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace HyoutaUtilities {
|
||||
// Like RangeSet, but additionally stores a map of the ranges sorted by their size, for quickly finding the largest or
|
||||
// smallest range.
|
||||
template <typename T> class RangeSizeSet {
|
||||
namespace Common
|
||||
{
|
||||
// Like RangeSet, but additionally stores a map of the ranges sorted by their size, for quickly
|
||||
// finding the largest or smallest range.
|
||||
template <typename T>
|
||||
class RangeSizeSet
|
||||
{
|
||||
private:
|
||||
// Key type used in the by-size multimap. Should be a type big enough to hold all possible distances between
|
||||
// possible 'from' and 'to'.
|
||||
// Key type used in the by-size multimap. Should be a type big enough to hold all possible
|
||||
// distances between possible 'from' and 'to'.
|
||||
// I'd actually love to just do
|
||||
// using SizeT = typename std::conditional<std::is_pointer_v<T>,
|
||||
// std::size_t, typename std::make_unsigned<T>::type>::type;
|
||||
// but that's apparently not possible due to the std::make_unsigned<T>::type not existing for pointer types
|
||||
// so we'll work around this...
|
||||
template <typename U, bool IsPointer> struct GetSizeType { using S = typename std::make_unsigned<U>::type; };
|
||||
template <typename U> struct GetSizeType<U, true> { using S = std::size_t; };
|
||||
// but that's apparently not possible due to the std::make_unsigned<T>::type not existing for
|
||||
// pointer types so we'll work around this...
|
||||
template <typename U, bool IsPointer>
|
||||
struct GetSizeType
|
||||
{
|
||||
using S = typename std::make_unsigned<U>::type;
|
||||
};
|
||||
template <typename U>
|
||||
struct GetSizeType<U, true>
|
||||
{
|
||||
using S = std::size_t;
|
||||
};
|
||||
|
||||
public:
|
||||
using SizeT = typename GetSizeType<T, std::is_pointer_v<T>>::S;
|
||||
|
||||
private:
|
||||
// Value type stored in the regular range map.
|
||||
struct Value {
|
||||
struct Value
|
||||
{
|
||||
// End point of the range.
|
||||
T To;
|
||||
|
||||
// Pointer to the same range in the by-size multimap.
|
||||
typename std::multimap<SizeT, typename std::map<T, Value>::iterator, std::greater<SizeT>>::iterator SizeIt;
|
||||
typename std::multimap<SizeT, typename std::map<T, Value>::iterator,
|
||||
std::greater<SizeT>>::iterator SizeIt;
|
||||
|
||||
Value(T to) : To(to) {}
|
||||
|
||||
bool operator==(const Value& other) const {
|
||||
return this->To == other.To;
|
||||
}
|
||||
bool operator==(const Value& other) const { return this->To == other.To; }
|
||||
|
||||
bool operator!=(const Value& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
bool operator!=(const Value& other) const { return !operator==(other); }
|
||||
};
|
||||
|
||||
using MapT = std::map<T, Value>;
|
||||
|
|
@ -50,49 +62,46 @@ private:
|
|||
public:
|
||||
struct by_size_const_iterator;
|
||||
|
||||
struct const_iterator {
|
||||
struct const_iterator
|
||||
{
|
||||
public:
|
||||
const T& from() const {
|
||||
return It->first;
|
||||
}
|
||||
const T& from() const { return It->first; }
|
||||
|
||||
const T& to() const {
|
||||
return It->second.To;
|
||||
}
|
||||
const T& to() const { return It->second.To; }
|
||||
|
||||
const_iterator& operator++() {
|
||||
std::pair<T, T> operator*() { return {from(), to()}; }
|
||||
|
||||
const_iterator& operator++()
|
||||
{
|
||||
++It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator++(int) {
|
||||
const_iterator operator++(int)
|
||||
{
|
||||
const_iterator old = *this;
|
||||
++It;
|
||||
return old;
|
||||
}
|
||||
|
||||
const_iterator& operator--() {
|
||||
const_iterator& operator--()
|
||||
{
|
||||
--It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const_iterator operator--(int) {
|
||||
const_iterator operator--(int)
|
||||
{
|
||||
const_iterator old = *this;
|
||||
--It;
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(const const_iterator& rhs) const {
|
||||
return this->It == rhs.It;
|
||||
}
|
||||
bool operator==(const const_iterator& rhs) const { return this->It == rhs.It; }
|
||||
|
||||
bool operator!=(const const_iterator& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
bool operator!=(const const_iterator& rhs) const { return !operator==(rhs); }
|
||||
|
||||
by_size_const_iterator to_size_iterator() {
|
||||
return by_size_const_iterator(It->second.SizeIt);
|
||||
}
|
||||
by_size_const_iterator to_size_iterator() { return by_size_const_iterator(It->second.SizeIt); }
|
||||
|
||||
private:
|
||||
typename MapT::const_iterator It;
|
||||
|
|
@ -100,49 +109,44 @@ public:
|
|||
friend class RangeSizeSet;
|
||||
};
|
||||
|
||||
struct by_size_const_iterator {
|
||||
struct by_size_const_iterator
|
||||
{
|
||||
public:
|
||||
const T& from() const {
|
||||
return It->second->first;
|
||||
}
|
||||
const T& from() const { return It->second->first; }
|
||||
|
||||
const T& to() const {
|
||||
return It->second->second.To;
|
||||
}
|
||||
const T& to() const { return It->second->second.To; }
|
||||
|
||||
by_size_const_iterator& operator++() {
|
||||
by_size_const_iterator& operator++()
|
||||
{
|
||||
++It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
by_size_const_iterator operator++(int) {
|
||||
by_size_const_iterator operator++(int)
|
||||
{
|
||||
by_size_const_iterator old = *this;
|
||||
++It;
|
||||
return old;
|
||||
}
|
||||
|
||||
by_size_const_iterator& operator--() {
|
||||
by_size_const_iterator& operator--()
|
||||
{
|
||||
--It;
|
||||
return *this;
|
||||
}
|
||||
|
||||
by_size_const_iterator operator--(int) {
|
||||
by_size_const_iterator operator--(int)
|
||||
{
|
||||
by_size_const_iterator old = *this;
|
||||
--It;
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(const by_size_const_iterator& rhs) const {
|
||||
return this->It == rhs.It;
|
||||
}
|
||||
bool operator==(const by_size_const_iterator& rhs) const { return this->It == rhs.It; }
|
||||
|
||||
bool operator!=(const by_size_const_iterator& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
bool operator!=(const by_size_const_iterator& rhs) const { return !operator==(rhs); }
|
||||
|
||||
const_iterator to_range_iterator() {
|
||||
return const_iterator(It->second);
|
||||
}
|
||||
const_iterator to_range_iterator() { return const_iterator(It->second); }
|
||||
|
||||
private:
|
||||
typename SizeMapT::const_iterator It;
|
||||
|
|
@ -157,7 +161,8 @@ public:
|
|||
RangeSizeSet<T>& operator=(const RangeSizeSet<T>&) = delete;
|
||||
RangeSizeSet<T>& operator=(RangeSizeSet<T>&&) = default;
|
||||
|
||||
void insert(T from, T to) {
|
||||
void insert(T from, T to)
|
||||
{
|
||||
if (from >= to)
|
||||
return;
|
||||
|
||||
|
|
@ -165,18 +170,21 @@ public:
|
|||
// upper_bound() returns the closest range whose starting position
|
||||
// is greater than 'from'.
|
||||
auto bound = Map.upper_bound(from);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// There is no range that starts greater than the given one.
|
||||
// This means we have three options:
|
||||
// - 1. No range exists yet, this is the first range.
|
||||
if (Map.empty()) {
|
||||
if (Map.empty())
|
||||
{
|
||||
insert_range(from, to);
|
||||
return;
|
||||
}
|
||||
|
||||
// - 2. The given range does not overlap the last range.
|
||||
--bound;
|
||||
if (from > get_to(bound)) {
|
||||
if (from > get_to(bound))
|
||||
{
|
||||
insert_range(from, to);
|
||||
return;
|
||||
}
|
||||
|
|
@ -186,7 +194,8 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (bound == Map.begin()) {
|
||||
if (bound == Map.begin())
|
||||
{
|
||||
// The given range starts before any of the existing ones.
|
||||
// We must insert this as a new range even if we potentially overlap
|
||||
// an existing one as we can't modify a key in a std::map.
|
||||
|
|
@ -201,7 +210,8 @@ public:
|
|||
// could possibly be affected.
|
||||
|
||||
// If 'bound' overlaps with given range, update bounds object.
|
||||
if (get_to(bound) >= from) {
|
||||
if (get_to(bound) >= from)
|
||||
{
|
||||
maybe_expand_to(bound, to);
|
||||
auto inserted = bound;
|
||||
++bound;
|
||||
|
|
@ -212,7 +222,8 @@ public:
|
|||
// 'bound' *doesn't* overlap with given range, check next range.
|
||||
|
||||
// If this range overlaps with given range,
|
||||
if (get_from(abound) <= to) {
|
||||
if (get_from(abound) <= to)
|
||||
{
|
||||
// insert new range
|
||||
auto inserted = insert_range(from, to >= get_to(abound) ? to : get_to(abound));
|
||||
// and delete overlaps
|
||||
|
|
@ -226,49 +237,61 @@ public:
|
|||
insert_range(from, to);
|
||||
}
|
||||
|
||||
void erase(T from, T to) {
|
||||
void erase(T from, T to)
|
||||
{
|
||||
if (from >= to)
|
||||
return;
|
||||
|
||||
// Like insert(), we use upper_bound to find the closest range.
|
||||
auto bound = Map.upper_bound(from);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// There is no range that starts greater than the given one.
|
||||
if (Map.empty()) {
|
||||
if (Map.empty())
|
||||
{
|
||||
// nothing to do
|
||||
return;
|
||||
}
|
||||
--bound;
|
||||
// 'bound' now points at the last range.
|
||||
if (from >= get_to(bound)) {
|
||||
if (from >= get_to(bound))
|
||||
{
|
||||
// Given range is larger than any range that exists, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (to >= get_to(bound)) {
|
||||
if (from == get_from(bound)) {
|
||||
if (to >= get_to(bound))
|
||||
{
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Given range fully overlaps last range, erase it.
|
||||
erase_range(bound);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Given range overlaps end of last range, reduce it.
|
||||
reduce_to(bound, from);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (from == get_from(bound)) {
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Given range overlaps begin of last range, reduce it.
|
||||
reduce_from(bound, to);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Given range overlaps middle of last range, bisect it.
|
||||
bisect_range(bound, from, to);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (bound == Map.begin()) {
|
||||
if (bound == Map.begin())
|
||||
{
|
||||
// If we found the first range that means 'from' is before any stored range.
|
||||
// This means we can just erase from start until 'to' and be done with it.
|
||||
erase_from_iterator_to_value(bound, to);
|
||||
|
|
@ -278,7 +301,8 @@ public:
|
|||
// check previous range
|
||||
auto abound = bound--;
|
||||
|
||||
if (from == get_from(bound)) {
|
||||
if (from == get_from(bound))
|
||||
{
|
||||
// Similarly, if the previous range starts with the given one, just erase until 'to'.
|
||||
erase_from_iterator_to_value(bound, to);
|
||||
return;
|
||||
|
|
@ -287,12 +311,16 @@ public:
|
|||
// If we come here, the given range may or may not overlap part of the current 'bound'
|
||||
// (but never the full range), which means we may need to update the end position of it,
|
||||
// or possibly even split it into two.
|
||||
if (from < get_to(bound)) {
|
||||
if (to < get_to(bound)) {
|
||||
if (from < get_to(bound))
|
||||
{
|
||||
if (to < get_to(bound))
|
||||
{
|
||||
// need to split in two
|
||||
bisect_range(bound, from, to);
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// just update end
|
||||
reduce_to(bound, from);
|
||||
}
|
||||
|
|
@ -303,20 +331,21 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
const_iterator erase(const_iterator it) {
|
||||
return const_iterator(erase_range(it.It));
|
||||
}
|
||||
const_iterator erase(const_iterator it) { return const_iterator(erase_range(it.It)); }
|
||||
|
||||
by_size_const_iterator erase(by_size_const_iterator it) {
|
||||
by_size_const_iterator erase(by_size_const_iterator it)
|
||||
{
|
||||
return by_size_const_iterator(erase_range_by_size(it.It));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
void clear()
|
||||
{
|
||||
Map.clear();
|
||||
Sizes.clear();
|
||||
}
|
||||
|
||||
bool contains(T value) const {
|
||||
bool contains(T value) const
|
||||
{
|
||||
auto it = Map.upper_bound(value);
|
||||
if (it == Map.begin())
|
||||
return false;
|
||||
|
|
@ -324,83 +353,73 @@ public:
|
|||
return get_from(it) <= value && value < get_to(it);
|
||||
}
|
||||
|
||||
std::size_t size() const {
|
||||
return Map.size();
|
||||
bool overlaps(T from, T to) const
|
||||
{
|
||||
if (from >= to)
|
||||
return false;
|
||||
|
||||
auto it = Map.lower_bound(to);
|
||||
if (it == Map.begin())
|
||||
return false;
|
||||
--it;
|
||||
return get_from(it) < to && from < get_to(it);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return Map.empty();
|
||||
}
|
||||
std::size_t size() const { return Map.size(); }
|
||||
|
||||
std::size_t by_size_count(const SizeT& key) const {
|
||||
return Sizes.count(key);
|
||||
}
|
||||
bool empty() const { return Map.empty(); }
|
||||
|
||||
by_size_const_iterator by_size_find(const SizeT& key) const {
|
||||
return Sizes.find(key);
|
||||
}
|
||||
std::size_t by_size_count(const SizeT& key) const { return Sizes.count(key); }
|
||||
|
||||
std::pair<by_size_const_iterator, by_size_const_iterator> by_size_equal_range(const SizeT& key) const {
|
||||
by_size_const_iterator by_size_find(const SizeT& key) const { return Sizes.find(key); }
|
||||
|
||||
std::pair<by_size_const_iterator, by_size_const_iterator>
|
||||
by_size_equal_range(const SizeT& key) const
|
||||
{
|
||||
auto p = Sizes.equal_range(key);
|
||||
return std::pair<by_size_const_iterator, by_size_const_iterator>(by_size_const_iterator(p.first),
|
||||
by_size_const_iterator(p.second));
|
||||
return std::pair<by_size_const_iterator, by_size_const_iterator>(
|
||||
by_size_const_iterator(p.first), by_size_const_iterator(p.second));
|
||||
}
|
||||
|
||||
by_size_const_iterator by_size_lower_bound(const SizeT& key) const {
|
||||
by_size_const_iterator by_size_lower_bound(const SizeT& key) const
|
||||
{
|
||||
return Sizes.lower_bound(key);
|
||||
}
|
||||
|
||||
by_size_const_iterator by_size_upper_bound(const SizeT& key) const {
|
||||
by_size_const_iterator by_size_upper_bound(const SizeT& key) const
|
||||
{
|
||||
return Sizes.upper_bound(key);
|
||||
}
|
||||
|
||||
void swap(RangeSizeSet<T>& other) {
|
||||
void swap(RangeSizeSet<T>& other)
|
||||
{
|
||||
Map.swap(other.Map);
|
||||
Sizes.swap(other.Sizes);
|
||||
}
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(Map.begin());
|
||||
}
|
||||
const_iterator begin() const { return const_iterator(Map.begin()); }
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(Map.end());
|
||||
}
|
||||
const_iterator end() const { return const_iterator(Map.end()); }
|
||||
|
||||
const_iterator cbegin() const {
|
||||
return const_iterator(Map.cbegin());
|
||||
}
|
||||
const_iterator cbegin() const { return const_iterator(Map.cbegin()); }
|
||||
|
||||
const_iterator cend() const {
|
||||
return const_iterator(Map.cend());
|
||||
}
|
||||
const_iterator cend() const { return const_iterator(Map.cend()); }
|
||||
|
||||
by_size_const_iterator by_size_begin() const {
|
||||
return by_size_const_iterator(Sizes.begin());
|
||||
}
|
||||
by_size_const_iterator by_size_begin() const { return by_size_const_iterator(Sizes.begin()); }
|
||||
|
||||
by_size_const_iterator by_size_end() const {
|
||||
return by_size_const_iterator(Sizes.end());
|
||||
}
|
||||
by_size_const_iterator by_size_end() const { return by_size_const_iterator(Sizes.end()); }
|
||||
|
||||
by_size_const_iterator by_size_cbegin() const {
|
||||
return by_size_const_iterator(Sizes.cbegin());
|
||||
}
|
||||
by_size_const_iterator by_size_cbegin() const { return by_size_const_iterator(Sizes.cbegin()); }
|
||||
|
||||
by_size_const_iterator by_size_cend() const {
|
||||
return by_size_const_iterator(Sizes.cend());
|
||||
}
|
||||
by_size_const_iterator by_size_cend() const { return by_size_const_iterator(Sizes.cend()); }
|
||||
|
||||
bool operator==(const RangeSizeSet<T>& other) const {
|
||||
return this->Map == other.Map;
|
||||
}
|
||||
bool operator==(const RangeSizeSet<T>& other) const { return this->Map == other.Map; }
|
||||
|
||||
bool operator!=(const RangeSizeSet<T>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool operator!=(const RangeSizeSet<T>& other) const { return !(*this == other); }
|
||||
|
||||
// Get free size and fragmentation ratio
|
||||
std::pair<std::size_t, double> get_stats() const {
|
||||
std::pair<std::size_t, double> get_stats() const
|
||||
{
|
||||
std::size_t free_total = 0;
|
||||
if (begin() == end())
|
||||
return {free_total, 1.0};
|
||||
|
|
@ -410,12 +429,16 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
static SizeT calc_size(T from, T to) {
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
static SizeT calc_size(T from, T to)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
// For pointers we don't want pointer arithmetic here, else void* breaks.
|
||||
static_assert(sizeof(T) <= sizeof(SizeT));
|
||||
return reinterpret_cast<SizeT>(to) - reinterpret_cast<SizeT>(from);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<SizeT>(to - from);
|
||||
}
|
||||
}
|
||||
|
|
@ -435,44 +458,41 @@ private:
|
|||
// We use std::greater so that Sizes.begin() gives us the largest range.
|
||||
SizeMapT Sizes;
|
||||
|
||||
T get_from(typename MapT::iterator it) const {
|
||||
return it->first;
|
||||
}
|
||||
T get_from(typename MapT::iterator it) const { return it->first; }
|
||||
|
||||
T get_to(typename MapT::iterator it) const {
|
||||
return it->second.To;
|
||||
}
|
||||
T get_to(typename MapT::iterator it) const { return it->second.To; }
|
||||
|
||||
T get_from(typename MapT::const_iterator it) const {
|
||||
return it->first;
|
||||
}
|
||||
T get_from(typename MapT::const_iterator it) const { return it->first; }
|
||||
|
||||
T get_to(typename MapT::const_iterator it) const {
|
||||
return it->second.To;
|
||||
}
|
||||
T get_to(typename MapT::const_iterator it) const { return it->second.To; }
|
||||
|
||||
typename MapT::iterator insert_range(T from, T to) {
|
||||
typename MapT::iterator insert_range(T from, T to)
|
||||
{
|
||||
auto m = Map.emplace(from, to).first;
|
||||
m->second.SizeIt = Sizes.emplace(calc_size(from, to), m);
|
||||
return m;
|
||||
}
|
||||
|
||||
typename MapT::iterator erase_range(typename MapT::iterator it) {
|
||||
typename MapT::iterator erase_range(typename MapT::iterator it)
|
||||
{
|
||||
Sizes.erase(it->second.SizeIt);
|
||||
return Map.erase(it);
|
||||
}
|
||||
|
||||
typename MapT::const_iterator erase_range(typename MapT::const_iterator it) {
|
||||
typename MapT::const_iterator erase_range(typename MapT::const_iterator it)
|
||||
{
|
||||
Sizes.erase(it->second.SizeIt);
|
||||
return Map.erase(it);
|
||||
}
|
||||
|
||||
typename SizeMapT::const_iterator erase_range_by_size(typename SizeMapT::const_iterator it) {
|
||||
typename SizeMapT::const_iterator erase_range_by_size(typename SizeMapT::const_iterator it)
|
||||
{
|
||||
Map.erase(it->second);
|
||||
return Sizes.erase(it);
|
||||
}
|
||||
|
||||
void bisect_range(typename MapT::iterator it, T from, T to) {
|
||||
void bisect_range(typename MapT::iterator it, T from, T to)
|
||||
{
|
||||
assert(get_from(it) < from);
|
||||
assert(get_from(it) < to);
|
||||
assert(get_to(it) > from);
|
||||
|
|
@ -483,58 +503,70 @@ private:
|
|||
insert_range(to, itto);
|
||||
}
|
||||
|
||||
typename MapT::iterator reduce_from(typename MapT::iterator it, T from) {
|
||||
typename MapT::iterator reduce_from(typename MapT::iterator it, T from)
|
||||
{
|
||||
assert(get_from(it) < from);
|
||||
T itto = get_to(it);
|
||||
erase_range(it);
|
||||
return insert_range(from, itto);
|
||||
}
|
||||
|
||||
void maybe_expand_to(typename MapT::iterator it, T to) {
|
||||
void maybe_expand_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
if (to <= get_to(it))
|
||||
return;
|
||||
|
||||
expand_to(it, to);
|
||||
}
|
||||
|
||||
void expand_to(typename MapT::iterator it, T to) {
|
||||
void expand_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
assert(get_to(it) < to);
|
||||
it->second.To = to;
|
||||
Sizes.erase(it->second.SizeIt);
|
||||
it->second.SizeIt = Sizes.emplace(calc_size(get_from(it), to), it);
|
||||
}
|
||||
|
||||
void reduce_to(typename MapT::iterator it, T to) {
|
||||
void reduce_to(typename MapT::iterator it, T to)
|
||||
{
|
||||
assert(get_to(it) > to);
|
||||
it->second.To = to;
|
||||
Sizes.erase(it->second.SizeIt);
|
||||
it->second.SizeIt = Sizes.emplace(calc_size(get_from(it), to), it);
|
||||
}
|
||||
|
||||
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound, T to) {
|
||||
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound,
|
||||
T to)
|
||||
{
|
||||
// Erase all ranges that overlap the inserted while updating the upper end.
|
||||
while (bound != Map.end() && get_from(bound) <= to) {
|
||||
while (bound != Map.end() && get_from(bound) <= to)
|
||||
{
|
||||
maybe_expand_to(inserted, get_to(bound));
|
||||
bound = erase_range(bound);
|
||||
}
|
||||
}
|
||||
|
||||
void erase_from_iterator_to_value(typename MapT::iterator bound, T to) {
|
||||
void erase_from_iterator_to_value(typename MapT::iterator bound, T to)
|
||||
{
|
||||
// Assumption: Given bound starts at or after the 'from' value of the range to erase.
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
// Given range starts before stored range.
|
||||
if (to <= get_from(bound)) {
|
||||
if (to <= get_from(bound))
|
||||
{
|
||||
// Range ends before this range too, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (to < get_to(bound)) {
|
||||
if (to < get_to(bound))
|
||||
{
|
||||
// Range ends in the middle of current range, reduce current.
|
||||
reduce_from(bound, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == get_to(bound)) {
|
||||
if (to == get_to(bound))
|
||||
{
|
||||
// Range ends exactly with current range, erase current.
|
||||
erase_range(bound);
|
||||
return;
|
||||
|
|
@ -543,11 +575,12 @@ private:
|
|||
// Range ends later than current range.
|
||||
// First erase current, then loop to check the range(s) after this one too.
|
||||
bound = erase_range(bound);
|
||||
if (bound == Map.end()) {
|
||||
if (bound == Map.end())
|
||||
{
|
||||
// Unless that was the last range, in which case there's nothing else to do.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace HyoutaUtilities
|
||||
} // namespace Common
|
||||
|
|
@ -660,7 +660,6 @@ PUBLIC
|
|||
inputcommon
|
||||
MbedTLS::mbedtls
|
||||
pugixml
|
||||
RangeSet::RangeSet
|
||||
sfml-network
|
||||
videonull
|
||||
videoogl
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@
|
|||
|
||||
#include <cstddef>
|
||||
|
||||
#include <rangeset/rangesizeset.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/RangeSizeSet.h"
|
||||
#include "Core/PowerPC/CachedInterpreter/CachedInterpreterBlockCache.h"
|
||||
#include "Core/PowerPC/CachedInterpreter/CachedInterpreterEmitter.h"
|
||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||
|
|
@ -112,7 +111,7 @@ private:
|
|||
static s32 CheckIdle(PowerPC::PowerPCState& ppc_state, const CheckIdleOperands& operands);
|
||||
static s32 CheckIdle(std::ostream& stream, const CheckIdleOperands& operands);
|
||||
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges;
|
||||
CachedInterpreterBlockCache m_block_cache;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#include <optional>
|
||||
|
||||
#include <rangeset/rangesizeset.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/RangeSizeSet.h"
|
||||
#include "Common/x64Emitter.h"
|
||||
#include "Core/PowerPC/Jit64/JitAsm.h"
|
||||
#include "Core/PowerPC/Jit64/RegCache/FPURegCache.h"
|
||||
|
|
@ -295,8 +294,8 @@ private:
|
|||
|
||||
Jit64AsmRoutineManager asm_routines{*this};
|
||||
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near;
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_near;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_far;
|
||||
|
||||
const bool m_im_here_debug = false;
|
||||
const bool m_im_here_log = false;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@
|
|||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include <rangeset/rangesizeset.h>
|
||||
|
||||
#include "Common/Arm64Emitter.h"
|
||||
#include "Common/RangeSizeSet.h"
|
||||
|
||||
#include "Core/PowerPC/JitArm64/JitArm64Cache.h"
|
||||
#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h"
|
||||
|
|
@ -431,10 +430,10 @@ protected:
|
|||
u8* m_near_code_end = nullptr;
|
||||
bool m_near_code_write_failed = false;
|
||||
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near_0;
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_near_1;
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far_0;
|
||||
HyoutaUtilities::RangeSizeSet<u8*> m_free_ranges_far_1;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_near_0;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_near_1;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_far_0;
|
||||
Common::RangeSizeSet<u8*> m_free_ranges_far_1;
|
||||
|
||||
std::unique_ptr<HostDisassembler> m_disassembler;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ using namespace Gen;
|
|||
|
||||
bool JitBlock::OverlapsPhysicalRange(u32 address, u32 length) const
|
||||
{
|
||||
return physical_addresses.lower_bound(address) !=
|
||||
physical_addresses.lower_bound(address + length);
|
||||
return physical_addresses.overlaps(address, address + length);
|
||||
}
|
||||
|
||||
void JitBlock::ProfileData::BeginProfiling(ProfileData* data)
|
||||
|
|
@ -171,10 +170,13 @@ void JitBaseBlockCache::FinalizeBlock(JitBlock& block, bool block_link,
|
|||
original_buffer_transform_view.end());
|
||||
}
|
||||
|
||||
for (u32 addr : block.physical_addresses)
|
||||
for (auto [range_start, range_end] : block.physical_addresses)
|
||||
{
|
||||
valid_block.Set(addr / 32);
|
||||
block_range_map[addr & BLOCK_RANGE_MAP_MASK].insert(&block);
|
||||
for (u32 i = range_start & ~31; i < range_end; i += 32)
|
||||
valid_block.Set(i / 32);
|
||||
|
||||
for (u32 i = range_start & BLOCK_RANGE_MAP_MASK; i < range_end; i += BLOCK_RANGE_SIZE)
|
||||
block_range_map[i].insert(&block);
|
||||
}
|
||||
|
||||
if (block_link)
|
||||
|
|
@ -362,9 +364,15 @@ void JitBaseBlockCache::ErasePhysicalRange(u32 address, u32 length)
|
|||
{
|
||||
// If the block overlaps, also remove all other occupied slots in the other macro blocks.
|
||||
// This will leak empty macro blocks, but they may be reused or cleared later on.
|
||||
for (u32 addr : block->physical_addresses)
|
||||
if ((addr & BLOCK_RANGE_MAP_MASK) != start->first)
|
||||
block_range_map[addr & BLOCK_RANGE_MAP_MASK].erase(block);
|
||||
for (auto [range_start, range_end] : block->physical_addresses)
|
||||
{
|
||||
DEBUG_ASSERT(range_start != range_end);
|
||||
for (u32 i = range_start & BLOCK_RANGE_MAP_MASK; i < range_end; i += BLOCK_RANGE_SIZE)
|
||||
{
|
||||
if (i != start->first)
|
||||
block_range_map[i].erase(block);
|
||||
}
|
||||
}
|
||||
|
||||
// And remove the block.
|
||||
DestroyBlock(*block);
|
||||
|
|
@ -404,8 +412,11 @@ void JitBaseBlockCache::EraseSingleBlock(const JitBlock& block)
|
|||
|
||||
JitBlock& mutable_block = block_map_iter->second;
|
||||
|
||||
for (const u32 addr : mutable_block.physical_addresses)
|
||||
block_range_map[addr & BLOCK_RANGE_MAP_MASK].erase(&mutable_block);
|
||||
for (auto [range_start, range_end] : mutable_block.physical_addresses)
|
||||
{
|
||||
for (u32 i = range_start & BLOCK_RANGE_MAP_MASK; i < range_end; i += BLOCK_RANGE_SIZE)
|
||||
block_range_map[i].erase(&mutable_block);
|
||||
}
|
||||
|
||||
DestroyBlock(mutable_block);
|
||||
block_map.erase(block_map_iter); // The original JitBlock reference is now dangling.
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@
|
|||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/RangeSet.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
|
|
@ -101,7 +101,7 @@ struct JitBlock : public JitBlockData
|
|||
std::vector<LinkData> linkData;
|
||||
|
||||
// This set stores all physical addresses of all occupied instructions.
|
||||
std::set<u32> physical_addresses;
|
||||
Common::RangeSet<u32> physical_addresses;
|
||||
|
||||
// This is only available when debugging is enabled. It is a trimmed-down copy of the
|
||||
// PPCAnalyst::CodeBuffer used to recompile this block, including repeat instructions.
|
||||
|
|
@ -218,7 +218,8 @@ private:
|
|||
// Range of overlapping code indexed by a masked physical address.
|
||||
// This is used for invalidation of memory regions. The range is grouped
|
||||
// in macro blocks of each 0x100 bytes.
|
||||
static constexpr u32 BLOCK_RANGE_MAP_MASK = ~(0x100 - 1);
|
||||
static constexpr u32 BLOCK_RANGE_SIZE = 0x100;
|
||||
static constexpr u32 BLOCK_RANGE_MAP_MASK = ~(BLOCK_RANGE_SIZE - 1);
|
||||
std::map<u32, std::unordered_set<JitBlock*>> block_range_map;
|
||||
|
||||
// This bitsets shows which cachelines overlap with any blocks.
|
||||
|
|
|
|||
|
|
@ -849,7 +849,8 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer,
|
|||
code[i].inst = inst;
|
||||
code[i].skip = false;
|
||||
block->m_stats->numCycles += opinfo->num_cycles;
|
||||
block->m_physical_addresses.insert(result.physical_address);
|
||||
block->m_physical_addresses.insert(result.physical_address,
|
||||
result.physical_address + sizeof(UGeckoInstruction));
|
||||
|
||||
SetInstructionStats(block, &code[i], opinfo);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/RangeSet.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
|
||||
class PPCSymbolDB;
|
||||
|
|
@ -129,7 +129,7 @@ struct CodeBlock
|
|||
BitSet32 m_gpr_inputs;
|
||||
|
||||
// Which memory locations are occupied by this block.
|
||||
std::set<u32> m_physical_addresses;
|
||||
Common::RangeSet<u32> m_physical_addresses;
|
||||
};
|
||||
|
||||
class PPCAnalyzer
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@
|
|||
<ClInclude Include="Common\Projection.h" />
|
||||
<ClInclude Include="Common\QoSSession.h" />
|
||||
<ClInclude Include="Common\Random.h" />
|
||||
<ClInclude Include="Common\RangeSet.h" />
|
||||
<ClInclude Include="Common\RangeSizeSet.h" />
|
||||
<ClInclude Include="Common\scmrev.h" />
|
||||
<ClInclude Include="Common\ScopeGuard.h" />
|
||||
<ClInclude Include="Common\SDCardUtil.h" />
|
||||
|
|
|
|||
|
|
@ -236,7 +236,8 @@ QVariant JitBlockTableModel::DisplayRoleData(const QModelIndex& index) const
|
|||
case Column::CodeBufferSize:
|
||||
return QString::number(jit_block.originalSize * sizeof(UGeckoInstruction));
|
||||
case Column::RepeatInstructions:
|
||||
return QString::number(jit_block.originalSize - jit_block.physical_addresses.size());
|
||||
return QString::number(jit_block.originalSize - jit_block.physical_addresses.get_stats().first /
|
||||
sizeof(UGeckoInstruction));
|
||||
case Column::HostNearCodeSize:
|
||||
return QString::number(jit_block.near_end - jit_block.near_begin);
|
||||
case Column::HostFarCodeSize:
|
||||
|
|
@ -329,7 +330,9 @@ QVariant JitBlockTableModel::SortRoleData(const QModelIndex& index) const
|
|||
case Column::CodeBufferSize:
|
||||
return static_cast<qulonglong>(jit_block.originalSize);
|
||||
case Column::RepeatInstructions:
|
||||
return static_cast<qulonglong>(jit_block.originalSize - jit_block.physical_addresses.size());
|
||||
return static_cast<qulonglong>(jit_block.originalSize -
|
||||
jit_block.physical_addresses.get_stats().first /
|
||||
sizeof(UGeckoInstruction));
|
||||
case Column::HostNearCodeSize:
|
||||
return static_cast<qulonglong>(jit_block.near_end - jit_block.near_begin);
|
||||
case Column::HostFarCodeSize:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
<AdditionalIncludeDirectories>$(ExternalsDir)FFmpeg-bin\$(Platform)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)OpenAL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)expr\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)rangeset\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan-Headers\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)VulkanMemoryAllocator\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ExternalsDir)watcher\watcher\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user