backend/arm64: Add InvalidateCacheRanges
This commit is contained in:
parent
165621a872
commit
082167feeb
13 changed files with 69 additions and 28 deletions
|
@ -1,6 +1,8 @@
|
||||||
include(TargetArchitectureSpecificSources)
|
include(TargetArchitectureSpecificSources)
|
||||||
|
|
||||||
add_library(dynarmic
|
add_library(dynarmic
|
||||||
|
backend/block_range_information.cpp
|
||||||
|
backend/block_range_information.h
|
||||||
backend/exception_handler.h
|
backend/exception_handler.h
|
||||||
common/always_false.h
|
common/always_false.h
|
||||||
common/cast_util.h
|
common/cast_util.h
|
||||||
|
@ -271,8 +273,6 @@ if ("x86_64" IN_LIST ARCHITECTURE)
|
||||||
backend/x64/abi.h
|
backend/x64/abi.h
|
||||||
backend/x64/block_of_code.cpp
|
backend/x64/block_of_code.cpp
|
||||||
backend/x64/block_of_code.h
|
backend/x64/block_of_code.h
|
||||||
backend/x64/block_range_information.cpp
|
|
||||||
backend/x64/block_range_information.h
|
|
||||||
backend/x64/callback.cpp
|
backend/x64/callback.cpp
|
||||||
backend/x64/callback.h
|
backend/x64/callback.h
|
||||||
backend/x64/constant_pool.cpp
|
backend/x64/constant_pool.cpp
|
||||||
|
|
|
@ -181,6 +181,10 @@ IR::Block A32AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
||||||
return ir_block;
|
return ir_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A32AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges) {
|
||||||
|
InvalidateBasicBlocks(block_ranges.InvalidateRanges(ranges));
|
||||||
|
}
|
||||||
|
|
||||||
void A32AddressSpace::EmitPrelude() {
|
void A32AddressSpace::EmitPrelude() {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
|
@ -392,4 +396,11 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A32AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) {
|
||||||
|
const A32::LocationDescriptor descriptor{block.Location()};
|
||||||
|
const A32::LocationDescriptor end_location{block.EndLocation()};
|
||||||
|
const auto range = boost::icl::discrete_interval<u32>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||||
|
block_ranges.AddRange(range, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::Arm64
|
} // namespace Dynarmic::Backend::Arm64
|
||||||
|
|
|
@ -6,23 +6,30 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dynarmic/backend/arm64/address_space.h"
|
#include "dynarmic/backend/arm64/address_space.h"
|
||||||
|
#include "dynarmic/backend/block_range_information.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::Arm64 {
|
namespace Dynarmic::Backend::Arm64 {
|
||||||
|
|
||||||
|
struct EmittedBlockInfo;
|
||||||
|
|
||||||
class A32AddressSpace final : public AddressSpace {
|
class A32AddressSpace final : public AddressSpace {
|
||||||
public:
|
public:
|
||||||
explicit A32AddressSpace(const A32::UserConfig& conf);
|
explicit A32AddressSpace(const A32::UserConfig& conf);
|
||||||
|
|
||||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
||||||
|
|
||||||
|
void InvalidateCacheRanges(const boost::icl::interval_set<u32>& ranges);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class A32Core;
|
friend class A32Core;
|
||||||
|
|
||||||
void EmitPrelude();
|
void EmitPrelude();
|
||||||
EmitConfig GetEmitConfig() override;
|
EmitConfig GetEmitConfig() override;
|
||||||
|
void RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo& block_info) override;
|
||||||
|
|
||||||
const A32::UserConfig conf;
|
const A32::UserConfig conf;
|
||||||
|
BlockRangeInformation<u32> block_ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::Arm64
|
} // namespace Dynarmic::Backend::Arm64
|
||||||
|
|
|
@ -209,8 +209,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!invalid_cache_ranges.empty()) {
|
if (!invalid_cache_ranges.empty()) {
|
||||||
// TODO: Optimize
|
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
||||||
current_address_space.ClearCache();
|
|
||||||
|
|
||||||
invalid_cache_ranges.clear();
|
invalid_cache_ranges.clear();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -350,6 +350,10 @@ IR::Block A64AddressSpace::GenerateIR(IR::LocationDescriptor descriptor) const {
|
||||||
return ir_block;
|
return ir_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A64AddressSpace::InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges) {
|
||||||
|
InvalidateBasicBlocks(block_ranges.InvalidateRanges(ranges));
|
||||||
|
}
|
||||||
|
|
||||||
void A64AddressSpace::EmitPrelude() {
|
void A64AddressSpace::EmitPrelude() {
|
||||||
using namespace oaknut::util;
|
using namespace oaknut::util;
|
||||||
|
|
||||||
|
@ -568,4 +572,11 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A64AddressSpace::RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo&) {
|
||||||
|
const A64::LocationDescriptor descriptor{block.Location()};
|
||||||
|
const A64::LocationDescriptor end_location{block.EndLocation()};
|
||||||
|
const auto range = boost::icl::discrete_interval<u64>::closed(descriptor.PC(), end_location.PC() - 1);
|
||||||
|
block_ranges.AddRange(range, descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::Arm64
|
} // namespace Dynarmic::Backend::Arm64
|
||||||
|
|
|
@ -6,23 +6,30 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dynarmic/backend/arm64/address_space.h"
|
#include "dynarmic/backend/arm64/address_space.h"
|
||||||
|
#include "dynarmic/backend/block_range_information.h"
|
||||||
#include "dynarmic/interface/A64/config.h"
|
#include "dynarmic/interface/A64/config.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::Arm64 {
|
namespace Dynarmic::Backend::Arm64 {
|
||||||
|
|
||||||
|
struct EmittedBlockInfo;
|
||||||
|
|
||||||
class A64AddressSpace final : public AddressSpace {
|
class A64AddressSpace final : public AddressSpace {
|
||||||
public:
|
public:
|
||||||
explicit A64AddressSpace(const A64::UserConfig& conf);
|
explicit A64AddressSpace(const A64::UserConfig& conf);
|
||||||
|
|
||||||
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
IR::Block GenerateIR(IR::LocationDescriptor) const override;
|
||||||
|
|
||||||
|
void InvalidateCacheRanges(const boost::icl::interval_set<u64>& ranges);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class A64Core;
|
friend class A64Core;
|
||||||
|
|
||||||
void EmitPrelude();
|
void EmitPrelude();
|
||||||
EmitConfig GetEmitConfig() override;
|
EmitConfig GetEmitConfig() override;
|
||||||
|
void RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo& block_info) override;
|
||||||
|
|
||||||
const A64::UserConfig conf;
|
const A64::UserConfig conf;
|
||||||
|
BlockRangeInformation<u64> block_ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::Arm64
|
} // namespace Dynarmic::Backend::Arm64
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct Jit::Impl final {
|
||||||
|
|
||||||
HaltReason Run() {
|
HaltReason Run() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
|
@ -39,14 +39,14 @@ struct Jit::Impl final {
|
||||||
|
|
||||||
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Run(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
HaltReason Step() {
|
HaltReason Step() {
|
||||||
ASSERT(!is_executing);
|
ASSERT(!is_executing);
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation(static_cast<HaltReason>(Atomic::Load(&halt_reason)));
|
||||||
|
|
||||||
is_executing = true;
|
is_executing = true;
|
||||||
SCOPE_EXIT {
|
SCOPE_EXIT {
|
||||||
|
@ -55,7 +55,7 @@ struct Jit::Impl final {
|
||||||
|
|
||||||
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
HaltReason hr = core.Step(current_address_space, current_state, &halt_reason);
|
||||||
|
|
||||||
PerformRequestedCacheInvalidation();
|
PerformRequestedCacheInvalidation(hr);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
@ -157,23 +157,26 @@ struct Jit::Impl final {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PerformRequestedCacheInvalidation() {
|
void PerformRequestedCacheInvalidation(HaltReason hr) {
|
||||||
ClearHalt(HaltReason::CacheInvalidation);
|
if (Has(hr, HaltReason::CacheInvalidation)) {
|
||||||
|
std::unique_lock lock{invalidation_mutex};
|
||||||
|
|
||||||
if (invalidate_entire_cache) {
|
ClearHalt(HaltReason::CacheInvalidation);
|
||||||
current_address_space.ClearCache();
|
|
||||||
|
|
||||||
invalidate_entire_cache = false;
|
if (invalidate_entire_cache) {
|
||||||
invalid_cache_ranges.clear();
|
current_address_space.ClearCache();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!invalid_cache_ranges.empty()) {
|
invalidate_entire_cache = false;
|
||||||
// TODO: Optimize
|
invalid_cache_ranges.clear();
|
||||||
current_address_space.ClearCache();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
invalid_cache_ranges.clear();
|
if (!invalid_cache_ranges.empty()) {
|
||||||
return;
|
current_address_space.InvalidateCacheRanges(invalid_cache_ranges);
|
||||||
|
|
||||||
|
invalid_cache_ranges.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,8 @@ EmittedBlockInfo AddressSpace::Emit(IR::Block block) {
|
||||||
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
mem.invalidate(reinterpret_cast<u32*>(block_info.entry_point), block_info.size);
|
||||||
mem.protect();
|
mem.protect();
|
||||||
|
|
||||||
|
RegisterNewBasicBlock(block, block_info);
|
||||||
|
|
||||||
return block_info;
|
return block_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual EmitConfig GetEmitConfig() = 0;
|
virtual EmitConfig GetEmitConfig() = 0;
|
||||||
|
virtual void RegisterNewBasicBlock(const IR::Block& block, const EmittedBlockInfo& block_info) = 0;
|
||||||
|
|
||||||
size_t GetRemainingSize();
|
size_t GetRemainingSize();
|
||||||
EmittedBlockInfo Emit(IR::Block ir_block);
|
EmittedBlockInfo Emit(IR::Block ir_block);
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dynarmic/backend/x64/block_range_information.h"
|
#include "dynarmic/backend/block_range_information.h"
|
||||||
|
|
||||||
#include <boost/icl/interval_map.hpp>
|
#include <boost/icl/interval_map.hpp>
|
||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
#include <mcl/stdint.hpp>
|
#include <mcl/stdint.hpp>
|
||||||
#include <tsl/robin_set.h>
|
#include <tsl/robin_set.h>
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend {
|
||||||
|
|
||||||
template<typename ProgramCounterType>
|
template<typename ProgramCounterType>
|
||||||
void BlockRangeInformation<ProgramCounterType>::AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location) {
|
void BlockRangeInformation<ProgramCounterType>::AddRange(boost::icl::discrete_interval<ProgramCounterType> range, IR::LocationDescriptor location) {
|
||||||
|
@ -40,4 +40,4 @@ tsl::robin_set<IR::LocationDescriptor> BlockRangeInformation<ProgramCounterType>
|
||||||
template class BlockRangeInformation<u32>;
|
template class BlockRangeInformation<u32>;
|
||||||
template class BlockRangeInformation<u64>;
|
template class BlockRangeInformation<u64>;
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::X64
|
} // namespace Dynarmic::Backend
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include "dynarmic/ir/location_descriptor.h"
|
#include "dynarmic/ir/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic::Backend::X64 {
|
namespace Dynarmic::Backend {
|
||||||
|
|
||||||
template<typename ProgramCounterType>
|
template<typename ProgramCounterType>
|
||||||
class BlockRangeInformation {
|
class BlockRangeInformation {
|
||||||
|
@ -26,4 +26,4 @@ private:
|
||||||
boost::icl::interval_map<ProgramCounterType, std::set<IR::LocationDescriptor>> block_ranges;
|
boost::icl::interval_map<ProgramCounterType, std::set<IR::LocationDescriptor>> block_ranges;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Dynarmic::Backend::X64
|
} // namespace Dynarmic::Backend
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
#include <tsl/robin_map.h>
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
|
#include "dynarmic/backend/block_range_information.h"
|
||||||
#include "dynarmic/backend/x64/a32_jitstate.h"
|
#include "dynarmic/backend/x64/a32_jitstate.h"
|
||||||
#include "dynarmic/backend/x64/block_range_information.h"
|
|
||||||
#include "dynarmic/backend/x64/emit_x64.h"
|
#include "dynarmic/backend/x64/emit_x64.h"
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "dynarmic/backend/block_range_information.h"
|
||||||
#include "dynarmic/backend/x64/a64_jitstate.h"
|
#include "dynarmic/backend/x64/a64_jitstate.h"
|
||||||
#include "dynarmic/backend/x64/block_range_information.h"
|
|
||||||
#include "dynarmic/backend/x64/emit_x64.h"
|
#include "dynarmic/backend/x64/emit_x64.h"
|
||||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
||||||
#include "dynarmic/interface/A64/a64.h"
|
#include "dynarmic/interface/A64/a64.h"
|
||||||
|
|
Loading…
Reference in a new issue