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
This commit is contained in:
parent
4e89756169
commit
cb8abc3ae5
16 changed files with 2331 additions and 82 deletions
2
.github/workflows/build-and-test.yml
vendored
2
.github/workflows/build-and-test.yml
vendored
|
@ -29,7 +29,7 @@ jobs:
|
||||||
-B ${{github.workspace}}/build
|
-B ${{github.workspace}}/build
|
||||||
-H.
|
-H.
|
||||||
-GNinja
|
-GNinja
|
||||||
-DDYNARMIC_USE_BUNDLED_CATCH=ON
|
-DOAKNUT_USE_BUNDLED_CATCH=ON
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.8)
|
cmake_minimum_required(VERSION 3.8)
|
||||||
project(oaknut LANGUAGES CXX VERSION 0.0.0)
|
project(oaknut LANGUAGES CXX VERSION 1.1.3)
|
||||||
|
|
||||||
# Determine if we're built as a subproject (using add_subdirectory)
|
# Determine if we're built as a subproject (using add_subdirectory)
|
||||||
# or if this is the master project.
|
# or if this is the master project.
|
||||||
|
@ -18,11 +18,13 @@ endif()
|
||||||
# Source project files
|
# Source project files
|
||||||
set(header_files
|
set(header_files
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/arm64_encode_helpers.inc.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/arm64_encode_helpers.inc.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/arm64_mnemonics.inc.hpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/enum.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/enum.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/fpsimd_mnemonics.inc.hpp
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/imm.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/imm.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/list.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/list.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/mnemonics_fpsimd_v8.0.inc.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/mnemonics_fpsimd_v8.1.inc.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/mnemonics_generic_v8.0.inc.hpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/mnemonics_generic_v8.1.inc.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/multi_typed_name.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/multi_typed_name.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/offset.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/offset.hpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/reg.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/include/oaknut/impl/reg.hpp
|
||||||
|
@ -39,7 +41,8 @@ target_compile_features(oaknut INTERFACE cxx_std_20)
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
if (MASTER_PROJECT)
|
if (MASTER_PROJECT)
|
||||||
if (DYNARMIC_USE_BUNDLED_CATCH)
|
option(OAKNUT_USE_BUNDLED_CATCH "Use the embedded Catch2 submodule" OFF)
|
||||||
|
if (OAKNUT_USE_BUNDLED_CATCH)
|
||||||
add_subdirectory(externals/catch)
|
add_subdirectory(externals/catch)
|
||||||
else()
|
else()
|
||||||
find_package(Catch2 3 REQUIRED)
|
find_package(Catch2 3 REQUIRED)
|
||||||
|
@ -52,5 +55,33 @@ if (MASTER_PROJECT)
|
||||||
)
|
)
|
||||||
target_include_directories(oaknut-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
target_include_directories(oaknut-tests PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||||
target_link_libraries(oaknut-tests PRIVATE Catch2::Catch2WithMain merry::oaknut)
|
target_link_libraries(oaknut-tests PRIVATE Catch2::Catch2WithMain merry::oaknut)
|
||||||
|
if (MSVC)
|
||||||
|
target_compile_options(oaknut-tests PRIVATE
|
||||||
|
/experimental:external
|
||||||
|
/external:W0
|
||||||
|
/external:anglebrackets
|
||||||
|
/W4
|
||||||
|
/w44263 # Non-virtual member function hides base class virtual function
|
||||||
|
/w44265 # Class has virtual functions, but destructor is not virtual
|
||||||
|
/w44456 # Declaration of 'var' hides previous local declaration
|
||||||
|
/w44457 # Declaration of 'var' hides function parameter
|
||||||
|
/w44458 # Declaration of 'var' hides class member
|
||||||
|
/w44459 # Declaration of 'var' hides global definition
|
||||||
|
/w44946 # Reinterpret-cast between related types
|
||||||
|
/wd4592 # Symbol will be dynamically initialized (implementation limitation)
|
||||||
|
/permissive- # Stricter C++ standards conformance
|
||||||
|
/MP
|
||||||
|
/Zi
|
||||||
|
/Zo
|
||||||
|
/EHsc
|
||||||
|
/Zc:externConstexpr # Allows external linkage for variables declared "extern constexpr", as the standard permits.
|
||||||
|
/Zc:inline # Omits inline functions from object-file output.
|
||||||
|
/Zc:throwingNew # Assumes new (without std::nothrow) never returns null.
|
||||||
|
/volatile:iso # Use strict standard-abiding volatile semantics
|
||||||
|
/bigobj # Increase number of sections in .obj files
|
||||||
|
/DNOMINMAX
|
||||||
|
)
|
||||||
|
else()
|
||||||
target_compile_options(oaknut-tests PRIVATE -Wall -Wextra -Wcast-qual -pedantic -pedantic-errors -Wfatal-errors -Wno-missing-braces)
|
target_compile_options(oaknut-tests PRIVATE -Wall -Wextra -Wcast-qual -pedantic -pedantic-errors -Wfatal-errors -Wno-missing-braces)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
88
README.md
88
README.md
|
@ -1,14 +1,19 @@
|
||||||
# Oaknut
|
# Oaknut
|
||||||
|
|
||||||
*A C++20 assembler for AArch64 (ARMv8.0)*
|
*A C++20 assembler for AArch64 (ARMv8.0 to ARMv8.2)*
|
||||||
|
|
||||||
Oaknut is a header-only library that allows one to dynamically assemble code in-memory at runtime.
|
Oaknut is a header-only library that allows one to dynamically assemble code in-memory at runtime.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
Provide `oaknut::CodeGenerator` with a pointer to a block of memory. Call functions on it to emit code.
|
||||||
|
|
||||||
Simple example:
|
Simple example:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
#include <cstdio>
|
||||||
|
#include <oaknut/oaknut.hpp>
|
||||||
|
|
||||||
using EmittedFunction = int (*)();
|
using EmittedFunction = int (*)();
|
||||||
|
|
||||||
EmittedFunction EmitExample(oaknut::CodeGenerator& code, int value)
|
EmittedFunction EmitExample(oaknut::CodeGenerator& code, int value)
|
||||||
|
@ -17,13 +22,92 @@ EmittedFunction EmitExample(oaknut::CodeGenerator& code, int value)
|
||||||
|
|
||||||
EmittedFunction result = code.ptr<EmittedFunction>();
|
EmittedFunction result = code.ptr<EmittedFunction>();
|
||||||
|
|
||||||
code.MOVZ(W0, value);
|
code.MOV(W0, value);
|
||||||
code.RET();
|
code.RET();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
oaknut::CodeBlock mem{4096};
|
||||||
|
oaknut::CodeGenerator code{mem.ptr()};
|
||||||
|
|
||||||
|
mem.unprotect();
|
||||||
|
|
||||||
|
EmittedFunction fn = EmitExample(code, 42);
|
||||||
|
|
||||||
|
mem.protect();
|
||||||
|
mem.invalidate_all();
|
||||||
|
|
||||||
|
std::printf("%i\n", fn()); // Output: 42
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
|
||||||
|
Each AArch64 instruction corresponds to one emitter function. For a list of emitter functions see:
|
||||||
|
* ARMv8.0: [general instructions](include/oaknut/impl/mnemonics_generic_v8.0.inc.hpp), [FP & SIMD instructions](include/oaknut/impl/mnemonics_fpsimd_v8.0.inc.hpp)
|
||||||
|
* ARMv8.1: [general instructions](include/oaknut/impl/mnemonics_generic_v8.1.inc.hpp), [FP & SIMD instructions](include/oaknut/impl/mnemonics_fpsimd_v8.1.inc.hpp)
|
||||||
|
* ARMv8.2: [general instructions](include/oaknut/impl/mnemonics_generic_v8.2.inc.hpp), [FP & SIMD instructions](include/oaknut/impl/mnemonics_fpsimd_v8.2.inc.hpp)
|
||||||
|
|
||||||
|
### Operands
|
||||||
|
|
||||||
|
The `oaknut::util` namespace provides convenient names for operands for instructions. For example:
|
||||||
|
|
||||||
|
|Name|Class| |
|
||||||
|
|----|----|----|
|
||||||
|
|W0, W1, ..., W30|`WReg`|32-bit general purpose registers|
|
||||||
|
|X0, X1, ..., X30|`XReg`|64-bit general purpose registers|
|
||||||
|
|WZR|`WzrReg` (convertable to `WReg`)|32-bit zero register|
|
||||||
|
|XZR|`ZrReg` (convertable to `XReg`)|64-bit zero register|
|
||||||
|
|WSP|`WspReg` (convertable to `WRegSp`)|32-bit stack pointer|
|
||||||
|
|SP|`SpReg` (convertable to `XRegSp`)|64-bit stack pointer|
|
||||||
|
|B0, B1, ..., B31|`BReg`|8-bit scalar SIMD register|
|
||||||
|
|H0, H1, ..., H31|`HReg`|16-bit scalar SIMD register|
|
||||||
|
|S0, S1, ..., S31|`SReg`|32-bit scalar SIMD register|
|
||||||
|
|D0, D1, ..., D31|`DReg`|64-bit scalar SIMD register|
|
||||||
|
|Q0, Q1, ..., Q31|`QReg`|128-bit scalar SIMD register|
|
||||||
|
|
||||||
|
For vector operations, you can specify registers like so:
|
||||||
|
|
||||||
|
|Name|Class| |
|
||||||
|
|----|----|----|
|
||||||
|
|V0.B8(), ...|`VReg_8B`|8 elements each 8 bits in size|
|
||||||
|
|V0.B16(), ...|`VReg_16B`|16 elements each 8 bits in size|
|
||||||
|
|V0.H4(), ...|`VReg_4H`|4 elements each 16 bits in size|
|
||||||
|
|V0.H8(), ...|`VReg_8H`|8 elements each 16 bits in size|
|
||||||
|
|V0.S2(), ...|`VReg_2S`|2 elements each 32 bits in size|
|
||||||
|
|V0.S4(), ...|`VReg_4S`|4 elements each 32 bits in size|
|
||||||
|
|V0.D1(), ...|`VReg_1D`|1 elements each 64 bits in size|
|
||||||
|
|V0.D2(), ...|`VReg_2D`|2 elements each 64 bits in size|
|
||||||
|
|
||||||
|
And you can specify elements like so:
|
||||||
|
|
||||||
|
|Name|Class| |
|
||||||
|
|----|----|----|
|
||||||
|
|V0.B()[0]|`BElem`|0th 8-bit element of V0 register|
|
||||||
|
|V0.H()[0]|`HElem`|0th 16-bit element of V0 register|
|
||||||
|
|V0.S()[0]|`SElem`|0th 32-bit element of V0 register|
|
||||||
|
|V0.D()[0]|`DElem`|0th 64-bit element of V0 register|
|
||||||
|
|
||||||
|
Register lists are specified using `List`:
|
||||||
|
|
||||||
|
```
|
||||||
|
List{V0.B16(), V1.B16(), V2.B16()} // This expression has type List<VReg_16B, 3>
|
||||||
|
```
|
||||||
|
|
||||||
|
And lists of elements similarly (both forms are equivalent):
|
||||||
|
|
||||||
|
```
|
||||||
|
List{V0.B()[1], V1.B()[1], V2.B()[1]} // This expression has type List<BElem, 3>
|
||||||
|
List{V0.B(), V1.B(), V2.B()}[1] // This expression has type List<BElem, 3>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can find examples of instruction use in [tests/general.cpp](tests/general.cpp) and [tests/fpsimd.cpp](tests/fpsimd.cpp).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is [MIT licensed](LICENSE).
|
This project is [MIT licensed](LICENSE).
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
# define NOMINMAX
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
# include <libkern/OSCacheControl.h>
|
# include <libkern/OSCacheControl.h>
|
||||||
|
@ -78,6 +79,8 @@ public:
|
||||||
{
|
{
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
sys_icache_invalidate(mem, size);
|
sys_icache_invalidate(mem, size);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), mem, size);
|
||||||
#else
|
#else
|
||||||
static std::size_t icache_line_size = 0x10000, dcache_line_size = 0x10000;
|
static std::size_t icache_line_size = 0x10000, dcache_line_size = 0x10000;
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,15 @@ enum class PstateField {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SystemReg {
|
enum class SystemReg {
|
||||||
|
CNTFRQ_EL0 = 0b11'011'1110'0000'000,
|
||||||
|
CNTPCT_EL0 = 0b11'011'1110'0000'001,
|
||||||
|
CTR_EL0 = 0b11'011'0000'0000'001,
|
||||||
|
DCZID_EL0 = 0b11'011'0000'0000'111,
|
||||||
|
FPCR = 0b11'011'0100'0100'000,
|
||||||
|
FPSR = 0b11'011'0100'0100'001,
|
||||||
|
NZCV = 0b11'011'0100'0010'000,
|
||||||
|
TPIDR_EL0 = 0b11'011'1101'0000'010,
|
||||||
|
TPIDRRO_EL0 = 0b11'011'1101'0000'011,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AtOp {
|
enum class AtOp {
|
||||||
|
|
|
@ -4038,19 +4038,19 @@ void MOV(DReg rd, DElem en)
|
||||||
}
|
}
|
||||||
void MOV(WReg wd, SElem en)
|
void MOV(WReg wd, SElem en)
|
||||||
{
|
{
|
||||||
emit<"00001110000ii100001111nnnnnddddd", "d", "n", "x">(wd, en.reg_index(), en.elem_index());
|
emit<"00001110000xx100001111nnnnnddddd", "d", "n", "x">(wd, en.reg_index(), en.elem_index());
|
||||||
}
|
}
|
||||||
void MOV(XReg xd, DElem en)
|
void MOV(XReg xd, DElem en)
|
||||||
{
|
{
|
||||||
emit<"01001110000i1000001111nnnnnddddd", "d", "n", "x">(xd, en.reg_index(), en.elem_index());
|
emit<"01001110000x1000001111nnnnnddddd", "d", "n", "x">(xd, en.reg_index(), en.elem_index());
|
||||||
}
|
}
|
||||||
void MOV(VReg_8B rd, VReg_8B rn)
|
void MOV(VReg_8B rd, VReg_8B rn)
|
||||||
{
|
{
|
||||||
emit<"00001110101mmmmm000111nnnnnddddd", "d", "n">(rd, rn);
|
emit<"00001110101mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rn);
|
||||||
}
|
}
|
||||||
void MOV(VReg_16B rd, VReg_16B rn)
|
void MOV(VReg_16B rd, VReg_16B rn)
|
||||||
{
|
{
|
||||||
emit<"01001110101mmmmm000111nnnnnddddd", "d", "n">(rd, rn);
|
emit<"01001110101mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rn);
|
||||||
}
|
}
|
||||||
void MOVI(VReg_8B rd, Imm<8> imm, LslSymbol = LslSymbol::LSL, ImmConst<0> = 0)
|
void MOVI(VReg_8B rd, Imm<8> imm, LslSymbol = LslSymbol::LSL, ImmConst<0> = 0)
|
||||||
{
|
{
|
||||||
|
@ -8279,7 +8279,7 @@ void UMOV(WReg wd, SElem en)
|
||||||
}
|
}
|
||||||
void UMOV(XReg xd, DElem en)
|
void UMOV(XReg xd, DElem en)
|
||||||
{
|
{
|
||||||
emit<"01001110000i1000001111nnnnnddddd", "d", "n", "x">(xd, en.reg_index(), en.elem_index());
|
emit<"01001110000x1000001111nnnnnddddd", "d", "n", "x">(xd, en.reg_index(), en.elem_index());
|
||||||
}
|
}
|
||||||
void UMULL(VReg_4S rd, VReg_4H rn, HElem em)
|
void UMULL(VReg_4S rd, VReg_4H rn, HElem em)
|
||||||
{
|
{
|
111
include/oaknut/impl/mnemonics_fpsimd_v8.1.inc.hpp
Normal file
111
include/oaknut/impl/mnemonics_fpsimd_v8.1.inc.hpp
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
void SQRDMLAH(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0111111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(SReg rd, SReg rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0111111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_4H rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0010111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_8H rd, VReg_8H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0110111101LMmmmm1101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_2S rd, VReg_2S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0010111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0110111110LMmmmm1101H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(SReg rd, SReg rn, SReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_2S rd, VReg_2S rn, VReg_2S rm)
|
||||||
|
{
|
||||||
|
emit<"00101110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLAH(VReg_4S rd, VReg_4S rn, VReg_4S rm)
|
||||||
|
{
|
||||||
|
emit<"01101110100mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0111111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(SReg rd, SReg rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0111111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_4H rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0010111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_8H rd, VReg_8H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0110111101LMmmmm1111H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_2S rd, VReg_2S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0010111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0110111110LMmmmm1111H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(SReg rd, SReg rn, SReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_2S rd, VReg_2S rn, VReg_2S rm)
|
||||||
|
{
|
||||||
|
emit<"00101110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SQRDMLSH(VReg_4S rd, VReg_4S rn, VReg_4S rm)
|
||||||
|
{
|
||||||
|
emit<"01101110100mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
855
include/oaknut/impl/mnemonics_fpsimd_v8.2.inc.hpp
Normal file
855
include/oaknut/impl/mnemonics_fpsimd_v8.2.inc.hpp
Normal file
|
@ -0,0 +1,855 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
void BCAX(VReg_16B rd, VReg_16B rn, VReg_16B rm, VReg_16B ra)
|
||||||
|
{
|
||||||
|
emit<"11001110001mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
|
||||||
|
}
|
||||||
|
void EOR3(VReg_16B rd, VReg_16B rn, VReg_16B rm, VReg_16B ra)
|
||||||
|
{
|
||||||
|
emit<"11001110000mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
|
||||||
|
}
|
||||||
|
void FABD(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FABD(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FABD(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FABS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FABS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FACGE(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FACGE(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FACGE(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FACGT(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FACGT(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FACGT(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110110mmmmm001011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FADD(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FADD(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FADDP(HReg rd, VReg_2H rn)
|
||||||
|
{
|
||||||
|
emit<"0101111000110000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FADDP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FADDP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMEQ(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01011110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMEQ(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMEQ(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMEQ(HReg rd, HReg rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0101111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMEQ(VReg_4H rd, VReg_4H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0000111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMEQ(VReg_8H rd, VReg_8H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0100111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGE(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGE(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGE(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGE(HReg rd, HReg rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0111111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGE(VReg_4H rd, VReg_4H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0010111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGE(VReg_8H rd, VReg_8H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0110111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGT(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01111110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGT(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGT(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110110mmmmm001001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FCMGT(HReg rd, HReg rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0101111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGT(VReg_4H rd, VReg_4H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0000111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMGT(VReg_8H rd, VReg_8H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0100111011111000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLE(HReg rd, HReg rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0111111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLE(VReg_4H rd, VReg_4H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0010111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLE(VReg_8H rd, VReg_8H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0110111011111000110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLT(HReg rd, HReg rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0101111011111000111010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLT(VReg_4H rd, VReg_4H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0000111011111000111010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCMLT(VReg_8H rd, VReg_8H rn, ImmConstFZero)
|
||||||
|
{
|
||||||
|
emit<"0100111011111000111010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAS(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAU(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAU(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTAU(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMS(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMU(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMU(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTMU(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNS(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNU(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNU(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTNU(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPS(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPU(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPU(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTPU(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111001101010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZS(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZS(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZS(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZU(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZU(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FCVTZU(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111001101110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FDIV(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FDIV(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAX(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAX(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXNM(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXNM(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXNMP(HReg rd, VReg_2H rn)
|
||||||
|
{
|
||||||
|
emit<"0101111000110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMAXNMP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXNMP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXNMV(HReg rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111000110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMAXNMV(HReg rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111000110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMAXP(HReg rd, VReg_2H rn)
|
||||||
|
{
|
||||||
|
emit<"0101111000110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMAXP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMAXV(HReg rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111000110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMAXV(HReg rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111000110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMIN(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMIN(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINNM(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINNM(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINNMP(HReg rd, VReg_2H rn)
|
||||||
|
{
|
||||||
|
emit<"0101111010110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMINNMP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINNMP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110110mmmmm000001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINNMV(HReg rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111010110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMINNMV(HReg rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111010110000110010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMINP(HReg rd, VReg_2H rn)
|
||||||
|
{
|
||||||
|
emit<"0101111010110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMINP(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINP(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110110mmmmm001101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMINV(HReg rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111010110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMINV(HReg rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111010110000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FMLA(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0101111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLA(VReg_8B rd, VReg_8B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0000111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLA(VReg_16B rd, VReg_16B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0100111100LMmmmm0001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLA(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLA(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLAL(VReg_2S rd, VReg_2H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0000111110LMmmmm0000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLAL(VReg_4S rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0100111110LMmmmm0000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLAL2(VReg_2S rd, VReg_2H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0010111110LMmmmm1000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLAL2(VReg_4S rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0110111110LMmmmm1000H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLAL(VReg_2S rd, VReg_2H rn, VReg_2H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110001mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLAL(VReg_4S rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110001mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLAL2(VReg_2S rd, VReg_2H rn, VReg_2H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110001mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLAL2(VReg_4S rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110001mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLS(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0101111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLS(VReg_8B rd, VReg_8B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0000111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLS(VReg_16B rd, VReg_16B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0100111100LMmmmm0101H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110110mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110110mmmmm000011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLSL(VReg_2S rd, VReg_2H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0000111110LMmmmm0100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLSL(VReg_4S rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0100111110LMmmmm0100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLSL2(VReg_2S rd, VReg_2H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0010111110LMmmmm1100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLSL2(VReg_4S rd, VReg_4H rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0110111110LMmmmm1100H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMLSL(VReg_2S rd, VReg_2H rn, VReg_2H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110101mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLSL(VReg_4S rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110101mmmmm111011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLSL2(VReg_2S rd, VReg_2H rn, VReg_2H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110101mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMLSL2(VReg_4S rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110101mmmmm110011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMOV(VReg_4H rd, FImm8 imm)
|
||||||
|
{
|
||||||
|
emit<"0000111100000vvv111111vvvvvddddd", "d", "v">(rd, imm);
|
||||||
|
}
|
||||||
|
void FMOV(VReg_8H rd, FImm8 imm)
|
||||||
|
{
|
||||||
|
emit<"0100111100000vvv111111vvvvvddddd", "d", "v">(rd, imm);
|
||||||
|
}
|
||||||
|
void FMUL(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0101111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMUL(VReg_8B rd, VReg_8B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0000111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMUL(VReg_16B rd, VReg_16B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0100111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMUL(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00101110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMUL(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01101110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMULX(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01011110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMULX(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMULX(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm000111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FMULX(HReg rd, HReg rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0111111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMULX(VReg_8B rd, VReg_8B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0010111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FMULX(VReg_16B rd, VReg_16B rn, HElem em)
|
||||||
|
{
|
||||||
|
if (em.reg_index() >= 16)
|
||||||
|
throw "InvalidCombination";
|
||||||
|
emit<"0110111100LMmmmm1001H0nnnnnddddd", "d", "n", "m", "H", "L", "M">(rd, rn, em.reg_index(), em.elem_index() >> 2, (em.elem_index() >> 1) & 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void FNEG(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FNEG(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111000111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRECPE(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRECPE(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRECPE(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRECPS(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01011110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FRECPS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FRECPS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110010mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FRECPX(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111011111001111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTA(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTA(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTI(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTI(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTM(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTM(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTN(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTN(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTP(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTP(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111001100010nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTX(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTX(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTZ(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111011111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRINTZ(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111011111001100110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRSQRTE(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRSQRTE(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRSQRTE(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FRSQRTS(HReg rd, HReg rn, HReg rm)
|
||||||
|
{
|
||||||
|
emit<"01011110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FRSQRTS(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FRSQRTS(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110110mmmmm001111nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FSQRT(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111011111001111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FSQRT(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111011111001111110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void FSUB(VReg_4H rd, VReg_4H rn, VReg_4H rm)
|
||||||
|
{
|
||||||
|
emit<"00001110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void FSUB(VReg_8H rd, VReg_8H rn, VReg_8H rm)
|
||||||
|
{
|
||||||
|
emit<"01001110110mmmmm000101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void RAX1(VReg_2D rd, VReg_2D rn, VReg_2D rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm100011nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SCVTF(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0101111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void SCVTF(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0000111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void SCVTF(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0100111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void SDOT(VReg_2S rd, VReg_8B rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0000111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SDOT(VReg_4S rd, VReg_16B rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0100111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void SDOT(VReg_2S rd, VReg_8B rn, VReg_8B rm)
|
||||||
|
{
|
||||||
|
emit<"00001110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SDOT(VReg_4S rd, VReg_16B rn, VReg_16B rm)
|
||||||
|
{
|
||||||
|
emit<"01001110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SHA512H(QReg rd, QReg rn, VReg_2D rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm100000nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SHA512H2(QReg rd, QReg rn, VReg_2D rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm100001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SHA512SU0(VReg_2D rd, VReg_2D rn)
|
||||||
|
{
|
||||||
|
emit<"1100111011000000100000nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void SHA512SU1(VReg_2D rd, VReg_2D rn, VReg_2D rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm100010nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SM3PARTW1(VReg_4S rd, VReg_4S rn, VReg_4S rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm110000nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SM3PARTW2(VReg_4S rd, VReg_4S rn, VReg_4S rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm110001nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void SM3SS1(VReg_4S rd, VReg_4S rn, VReg_4S rm, VReg_4S ra)
|
||||||
|
{
|
||||||
|
emit<"11001110010mmmmm0aaaaannnnnddddd", "d", "n", "m", "a">(rd, rn, rm, ra);
|
||||||
|
}
|
||||||
|
void SM3TT1A(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"11001110010mmmmm10ii00nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
|
||||||
|
}
|
||||||
|
void SM3TT1B(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"11001110010mmmmm10ii01nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
|
||||||
|
}
|
||||||
|
void SM3TT2A(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"11001110010mmmmm10ii10nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
|
||||||
|
}
|
||||||
|
void SM3TT2B(VReg_4S rd, VReg_4S rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"11001110010mmmmm10ii11nnnnnddddd", "d", "n", "m", "i">(rd, rn, em.reg_index(), em.elem_index());
|
||||||
|
}
|
||||||
|
void SM4E(VReg_4S rd, VReg_4S rn)
|
||||||
|
{
|
||||||
|
emit<"1100111011000000100001nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void SM4EKEY(VReg_4S rd, VReg_4S rn, VReg_4S rm)
|
||||||
|
{
|
||||||
|
emit<"11001110011mmmmm110010nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void UCVTF(HReg rd, HReg rn)
|
||||||
|
{
|
||||||
|
emit<"0111111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void UCVTF(VReg_4H rd, VReg_4H rn)
|
||||||
|
{
|
||||||
|
emit<"0010111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void UCVTF(VReg_8H rd, VReg_8H rn)
|
||||||
|
{
|
||||||
|
emit<"0110111001111001110110nnnnnddddd", "d", "n">(rd, rn);
|
||||||
|
}
|
||||||
|
void UDOT(VReg_2S rd, VReg_8B rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0010111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void UDOT(VReg_4S rd, VReg_16B rn, SElem em)
|
||||||
|
{
|
||||||
|
emit<"0110111110LMmmmm1110H0nnnnnddddd", "d", "n", "Mm", "H", "L">(rd, rn, em.reg_index(), em.elem_index() >> 1, em.elem_index() & 1);
|
||||||
|
}
|
||||||
|
void UDOT(VReg_2S rd, VReg_8B rn, VReg_8B rm)
|
||||||
|
{
|
||||||
|
emit<"00101110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void UDOT(VReg_4S rd, VReg_16B rn, VReg_16B rm)
|
||||||
|
{
|
||||||
|
emit<"01101110100mmmmm100101nnnnnddddd", "d", "n", "m">(rd, rn, rm);
|
||||||
|
}
|
||||||
|
void XAR(VReg_2D rd, VReg_2D rn, VReg_2D rm, Imm<6> rotate_amount)
|
||||||
|
{
|
||||||
|
emit<"11001110100mmmmmiiiiiinnnnnddddd", "d", "n", "m", "i">(rd, rn, rm, rotate_amount);
|
||||||
|
}
|
|
@ -87,11 +87,11 @@ void ADDS(XReg xd, XReg xn, XReg xm, AddSubShift shift = AddSubShift::LSL, Imm<6
|
||||||
{
|
{
|
||||||
emit<"10101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount);
|
emit<"10101011ss0mmmmmiiiiiinnnnnddddd", "d", "n", "m", "s", "i">(xd, xn, xm, shift, shift_amount);
|
||||||
}
|
}
|
||||||
void ADR(XReg xd, AddrOffset<21, 0> label)
|
void ADR(XReg xd, PageOffset<21, 0> label)
|
||||||
{
|
{
|
||||||
emit<"0ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label);
|
emit<"0ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label);
|
||||||
}
|
}
|
||||||
void ADRP(XReg xd, PageOffset<21> label)
|
void ADRP(XReg xd, PageOffset<21, 12> label)
|
||||||
{
|
{
|
||||||
emit<"1ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label);
|
emit<"1ii10000iiiiiiiiiiiiiiiiiiiddddd", "d", "i">(xd, label);
|
||||||
}
|
}
|
1027
include/oaknut/impl/mnemonics_generic_v8.1.inc.hpp
Normal file
1027
include/oaknut/impl/mnemonics_generic_v8.1.inc.hpp
Normal file
File diff suppressed because it is too large
Load diff
23
include/oaknut/impl/mnemonics_generic_v8.2.inc.hpp
Normal file
23
include/oaknut/impl/mnemonics_generic_v8.2.inc.hpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2022 merryhime <https://mary.rs>
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
void BFC(WReg wd, Imm<5> lsb, Imm<5> width)
|
||||||
|
{
|
||||||
|
if (width.value() == 0 || width.value() > (32 - lsb.value()))
|
||||||
|
throw "invalid width";
|
||||||
|
emit<"0011001100rrrrrrssssss11111ddddd", "d", "r", "s">(wd, (-lsb.value()) & 31, width.value() - 1);
|
||||||
|
}
|
||||||
|
void BFC(XReg xd, Imm<6> lsb, Imm<6> width)
|
||||||
|
{
|
||||||
|
if (width.value() == 0 || width.value() > (64 - lsb.value()))
|
||||||
|
throw "invalid width";
|
||||||
|
emit<"1011001101rrrrrrssssss11111ddddd", "d", "r", "s">(xd, (-lsb.value()) & 63, width.value() - 1);
|
||||||
|
}
|
||||||
|
void ESB()
|
||||||
|
{
|
||||||
|
emit<"11010101000000110010001000011111">();
|
||||||
|
}
|
||||||
|
void PSB()
|
||||||
|
{
|
||||||
|
emit<"11010101000000110010001000111111">();
|
||||||
|
}
|
|
@ -64,7 +64,7 @@ private:
|
||||||
std::variant<std::uint32_t, Label*, void*> m_payload;
|
std::variant<std::uint32_t, Label*, void*> m_payload;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<std::size_t bitsize>
|
template<std::size_t bitsize, std::size_t shift_amount>
|
||||||
struct PageOffset {
|
struct PageOffset {
|
||||||
PageOffset(void* ptr)
|
PageOffset(void* ptr)
|
||||||
: m_payload(ptr)
|
: m_payload(ptr)
|
||||||
|
@ -76,10 +76,11 @@ struct PageOffset {
|
||||||
|
|
||||||
static std::uint32_t encode(std::uintptr_t current_addr, std::uintptr_t target)
|
static std::uint32_t encode(std::uintptr_t current_addr, std::uintptr_t target)
|
||||||
{
|
{
|
||||||
const std::int64_t page_diff = (static_cast<std::int64_t>(target) >> 12) - (static_cast<std::int64_t>(current_addr) >> 12);
|
std::uint64_t diff = (static_cast<std::uint64_t>(target) >> shift_amount) - (static_cast<std::uint64_t>(current_addr) >> shift_amount);
|
||||||
if (detail::sign_extend<bitsize>(page_diff) != page_diff)
|
if (detail::sign_extend<bitsize>(diff) != diff)
|
||||||
throw "out of range";
|
throw "out of range";
|
||||||
return static_cast<std::uint32_t>(page_diff & detail::mask_from_size(bitsize));
|
diff &= detail::mask_from_size(bitsize);
|
||||||
|
return static_cast<std::uint32_t>(((diff & 3) << (bitsize - 2)) | (diff >> 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct HReg;
|
||||||
struct SReg;
|
struct SReg;
|
||||||
struct DReg;
|
struct DReg;
|
||||||
struct QReg;
|
struct QReg;
|
||||||
|
struct VReg_2H;
|
||||||
struct VReg_8B;
|
struct VReg_8B;
|
||||||
struct VReg_4H;
|
struct VReg_4H;
|
||||||
struct VReg_2S;
|
struct VReg_2S;
|
||||||
|
@ -185,10 +186,10 @@ struct VReg : public Reg {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VRegArranged : public Reg {
|
struct VRegArranged : public Reg {
|
||||||
|
protected:
|
||||||
constexpr explicit VRegArranged(unsigned bitsize_, int index_, unsigned esize_)
|
constexpr explicit VRegArranged(unsigned bitsize_, int index_, unsigned esize_)
|
||||||
: Reg(true, bitsize_, index_), m_esize(esize_)
|
: Reg(true, bitsize_, index_), m_esize(esize_)
|
||||||
{
|
{
|
||||||
assert(bitsize_ == 64 || bitsize_ == 128);
|
|
||||||
assert(esize_ != 0 && (esize_ & (esize_ - 1)) == 0 && "esize must be a power of two");
|
assert(esize_ != 0 && (esize_ & (esize_ - 1)) == 0 && "esize must be a power of two");
|
||||||
assert(esize_ <= bitsize_);
|
assert(esize_ <= bitsize_);
|
||||||
}
|
}
|
||||||
|
@ -200,45 +201,9 @@ private:
|
||||||
int m_esize : 8;
|
int m_esize : 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BReg : public VReg {
|
struct VReg_2H : public VRegArranged {
|
||||||
constexpr explicit BReg(int index_)
|
constexpr explicit VReg_2H(int reg_index_)
|
||||||
: VReg(8, index_)
|
: VRegArranged(32, reg_index_, 32 / 2)
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename Policy>
|
|
||||||
friend class BasicCodeGenerator;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HReg : public VReg {
|
|
||||||
constexpr explicit HReg(int index_)
|
|
||||||
: VReg(16, index_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename Policy>
|
|
||||||
friend class BasicCodeGenerator;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SReg : public VReg {
|
|
||||||
constexpr explicit SReg(int index_)
|
|
||||||
: VReg(32, index_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename Policy>
|
|
||||||
friend class BasicCodeGenerator;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DReg : public VReg {
|
|
||||||
constexpr explicit DReg(int index_)
|
|
||||||
: VReg(64, index_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename Policy>
|
|
||||||
friend class BasicCodeGenerator;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct QReg : public VReg {
|
|
||||||
constexpr explicit QReg(int index_)
|
|
||||||
: VReg(128, index_)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename Policy>
|
template<typename Policy>
|
||||||
|
@ -344,20 +309,6 @@ private:
|
||||||
unsigned m_elem_index;
|
unsigned m_elem_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename E>
|
|
||||||
struct ElemSelector {
|
|
||||||
constexpr explicit ElemSelector(int reg_index_)
|
|
||||||
: m_reg_index(reg_index_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
constexpr int reg_index() const { return m_reg_index; }
|
|
||||||
|
|
||||||
constexpr E operator[](unsigned elem_index) const { return E{m_reg_index, elem_index}; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_reg_index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BElem : public Elem {
|
struct BElem : public Elem {
|
||||||
constexpr explicit BElem(int reg_, unsigned elem_index_)
|
constexpr explicit BElem(int reg_, unsigned elem_index_)
|
||||||
: Elem(2, reg_, elem_index_)
|
: Elem(2, reg_, elem_index_)
|
||||||
|
@ -391,6 +342,86 @@ struct DElem_1 : public DElem {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename E>
|
||||||
|
struct ElemSelector {
|
||||||
|
constexpr explicit ElemSelector(int reg_index_)
|
||||||
|
: m_reg_index(reg_index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr int reg_index() const { return m_reg_index; }
|
||||||
|
|
||||||
|
constexpr E operator[](unsigned elem_index) const { return E{m_reg_index, elem_index}; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_reg_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BReg : public VReg {
|
||||||
|
constexpr explicit BReg(int index_)
|
||||||
|
: VReg(8, index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Policy>
|
||||||
|
friend class BasicCodeGenerator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HReg : public VReg {
|
||||||
|
constexpr explicit HReg(int index_)
|
||||||
|
: VReg(16, index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Policy>
|
||||||
|
friend class BasicCodeGenerator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SReg : public VReg {
|
||||||
|
constexpr explicit SReg(int index_)
|
||||||
|
: VReg(32, index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Policy>
|
||||||
|
friend class BasicCodeGenerator;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DReg : public VReg {
|
||||||
|
constexpr explicit DReg(int index_)
|
||||||
|
: VReg(64, index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Policy>
|
||||||
|
friend class BasicCodeGenerator;
|
||||||
|
|
||||||
|
constexpr ElemSelector<BElem> Belem() const { return ElemSelector<BElem>(index()); }
|
||||||
|
constexpr ElemSelector<HElem> Helem() const { return ElemSelector<HElem>(index()); }
|
||||||
|
constexpr ElemSelector<SElem> Selem() const { return ElemSelector<SElem>(index()); }
|
||||||
|
constexpr ElemSelector<DElem> Delem() const { return ElemSelector<DElem>(index()); }
|
||||||
|
|
||||||
|
constexpr VReg_8B B8() const { return VReg_8B{index()}; }
|
||||||
|
constexpr VReg_4H H4() const { return VReg_4H{index()}; }
|
||||||
|
constexpr VReg_2S S2() const { return VReg_2S{index()}; }
|
||||||
|
constexpr VReg_1D D1() const { return VReg_1D{index()}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QReg : public VReg {
|
||||||
|
constexpr explicit QReg(int index_)
|
||||||
|
: VReg(128, index_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Policy>
|
||||||
|
friend class BasicCodeGenerator;
|
||||||
|
|
||||||
|
constexpr ElemSelector<BElem> Belem() const { return ElemSelector<BElem>(index()); }
|
||||||
|
constexpr ElemSelector<HElem> Helem() const { return ElemSelector<HElem>(index()); }
|
||||||
|
constexpr ElemSelector<SElem> Selem() const { return ElemSelector<SElem>(index()); }
|
||||||
|
constexpr ElemSelector<DElem> Delem() const { return ElemSelector<DElem>(index()); }
|
||||||
|
|
||||||
|
constexpr VReg_16B B16() const { return VReg_16B{index()}; }
|
||||||
|
constexpr VReg_8H H8() const { return VReg_8H{index()}; }
|
||||||
|
constexpr VReg_4S S4() const { return VReg_4S{index()}; }
|
||||||
|
constexpr VReg_2D D2() const { return VReg_2D{index()}; }
|
||||||
|
constexpr VReg_1Q Q1() const { return VReg_1Q{index()}; }
|
||||||
|
};
|
||||||
|
|
||||||
constexpr BReg VReg::toB() const
|
constexpr BReg VReg::toB() const
|
||||||
{
|
{
|
||||||
return BReg{index()};
|
return BReg{index()};
|
||||||
|
@ -424,6 +455,7 @@ struct VRegSelector {
|
||||||
constexpr ElemSelector<SElem> S() const { return ElemSelector<SElem>(index()); }
|
constexpr ElemSelector<SElem> S() const { return ElemSelector<SElem>(index()); }
|
||||||
constexpr ElemSelector<DElem> D() const { return ElemSelector<DElem>(index()); }
|
constexpr ElemSelector<DElem> D() const { return ElemSelector<DElem>(index()); }
|
||||||
|
|
||||||
|
constexpr VReg_2H H2() const { return VReg_2H{index()}; }
|
||||||
constexpr VReg_8B B8() const { return VReg_8B{index()}; }
|
constexpr VReg_8B B8() const { return VReg_8B{index()}; }
|
||||||
constexpr VReg_4H H4() const { return VReg_4H{index()}; }
|
constexpr VReg_4H H4() const { return VReg_4H{index()}; }
|
||||||
constexpr VReg_2S S2() const { return VReg_2S{index()}; }
|
constexpr VReg_2S S2() const { return VReg_2S{index()}; }
|
||||||
|
|
|
@ -98,8 +98,12 @@ public:
|
||||||
label.m_wbs.clear();
|
label.m_wbs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "oaknut/impl/arm64_mnemonics.inc.hpp"
|
#include "oaknut/impl/mnemonics_fpsimd_v8.0.inc.hpp"
|
||||||
#include "oaknut/impl/fpsimd_mnemonics.inc.hpp"
|
#include "oaknut/impl/mnemonics_fpsimd_v8.1.inc.hpp"
|
||||||
|
#include "oaknut/impl/mnemonics_fpsimd_v8.2.inc.hpp"
|
||||||
|
#include "oaknut/impl/mnemonics_generic_v8.0.inc.hpp"
|
||||||
|
#include "oaknut/impl/mnemonics_generic_v8.1.inc.hpp"
|
||||||
|
#include "oaknut/impl/mnemonics_generic_v8.2.inc.hpp"
|
||||||
|
|
||||||
void RET()
|
void RET()
|
||||||
{
|
{
|
||||||
|
@ -112,8 +116,8 @@ public:
|
||||||
return;
|
return;
|
||||||
if (MovImm16::is_valid(imm))
|
if (MovImm16::is_valid(imm))
|
||||||
return MOVZ(wd, imm);
|
return MOVZ(wd, imm);
|
||||||
if (MovImm16::is_valid(~static_cast<std::uint64_t>(imm)))
|
if (MovImm16::is_valid(~imm))
|
||||||
return MOVN(wd, imm);
|
return MOVN(wd, ~imm);
|
||||||
if (detail::encode_bit_imm(imm))
|
if (detail::encode_bit_imm(imm))
|
||||||
return ORR(wd, WzrReg{}, imm);
|
return ORR(wd, WzrReg{}, imm);
|
||||||
|
|
||||||
|
@ -130,7 +134,7 @@ public:
|
||||||
if (MovImm16::is_valid(imm))
|
if (MovImm16::is_valid(imm))
|
||||||
return MOVZ(xd, imm);
|
return MOVZ(xd, imm);
|
||||||
if (MovImm16::is_valid(~imm))
|
if (MovImm16::is_valid(~imm))
|
||||||
return MOVN(xd, imm);
|
return MOVN(xd, ~imm);
|
||||||
if (detail::encode_bit_imm(imm))
|
if (detail::encode_bit_imm(imm))
|
||||||
return ORR(xd, ZrReg{}, imm);
|
return ORR(xd, ZrReg{}, imm);
|
||||||
|
|
||||||
|
@ -159,6 +163,27 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void align(std::size_t alignment)
|
||||||
|
{
|
||||||
|
if (alignment < 4 || (alignment & (alignment - 1)) != 0)
|
||||||
|
throw "invalid alignment";
|
||||||
|
|
||||||
|
while (Policy::template ptr<std::uintptr_t>() & (alignment - 1)) {
|
||||||
|
NOP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dw(std::uint32_t value)
|
||||||
|
{
|
||||||
|
Policy::append(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dx(std::uint64_t value)
|
||||||
|
{
|
||||||
|
Policy::append(static_cast<std::uint32_t>(value));
|
||||||
|
Policy::append(static_cast<std::uint32_t>(value >> 32));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#include "oaknut/impl/arm64_encode_helpers.inc.hpp"
|
#include "oaknut/impl/arm64_encode_helpers.inc.hpp"
|
||||||
|
|
||||||
|
@ -199,13 +224,13 @@ private:
|
||||||
v.m_payload);
|
v.m_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::uint32_t splat, std::size_t size>
|
template<std::uint32_t splat, std::size_t size, std::size_t shift_amount>
|
||||||
std::uint32_t encode(PageOffset<size> v)
|
std::uint32_t encode(PageOffset<size, shift_amount> v)
|
||||||
{
|
{
|
||||||
static_assert(std::popcount(splat) == size);
|
static_assert(std::popcount(splat) == size);
|
||||||
|
|
||||||
const auto encode_fn = [](std::uintptr_t current_addr, std::uintptr_t target) {
|
const auto encode_fn = [](std::uintptr_t current_addr, std::uintptr_t target) {
|
||||||
return pdep<splat>(PageOffset<size>::encode(current_addr, target));
|
return pdep<splat>(PageOffset<size, shift_amount>::encode(current_addr, target));
|
||||||
};
|
};
|
||||||
|
|
||||||
return std::visit(detail::overloaded{
|
return std::visit(detail::overloaded{
|
||||||
|
@ -230,7 +255,7 @@ public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T ptr()
|
T ptr()
|
||||||
{
|
{
|
||||||
static_assert(std::is_pointer_v<T>);
|
static_assert(std::is_pointer_v<T> || std::is_same_v<T, std::uintptr_t> || std::is_same_v<T, std::intptr_t>);
|
||||||
return reinterpret_cast<T>(m_ptr);
|
return reinterpret_cast<T>(m_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,3 +115,47 @@ TEST_CASE("Immediate generation (64-bit)")
|
||||||
REQUIRE(f() == value);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -432,6 +432,10 @@ T(0x6e135ec1, MOV(V1.B()[9], V22.B()[11]))
|
||||||
T(0x4e0f1da9, MOV(V9.B()[7], W13))
|
T(0x4e0f1da9, MOV(V9.B()[7], W13))
|
||||||
T(0x5e0e045d, MOV(H29, V2.H()[3]))
|
T(0x5e0e045d, MOV(H29, V2.H()[3]))
|
||||||
T(0x0e043ca1, MOV(W1, V5.S()[0]))
|
T(0x0e043ca1, MOV(W1, V5.S()[0]))
|
||||||
|
T(0x0e0c3da8, MOV(W8, V13.S()[1]))
|
||||||
|
T(0x0e143da8, MOV(W8, V13.S()[2]))
|
||||||
|
T(0x0e1c3da8, MOV(W8, V13.S()[3]))
|
||||||
|
T(0x4e183d03, MOV(X3, V8.D()[1]))
|
||||||
T(0x4e083df7, MOV(X23, V15.D()[0]))
|
T(0x4e083df7, MOV(X23, V15.D()[0]))
|
||||||
// MOV
|
// MOV
|
||||||
T(0x0f06e58e, MOVI(V14.B8(), 204))
|
T(0x0f06e58e, MOVI(V14.B8(), 204))
|
||||||
|
|
Loading…
Reference in a new issue