dynarmic/tests/basic.cpp
Merry cb8abc3ae5 Squashed 'externals/oaknut/' changes from c0c715505..72f7ccd94
72f7ccd94 oaknut: 1.1.3
0b5745e4e oaknut: Add Windows on Arm support (#1)
5de40335d oaknut: 1.1.2
2952b759f oaknut: Correct MOV (UMOV alias)
c90eb31ca oaknut: 1.1.1
7c777a28f oaknut: Fix ADR and ADRP
7470c7611 oaknut: Add ARMv8.2 instructions
9eb7cca88 oaknut: Update README
3fe32849a oaknut: 1.1.0
542128b51 oaknut: Add ARMv8.1 instructions
9acafdcdd oaknut: fpsimd MOV and UMOV corrections
636f91bac oaknut: MOV: Fix MOVN case
9cb332621 oaknut: Implement arranged accessors from DReg and QReg
ba2dc2afe oaknut: dx
94bf56b08 oaknut: align
aa7a3519f oaknut: Add dw
898f666ec oaknut: Add common system registers

git-subtree-dir: externals/oaknut
git-subtree-split: 72f7ccd9409dadf6a4ab98bad1fb11fbf0ca4d74
2022-11-15 15:36:04 +00:00

161 lines
3.5 KiB
C++

// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
// SPDX-License-Identifier: MIT
#include <cstdint>
#include <cstdio>
#include <catch2/catch_test_macros.hpp>
#include "oaknut/code_block.hpp"
#include "oaknut/oaknut.hpp"
#include "rand_int.hpp"
using namespace oaknut;
using namespace oaknut::util;
TEST_CASE("Basic Test")
{
CodeBlock mem{4096};
CodeGenerator code{mem.ptr()};
mem.unprotect();
code.MOV(W0, 42);
code.RET();
mem.protect();
mem.invalidate_all();
int result = ((int (*)())mem.ptr())();
REQUIRE(result == 42);
}
TEST_CASE("Fibonacci")
{
CodeBlock mem{4096};
CodeGenerator code{mem.ptr()};
mem.unprotect();
auto fib = code.ptr<int (*)(int)>();
Label start, end, zero, recurse;
code.l(start);
code.STP(X29, X30, SP, PRE_INDEXED, -32);
code.STP(X20, X19, SP, 16);
code.MOV(X29, SP);
code.MOV(W19, W0);
code.SUBS(W0, W0, 1);
code.B(LT, zero);
code.B(NE, recurse);
code.MOV(W0, 1);
code.B(end);
code.l(zero);
code.MOV(W0, WZR);
code.B(end);
code.l(recurse);
code.BL(start);
code.MOV(W20, W0);
code.SUB(W0, W19, 2);
code.BL(start);
code.ADD(W0, W0, W20);
code.l(end);
code.LDP(X20, X19, SP, 16);
code.LDP(X29, X30, SP, POST_INDEXED, 32);
code.RET();
mem.protect();
mem.invalidate_all();
REQUIRE(fib(0) == 0);
REQUIRE(fib(1) == 1);
REQUIRE(fib(5) == 5);
REQUIRE(fib(9) == 34);
}
TEST_CASE("Immediate generation (32-bit)")
{
CodeBlock mem{4096};
for (int i = 0; i < 0x100000; i++) {
const std::uint32_t value = RandInt<std::uint32_t>(0, 0xffffffff);
CodeGenerator code{mem.ptr()};
auto f = code.ptr<std::uint64_t (*)()>();
mem.unprotect();
code.MOV(W0, value);
code.RET();
mem.protect();
mem.invalidate_all();
REQUIRE(f() == value);
}
}
TEST_CASE("Immediate generation (64-bit)")
{
CodeBlock mem{4096};
for (int i = 0; i < 0x100000; i++) {
const std::uint64_t value = RandInt<std::uint64_t>(0, 0xffffffff'ffffffff);
CodeGenerator code{mem.ptr()};
auto f = code.ptr<std::uint64_t (*)()>();
mem.unprotect();
code.MOV(X0, value);
code.RET();
mem.protect();
mem.invalidate_all();
REQUIRE(f() == value);
}
}
TEST_CASE("ADR")
{
CodeBlock mem{4096};
for (std::int64_t i = -1048576; i < 1048576; i++) {
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem.ptr()) + i;
CodeGenerator code{mem.ptr()};
auto f = code.ptr<std::intptr_t (*)()>();
mem.unprotect();
code.ADR(X0, reinterpret_cast<void*>(value));
code.RET();
mem.protect();
mem.invalidate_all();
INFO(i);
REQUIRE(f() == value);
}
}
TEST_CASE("ADRP")
{
CodeBlock mem{4096};
for (int i = 0; i < 0x200000; i++) {
const std::int64_t diff = RandInt<std::int64_t>(-4294967296, 4294967295);
const std::intptr_t value = reinterpret_cast<std::intptr_t>(mem.ptr()) + diff;
const std::uint64_t expect = static_cast<std::uint64_t>(value) & ~static_cast<std::uint64_t>(0xfff);
CodeGenerator code{mem.ptr()};
auto f = code.ptr<std::uint64_t (*)()>();
mem.unprotect();
code.ADRP(X0, reinterpret_cast<void*>(value));
code.RET();
mem.protect();
mem.invalidate_all();
INFO(i);
REQUIRE(f() == expect);
}
}