Compare commits

..

1 Commits

Author SHA1 Message Date
lizzie 382157249d [dynarmic] Add A64:SM4/SM3 tests
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-10-08 16:15:58 +00:00
3 changed files with 103 additions and 20 deletions
@@ -7,27 +7,34 @@
*/
#include <cstring>
#include <cassert>
#include "common/assert.h"
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/constant_pool.h"
namespace Dynarmic::Backend::X64 {
ConstantPool::ConstantPool(BlockOfCode& code, size_t size) noexcept {
auto const align_size = 64; //always align to cacheline
code.EnsureMemoryCommitted(2 * align_size + size);
ConstantPool::ConstantPool(BlockOfCode& code, size_t size)
: insertion_point(0)
{
code.EnsureMemoryCommitted(align_size + size);
code.int3();
code.align(align_size);
pool = std::span<u128>(static_cast<u128*>(code.AllocateFromCodeSpace(size)), size / sizeof(u128));
pool = std::span<ConstantT>(reinterpret_cast<ConstantT*>(code.AllocateFromCodeSpace(size)), size / align_size);
}
Xbyak::Address ConstantPool::GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lo, u64 hi) noexcept {
// offset grows iff new constant is added
auto const key = std::make_pair(lo, hi);
auto const val = u32(constant_info.size());
auto const [it, _] = constant_info.insert({key, val});
// if it != constant_info.end(): assume(pool[it->second] == c);
pool[it->second] = u128{lo, hi};
return frame[code.rip + std::addressof(pool[it->second])];
Xbyak::Address ConstantPool::GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper) {
const auto constant = ConstantT(lower, upper);
auto it = constant_info.find(constant);
if (it == constant_info.end()) {
ASSERT(insertion_point < pool.size());
ConstantT& target_constant = pool[insertion_point];
target_constant = constant;
it = constant_info.insert({constant, &target_constant}).first;
++insertion_point;
}
return frame[code.rip + it->second];
}
} // namespace Dynarmic::Backend::X64
@@ -12,7 +12,6 @@
#include <cstddef>
#include <span>
#include <utility>
#include <boost/functional/hash.hpp>
#include "common/common_types.h"
#include "common/container/unordered_map.h"
@@ -22,17 +21,31 @@ namespace Dynarmic::Backend::X64 {
class BlockOfCode;
/// @brief ConstantPool allocates a block of memory from BlockOfCode.
/// ConstantPool allocates a block of memory from BlockOfCode.
/// It places constants into this block of memory, returning the address
/// of the memory location where the constant is placed. If the constant
/// already exists, its memory location is reused.
class ConstantPool final {
public:
ConstantPool(BlockOfCode& code, size_t size) noexcept;
Xbyak::Address GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0) noexcept;
// key = identity hash, value = offset from pool.data()
::Common::unordered_map<std::pair<u64, u64>, u32, boost::hash<std::pair<u64, u64>>> constant_info;
std::span<u128> pool;
ConstantPool(BlockOfCode& code, size_t size);
Xbyak::Address GetConstant(BlockOfCode& code, const Xbyak::AddressFrame& frame, u64 lower, u64 upper = 0);
private:
static constexpr size_t align_size = 16; // bytes
using ConstantT = std::pair<u64, u64>;
static_assert(sizeof(ConstantT) == align_size);
struct ConstantHash {
std::size_t operator()(const ConstantT& constant) const noexcept {
return constant.first ^ std::rotl<u64>(constant.second, 1);
}
};
::Common::unordered_map<ConstantT, void*, ConstantHash> constant_info;
std::span<ConstantT> pool;
std::size_t insertion_point;
};
} // namespace Dynarmic::Backend::X64
+63
View File
@@ -2632,3 +2632,66 @@ TEST_CASE("A64: Rounding", "[a64]") {
CHECK(jit.GetVector(5) == Vector{0x4000000040000000, 0x4000000040000000});
CHECK(jit.GetVector(6) == Vector{0x4000000040000000, 0x4000000040000000});
}
TEST_CASE("A64: SM4", "[a64]") {
A64TestEnv env;
A64::UserConfig jit_user_config{};
jit_user_config.callbacks = &env;
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.SM4EKEY(V4.S4(), V0.S4(), V1.S4());
code.SM4E(V5.S4(), V0.S4(), V1.S4());
jit.SetPC(0);
jit.SetVector(0, {0xefcdab8967452301, 0x1032547698badcfe});
jit.SetVector(1, {0xefcdab8967452301, 0x1032547698badcfe});
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(4) == Vector{0x486a0c2e00224466, 0x5c7e183a62402604});
CHECK(jit.GetVector(5) == Vector{0xc2e086a43c1e785a, 0xd7f593b104264062});
}
TEST_CASE("A64: SM3", "[a64]") {
A64TestEnv env;
A64::UserConfig jit_user_config{};
jit_user_config.callbacks = &env;
SECTION("SM3SS1") {
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.SM3SS1(V0.S4(), V0.S4(), V1.S4(), V2.S4());
jit.SetPC(0);
jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29});
jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76});
jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25});
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(0) == Vector{0x0000000000000000, 0x73d67cd700000000});
}
SECTION("SM3PARTW1") {
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.SM3PARTW1(V0.S4(), V0.S4(), V1.S4(), V2.S4());
jit.SetPC(0);
jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29});
jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76});
jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25});
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(0) == Vector{0x653c64995693280c, 0xabcc7db97adebf12});
}
SECTION("SM3PARTW2") {
A64::Jit jit{jit_user_config};
oaknut::VectorCodeGenerator code{env.code_mem, nullptr};
code.SM3PARTW2(V0.S4(), V0.S4(), V1.S4(), V2.S4());
jit.SetPC(0);
jit.SetVector(0, {0xec4aff517369c667, 0x46e3fbf2abbacd29});
jit.SetVector(1, {0x8de7e81bf854c27c, 0x9ac99f33632e5a76});
jit.SetVector(2, {0x5aa35831b70d3266, 0xd45ee95817055d25});
env.ticks_left = env.code_mem.size();
CheckedRun([&]() { jit.Run(); });
CHECK(jit.GetVector(0) == Vector{0x30010fe70da43740, 0x6702425b4a3a05d4});
}
}