diff --git a/externals/oaknut/.github/workflows/build-and-test.yml b/externals/oaknut/.github/workflows/build-and-test.yml index 149efbaf..b7c396d7 100644 --- a/externals/oaknut/.github/workflows/build-and-test.yml +++ b/externals/oaknut/.github/workflows/build-and-test.yml @@ -18,7 +18,11 @@ jobs: qemu-user - name: Checkout Catch2 v3 repo - run: git clone https://github.com/catchorg/Catch2.git externals/catch + uses: actions/checkout@v3 + with: + repository: catchorg/Catch2 + ref: v3.2.0 + path: externals/catch - name: Configure CMake env: @@ -38,3 +42,34 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build run: qemu-aarch64 -L /usr/aarch64-linux-gnu ./oaknut-tests -d yes + + test_on_windows: + runs-on: windows-latest + name: msvc-arm64 + + steps: + - name: Checkout oaknut repo + uses: actions/checkout@v3 + + - name: Checkout Catch2 v3 repo + uses: actions/checkout@v3 + with: + repository: catchorg/Catch2 + ref: v3.2.0 + path: externals/catch + + - name: Setup msvc-arm64 environment + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_arm64 + + - name: Configure CMake + run: > + cmake + -B ${{github.workspace}}/build + -GNinja + -DOAKNUT_USE_BUNDLED_CATCH=ON + + - name: Build + working-directory: ${{github.workspace}}/build + run: cmake --build . --config Release diff --git a/externals/oaknut/CMakeLists.txt b/externals/oaknut/CMakeLists.txt index d2c9726b..7d764fb6 100644 --- a/externals/oaknut/CMakeLists.txt +++ b/externals/oaknut/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.8) -project(oaknut LANGUAGES CXX VERSION 1.1.3) +project(oaknut LANGUAGES CXX VERSION 1.1.4) # Determine if we're built as a subproject (using add_subdirectory) # or if this is the master project. @@ -85,3 +85,12 @@ if (MASTER_PROJECT) target_compile_options(oaknut-tests PRIVATE -Wall -Wextra -Wcast-qual -pedantic -pedantic-errors -Wfatal-errors -Wno-missing-braces) endif() endif() + +# Export +include(GNUInstallDirs) + +install(TARGETS oaknut EXPORT oaknutTargets) +install(EXPORT oaknutTargets + NAMESPACE merry:: + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/oaknut" +) diff --git a/externals/oaknut/include/oaknut/impl/offset.hpp b/externals/oaknut/include/oaknut/impl/offset.hpp index 470de8fb..db65fe37 100644 --- a/externals/oaknut/include/oaknut/impl/offset.hpp +++ b/externals/oaknut/include/oaknut/impl/offset.hpp @@ -66,7 +66,7 @@ private: template struct PageOffset { - PageOffset(void* ptr) + PageOffset(const void* ptr) : m_payload(ptr) {} @@ -86,7 +86,7 @@ struct PageOffset { private: template friend class BasicCodeGenerator; - std::variant m_payload; + std::variant m_payload; }; template diff --git a/externals/oaknut/include/oaknut/oaknut.hpp b/externals/oaknut/include/oaknut/oaknut.hpp index e6ab27ef..e512afc1 100644 --- a/externals/oaknut/include/oaknut/oaknut.hpp +++ b/externals/oaknut/include/oaknut/oaknut.hpp @@ -110,6 +110,12 @@ public: return RET(XReg{30}); } + void ADRL(XReg xd, const void* addr) + { + ADRP(xd, addr); + ADD(xd, xd, reinterpret_cast(addr) & 0xFFF); + } + void MOV(WReg wd, uint32_t imm) { if (wd.index() == 31) @@ -163,6 +169,18 @@ public: } } + // Convenience function for moving pointers to registers + void MOVP2R(XReg xd, const void* addr) { + int64_t diff = reinterpret_cast(addr) - Policy::current_address(); + if (diff >= -0xF'FFFF && diff <= 0xF'FFFF) { + ADR(xd, addr); + } else if (diff >= -int64_t{0xFFFF'FFFF} && diff <= int64_t{0xFFFF'FFFF}) { + ADRL(xd, addr); + } else { + MOV(xd, reinterpret_cast(addr)); + } + } + void align(std::size_t alignment) { if (alignment < 4 || (alignment & (alignment - 1)) != 0) @@ -242,7 +260,7 @@ private: label->m_wbs.emplace_back(Label::Writeback{Policy::current_address(), ~splat, static_cast(encode_fn)}); return 0u; }, - [&](void* p) { + [&](const void* p) { return encode_fn(Policy::current_address(), reinterpret_cast(p)); }, }, diff --git a/externals/oaknut/tests/basic.cpp b/externals/oaknut/tests/basic.cpp index 9bcd28f8..e1d3c5e1 100644 --- a/externals/oaknut/tests/basic.cpp +++ b/externals/oaknut/tests/basic.cpp @@ -3,6 +3,7 @@ #include #include +#include #include @@ -159,3 +160,48 @@ TEST_CASE("ADRP") REQUIRE(f() == expect); } } + +TEST_CASE("ADRL") +{ + CodeBlock mem{4096}; + + for (int i = 0; i < 0x200000; i++) { + const std::int64_t diff = RandInt(-4294967296, 4294967295); + const std::intptr_t value = reinterpret_cast(mem.ptr()) + diff; + + CodeGenerator code{mem.ptr()}; + + auto f = code.ptr(); + mem.unprotect(); + code.ADRL(X0, reinterpret_cast(value)); + code.RET(); + mem.protect(); + mem.invalidate_all(); + + INFO(i); + REQUIRE(f() == static_cast(value)); + } +} + +TEST_CASE("MOVP2R") +{ + CodeBlock mem{4096}; + + for (int i = 0; i < 0x200'0000; i++) + { + const std::int64_t diff = RandInt(std::numeric_limits::min(), + std::numeric_limits::max()); + const std::intptr_t value = reinterpret_cast(mem.ptr()) + diff; + + CodeGenerator code{mem.ptr()}; + + auto f = code.ptr(); + mem.unprotect(); + code.MOVP2R(X0, reinterpret_cast(value)); + code.RET(); + mem.protect(); + mem.invalidate_all(); + + REQUIRE(f() == static_cast(value)); + } +}