early-access version 2687

main
pineappleEA 2022-04-20 01:28:43 +02:00
parent cd45d7e9d5
commit 8aa17b7ffc
251 changed files with 4148 additions and 1023 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access
=============
This is the source code for early-access 2686.
This is the source code for early-access 2687.
## Legal Notice

View File

@ -19,10 +19,11 @@ if (NOT TARGET fmt AND NOT TARGET fmt::fmt)
add_subdirectory(fmt)
endif()
# mp
# mcl
add_library(mp INTERFACE)
target_include_directories(mp INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/mp/include>)
if (NOT TARGET merry::mcl)
add_subdirectory(mcl)
endif()
# robin-map

View File

@ -4,7 +4,7 @@ This repository uses subtrees to manage some of its externals.
```
git remote add externals-fmt https://github.com/fmtlib/fmt.git --no-tags
git remote add externals-mp https://github.com/MerryMage/mp.git --no-tags
git remote add externals-mcl https://github.com/merryhime/mcl.git --no-tags
git remote add externals-robin-map https://github.com/Tessil/robin-map.git --no-tags
git remote add externals-vixl https://git.linaro.org/arm/vixl.git --no-tags
git remote add externals-xbyak https://github.com/herumi/xbyak.git --no-tags
@ -18,14 +18,14 @@ Change `<ref>` to refer to the appropriate git reference.
```
git fetch externals-fmt
git fetch externals-mp
git fetch externals-mcl
git fetch externals-robin-map
git fetch externals-vixl
git fetch externals-xbyak
git fetch externals-zycore
git fetch externals-zydis
git subtree pull --squash --prefix=externals/fmt externals-fmt <ref>
git subtree pull --squash --prefix=externals/mp externals-mp <ref>
git subtree pull --squash --prefix=externals/mcl externals-mcl <ref>
git subtree pull --squash --prefix=externals/robin-map externals-robin-map <ref>
git subtree pull --squash --prefix=externals/vixl/vixl externals-vixl <ref>
git subtree pull --squash --prefix=externals/xbyak externals-xbyak <ref>

218
externals/dynarmic/externals/mcl/.clang-format vendored Executable file
View File

@ -0,0 +1,218 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: None
AlignEscapedNewlines: Right
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakBeforeInheritanceComma: false
BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
# EmptyLineAfterAccessModifier: Leave
EmptyLineBeforeAccessModifier: Always
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<mach/'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<windows.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '(^<signal.h>)|(^<sys/ucontext.h>)|(^<ucontext.h>)'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<([^\.])*>$'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 4
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
# IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: NoIndent
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
# InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
NamespaceMacros:
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
- ParseTestProto
- ParsePartialTestProto
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
# ShortNamespaceLines: 5
SortIncludes: true
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
# SpacesInLineCommentPrefix: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
TypenameMacros:
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
- FCODE
- ICODE
...

2
externals/dynarmic/externals/mcl/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*build*/
.DS_Store

View File

@ -0,0 +1,126 @@
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
include(GNUInstallDirs)
project(mcl LANGUAGES CXX VERSION 0.1.5)
# Project options
option(MCL_WARNINGS_AS_ERRORS "Warnings as errors" ON)
# Default to a Release build
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
message(STATUS "Defaulting to a Release build")
endif()
# Set hard requirements for C++
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Warn on CMake API deprecations
set(CMAKE_WARN_DEPRECATED ON)
# Disable in-source builds
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(SEND_ERROR "In-source builds are not allowed.")
endif()
# Add the module directory to the list of paths
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
# Compiler flags
if (MSVC)
set(MCL_CXX_FLAGS
/std:c++latest
/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)
if (MCL_WARNINGS_AS_ERRORS)
list(APPEND MCL_CXX_FLAGS /WX)
endif()
if (CMAKE_VS_PLATFORM_TOOLSET MATCHES "LLVM-vs[0-9]+")
list(APPEND MCL_CXX_FLAGS
-Qunused-arguments
-Wno-missing-braces)
endif()
else()
set(MCL_CXX_FLAGS
-Wall
-Wextra
-Wcast-qual
-pedantic
-pedantic-errors
-Wfatal-errors
-Wno-missing-braces)
if (MCL_WARNINGS_AS_ERRORS)
list(APPEND MCL_CXX_FLAGS -Werror)
endif()
endif()
# Dependencies
if (NOT TARGET Catch2::Catch2)
find_package(Catch2 QUIET)
endif()
if (NOT TARGET fmt::fmt)
find_package(fmt REQUIRED)
endif()
# Project files
add_subdirectory(src)
if (TARGET Catch2::Catch2)
add_subdirectory(tests)
endif()
# Install instructions
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
install(TARGETS mcl EXPORT mclTargets)
install(EXPORT mclTargets
NAMESPACE merry::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl"
)
configure_package_config_file(CMakeModules/mclConfig.cmake.in
mclConfig.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl"
)
write_basic_package_version_file(mclConfigVersion.cmake
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/mclConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/mclConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/mcl"
)
install(DIRECTORY include/ TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp")

View File

@ -0,0 +1,17 @@
# This function should be passed a name of an existing target. It will automatically generate
# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the
# one in the filesystem.
function(create_target_directory_groups target_name)
# Place any files that aren't in the source list in a separate group so that they don't get in
# the way.
source_group("Other Files" REGULAR_EXPRESSION ".")
get_target_property(target_sources "${target_name}" SOURCES)
foreach(file_name IN LISTS target_sources)
get_filename_component(dir_name "${file_name}" PATH)
# Group names use '\' as a separator even though the entire rest of CMake uses '/'...
string(REPLACE "/" "\\" group_name "${dir_name}")
source_group("${group_name}" FILES "${file_name}")
endforeach()
endfunction()

View File

@ -0,0 +1,56 @@
include(CheckSymbolExists)
function(detect_architecture symbol arch)
if (NOT DEFINED ARCHITECTURE)
set(CMAKE_REQUIRED_QUIET YES)
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
unset(CMAKE_REQUIRED_QUIET)
if (DETECT_ARCHITECTURE_${arch})
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
endif()
unset(DETECT_ARCHITECTURE_${arch} CACHE)
endif()
endfunction()
detect_architecture("__ARM64__" arm64)
detect_architecture("__aarch64__" arm64)
detect_architecture("_M_ARM64" arm64)
detect_architecture("__arm__" arm32)
detect_architecture("__TARGET_ARCH_ARM" arm32)
detect_architecture("_M_ARM" arm32)
detect_architecture("__x86_64" x86_64)
detect_architecture("__x86_64__" x86_64)
detect_architecture("__amd64" x86_64)
detect_architecture("_M_X64" x86_64)
detect_architecture("__i386" x86_32)
detect_architecture("__i386__" x86_32)
detect_architecture("_M_IX86" x86_32)
detect_architecture("__ia64" ia64)
detect_architecture("__ia64__" ia64)
detect_architecture("_M_IA64" ia64)
detect_architecture("__mips" mips)
detect_architecture("__mips__" mips)
detect_architecture("_M_MRX000" mips)
detect_architecture("__ppc64__" ppc64)
detect_architecture("__powerpc64__" ppc64)
detect_architecture("__ppc__" ppc32)
detect_architecture("__ppc" ppc32)
detect_architecture("__powerpc__" ppc32)
detect_architecture("_ARCH_COM" ppc32)
detect_architecture("_ARCH_PWR" ppc32)
detect_architecture("_ARCH_PPC" ppc32)
detect_architecture("_M_MPPC" ppc32)
detect_architecture("_M_PPC" ppc32)
detect_architecture("__riscv" riscv)
detect_architecture("__EMSCRIPTEN__" wasm)

View File

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components(@PROJECT_NAME@)

21
externals/dynarmic/externals/mcl/LICENSE vendored Executable file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 merryhime
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17
externals/dynarmic/externals/mcl/README vendored Executable file
View File

@ -0,0 +1,17 @@
oooo
`888
ooo. .oo. .oo. .ooooo. 888
`888P"Y88bP"Y88b d88' `"Y8 888
888 888 888 888 888
888 888 888 888 .o8 888
o888o o888o o888o `Y8bod8P' o888o
.-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-. .-.-.
/ / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \ / / \ \
`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`-' `-`
A collection of C++20 utilities which is common to a number of merry's projects.
MIT licensed.

View File

@ -0,0 +1,61 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <stdexcept>
#include <type_traits>
#include <fmt/format.h>
#include "mcl/hint/assume.hpp"
namespace mcl::detail {
[[noreturn]] void assert_terminate_impl(fmt::string_view msg, fmt::format_args args);
template<typename... Ts>
[[noreturn]] void assert_terminate(fmt::string_view msg, Ts... args) {
assert_terminate_impl(msg, fmt::make_format_args(args...));
}
} // namespace mcl::detail
#define UNREACHABLE() ASSERT_FALSE("Unreachable code!")
#define ASSERT(expr) \
[&] { \
if (std::is_constant_evaluated()) { \
if (!(expr)) { \
throw std::logic_error{"ASSERT failed at compile time"}; \
} \
} else { \
if (!(expr)) [[unlikely]] { \
::mcl::detail::assert_terminate(#expr); \
} \
} \
}()
#define ASSERT_MSG(expr, ...) \
[&] { \
if (std::is_constant_evaluated()) { \
if (!(expr)) { \
throw std::logic_error{"ASSERT_MSG failed at compile time"}; \
} \
} else { \
if (!(expr)) [[unlikely]] { \
::mcl::detail::assert_terminate(#expr "\nMessage: " __VA_ARGS__); \
} \
} \
}()
#define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false\nMessage: " __VA_ARGS__)
#if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS)
# define DEBUG_ASSERT(expr) ASSUME(expr)
# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
#else
# define DEBUG_ASSERT(expr) ASSERT(expr)
# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
#endif

View File

@ -0,0 +1,54 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <bitset>
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
template<BitIntegral T>
inline size_t count_ones(T x) {
return std::bitset<bitsizeof<T>>(x).count();
}
template<BitIntegral T>
constexpr size_t count_leading_zeros(T x) {
size_t result = bitsizeof<T>;
while (x != 0) {
x >>= 1;
result--;
}
return result;
}
template<BitIntegral T>
constexpr int highest_set_bit(T x) {
int result = -1;
while (x != 0) {
x >>= 1;
result++;
}
return result;
}
template<BitIntegral T>
constexpr size_t lowest_set_bit(T x) {
if (x == 0) {
return bitsizeof<T>;
}
size_t result = 0;
while ((x & 1) == 0) {
x >>= 1;
result++;
}
return result;
}
} // namespace mcl::bit

View File

@ -0,0 +1,203 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/assert.hpp"
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
/// Create a mask with `count` number of one bits.
template<size_t count, BitIntegral T>
constexpr T ones() {
static_assert(count <= bitsizeof<T>, "count larger than bitsize of T");
if constexpr (count == 0) {
return 0;
} else {
return static_cast<T>(~static_cast<T>(0)) >> (bitsizeof<T> - count);
}
}
/// Create a mask with `count` number of one bits.
template<BitIntegral T>
constexpr T ones(size_t count) {
ASSERT_MSG(count <= bitsizeof<T>, "count larger than bitsize of T");
if (count == 0) {
return 0;
}
return static_cast<T>(~static_cast<T>(0)) >> (bitsizeof<T> - count);
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T mask() {
static_assert(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
static_assert(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T");
static_assert(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<end_bit - begin_bit + 1, T>() << begin_bit;
}
/// Create a mask of type T for bits [begin_bit, end_bit] inclusive.
template<BitIntegral T>
constexpr T mask(size_t begin_bit, size_t end_bit) {
ASSERT_MSG(begin_bit <= end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
ASSERT_MSG(begin_bit < bitsizeof<T>, "begin_bit must be smaller than size of T");
ASSERT_MSG(end_bit < bitsizeof<T>, "end_bit must be smaller than size of T");
return ones<T>(end_bit - begin_bit + 1) << begin_bit;
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T get_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>();
return (value & m) >> begin_bit;
}
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
template<BitIntegral T>
constexpr T get_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit);
return (value & m) >> begin_bit;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T clear_bits(T value) {
constexpr T m = mask<begin_bit, end_bit, T>();
return value & ~m;
}
/// Clears bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
constexpr T clear_bits(size_t begin_bit, size_t end_bit, T value) {
const T m = mask<T>(begin_bit, end_bit);
return value & ~m;
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<size_t begin_bit, size_t end_bit, BitIntegral T>
constexpr T set_bits(T value, T new_bits) {
constexpr T m = mask<begin_bit, end_bit, T>();
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// Modifies bits [begin_bit, end_bit] inclusive of value of type T.
template<BitIntegral T>
constexpr T set_bits(size_t begin_bit, size_t end_bit, T value, T new_bits) {
const T m = mask<T>(begin_bit, end_bit);
return (value & ~m) | ((new_bits << begin_bit) & m);
}
/// Extract bit at bit_position from value of type T.
template<size_t bit_position, BitIntegral T>
constexpr bool get_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>();
return (value & m) != 0;
}
/// Extract bit at bit_position from value of type T.
template<BitIntegral T>
constexpr bool get_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position);
return (value & m) != 0;
}
/// Clears bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
constexpr T clear_bit(T value) {
constexpr T m = mask<bit_position, bit_position, T>();
return value & ~m;
}
/// Clears bit at bit_position of value of type T.
template<BitIntegral T>
constexpr T clear_bit(size_t bit_position, T value) {
const T m = mask<T>(bit_position, bit_position);
return value & ~m;
}
/// Modifies bit at bit_position of value of type T.
template<size_t bit_position, BitIntegral T>
constexpr T set_bit(T value, bool new_bit) {
constexpr T m = mask<bit_position, bit_position, T>();
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
}
/// Modifies bit at bit_position of value of type T.
template<BitIntegral T>
constexpr T set_bit(size_t bit_position, T value, bool new_bit) {
const T m = mask<T>(bit_position, bit_position);
return (value & ~m) | (new_bit ? m : static_cast<T>(0));
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<size_t bit_count, BitIntegral T>
constexpr T sign_extend(T value) {
static_assert(bit_count != 0, "cannot sign-extend zero-sized value");
constexpr T m = ones<bit_count, T>();
if (get_bit<bit_count - 1, T>(value)) {
return value | ~m;
}
return value;
}
/// Sign-extends a value that has bit_count bits to the full bitwidth of type T.
template<BitIntegral T>
constexpr T sign_extend(size_t bit_count, T value) {
ASSERT_MSG(bit_count != 0, "cannot sign-extend zero-sized value");
const T m = ones<T>(bit_count);
if (get_bit<T>(bit_count - 1, value)) {
return value | ~m;
}
return value;
}
/// Replicate an element across a value of type T.
template<size_t element_size, BitIntegral T>
constexpr T replicate_element(T value) {
static_assert(element_size <= bitsizeof<T>, "element_size is too large");
static_assert(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size");
if constexpr (element_size == bitsizeof<T>) {
return value;
} else {
return replicate_element<element_size * 2, T>(static_cast<T>(value | (value << element_size)));
}
}
/// Replicate an element of type U across a value of type T.
template<BitIntegral U, BitIntegral T>
constexpr T replicate_element(T value) {
static_assert(bitsizeof<U> <= bitsizeof<T>, "element_size is too large");
return replicate_element<bitsizeof<U>, T>(value);
}
/// Replicate an element across a value of type T.
template<BitIntegral T>
constexpr T replicate_element(size_t element_size, T value) {
ASSERT_MSG(element_size <= bitsizeof<T>, "element_size is too large");
ASSERT_MSG(bitsizeof<T> % element_size == 0, "bitsize of T not divisible by element_size");
if (element_size == bitsizeof<T>) {
return value;
}
return replicate_element<T>(element_size * 2, static_cast<T>(value | (value << element_size)));
}
template<BitIntegral T>
constexpr bool most_significant_bit(T value) {
return get_bit<bitsizeof<T> - 1, T>(value);
}
} // namespace mcl::bit

View File

@ -0,0 +1,31 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/bitsizeof.hpp"
#include "mcl/concepts/bit_integral.hpp"
#include "mcl/stdint.hpp"
namespace mcl::bit {
template<BitIntegral T>
constexpr T rotate_right(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x >> amount) | (x << (bitsizeof<T> - amount)));
}
template<BitIntegral T>
constexpr T rotate_left(T x, size_t amount) {
amount %= bitsizeof<T>;
if (amount == 0) {
return x;
}
return static_cast<T>((x << amount) | (x >> (bitsizeof<T> - amount)));
}
} // namespace mcl::bit

View File

@ -0,0 +1,50 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/bit_integral.hpp"
namespace mcl::bit {
constexpr u16 swap_bytes_16(u16 value) {
return static_cast<u16>(u32{value} >> 8 | u32{value} << 8);
}
constexpr u32 swap_bytes_32(u32 value) {
return ((value & 0xff000000u) >> 24)
| ((value & 0x00ff0000u) >> 8)
| ((value & 0x0000ff00u) << 8)
| ((value & 0x000000ffu) << 24);
}
constexpr u64 swap_bytes_64(u64 value) {
return ((value & 0xff00000000000000ull) >> 56)
| ((value & 0x00ff000000000000ull) >> 40)
| ((value & 0x0000ff0000000000ull) >> 24)
| ((value & 0x000000ff00000000ull) >> 8)
| ((value & 0x00000000ff000000ull) << 8)
| ((value & 0x0000000000ff0000ull) << 24)
| ((value & 0x000000000000ff00ull) << 40)
| ((value & 0x00000000000000ffull) << 56);
}
constexpr u32 swap_halves_32(u32 value) {
return ((value & 0xffff0000u) >> 16)
| ((value & 0x0000ffffu) << 16);
}
constexpr u64 swap_halves_64(u64 value) {
return ((value & 0xffff000000000000ull) >> 48)
| ((value & 0x0000ffff00000000ull) >> 16)
| ((value & 0x00000000ffff0000ull) << 16)
| ((value & 0x000000000000ffffull) << 48);
}
constexpr u64 swap_words_64(u64 value) {
return ((value & 0xffffffff00000000ull) >> 32)
| ((value & 0x00000000ffffffffull) << 32);
}
} // namespace mcl::bit

View File

@ -0,0 +1,36 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstring>
#include <type_traits>
namespace mcl {
/// Reinterpret objects of one type as another by bit-casting between object representations.
template<class Dest, class Source>
inline Dest bit_cast(const Source& source) noexcept {
static_assert(sizeof(Dest) == sizeof(Source), "size of destination and source objects must be equal");
static_assert(std::is_trivially_copyable_v<Dest>, "destination type must be trivially copyable.");
static_assert(std::is_trivially_copyable_v<Source>, "source type must be trivially copyable");
std::aligned_storage_t<sizeof(Dest), alignof(Dest)> dest;
std::memcpy(&dest, &source, sizeof(dest));
return reinterpret_cast<Dest&>(dest);
}
/// Reinterpret objects of any arbitrary type as another type by bit-casting between object representations.
/// Note that here we do not verify if source pointed to by source_ptr has enough bytes to read from.
template<class Dest, class SourcePtr>
inline Dest bit_cast_pointee(const SourcePtr source_ptr) noexcept {
static_assert(sizeof(SourcePtr) == sizeof(void*), "source pointer must have size of a pointer");
static_assert(std::is_trivially_copyable_v<Dest>, "destination type must be trivially copyable.");
std::aligned_storage_t<sizeof(Dest), alignof(Dest)> dest;
std::memcpy(&dest, bit_cast<void*>(source_ptr), sizeof(dest));
return reinterpret_cast<Dest&>(dest);
}
} // namespace mcl

View File

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <climits>
#include <cstddef>
namespace mcl {
template<typename T>
constexpr std::size_t bitsizeof = CHAR_BIT * sizeof(T);
} // namespace mcl

View File

@ -0,0 +1,16 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/is_any_of.hpp"
#include "mcl/stdint.hpp"
namespace mcl {
/// Integral upon which bit operations can be safely performed.
template<typename T>
concept BitIntegral = IsAnyOf<T, u8, u16, u32, u64, uptr, size_t>;
} // namespace mcl

View File

@ -0,0 +1,14 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/concepts/same_as.hpp"
namespace mcl {
template<typename T, typename... U>
concept IsAnyOf = (SameAs<T, U> || ...);
} // namespace mcl

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl {
namespace detail {
template<typename T, typename U>
concept SameHelper = std::is_same_v<T, U>;
} // namespace detail
template<typename T, typename U>
concept SameAs = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
} // namespace mcl

View File

@ -0,0 +1,378 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include "mcl/assert.hpp"
namespace mcl {
template<typename T>
class intrusive_list;
template<typename T>
class intrusive_list_iterator;
template<typename T>
class intrusive_list_node {
public:
bool is_sentinel() const {
return is_sentinel_;
}
protected:
intrusive_list_node* next = nullptr;
intrusive_list_node* prev = nullptr;
bool is_sentinel_ = false;
friend class intrusive_list<T>;
friend class intrusive_list_iterator<T>;
friend class intrusive_list_iterator<const T>;
};
template<typename T>
class intrusive_list_sentinel final : public intrusive_list_node<T> {
using intrusive_list_node<T>::next;
using intrusive_list_node<T>::prev;
using intrusive_list_node<T>::is_sentinel_;
public:
intrusive_list_sentinel() {
next = this;
prev = this;
is_sentinel_ = true;
}
};
template<typename T>
class intrusive_list_iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
// If value_type is const, we want "const intrusive_list_node<value_type>", not "intrusive_list_node<const value_type>"
using node_type = std::conditional_t<std::is_const<value_type>::value,
const intrusive_list_node<std::remove_const_t<value_type>>,
intrusive_list_node<value_type>>;
using node_pointer = node_type*;
using node_reference = node_type&;
intrusive_list_iterator() = default;
intrusive_list_iterator(const intrusive_list_iterator& other) = default;
intrusive_list_iterator& operator=(const intrusive_list_iterator& other) = default;
explicit intrusive_list_iterator(node_pointer list_node)
: node(list_node) {
}
explicit intrusive_list_iterator(pointer data)
: node(data) {
}
explicit intrusive_list_iterator(reference data)
: node(&data) {
}
intrusive_list_iterator& operator++() {
node = node->next;
return *this;
}
intrusive_list_iterator& operator--() {
node = node->prev;
return *this;
}
intrusive_list_iterator operator++(int) {
intrusive_list_iterator it(*this);
++*this;
return it;
}
intrusive_list_iterator operator--(int) {
intrusive_list_iterator it(*this);
--*this;
return it;
}
bool operator==(const intrusive_list_iterator& other) const {
return node == other.node;
}
bool operator!=(const intrusive_list_iterator& other) const {
return !operator==(other);
}
reference operator*() const {
DEBUG_ASSERT(!node->is_sentinel());
return static_cast<reference>(*node);
}
pointer operator->() const {
return std::addressof(operator*());
}
node_pointer AsNodePointer() const {
return node;
}
private:
friend class intrusive_list<T>;
node_pointer node = nullptr;
};
template<typename T>
class intrusive_list {
public:
using difference_type = std::ptrdiff_t;
using size_type = std::size_t;
using value_type = T;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = intrusive_list_iterator<value_type>;
using const_iterator = intrusive_list_iterator<const value_type>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
/**
* Inserts a node at the given location indicated by an iterator.
*
* @param location The location to insert the node.
* @param new_node The node to add.
*/
iterator insert(iterator location, pointer new_node) {
return insert_before(location, new_node);
}
/**
* Inserts a node at the given location, moving the previous
* node occupant ahead of the one inserted.
*
* @param location The location to insert the new node.
* @param new_node The node to insert into the list.
*/
iterator insert_before(iterator location, pointer new_node) {
auto existing_node = location.AsNodePointer();
new_node->next = existing_node;
new_node->prev = existing_node->prev;
existing_node->prev->next = new_node;
existing_node->prev = new_node;
return iterator(new_node);
}
/**
* Inserts a new node into the list ahead of the position indicated.
*
* @param position Location to insert the node in front of.
* @param new_node The node to be inserted into the list.
*/
iterator insert_after(iterator position, pointer new_node) {
if (empty())
return insert(begin(), new_node);
return insert(++position, new_node);
}
/**
* Add an entry to the start of the list.
* @param node Node to add to the list.
*/
void push_front(pointer node) {
insert(begin(), node);
}
/**
* Add an entry to the end of the list
* @param node Node to add to the list.
*/
void push_back(pointer node) {
insert(end(), node);
}
/**
* Erases the node at the front of the list.
* @note Must not be called on an empty list.
*/
void pop_front() {
DEBUG_ASSERT(!empty());
erase(begin());
}
/**
* Erases the node at the back of the list.
* @note Must not be called on an empty list.
*/
void pop_back() {
DEBUG_ASSERT(!empty());
erase(--end());
}
/**
* Removes a node from this list
* @param it An iterator that points to the node to remove from list.
*/
pointer remove(iterator& it) {
DEBUG_ASSERT(it != end());
pointer node = &*it++;
node->prev->next = node->next;
node->next->prev = node->prev;
#if !defined(NDEBUG)
node->next = nullptr;
node->prev = nullptr;
#endif
return node;
}
/**
* Removes a node from this list
* @param it A constant iterator that points to the node to remove from list.
*/
pointer remove(const iterator& it) {
iterator copy = it;
return remove(copy);
}
/**
* Removes a node from this list.
* @param node A pointer to the node to remove.
*/
pointer remove(pointer node) {
return remove(iterator(node));
}
/**
* Removes a node from this list.
* @param node A reference to the node to remove.
*/
pointer remove(reference node) {
return remove(iterator(node));
}
/**
* Is this list empty?
* @returns true if there are no nodes in this list.
*/
bool empty() const {
return root->next == root.get();
}
/**
* Gets the total number of elements within this list.
* @return the number of elements in this list.
*/
size_type size() const {
return static_cast<size_type>(std::distance(begin(), end()));
}
/**
* Retrieves a reference to the node at the front of the list.
* @note Must not be called on an empty list.
*/
reference front() {
DEBUG_ASSERT(!empty());
return *begin();
}
/**
* Retrieves a constant reference to the node at the front of the list.
* @note Must not be called on an empty list.
*/
const_reference front() const {
DEBUG_ASSERT(!empty());
return *begin();
}
/**
* Retrieves a reference to the node at the back of the list.
* @note Must not be called on an empty list.
*/
reference back() {
DEBUG_ASSERT(!empty());
return *--end();
}
/**
* Retrieves a constant reference to the node at the back of the list.
* @note Must not be called on an empty list.
*/
const_reference back() const {
DEBUG_ASSERT(!empty());
return *--end();
}
// Iterator interface
iterator begin() { return iterator(root->next); }
const_iterator begin() const { return const_iterator(root->next); }
const_iterator cbegin() const { return begin(); }
iterator end() { return iterator(root.get()); }
const_iterator end() const { return const_iterator(root.get()); }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
const_reverse_iterator crend() const { return rend(); }
/**
* Erases a node from the list, indicated by an iterator.
* @param it The iterator that points to the node to erase.
*/
iterator erase(iterator it) {
remove(it);
return it;
}
/**
* Erases a node from this list.
* @param node A pointer to the node to erase from this list.
*/
iterator erase(pointer node) {
return erase(iterator(node));
}
/**
* Erases a node from this list.
* @param node A reference to the node to erase from this list.
*/
iterator erase(reference node) {
return erase(iterator(node));
}
/**
* Exchanges contents of this list with another list instance.
* @param other The other list to swap with.
*/
void swap(intrusive_list& other) noexcept {
root.swap(other.root);
}
private:
std::shared_ptr<intrusive_list_node<T>> root = std::make_shared<intrusive_list_sentinel<T>>();
};
/**
* Exchanges contents of an intrusive list with another intrusive list.
* @tparam T The type of data being kept track of by the lists.
* @param lhs The first list.
* @param rhs The second list.
*/
template<typename T>
void swap(intrusive_list<T>& lhs, intrusive_list<T>& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace mcl

View File

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#if defined(__clang) || defined(__GNUC__)
# define ASSUME(expr) [&] { if (!(expr)) __builtin_unreachable(); }()
#elif defined(_MSC_VER)
# define ASSUME(expr) __assume(expr)
#else
# define ASSUME(expr)
#endif

View File

@ -0,0 +1,34 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <iterator>
namespace mcl::iterator {
namespace detail {
template<typename T>
struct reverse_adapter {
T& iterable;
constexpr auto begin() {
using namespace std;
return rbegin(iterable);
}
constexpr auto end() {
using namespace std;
return rend(iterable);
}
};
} // namespace detail
template<typename T>
constexpr detail::reverse_adapter<T> reverse(T&& iterable) {
return detail::reverse_adapter<T>{iterable};
}
} // namespace mcl::iterator

View File

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <mcl/macro/concatenate_tokens.hpp>
#ifdef __COUNTER__
# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __COUNTER__)
#else
# define ANONYMOUS_VARIABLE(str) CONCATENATE_TOKENS(str, __LINE__)
#endif

View File

@ -0,0 +1,40 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#if defined(__ARM64__) || defined(__aarch64__) || defined(_M_ARM64)
# define MCL_ARCHITECTURE arm64
# define MCL_ARCHITECTURE_ARM64 1
#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM)
# define MCL_ARCHITECTURE arm32
# define MCL_ARCHITECTURE_ARM32 1
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
# define MCL_ARCHITECTURE x86_64
# define MCL_ARCHITECTURE_X86_64 1
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define MCL_ARCHITECTURE x86_32
# define MCL_ARCHITECTURE_X86_32 1
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
# define MCL_ARCHITECTURE ia64
# define MCL_ARCHITECTURE_IA64 1
#elif defined(__mips) || defined(__mips__) || defined(_M_MRX000)
# define MCL_ARCHITECTURE mips
# define MCL_ARCHITECTURE_MIPS 1
#elif defined(__ppc64__) || defined(__powerpc64__)
# define MCL_ARCHITECTURE ppc64
# define MCL_ARCHITECTURE_PPC64 1
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) || defined(_M_MPPC) || defined(_M_PPC)
# define MCL_ARCHITECTURE ppc32
# define MCL_ARCHITECTURE_PPC32 1
#elif defined(__riscv)
# define MCL_ARCHITECTURE riscv
# define MCL_ARCHITECTURE_RISCV 1
#elif defined(__EMSCRIPTEN__)
# define MCL_ARCHITECTURE wasm
# define MCL_ARCHITECTURE_WASM 1
#else
# define MCL_ARCHITECTURE generic
# define MCL_ARCHITECTURE_GENERIC 1
#endif

View File

@ -0,0 +1,8 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#define CONCATENATE_TOKENS(x, y) CONCATENATE_TOKENS_IMPL(x, y)
#define CONCATENATE_TOKENS_IMPL(x, y) x##y

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<template<class...> class F, class L>
struct apply_impl;
template<template<class...> class F, template<class...> class LT, class... Es>
struct apply_impl<F, LT<Es...>> {
using type = F<Es...>;
};
} // namespace detail
/// Invokes metafunction F where the arguments are all the members of list L
template<template<class...> class F, class L>
using apply = typename detail::apply_impl<F, L>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,18 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
/// Binds the first sizeof...(A) arguments of metafunction F with arguments A
template<template<class...> class F, class... As>
struct bind {
template<class... Rs>
using type = F<As..., Rs...>;
};
} // namespace mcl::mp
#define MCL_MP_BIND(...) ::mcl::mp::bind<__VA_ARGS__>::template type

View File

@ -0,0 +1,22 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class T>
struct identity_impl {
using type = T;
};
} // namespace detail
/// Identity metafunction
template<class T>
using identity = typename identity_impl<T>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<template<class...> class F, class L>
struct map_impl;
template<template<class...> class F, template<class...> class LT, class... Es>
struct map_impl<F, LT<Es...>> {
using type = LT<F<Es>...>;
};
} // namespace detail
/// Applies each element of list L to metafunction F
template<template<class...> class F, class L>
using map = typename detail::map_impl<F, L>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise and of metavalues Vs
template<class... Vs>
using bit_and = lift_value<(Vs::value & ...)>;
/// Bitwise and of metavalues Vs
template<class... Vs>
constexpr auto bit_and_v = (Vs::value & ...);
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise not of metavalue V
template<class V>
using bit_not = lift_value<~V::value>;
/// Bitwise not of metavalue V
template<class V>
constexpr auto bit_not_v = ~V::value;
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise or of metavalues Vs
template<class... Vs>
using bit_or = lift_value<(Vs::value | ...)>;
/// Bitwise or of metavalues Vs
template<class... Vs>
constexpr auto bit_or_v = (Vs::value | ...);
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Bitwise xor of metavalues Vs
template<class... Vs>
using bit_xor = lift_value<(Vs::value ^ ...)>;
/// Bitwise xor of metavalues Vs
template<class... Vs>
constexpr auto bit_xor_v = (Vs::value ^ ...);
} // namespace mcl::mp

View File

@ -0,0 +1,42 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/logic_if.hpp"
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
namespace detail {
template<class...>
struct conjunction_impl;
template<>
struct conjunction_impl<> {
using type = false_type;
};
template<class V>
struct conjunction_impl<V> {
using type = V;
};
template<class V1, class... Vs>
struct conjunction_impl<V1, Vs...> {
using type = logic_if<V1, typename conjunction_impl<Vs...>::type, V1>;
};
} // namespace detail
/// Conjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
using conjunction = typename detail::conjunction_impl<Vs...>::type;
/// Conjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
constexpr auto conjunction_v = conjunction<Vs...>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,42 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/logic_if.hpp"
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
namespace detail {
template<class...>
struct disjunction_impl;
template<>
struct disjunction_impl<> {
using type = false_type;
};
template<class V>
struct disjunction_impl<V> {
using type = V;
};
template<class V1, class... Vs>
struct disjunction_impl<V1, Vs...> {
using type = logic_if<V1, V1, typename disjunction_impl<Vs...>::type>;
};
} // namespace detail
/// Disjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
using disjunction = typename detail::disjunction_impl<Vs...>::type;
/// Disjunction of metavalues Vs with short-circuiting and type preservation.
template<class... Vs>
constexpr auto disjunction_v = disjunction<Vs...>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Lifts a value into a type (a metavalue)
template<auto V>
using lift_value = std::integral_constant<decltype(V), V>;
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical conjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
using logic_and = bool_value<(true && ... && Vs::value)>;
/// Logical conjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
constexpr bool logic_and_v = (true && ... && Vs::value);
} // namespace mcl::mp

View File

@ -0,0 +1,21 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Conditionally select between types T and F based on boolean metavalue V
template<class V, class T, class F>
using logic_if = std::conditional_t<bool(V::value), T, F>;
/// Conditionally select between metavalues T and F based on boolean metavalue V
template<class V, class TV, class FV>
constexpr auto logic_if_v = logic_if<V, TV, FV>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical negation of metavalue V.
template<class V>
using logic_not = bool_value<!bool(V::value)>;
/// Logical negation of metavalue V.
template<class V>
constexpr bool logic_not_v = !bool(V::value);
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Logical disjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
using logic_or = bool_value<(false || ... || Vs::value)>;
/// Logical disjunction of metavalues Vs without short-circuiting or type presevation.
template<class... Vs>
constexpr bool logic_or_v = (false || ... || Vs::value);
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Product of metavalues Vs
template<class... Vs>
using product = lift_value<(Vs::value * ...)>;
/// Product of metavalues Vs
template<class... Vs>
constexpr auto product_v = (Vs::value * ...);
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Sum of metavalues Vs
template<class... Vs>
using sum = lift_value<(Vs::value + ...)>;
/// Sum of metavalues Vs
template<class... Vs>
constexpr auto sum_v = (Vs::value + ...);
} // namespace mcl::mp

View File

@ -0,0 +1,30 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <type_traits>
namespace mcl::mp {
/// A metavalue (of type VT and value v).
template<class VT, VT v>
using value = std::integral_constant<VT, v>;
/// A metavalue of type size_t (and value v).
template<size_t v>
using size_value = value<size_t, v>;
/// A metavalue of type bool (and value v). (Aliases to std::bool_constant.)
template<bool v>
using bool_value = value<bool, v>;
/// true metavalue (Aliases to std::true_type).
using true_type = bool_value<true>;
/// false metavalue (Aliases to std::false_type).
using false_type = bool_value<false>;
} // namespace mcl::mp

View File

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Casts a metavalue from one type to another
template<class T, class V>
using value_cast = std::integral_constant<T, static_cast<T>(V::value)>;
} // namespace mcl::mp

View File

@ -0,0 +1,15 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
namespace mcl::mp {
/// Do two metavalues contain the same value?
template<class V1, class V2>
using value_equal = std::bool_constant<V1::value == V2::value>;
} // namespace mcl::mp

View File

@ -0,0 +1,19 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/lift_value.hpp"
namespace mcl::mp {
/// Metafunction that returns the number of arguments it has
template<typename... Ts>
using argument_count = lift_value<sizeof...(Ts)>;
/// Metafunction that returns the number of arguments it has
template<typename... Ts>
constexpr auto argument_count_v = sizeof...(Ts);
} // namespace mcl::mp

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class... L>
struct append_impl;
template<template<class...> class LT, class... E1s, class... E2s>
struct append_impl<LT<E1s...>, E2s...> {
using type = LT<E1s..., E2s...>;
};
} // namespace detail
/// Append items E to list L
template<class L, class... Es>
using append = typename detail::append_impl<L, Es...>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,47 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metafunction/bind.hpp"
#include "mcl/mp/metafunction/map.hpp"
#include "mcl/mp/typelist/append.hpp"
#include "mcl/mp/typelist/concat.hpp"
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class... Ls>
struct cartesian_product_impl;
template<class RL>
struct cartesian_product_impl<RL> {
using type = RL;
};
template<template<class...> class LT, class... REs, class... E2s>
struct cartesian_product_impl<LT<REs...>, LT<E2s...>> {
using type = concat<
map<MCL_MP_BIND(append, REs), list<E2s...>>...>;
};
template<class RL, class L2, class L3, class... Ls>
struct cartesian_product_impl<RL, L2, L3, Ls...> {
using type = typename cartesian_product_impl<
typename cartesian_product_impl<RL, L2>::type,
L3,
Ls...>::type;
};
} // namespace detail
/// Produces the cartesian product of a set of lists
/// For example:
/// cartesian_product<list<A, B>, list<D, E>> == list<list<A, D>, list<A, E>, list<B, D>, list<B, E>
template<typename L1, typename... Ls>
using cartesian_product = typename detail::cartesian_product_impl<map<list, L1>, Ls...>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,94 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class... Ls>
struct concat_impl;
template<>
struct concat_impl<> {
using type = list<>;
};
template<class L>
struct concat_impl<L> {
using type = L;
};
template<template<class...> class LT, class... E1s, class... E2s, class... Ls>
struct concat_impl<LT<E1s...>, LT<E2s...>, Ls...> {
using type = typename concat_impl<LT<E1s..., E2s...>, Ls...>::type;
};
template<template<class...> class LT,
class... E1s,
class... E2s,
class... E3s,
class... E4s,
class... E5s,
class... E6s,
class... E7s,
class... E8s,
class... E9s,
class... E10s,
class... E11s,
class... E12s,
class... E13s,
class... E14s,
class... E15s,
class... E16s,
class... Ls>
struct concat_impl<
LT<E1s...>,
LT<E2s...>,
LT<E3s...>,
LT<E4s...>,
LT<E5s...>,
LT<E6s...>,
LT<E7s...>,
LT<E8s...>,
LT<E9s...>,
LT<E10s...>,
LT<E11s...>,
LT<E12s...>,
LT<E13s...>,
LT<E14s...>,
LT<E15s...>,
LT<E16s...>,
Ls...> {
using type = typename concat_impl<
LT<
E1s...,
E2s...,
E3s...,
E4s...,
E5s...,
E6s...,
E7s...,
E8s...,
E9s...,
E10s...,
E11s...,
E12s...,
E13s...,
E14s...,
E15s...,
E16s...>,
Ls...>::type;
};
} // namespace detail
/// Concatenate lists together
template<class... Ls>
using concat = typename detail::concat_impl<Ls...>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,23 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl::mp {
/// Does list L contain an element which is same as type T?
template<class L, class T>
struct contains;
template<template<class...> class LT, class... Ts, class T>
struct contains<LT<Ts...>, T>
: bool_value<(false || ... || std::is_same_v<Ts, T>)> {};
/// Does list L contain an element which is same as type T?
template<class L, class T>
constexpr bool contains_v = contains<L, T>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,33 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <type_traits>
namespace mcl::mp {
namespace detail {
template<size_t N, class L>
struct drop_impl;
template<size_t N, template<class...> class LT>
struct drop_impl<N, LT<>> {
using type = LT<>;
};
template<size_t N, template<class...> class LT, class E1, class... Es>
struct drop_impl<N, LT<E1, Es...>> {
using type = std::conditional_t<N == 0, LT<E1, Es...>, typename drop_impl<N - 1, LT<Es...>>::type>;
};
} // namespace detail
/// Drops the first N elements of list L
template<std::size_t N, class L>
using drop = typename detail::drop_impl<N, L>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,18 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <tuple>
#include "mcl/mp/metafunction/apply.hpp"
namespace mcl::mp {
/// Get element I from list L
template<std::size_t I, class L>
using get = std::tuple_element_t<I, apply<std::tuple, L>>;
} // namespace mcl::mp

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class L>
struct head_impl;
template<template<class...> class LT, class E1, class... Es>
struct head_impl<LT<E1, Es...>> {
using type = E1;
};
} // namespace detail
/// Gets the tail/cdr/all-but-the-first-element of list L
template<class L>
using head = typename detail::head_impl<L>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,20 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metafunction/apply.hpp"
#include "mcl/mp/misc/argument_count.hpp"
namespace mcl::mp {
/// Length of list L
template<class L>
using length = apply<argument_count, L>;
/// Length of list L
template<class L>
constexpr auto length_v = length<L>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,29 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <type_traits>
#include "mcl/mp/typelist/list.hpp"
namespace mcl::mp {
namespace detail {
template<class VL>
struct lift_sequence_impl;
template<class T, template<class, T...> class VLT, T... values>
struct lift_sequence_impl<VLT<T, values...>> {
using type = list<std::integral_constant<T, values>...>;
};
} // namespace detail
/// Lifts values in value list VL to create a type list.
template<class VL>
using lift_sequence = typename detail::lift_sequence_impl<VL>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,13 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
/// Contains a list of types
template<class... E>
struct list {};
} // namespace mcl::mp

View File

@ -0,0 +1,24 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <tuple>
namespace mcl::mp {
/// Converts a list of metavalues to a tuple.
template<class L>
struct lower_to_tuple;
template<template<class...> class LT, class... Es>
struct lower_to_tuple<LT<Es...>> {
static constexpr auto value = std::make_tuple(static_cast<typename Es::value_type>(Es::value)...);
};
/// Converts a list of metavalues to a tuple.
template<class L>
constexpr auto lower_to_tuple_v = lower_to_tuple<L>::value;
} // namespace mcl::mp

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class... L>
struct prepend_impl;
template<template<class...> class LT, class... E1s, class... E2s>
struct prepend_impl<LT<E1s...>, E2s...> {
using type = LT<E2s..., E1s...>;
};
} // namespace detail
/// Prepend items E to list L
template<class L, class... Es>
using prepend = typename detail::prepend_impl<L, Es...>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,25 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
namespace mcl::mp {
namespace detail {
template<class L>
struct tail_impl;
template<template<class...> class LT, class E1, class... Es>
struct tail_impl<LT<E1, Es...>> {
using type = LT<Es...>;
};
} // namespace detail
/// Gets the first type of list L
template<class L>
using tail = typename detail::tail_impl<L>::type;
} // namespace mcl::mp

View File

@ -0,0 +1,85 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <exception>
#include <type_traits>
#include <utility>
#include <mcl/macro/anonymous_variable.hpp>
namespace mcl::detail {
struct scope_exit_tag {};
struct scope_fail_tag {};
struct scope_success_tag {};
template<typename Function>
class scope_exit final {
public:
explicit scope_exit(Function&& fn)
: function(std::move(fn)) {}
~scope_exit() noexcept {
function();
}
private:
Function function;
};
template<typename Function>
class scope_fail final {
public:
explicit scope_fail(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_fail() noexcept {
if (std::uncaught_exceptions() > exception_count) {
function();
}
}
private:
Function function;
int exception_count;
};
template<typename Function>
class scope_success final {
public:
explicit scope_success(Function&& fn)
: function(std::move(fn)), exception_count(std::uncaught_exceptions()) {}
~scope_success() {
if (std::uncaught_exceptions() <= exception_count) {
function();
}
}
private:
Function function;
int exception_count;
};
// We use ->* here as it has the highest precedence of the operators we can use.
template<typename Function>
auto operator->*(scope_exit_tag, Function&& function) {
return scope_exit<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_fail_tag, Function&& function) {
return scope_fail<std::decay_t<Function>>{std::forward<Function>(function)};
}
template<typename Function>
auto operator->*(scope_success_tag, Function&& function) {
return scope_success<std::decay_t<Function>>{std::forward<Function>(function)};
}
} // namespace mcl::detail
#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(MCL_SCOPE_EXIT_VAR_) = ::mcl::detail::scope_exit_tag{}->*[&]() noexcept
#define SCOPE_FAIL auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_fail_tag{}->*[&]() noexcept
#define SCOPE_SUCCESS auto ANONYMOUS_VARIABLE(MCL_SCOPE_FAIL_VAR_) = ::mcl::detail::scope_success_tag{}->*[&]()

View File

@ -0,0 +1,27 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <cstdint>
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using uptr = std::uintptr_t;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
using sptr = std::intptr_t;
using size_t = std::size_t;
using f32 = float;
using f64 = double;
static_assert(sizeof(f32) == sizeof(u32), "f32 must be 32 bits wide");
static_assert(sizeof(f64) == sizeof(u64), "f64 must be 64 bits wide");

View File

@ -0,0 +1,70 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include <cstddef>
#include <tuple>
#include "mcl/mp/typelist/list.hpp"
namespace mcl {
template<class F>
struct function_info : function_info<decltype(&F::operator())> {};
template<class R, class... As>
struct function_info<R(As...)> {
using return_type = R;
using parameter_list = mp::list<As...>;
static constexpr std::size_t parameter_count = sizeof...(As);
using equivalent_function_type = R(As...);
template<std::size_t I>
struct parameter {
static_assert(I < parameter_count, "Non-existent parameter");
using type = std::tuple_element_t<I, std::tuple<As...>>;
};
};
template<class R, class... As>
struct function_info<R (*)(As...)> : function_info<R(As...)> {};
template<class C, class R, class... As>
struct function_info<R (C::*)(As...)> : function_info<R(As...)> {
using class_type = C;
using equivalent_function_type_with_class = R(C*, As...);
};
template<class C, class R, class... As>
struct function_info<R (C::*)(As...) const> : function_info<R(As...)> {
using class_type = C;
using equivalent_function_type_with_class = R(C*, As...);
};
template<class F>
constexpr size_t parameter_count_v = function_info<F>::parameter_count;
template<class F>
using parameter_list = typename function_info<F>::parameter_list;
template<class F, std::size_t I>
using get_parameter = typename function_info<F>::template parameter<I>::type;
template<class F>
using equivalent_function_type = typename function_info<F>::equivalent_function_type;
template<class F>
using equivalent_function_type_with_class = typename function_info<F>::equivalent_function_type_with_class;
template<class F>
using return_type = typename function_info<F>::return_type;
template<class F>
using class_type = typename function_info<F>::class_type;
} // namespace mcl

View File

@ -0,0 +1,48 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/stdint.hpp"
namespace mcl {
namespace detail {
template<size_t size>
struct integer_of_size_impl {};
template<>
struct integer_of_size_impl<8> {
using unsigned_type = u8;
using signed_type = s8;
};
template<>
struct integer_of_size_impl<16> {
using unsigned_type = u16;
using signed_type = s16;
};
template<>
struct integer_of_size_impl<32> {
using unsigned_type = u32;
using signed_type = s32;
};
template<>
struct integer_of_size_impl<64> {
using unsigned_type = u64;
using signed_type = s64;
};
} // namespace detail
template<size_t size>
using unsigned_integer_of_size = typename detail::integer_of_size_impl<size>::unsigned_type;
template<size_t size>
using signed_integer_of_size = typename detail::integer_of_size_impl<size>::signed_type;
} // namespace mcl

View File

@ -0,0 +1,22 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#pragma once
#include "mcl/mp/metavalue/value.hpp"
namespace mcl {
/// Is type T an instance of template class C?
template<template<class...> class, class>
struct is_instance_of_template : mp::false_type {};
template<template<class...> class C, class... As>
struct is_instance_of_template<C, C<As...>> : mp::true_type {};
/// Is type T an instance of template class C?
template<template<class...> class C, class T>
constexpr bool is_instance_of_template_v = is_instance_of_template<C, T>::value;
} // namespace mcl

View File

@ -0,0 +1,69 @@
add_library(mcl
../include/mcl/assert.hpp
../include/mcl/bit/bit_count.hpp
../include/mcl/bit/bit_field.hpp
../include/mcl/bit/rotate.hpp
../include/mcl/bit/swap.hpp
../include/mcl/bit_cast.hpp
../include/mcl/bitsizeof.hpp
../include/mcl/concepts/bit_integral.hpp
../include/mcl/concepts/is_any_of.hpp
../include/mcl/concepts/same_as.hpp
../include/mcl/container/intrusive_list.hpp
../include/mcl/hint/assume.hpp
../include/mcl/iterator/reverse.hpp
../include/mcl/macro/anonymous_variable.hpp
../include/mcl/macro/architecture.hpp
../include/mcl/macro/concatenate_tokens.hpp
../include/mcl/mp/metafunction/apply.hpp
../include/mcl/mp/metafunction/bind.hpp
../include/mcl/mp/metafunction/identity.hpp
../include/mcl/mp/metafunction/map.hpp
../include/mcl/mp/metavalue/bit_and.hpp
../include/mcl/mp/metavalue/bit_not.hpp
../include/mcl/mp/metavalue/bit_or.hpp
../include/mcl/mp/metavalue/bit_xor.hpp
../include/mcl/mp/metavalue/conjunction.hpp
../include/mcl/mp/metavalue/disjunction.hpp
../include/mcl/mp/metavalue/lift_value.hpp
../include/mcl/mp/metavalue/logic_and.hpp
../include/mcl/mp/metavalue/logic_if.hpp
../include/mcl/mp/metavalue/logic_not.hpp
../include/mcl/mp/metavalue/logic_or.hpp
../include/mcl/mp/metavalue/product.hpp
../include/mcl/mp/metavalue/sum.hpp
../include/mcl/mp/metavalue/value.hpp
../include/mcl/mp/metavalue/value_cast.hpp
../include/mcl/mp/metavalue/value_equal.hpp
../include/mcl/mp/misc/argument_count.hpp
../include/mcl/mp/typelist/append.hpp
../include/mcl/mp/typelist/cartesian_product.hpp
../include/mcl/mp/typelist/concat.hpp
../include/mcl/mp/typelist/contains.hpp
../include/mcl/mp/typelist/drop.hpp
../include/mcl/mp/typelist/get.hpp
../include/mcl/mp/typelist/head.hpp
../include/mcl/mp/typelist/length.hpp
../include/mcl/mp/typelist/lift_sequence.hpp
../include/mcl/mp/typelist/list.hpp
../include/mcl/mp/typelist/lower_to_tuple.hpp
../include/mcl/mp/typelist/prepend.hpp
../include/mcl/mp/typelist/tail.hpp
../include/mcl/scope_exit.hpp
../include/mcl/stdint.hpp
../include/mcl/type_traits/function_info.hpp
../include/mcl/type_traits/integer_of_size.hpp
../include/mcl/type_traits/is_instance_of_template.hpp
assert.cpp
)
target_include_directories(mcl
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_options(mcl PRIVATE ${MCL_CXX_FLAGS})
target_link_libraries(mcl PUBLIC $<BUILD_INTERFACE:fmt::fmt>)
add_library(merry::mcl ALIAS mcl)
include(CreateTargetDirectoryGroups)
create_target_directory_groups(mcl)

View File

@ -0,0 +1,20 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#include "mcl/assert.hpp"
#include <cstdio>
#include <exception>
#include <fmt/format.h>
namespace mcl::detail {
[[noreturn]] void assert_terminate_impl(fmt::string_view msg, fmt::format_args args) {
fmt::print(stderr, "assertion failed: ");
fmt::vprint(stderr, msg, args);
std::terminate();
}
} // namespace mcl::detail

View File

@ -0,0 +1,15 @@
add_executable(mcl-tests
bit/bit_field_tests.cpp
main.cpp
mp/metavalue_tests.cpp
mp/typelist_tests.cpp
type_traits/type_traits_tests.cpp
)
target_include_directories(mcl-tests PUBLIC .)
target_compile_options(mcl-tests PRIVATE ${STAMINA_CXX_FLAGS})
target_link_libraries(mcl-tests PRIVATE Catch2::Catch2 mcl)
include(CTest)
include(Catch)
catch_discover_tests(mcl-tests)
enable_testing()

View File

@ -0,0 +1,41 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#include <array>
#include <tuple>
#include <catch2/catch.hpp>
#include <mcl/bit/bit_field.hpp>
#include <mcl/stdint.hpp>
TEST_CASE("mcl::bit::ones", "[bit]") {
const std::array cases{
std::make_tuple<size_t, u8>(0, 0x00),
std::make_tuple<size_t, u8>(1, 0x01),
std::make_tuple<size_t, u8>(2, 0x03),
std::make_tuple<size_t, u8>(3, 0x07),
std::make_tuple<size_t, u8>(4, 0x0f),
std::make_tuple<size_t, u8>(5, 0x1f),
std::make_tuple<size_t, u8>(6, 0x3f),
std::make_tuple<size_t, u8>(7, 0x7f),
std::make_tuple<size_t, u8>(8, 0xff),
};
for (const auto [count, expected] : cases) {
REQUIRE(mcl::bit::ones<u8>(count) == expected);
REQUIRE(mcl::bit::ones<u16>(count) == expected);
REQUIRE(mcl::bit::ones<u32>(count) == expected);
REQUIRE(mcl::bit::ones<u64>(count) == expected);
REQUIRE(mcl::bit::ones<uptr>(count) == expected);
REQUIRE(mcl::bit::ones<size_t>(count) == expected);
}
}
static_assert(mcl::bit::ones<3, u8>() == 0x7);
static_assert(mcl::bit::ones<15, u16>() == 0x7fff);
static_assert(mcl::bit::ones<16, u16>() == 0xffff);
static_assert(mcl::bit::ones<31, u32>() == 0x7fff'ffff);
static_assert(mcl::bit::ones<32, u32>() == 0xffff'ffff);
static_assert(mcl::bit::ones<63, u64>() == 0x7fff'ffff'ffff'ffff);
static_assert(mcl::bit::ones<64, u64>() == 0xffff'ffff'ffff'ffff);

View File

@ -0,0 +1,6 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"

View File

@ -0,0 +1,90 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#include <type_traits>
#include <mcl/mp/metavalue/bit_and.hpp>
#include <mcl/mp/metavalue/bit_not.hpp>
#include <mcl/mp/metavalue/bit_or.hpp>
#include <mcl/mp/metavalue/bit_xor.hpp>
#include <mcl/mp/metavalue/conjunction.hpp>
#include <mcl/mp/metavalue/disjunction.hpp>
#include <mcl/mp/metavalue/lift_value.hpp>
#include <mcl/mp/metavalue/logic_and.hpp>
#include <mcl/mp/metavalue/logic_not.hpp>
#include <mcl/mp/metavalue/logic_or.hpp>
#include <mcl/mp/metavalue/product.hpp>
#include <mcl/mp/metavalue/sum.hpp>
#include <mcl/mp/metavalue/value.hpp>
#include <mcl/mp/metavalue/value_cast.hpp>
#include <mcl/mp/metavalue/value_equal.hpp>
using namespace mcl::mp;
// bit_and
static_assert(bit_and<lift_value<3>, lift_value<1>>::value == 1);
// bit_not
static_assert(bit_not<lift_value<0>>::value == ~0);
// bit_or
static_assert(bit_or<lift_value<1>, lift_value<3>>::value == 3);
// bit_xor
static_assert(bit_xor<lift_value<1>, lift_value<3>>::value == 2);
// conjunction
static_assert(std::is_same_v<conjunction<std::true_type>, std::true_type>);
static_assert(std::is_same_v<conjunction<std::true_type, lift_value<0>>, lift_value<0>>);
static_assert(std::is_same_v<conjunction<std::true_type, lift_value<42>, std::true_type>, std::true_type>);
// disjunction
static_assert(std::is_same_v<disjunction<std::true_type>, std::true_type>);
static_assert(std::is_same_v<disjunction<std::false_type, lift_value<0>>, lift_value<0>>);
static_assert(std::is_same_v<disjunction<std::false_type, lift_value<42>, std::true_type>, lift_value<42>>);
// lift_value
static_assert(std::is_same_v<lift_value<3>, std::integral_constant<int, 3>>);
static_assert(std::is_same_v<lift_value<false>, std::false_type>);
// logic_and
static_assert(std::is_same_v<logic_and<>, std::true_type>);
static_assert(std::is_same_v<logic_and<std::true_type>, std::true_type>);
static_assert(std::is_same_v<logic_and<lift_value<1>>, std::true_type>);
static_assert(std::is_same_v<logic_and<std::true_type, std::false_type>, std::false_type>);
// logic_not
static_assert(std::is_same_v<logic_not<std::false_type>, std::true_type>);
// logic_or
static_assert(std::is_same_v<logic_or<>, std::false_type>);
static_assert(std::is_same_v<logic_or<std::true_type>, std::true_type>);
static_assert(std::is_same_v<logic_or<lift_value<0>>, std::false_type>);
static_assert(std::is_same_v<logic_or<std::true_type, std::false_type>, std::true_type>);
// product
static_assert(product<lift_value<1>, lift_value<2>, lift_value<3>, lift_value<4>>::value == 24);
// sum
static_assert(sum<lift_value<1>, lift_value<2>, lift_value<3>, lift_value<4>>::value == 10);
// value_cast
static_assert(std::is_same_v<value_cast<int, std::true_type>, std::integral_constant<int, 1>>);
// value_equal
static_assert(std::is_same_v<value_equal<std::true_type, std::integral_constant<int, 1>>, std::true_type>);

View File

@ -0,0 +1,104 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#include <mcl/mp/metavalue/value.hpp>
#include <mcl/mp/typelist/append.hpp>
#include <mcl/mp/typelist/cartesian_product.hpp>
#include <mcl/mp/typelist/concat.hpp>
#include <mcl/mp/typelist/contains.hpp>
#include <mcl/mp/typelist/drop.hpp>
#include <mcl/mp/typelist/get.hpp>
#include <mcl/mp/typelist/head.hpp>
#include <mcl/mp/typelist/length.hpp>
#include <mcl/mp/typelist/lift_sequence.hpp>
#include <mcl/mp/typelist/list.hpp>
#include <mcl/mp/typelist/lower_to_tuple.hpp>
#include <mcl/mp/typelist/prepend.hpp>
#include <mcl/mp/typelist/tail.hpp>
using namespace mcl::mp;
// append
static_assert(std::is_same_v<append<list<int, bool>, double>, list<int, bool, double>>);
static_assert(std::is_same_v<append<list<>, int, int>, list<int, int>>);
// cartesian_product
static_assert(
std::is_same_v<
cartesian_product<list<int, bool>, list<double, float>, list<char, unsigned>>,
list<
list<int, double, char>,
list<int, double, unsigned>,
list<int, float, char>,
list<int, float, unsigned>,
list<bool, double, char>,
list<bool, double, unsigned>,
list<bool, float, char>,
list<bool, float, unsigned>>>);
// concat
static_assert(std::is_same_v<concat<list<int, bool>, list<double>>, list<int, bool, double>>);
static_assert(std::is_same_v<concat<list<>, list<int>, list<int>>, list<int, int>>);
// contains
static_assert(contains_v<list<int>, int>);
static_assert(!contains_v<list<>, int>);
static_assert(!contains_v<list<double>, int>);
static_assert(contains_v<list<double, int>, int>);
// drop
static_assert(std::is_same_v<list<>, drop<3, list<int, int>>>);
static_assert(std::is_same_v<list<>, drop<3, list<int, int, int>>>);
static_assert(std::is_same_v<list<int>, drop<3, list<int, int, int, int>>>);
static_assert(std::is_same_v<list<double>, drop<3, list<int, int, int, double>>>);
static_assert(std::is_same_v<list<int, double, bool>, drop<0, list<int, double, bool>>>);
// get
static_assert(std::is_same_v<get<0, list<int, double>>, int>);
static_assert(std::is_same_v<get<1, list<int, double>>, double>);
// head
static_assert(std::is_same_v<head<list<int, double>>, int>);
static_assert(std::is_same_v<head<list<int>>, int>);
// length
static_assert(length_v<list<>> == 0);
static_assert(length_v<list<int>> == 1);
static_assert(length_v<list<int, int, int>> == 3);
// lift_sequence
static_assert(
std::is_same_v<
lift_sequence<std::make_index_sequence<3>>,
list<size_value<0>, size_value<1>, size_value<2>>>);
// lower_to_tuple
static_assert(lower_to_tuple_v<list<size_value<0>, size_value<1>, size_value<2>>> == std::tuple<std::size_t, std::size_t, std::size_t>(0, 1, 2));
static_assert(lower_to_tuple_v<list<std::true_type, std::false_type>> == std::make_tuple(true, false));
// prepend
static_assert(std::is_same_v<prepend<list<int, int>, double>, list<double, int, int>>);
static_assert(std::is_same_v<prepend<list<>, double>, list<double>>);
static_assert(std::is_same_v<prepend<list<int>, double, bool>, list<double, bool, int>>);
// tail
static_assert(std::is_same_v<tail<list<int, double>>, list<double>>);
static_assert(std::is_same_v<tail<list<int>>, list<>>);

View File

@ -0,0 +1,39 @@
// This file is part of the mcl project.
// Copyright (c) 2022 merryhime
// SPDX-License-Identifier: MIT
#include <tuple>
#include <type_traits>
#include <mcl/type_traits/function_info.hpp>
#include <mcl/type_traits/is_instance_of_template.hpp>
using namespace mcl;
// function_info
struct Bar {
int frob(double a) { return a; }
};
static_assert(parameter_count_v<void()> == 0);
static_assert(parameter_count_v<void(int, int, int)> == 3);
static_assert(std::is_same_v<get_parameter<void (*)(bool, int, double), 2>, double>);
static_assert(std::is_same_v<equivalent_function_type<void (*)(bool, int, double)>, void(bool, int, double)>);
static_assert(std::is_same_v<return_type<void (*)(bool, int, double)>, void>);
static_assert(std::is_same_v<equivalent_function_type<decltype(&Bar::frob)>, int(double)>);
static_assert(std::is_same_v<class_type<decltype(&Bar::frob)>, Bar>);
// is_instance_of_template
template<class, class...>
class Foo {};
template<class, class>
class Pair {};
static_assert(is_instance_of_template_v<std::tuple, std::tuple<int, bool>>);
static_assert(!is_instance_of_template_v<std::tuple, bool>);
static_assert(is_instance_of_template_v<Foo, Foo<bool>>);
static_assert(is_instance_of_template_v<Pair, Pair<bool, int>>);
static_assert(!is_instance_of_template_v<Pair, Foo<bool, int>>);

View File

@ -1,9 +1,5 @@
add_library(dynarmic
common/assert.cpp
common/assert.h
common/bit_util.h
common/cast_util.h
common/common_types.h
common/crypto/aes.cpp
common/crypto/aes.h
common/crypto/crc32.cpp
@ -46,18 +42,14 @@ add_library(dynarmic
common/fp/unpacked.cpp
common/fp/unpacked.h
common/fp/util.h
common/intrusive_list.h
common/iterator_util.h
common/llvm_disassemble.cpp
common/llvm_disassemble.h
common/lut_from_list.h
common/macro_util.h
common/math_util.cpp
common/math_util.h
common/memory_pool.cpp
common/memory_pool.h
common/safe_ops.h
common/scope_exit.h
common/spin_lock.h
common/string_util.h
common/u128.cpp
@ -385,10 +377,11 @@ set_target_properties(dynarmic PROPERTIES
target_compile_options(dynarmic PRIVATE ${DYNARMIC_CXX_FLAGS})
# $<BUILD_INTERFACE:> required because of https://gitlab.kitware.com/cmake/cmake/-/issues/15415
target_link_libraries(dynarmic
PUBLIC
$<BUILD_INTERFACE:merry::mcl>
PRIVATE
$<BUILD_INTERFACE:boost>
$<BUILD_INTERFACE:fmt::fmt>
$<BUILD_INTERFACE:mp>
tsl::robin_map
$<BUILD_INTERFACE:xbyak>
$<BUILD_INTERFACE:Zydis>
@ -401,7 +394,7 @@ if (DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT)
target_compile_definitions(dynarmic PRIVATE DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=1)
endif()
if (DYNARMIC_IGNORE_ASSERTS)
target_compile_definitions(dynarmic PRIVATE DYNARMIC_IGNORE_ASSERTS=1)
target_compile_definitions(dynarmic PRIVATE MCL_IGNORE_ASSERTS=1)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_compile_definitions(dynarmic PRIVATE FMT_USE_WINDOWS_H=0)

View File

@ -11,6 +11,10 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/a32_jitstate.h"
#include "dynarmic/backend/x64/abi.h"
@ -20,10 +24,6 @@
#include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/backend/x64/perf_map.h"
#include "dynarmic/backend/x64/stack_layout.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/variant_util.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/a32_types.h"
@ -626,10 +626,10 @@ void A32EmitX64::EmitA32SetGEFlagsCompressed(A32EmitContext& ctx, IR::Inst* inst
if (args[0].IsImmediate()) {
const u32 imm = args[0].GetImmediateU32();
u32 ge = 0;
ge |= Common::Bit<19>(imm) ? 0xFF000000 : 0;
ge |= Common::Bit<18>(imm) ? 0x00FF0000 : 0;
ge |= Common::Bit<17>(imm) ? 0x0000FF00 : 0;
ge |= Common::Bit<16>(imm) ? 0x000000FF : 0;
ge |= mcl::bit::get_bit<19>(imm) ? 0xFF000000 : 0;
ge |= mcl::bit::get_bit<18>(imm) ? 0x00FF0000 : 0;
ge |= mcl::bit::get_bit<17>(imm) ? 0x0000FF00 : 0;
ge |= mcl::bit::get_bit<16>(imm) ? 0x000000FF : 0;
code.mov(dword[r15 + offsetof(A32JitState, cpsr_ge)], ge);
} else if (code.HasHostFeature(HostFeature::FastBMI2)) {
@ -689,8 +689,8 @@ void A32EmitX64::EmitA32BXWritePC(A32EmitContext& ctx, IR::Inst* inst) {
if (arg.IsImmediate()) {
const u32 new_pc = arg.GetImmediateU32();
const u32 mask = Common::Bit<0>(new_pc) ? 0xFFFFFFFE : 0xFFFFFFFC;
const u32 new_upper = upper_without_t | (Common::Bit<0>(new_pc) ? 1 : 0);
const u32 mask = mcl::bit::get_bit<0>(new_pc) ? 0xFFFFFFFE : 0xFFFFFFFC;
const u32 new_upper = upper_without_t | (mcl::bit::get_bit<0>(new_pc) ? 1 : 0);
code.mov(MJitStateReg(A32::Reg::PC), new_pc & mask);
code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], new_upper);

View File

@ -10,7 +10,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mp/traits/integer_of_size.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_emit_x64.h"

View File

@ -8,6 +8,10 @@
#include <boost/icl/interval_set.hpp>
#include <fmt/format.h>
#include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/a32_emit_x64.h"
#include "dynarmic/backend/x64/a32_jitstate.h"
@ -15,11 +19,7 @@
#include "dynarmic/backend/x64/callback.h"
#include "dynarmic/backend/x64/devirtualize.h"
#include "dynarmic/backend/x64/jitstate_info.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/atomic.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A32/translate/a32_translate.h"
#include "dynarmic/interface/A32/a32.h"
@ -44,10 +44,10 @@ static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*Lo
static std::function<void(BlockOfCode&)> GenRCP(const A32::UserConfig& conf) {
return [conf](BlockOfCode& code) {
if (conf.page_table) {
code.mov(code.r14, Common::BitCast<u64>(conf.page_table));
code.mov(code.r14, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.mov(code.r13, Common::BitCast<u64>(conf.fastmem_pointer));
code.mov(code.r13, mcl::bit_cast<u64>(conf.fastmem_pointer));
}
};
}

View File

@ -5,11 +5,12 @@
#include "dynarmic/backend/x64/a32_jitstate.h"
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
namespace Dynarmic::Backend::X64 {
@ -57,13 +58,13 @@ u32 A32JitState::Cpsr() const {
// Q flag
cpsr |= cpsr_q ? 1 << 27 : 0;
// GE flags
cpsr |= Common::Bit<31>(cpsr_ge) ? 1 << 19 : 0;
cpsr |= Common::Bit<23>(cpsr_ge) ? 1 << 18 : 0;
cpsr |= Common::Bit<15>(cpsr_ge) ? 1 << 17 : 0;
cpsr |= Common::Bit<7>(cpsr_ge) ? 1 << 16 : 0;
cpsr |= mcl::bit::get_bit<31>(cpsr_ge) ? 1 << 19 : 0;
cpsr |= mcl::bit::get_bit<23>(cpsr_ge) ? 1 << 18 : 0;
cpsr |= mcl::bit::get_bit<15>(cpsr_ge) ? 1 << 17 : 0;
cpsr |= mcl::bit::get_bit<7>(cpsr_ge) ? 1 << 16 : 0;
// E flag, T flag
cpsr |= Common::Bit<1>(upper_location_descriptor) ? 1 << 9 : 0;
cpsr |= Common::Bit<0>(upper_location_descriptor) ? 1 << 5 : 0;
cpsr |= mcl::bit::get_bit<1>(upper_location_descriptor) ? 1 << 9 : 0;
cpsr |= mcl::bit::get_bit<0>(upper_location_descriptor) ? 1 << 5 : 0;
// IT state
cpsr |= static_cast<u32>(upper_location_descriptor & 0b11111100'00000000);
cpsr |= static_cast<u32>(upper_location_descriptor & 0b00000011'00000000) << 17;
@ -77,18 +78,18 @@ void A32JitState::SetCpsr(u32 cpsr) {
// NZCV flags
cpsr_nzcv = NZCV::ToX64(cpsr);
// Q flag
cpsr_q = Common::Bit<27>(cpsr) ? 1 : 0;
cpsr_q = mcl::bit::get_bit<27>(cpsr) ? 1 : 0;
// GE flags
cpsr_ge = 0;
cpsr_ge |= Common::Bit<19>(cpsr) ? 0xFF000000 : 0;
cpsr_ge |= Common::Bit<18>(cpsr) ? 0x00FF0000 : 0;
cpsr_ge |= Common::Bit<17>(cpsr) ? 0x0000FF00 : 0;
cpsr_ge |= Common::Bit<16>(cpsr) ? 0x000000FF : 0;
cpsr_ge |= mcl::bit::get_bit<19>(cpsr) ? 0xFF000000 : 0;
cpsr_ge |= mcl::bit::get_bit<18>(cpsr) ? 0x00FF0000 : 0;
cpsr_ge |= mcl::bit::get_bit<17>(cpsr) ? 0x0000FF00 : 0;
cpsr_ge |= mcl::bit::get_bit<16>(cpsr) ? 0x000000FF : 0;
upper_location_descriptor &= 0xFFFF0000;
// E flag, T flag
upper_location_descriptor |= Common::Bit<9>(cpsr) ? 2 : 0;
upper_location_descriptor |= Common::Bit<5>(cpsr) ? 1 : 0;
upper_location_descriptor |= mcl::bit::get_bit<9>(cpsr) ? 2 : 0;
upper_location_descriptor |= mcl::bit::get_bit<5>(cpsr) ? 1 : 0;
// IT state
upper_location_descriptor |= (cpsr >> 0) & 0b11111100'00000000;
upper_location_descriptor |= (cpsr >> 17) & 0b00000011'00000000;
@ -197,7 +198,7 @@ void A32JitState::SetFpscr(u32 FPSCR) {
// Cumulative flags IDC, IOC, IXC, UFC, OFC, DZC
fpsr_exc = FPSCR & 0x9F;
if (Common::Bit<24>(FPSCR)) {
if (mcl::bit::get_bit<24>(FPSCR)) {
// VFP Flush to Zero
guest_MXCSR |= (1 << 15); // SSE Flush to Zero
guest_MXCSR |= (1 << 6); // SSE Denormals are Zero

View File

@ -7,7 +7,7 @@
#include <array>
#include "dynarmic/common/common_types.h"
#include <mcl/stdint.hpp>
namespace Dynarmic::Backend::X64 {

View File

@ -7,7 +7,10 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mp/traits/integer_of_size.h>
#include <mcl/assert.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include <mcl/type_traits/integer_of_size.hpp>
#include "dynarmic/backend/x64/a64_jitstate.h"
#include "dynarmic/backend/x64/abi.h"
@ -17,10 +20,6 @@
#include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/backend/x64/perf_map.h"
#include "dynarmic/backend/x64/stack_layout.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/a64_types.h"
#include "dynarmic/ir/basic_block.h"

View File

@ -10,7 +10,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mp/traits/integer_of_size.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a64_emit_x64.h"

View File

@ -8,15 +8,16 @@
#include <mutex>
#include <boost/icl/interval_set.hpp>
#include <mcl/assert.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/scope_exit.hpp>
#include "dynarmic/backend/x64/a64_emit_x64.h"
#include "dynarmic/backend/x64/a64_jitstate.h"
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/devirtualize.h"
#include "dynarmic/backend/x64/jitstate_info.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/atomic.h"
#include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/x64_disassemble.h"
#include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/interface/A64/a64.h"
@ -39,10 +40,10 @@ static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*Lo
static std::function<void(BlockOfCode&)> GenRCP(const A64::UserConfig& conf) {
return [conf](BlockOfCode& code) {
if (conf.page_table) {
code.mov(code.r14, Common::BitCast<u64>(conf.page_table));
code.mov(code.r14, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.mov(code.r13, Common::BitCast<u64>(conf.fastmem_pointer));
code.mov(code.r13, mcl::bit_cast<u64>(conf.fastmem_pointer));
}
};
}

View File

@ -5,7 +5,8 @@
#include "dynarmic/backend/x64/a64_jitstate.h"
#include "dynarmic/common/bit_util.h"
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
namespace Dynarmic::Backend::X64 {
@ -65,7 +66,7 @@ void A64JitState::SetFpcr(u32 value) {
const std::array<u32, 4> MXCSR_RMode{0x0, 0x4000, 0x2000, 0x6000};
guest_MXCSR |= MXCSR_RMode[(value >> 22) & 0x3];
if (Common::Bit<24>(value)) {
if (mcl::bit::get_bit<24>(value)) {
guest_MXCSR |= (1 << 15); // SSE Flush to Zero
guest_MXCSR |= (1 << 6); // SSE Denormals are Zero
}

View File

@ -7,8 +7,9 @@
#include <array>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
namespace Dynarmic::Backend::X64 {

View File

@ -8,11 +8,11 @@
#include <algorithm>
#include <vector>
#include <mcl/iterator/reverse.hpp>
#include <mcl/stdint.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/iterator_util.h"
namespace Dynarmic::Backend::X64 {
@ -97,7 +97,7 @@ void ABI_PopRegistersAndAdjustStack(BlockOfCode& code, size_t frame_size, const
code.add(rsp, u32(frame_info.stack_subtraction));
}
for (HostLoc gpr : Common::Reverse(regs)) {
for (HostLoc gpr : mcl::iterator::reverse(regs)) {
if (HostLocIsGPR(gpr)) {
code.pop(HostLocToReg64(gpr));
}

View File

@ -6,8 +6,9 @@
#include <array>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/hostloc.h"
#include "dynarmic/common/common_types.h"
namespace Dynarmic::Backend::X64 {

View File

@ -15,6 +15,8 @@
#include <array>
#include <cstring>
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_jitstate.h"
@ -22,8 +24,6 @@
#include "dynarmic/backend/x64/hostloc.h"
#include "dynarmic/backend/x64/perf_map.h"
#include "dynarmic/backend/x64/stack_layout.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
namespace Dynarmic::Backend::X64 {
@ -52,6 +52,41 @@ constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024;
class CustomXbyakAllocator : public Xbyak::Allocator {
public:
#ifndef _WIN32
static constexpr size_t PAGE_SIZE = 4096;
// Can't subclass Xbyak::MmapAllocator because it is not a pure interface
// and doesn't expose its construtor
uint8_t* alloc(size_t size) override {
// Waste a page to store the size
size += PAGE_SIZE;
# if defined(MAP_ANONYMOUS)
int mode = MAP_PRIVATE | MAP_ANONYMOUS;
# elif defined(MAP_ANON)
int mode = MAP_PRIVATE | MAP_ANON;
# else
# error "not supported"
# endif
# ifdef MAP_JIT
mode |= MAP_JIT;
# endif
void* p = mmap(nullptr, size, PROT_READ | PROT_WRITE, mode, -1, 0);
if (p == MAP_FAILED) {
throw Xbyak::Error(Xbyak::ERR_CANT_ALLOC);
}
std::memcpy(p, &size, sizeof(size_t));
return static_cast<uint8_t*>(p) + PAGE_SIZE;
}
void free(uint8_t* p) override {
size_t size;
std::memcpy(&size, p - PAGE_SIZE, sizeof(size_t));
munmap(p - PAGE_SIZE, size);
}
#endif
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
bool useProtect() const override { return false; }
#endif
@ -134,8 +169,8 @@ HostFeature GetHostFeatures() {
if (cpu_info.has(Cpu::tAMD)) {
std::array<u32, 4> data{};
cpu_info.getCpuid(1, data.data());
const u32 family_base = Common::Bits<8, 11>(data[0]);
const u32 family_extended = Common::Bits<20, 27>(data[0]);
const u32 family_base = mcl::bit::get_bits<8, 11>(data[0]);
const u32 family_extended = mcl::bit::get_bits<20, 27>(data[0]);
const u32 family = family_base + family_extended;
if (family >= 0x19)
features |= HostFeature::FastBMI2;

View File

@ -10,6 +10,7 @@
#include <memory>
#include <type_traits>
#include <mcl/stdint.hpp>
#include <xbyak/xbyak.h>
#include <xbyak/xbyak_util.h>
@ -19,7 +20,6 @@
#include "dynarmic/backend/x64/host_feature.h"
#include "dynarmic/backend/x64/jitstate_info.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/interface/halt_reason.h"
namespace Dynarmic::Backend::X64 {

View File

@ -7,10 +7,9 @@
#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
#include <mcl/stdint.hpp>
#include <tsl/robin_set.h>
#include "dynarmic/common/common_types.h"
namespace Dynarmic::Backend::X64 {
template<typename ProgramCounterType>

View File

@ -8,10 +8,9 @@
#include <functional>
#include <vector>
#include <mcl/stdint.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/common/common_types.h"
namespace Dynarmic::Backend::X64 {
using RegList = std::vector<Xbyak::Reg64>;

View File

@ -7,8 +7,9 @@
#include <cstring>
#include <mcl/assert.hpp>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/common/assert.h"
namespace Dynarmic::Backend::X64 {

View File

@ -8,11 +8,10 @@
#include <bit>
#include <utility>
#include <mcl/stdint.hpp>
#include <tsl/robin_map.h>
#include <xbyak/xbyak.h>
#include "dynarmic/common/common_types.h"
namespace Dynarmic::Backend::X64 {
class BlockOfCode;

View File

@ -7,8 +7,9 @@
#include <optional>
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include <mcl/bit/bit_field.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/common/fp/rounding_mode.h"
namespace Dynarmic::Backend::X64 {
@ -124,14 +125,14 @@ constexpr u32 FixupLUT(FpFixup src_qnan = FpFixup::A,
FpFixup src_pos = FpFixup::A,
FpFixup src_neg = FpFixup::A) {
u32 fixup_lut = 0;
fixup_lut = Common::ModifyBits<0, 3, u32>(fixup_lut, static_cast<u32>(src_qnan));
fixup_lut = Common::ModifyBits<4, 7, u32>(fixup_lut, static_cast<u32>(src_snan));
fixup_lut = Common::ModifyBits<8, 11, u32>(fixup_lut, static_cast<u32>(src_zero));
fixup_lut = Common::ModifyBits<12, 15, u32>(fixup_lut, static_cast<u32>(src_posone));
fixup_lut = Common::ModifyBits<16, 19, u32>(fixup_lut, static_cast<u32>(src_neginf));
fixup_lut = Common::ModifyBits<20, 23, u32>(fixup_lut, static_cast<u32>(src_posinf));
fixup_lut = Common::ModifyBits<24, 27, u32>(fixup_lut, static_cast<u32>(src_pos));
fixup_lut = Common::ModifyBits<28, 31, u32>(fixup_lut, static_cast<u32>(src_neg));
fixup_lut = mcl::bit::set_bits<0, 3, u32>(fixup_lut, static_cast<u32>(src_qnan));
fixup_lut = mcl::bit::set_bits<4, 7, u32>(fixup_lut, static_cast<u32>(src_snan));
fixup_lut = mcl::bit::set_bits<8, 11, u32>(fixup_lut, static_cast<u32>(src_zero));
fixup_lut = mcl::bit::set_bits<12, 15, u32>(fixup_lut, static_cast<u32>(src_posone));
fixup_lut = mcl::bit::set_bits<16, 19, u32>(fixup_lut, static_cast<u32>(src_neginf));
fixup_lut = mcl::bit::set_bits<20, 23, u32>(fixup_lut, static_cast<u32>(src_posinf));
fixup_lut = mcl::bit::set_bits<24, 27, u32>(fixup_lut, static_cast<u32>(src_pos));
fixup_lut = mcl::bit::set_bits<28, 31, u32>(fixup_lut, static_cast<u32>(src_neg));
return fixup_lut;
}
@ -153,8 +154,8 @@ enum class FpRangeSign : u8 {
// Generates 8-bit immediate LUT for vrange instruction
constexpr u8 FpRangeLUT(FpRangeSelect range_select, FpRangeSign range_sign) {
u8 range_lut = 0;
range_lut = Common::ModifyBits<0, 1, u8>(range_lut, static_cast<u8>(range_select));
range_lut = Common::ModifyBits<2, 3, u8>(range_lut, static_cast<u8>(range_sign));
range_lut = mcl::bit::set_bits<0, 1, u8>(range_lut, static_cast<u8>(range_select));
range_lut = mcl::bit::set_bits<2, 3, u8>(range_lut, static_cast<u8>(range_sign));
return range_lut;
}

View File

@ -8,11 +8,11 @@
#include <cstring>
#include <utility>
#include <mp/traits/function_info.h>
#include <mcl/bit_cast.hpp>
#include <mcl/stdint.hpp>
#include <mcl/type_traits/function_info.hpp>
#include "dynarmic/backend/x64/callback.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/common_types.h"
namespace Dynarmic {
namespace Backend::X64 {
@ -32,25 +32,25 @@ struct ThunkBuilder<R (C::*)(Args...), mfp> {
} // namespace impl
template<auto mfp>
ArgCallback DevirtualizeGeneric(mp::class_type<decltype(mfp)>* this_) {
ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)>* this_) {
return ArgCallback{&impl::ThunkBuilder<decltype(mfp), mfp>::Thunk, reinterpret_cast<u64>(this_)};
}
template<auto mfp>
ArgCallback DevirtualizeWindows(mp::class_type<decltype(mfp)>* this_) {
ArgCallback DevirtualizeWindows(mcl::class_type<decltype(mfp)>* this_) {
static_assert(sizeof(mfp) == 8);
return ArgCallback{Common::BitCast<u64>(mfp), reinterpret_cast<u64>(this_)};
return ArgCallback{mcl::bit_cast<u64>(mfp), reinterpret_cast<u64>(this_)};
}
template<auto mfp>
ArgCallback DevirtualizeItanium(mp::class_type<decltype(mfp)>* this_) {
ArgCallback DevirtualizeItanium(mcl::class_type<decltype(mfp)>* this_) {
struct MemberFunctionPointer {
/// For a non-virtual function, this is a simple function pointer.
/// For a virtual function, it is (1 + virtual table offset in bytes).
u64 ptr;
/// The required adjustment to `this`, prior to the call.
u64 adj;
} mfp_struct = Common::BitCast<MemberFunctionPointer>(mfp);
} mfp_struct = mcl::bit_cast<MemberFunctionPointer>(mfp);
static_assert(sizeof(MemberFunctionPointer) == 16);
static_assert(sizeof(MemberFunctionPointer) == sizeof(mfp));
@ -58,14 +58,14 @@ ArgCallback DevirtualizeItanium(mp::class_type<decltype(mfp)>* this_) {
u64 fn_ptr = mfp_struct.ptr;
u64 this_ptr = reinterpret_cast<u64>(this_) + mfp_struct.adj;
if (mfp_struct.ptr & 1) {
u64 vtable = Common::BitCastPointee<u64>(this_ptr);
fn_ptr = Common::BitCastPointee<u64>(vtable + fn_ptr - 1);
u64 vtable = mcl::bit_cast_pointee<u64>(this_ptr);
fn_ptr = mcl::bit_cast_pointee<u64>(vtable + fn_ptr - 1);
}
return ArgCallback{fn_ptr, this_ptr};
}
template<auto mfp>
ArgCallback Devirtualize(mp::class_type<decltype(mfp)>* this_) {
ArgCallback Devirtualize(mcl::class_type<decltype(mfp)>* this_) {
#if defined(__APPLE__) || defined(linux) || defined(__linux) || defined(__linux__)
return DevirtualizeItanium<mfp>(this_);
#elif defined(__MINGW64__)

View File

@ -7,16 +7,16 @@
#include <iterator>
#include <mcl/assert.hpp>
#include <mcl/bit/bit_field.hpp>
#include <mcl/scope_exit.hpp>
#include <mcl/stdint.hpp>
#include <tsl/robin_set.h>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/nzcv_util.h"
#include "dynarmic/backend/x64/perf_map.h"
#include "dynarmic/backend/x64/stack_layout.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/scope_exit.h"
#include "dynarmic/common/variant_util.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
@ -164,10 +164,10 @@ void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
if (args[0].IsImmediate()) {
const Xbyak::Reg32 nzcv = ctx.reg_alloc.ScratchGpr().cvt32();
u32 value = 0;
value |= Common::Bit<31>(args[0].GetImmediateU32()) ? (1 << 15) : 0;
value |= Common::Bit<30>(args[0].GetImmediateU32()) ? (1 << 14) : 0;
value |= Common::Bit<29>(args[0].GetImmediateU32()) ? (1 << 8) : 0;
value |= Common::Bit<28>(args[0].GetImmediateU32()) ? (1 << 0) : 0;
value |= mcl::bit::get_bit<31>(args[0].GetImmediateU32()) ? (1 << 15) : 0;
value |= mcl::bit::get_bit<30>(args[0].GetImmediateU32()) ? (1 << 14) : 0;
value |= mcl::bit::get_bit<29>(args[0].GetImmediateU32()) ? (1 << 8) : 0;
value |= mcl::bit::get_bit<28>(args[0].GetImmediateU32()) ? (1 << 0) : 0;
code.mov(nzcv, value);
ctx.reg_alloc.DefineValue(inst, nzcv);
} else if (code.HasHostFeature(HostFeature::FastBMI2)) {
@ -204,44 +204,44 @@ Xbyak::Label EmitX64::EmitCond(IR::Cond cond) {
// add al, 0x7F restores OF
switch (cond) {
case IR::Cond::EQ: //z
case IR::Cond::EQ: // z
code.sahf();
code.jz(pass);
break;
case IR::Cond::NE: //!z
case IR::Cond::NE: //! z
code.sahf();
code.jnz(pass);
break;
case IR::Cond::CS: //c
case IR::Cond::CS: // c
code.sahf();
code.jc(pass);
break;
case IR::Cond::CC: //!c
case IR::Cond::CC: //! c
code.sahf();
code.jnc(pass);
break;
case IR::Cond::MI: //n
case IR::Cond::MI: // n
code.sahf();
code.js(pass);
break;
case IR::Cond::PL: //!n
case IR::Cond::PL: //! n
code.sahf();
code.jns(pass);
break;
case IR::Cond::VS: //v
case IR::Cond::VS: // v
code.cmp(al, 0x81);
code.jo(pass);
break;
case IR::Cond::VC: //!v
case IR::Cond::VC: //! v
code.cmp(al, 0x81);
code.jno(pass);
break;
case IR::Cond::HI: //c & !z
case IR::Cond::HI: // c & !z
code.sahf();
code.cmc();
code.ja(pass);
break;
case IR::Cond::LS: //!c | z
case IR::Cond::LS: //! c | z
code.sahf();
code.cmc();
code.jna(pass);

View File

@ -11,13 +11,13 @@
#include <type_traits>
#include <vector>
#include <mcl/bitsizeof.hpp>
#include <tsl/robin_map.h>
#include <tsl/robin_set.h>
#include <xbyak/xbyak_util.h>
#include "dynarmic/backend/x64/exception_handler.h"
#include "dynarmic/backend/x64/reg_alloc.h"
#include "dynarmic/common/bit_util.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/ir/location_descriptor.h"
#include "dynarmic/ir/terminal.h"
@ -41,10 +41,10 @@ using A64FullVectorWidth = std::integral_constant<size_t, 128>;
// relative to the size of a vector register. e.g. T = u32 would result
// in a std::array<u32, 4>.
template<typename T>
using VectorArray = std::array<T, A64FullVectorWidth::value / Common::BitSize<T>()>;
using VectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T>>;
template<typename T>
using HalfVectorArray = std::array<T, A64FullVectorWidth::value / Common::BitSize<T>() / 2>;
using HalfVectorArray = std::array<T, A64FullVectorWidth::value / mcl::bitsizeof<T> / 2>;
struct EmitContext {
EmitContext(RegAlloc& reg_alloc, IR::Block& block);

View File

@ -3,10 +3,11 @@
* SPDX-License-Identifier: 0BSD
*/
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/abi.h"
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/crypto/aes.h"
#include "dynarmic/ir/microinstruction.h"

View File

@ -6,10 +6,11 @@
#include <cstddef>
#include <type_traits>
#include <mcl/assert.hpp>
#include <mcl/stdint.hpp>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
@ -146,44 +147,44 @@ static void EmitConditionalSelect(BlockOfCode& code, EmitContext& ctx, IR::Inst*
// add al, 0x7F restores OF
switch (args[0].GetImmediateCond()) {
case IR::Cond::EQ: //z
case IR::Cond::EQ: // z
code.sahf();
code.cmovz(else_, then_);
break;
case IR::Cond::NE: //!z
case IR::Cond::NE: //! z
code.sahf();
code.cmovnz(else_, then_);
break;
case IR::Cond::CS: //c
case IR::Cond::CS: // c
code.sahf();
code.cmovc(else_, then_);
break;
case IR::Cond::CC: //!c
case IR::Cond::CC: //! c
code.sahf();
code.cmovnc(else_, then_);
break;
case IR::Cond::MI: //n
case IR::Cond::MI: // n
code.sahf();
code.cmovs(else_, then_);
break;
case IR::Cond::PL: //!n
case IR::Cond::PL: //! n
code.sahf();
code.cmovns(else_, then_);
break;
case IR::Cond::VS: //v
case IR::Cond::VS: // v
code.cmp(nzcv.cvt8(), 0x81);
code.cmovo(else_, then_);
break;
case IR::Cond::VC: //!v
case IR::Cond::VC: //! v
code.cmp(nzcv.cvt8(), 0x81);
code.cmovno(else_, then_);
break;
case IR::Cond::HI: //c & !z
case IR::Cond::HI: // c & !z
code.sahf();
code.cmc();
code.cmova(else_, then_);
break;
case IR::Cond::LS: //!c | z
case IR::Cond::LS: //! c | z
code.sahf();
code.cmc();
code.cmovna(else_, then_);

View File

@ -7,20 +7,20 @@
#include <type_traits>
#include <utility>
#include <mp/metavalue/lift_value.h>
#include <mp/traits/integer_of_size.h>
#include <mp/typelist/cartesian_product.h>
#include <mp/typelist/lift_sequence.h>
#include <mp/typelist/list.h>
#include <mp/typelist/lower_to_tuple.h>
#include <mcl/assert.hpp>
#include <mcl/mp/metavalue/lift_value.hpp>
#include <mcl/mp/typelist/cartesian_product.hpp>
#include <mcl/mp/typelist/lift_sequence.hpp>
#include <mcl/mp/typelist/list.hpp>
#include <mcl/mp/typelist/lower_to_tuple.hpp>
#include <mcl/stdint.hpp>
#include <mcl/type_traits/integer_of_size.hpp>
#include "dynarmic/backend/x64/abi.h"
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/constants.h"
#include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/common/assert.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/common/fp/fpsr.h"
#include "dynarmic/common/fp/info.h"
@ -34,6 +34,7 @@
namespace Dynarmic::Backend::X64 {
using namespace Xbyak::util;
namespace mp = mcl::mp;
namespace {
@ -173,7 +174,7 @@ void PostProcessNaN(BlockOfCode& code, Xbyak::Xmm result, Xbyak::Xmm tmp) {
// We allow for the case where op1 and result are the same register. We do not read from op1 once result is written to.
template<size_t fsize>
void EmitPostProcessNaNs(BlockOfCode& code, Xbyak::Xmm result, Xbyak::Xmm op1, Xbyak::Xmm op2, Xbyak::Reg64 tmp, Xbyak::Label end) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT exponent_mask = FP::FPInfo<FPT>::exponent_mask;
constexpr FPT mantissa_msb = FP::FPInfo<FPT>::mantissa_msb;
constexpr u8 mantissa_msb_bit = static_cast<u8>(FP::FPInfo<FPT>::explicit_mantissa_width - 1);
@ -267,7 +268,7 @@ void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
template<size_t fsize, typename Function>
void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -324,7 +325,7 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
template<size_t fsize>
void FPAbs(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT non_sign_mask = FP::FPInfo<FPT>::sign_mask - FPT(1u);
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -350,7 +351,7 @@ void EmitX64::EmitFPAbs64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
void FPNeg(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT sign_mask = FP::FPInfo<FPT>::sign_mask;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -440,7 +441,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize, bool is_max>
static void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT default_nan = FP::FPInfo<FPT>::DefaultNaN();
constexpr u8 mantissa_msb_bit = static_cast<u8>(FP::FPInfo<FPT>::explicit_mantissa_width - 1);
@ -592,7 +593,7 @@ void EmitX64::EmitFPMul64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -697,7 +698,7 @@ void EmitX64::EmitFPMulAdd64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -755,7 +756,7 @@ void EmitX64::EmitFPMulX64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRecipEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
if constexpr (fsize != 16) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_ReducedErrorFP)) {
@ -801,7 +802,7 @@ void EmitX64::EmitFPRecipEstimate64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRecipExponent(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, args[0]);
@ -824,7 +825,7 @@ void EmitX64::EmitFPRecipExponent64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -949,7 +950,7 @@ static void EmitFPRound(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, siz
constexpr size_t fsize = std::get<0>(t);
constexpr FP::RoundingMode rounding_mode = std::get<1>(t);
constexpr bool exact = std::get<2>(t);
using InputSize = mp::unsigned_integer_of_size<fsize>;
using InputSize = mcl::unsigned_integer_of_size<fsize>;
return FP::FPRoundInt<InputSize>(static_cast<InputSize>(input), fpcr, rounding_mode, exact, fpsr);
})};
@ -977,7 +978,7 @@ void EmitX64::EmitFPRoundInt64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
if constexpr (fsize != 16) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_ReducedErrorFP)) {
@ -1156,7 +1157,7 @@ void EmitX64::EmitFPRSqrtEstimate64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -1589,7 +1590,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
constexpr auto t = mp::lower_to_tuple_v<decltype(args)>;
constexpr size_t fbits = std::get<0>(t);
constexpr FP::RoundingMode rounding_mode = std::get<1>(t);
using FPT = mp::unsigned_integer_of_size<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
return FP::FPToFixed<FPT>(isize, static_cast<FPT>(input), fbits, unsigned_, fpcr, rounding_mode, fpsr);
})};

Some files were not shown because too many files have changed in this diff Show More