Browse Source

Revert "[dynarmic] replace mcl::bit_cast with std::bit_cast; fix IR_emit codepath warnings for UNREACHABLE(); remove type trait mcl::integer_of_size dependency (#2775)" (#2863)

This reverts commit 61ab1be0e7.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2863
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
pull/2865/head
unknown 3 months ago
committed by crueter
parent
commit
6b01c13975
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 3
      src/dynarmic/src/dynarmic/CMakeLists.txt
  2. 22
      src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp
  3. 30
      src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp
  4. 7
      src/dynarmic/src/dynarmic/backend/arm64/abi.h
  5. 13
      src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp
  6. 13
      src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h
  7. 12
      src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp
  8. 11
      src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp
  9. 26
      src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp
  10. 21
      src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp
  11. 6
      src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp
  12. 15
      src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp
  13. 20
      src/dynarmic/src/dynarmic/backend/exception_handler.h
  14. 9
      src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp
  15. 2
      src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c
  16. 16
      src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp
  17. 2
      src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp
  18. 7
      src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp
  19. 4
      src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp
  20. 5
      src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp
  21. 1
      src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp
  22. 4
      src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp
  23. 5
      src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp
  24. 2
      src/dynarmic/src/dynarmic/backend/x64/block_of_code.h
  25. 12
      src/dynarmic/src/dynarmic/backend/x64/devirtualize.h
  26. 162
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp
  27. 87
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc
  28. 12
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h
  29. 7
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp
  30. 58
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp
  31. 19
      src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp
  32. 8
      src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp
  33. 9
      src/dynarmic/src/dynarmic/backend/x64/perf_map.h
  34. 2
      src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp
  35. 13
      src/dynarmic/src/dynarmic/common/always_false.h
  36. 45
      src/dynarmic/src/dynarmic/common/assert.h
  37. 18
      src/dynarmic/src/dynarmic/common/cast_util.h
  38. 4
      src/dynarmic/src/dynarmic/common/fp/util.h
  39. 5
      src/dynarmic/src/dynarmic/common/llvm_disassemble.cpp
  40. 31
      src/dynarmic/src/dynarmic/common/type_util.h
  41. 2
      src/dynarmic/src/dynarmic/ir/ir_emitter.cpp
  42. 10
      src/dynarmic/src/dynarmic/ir/ir_emitter.h
  43. 1
      src/dynarmic/tests/test_generator.cpp

3
src/dynarmic/src/dynarmic/CMakeLists.txt

@ -6,9 +6,10 @@ add_library(dynarmic STATIC
backend/block_range_information.cpp
backend/block_range_information.h
backend/exception_handler.h
common/always_false.h
common/assert.cpp
common/assert.h
common/type_util.h
common/cast_util.h
common/common_types.h
common/crypto/aes.cpp
common/crypto/aes.h

22
src/dynarmic/src/dynarmic/backend/arm64/a32_address_space.cpp

@ -13,7 +13,7 @@
#include "dynarmic/backend/arm64/devirtualize.h"
#include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/stack_layout.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
#include "dynarmic/frontend/A32/translate/a32_translate.h"
@ -93,9 +93,9 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -151,9 +151,9 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -219,7 +219,7 @@ void A32AddressSpace::EmitPrelude() {
code.MOV(Xstate, X1);
code.MOV(Xhalt, X2);
if (conf.page_table) {
code.MOV(Xpagetable, std::bit_cast<u64>(conf.page_table));
code.MOV(Xpagetable, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.MOV(Xfastmem, *conf.fastmem_pointer);
@ -258,7 +258,7 @@ void A32AddressSpace::EmitPrelude() {
code.MOV(Xstate, X1);
code.MOV(Xhalt, X2);
if (conf.page_table) {
code.MOV(Xpagetable, std::bit_cast<u64>(conf.page_table));
code.MOV(Xpagetable, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.MOV(Xfastmem, *conf.fastmem_pointer);
@ -317,9 +317,9 @@ void A32AddressSpace::EmitPrelude() {
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(this));
code.dx(mcl::bit_cast<u64>(this));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
}
prelude_info.return_from_run_code = code.xptr<void*>();
@ -347,7 +347,7 @@ void A32AddressSpace::EmitPrelude() {
code.align(8);
code.l(l_return_to_dispatcher);
code.dx(std::bit_cast<u64>(prelude_info.return_to_dispatcher));
code.dx(mcl::bit_cast<u64>(prelude_info.return_to_dispatcher));
prelude_info.end_of_prelude = code.offset();
@ -369,7 +369,7 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
.check_halt_on_memory_access = conf.check_halt_on_memory_access,
.page_table_pointer = std::bit_cast<u64>(conf.page_table),
.page_table_pointer = mcl::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = 32,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
.silently_mirror_page_table = true,

30
src/dynarmic/src/dynarmic/backend/arm64/a64_address_space.cpp

@ -13,7 +13,7 @@
#include "dynarmic/backend/arm64/devirtualize.h"
#include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/stack_layout.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
#include "dynarmic/frontend/A64/translate/a64_translate.h"
#include "dynarmic/interface/A64/config.h"
@ -92,9 +92,9 @@ static void* EmitExclusiveReadCallTrampoline(oaknut::CodeGenerator& code, const
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -150,9 +150,9 @@ static void* EmitExclusiveWriteCallTrampoline(oaknut::CodeGenerator& code, const
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -235,9 +235,9 @@ static void* EmitExclusiveRead128CallTrampoline(oaknut::CodeGenerator& code, con
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -317,9 +317,9 @@ static void* EmitExclusiveWrite128CallTrampoline(oaknut::CodeGenerator& code, co
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(&conf));
code.dx(mcl::bit_cast<u64>(&conf));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
return target;
}
@ -396,7 +396,7 @@ void A64AddressSpace::EmitPrelude() {
code.MOV(Xstate, X1);
code.MOV(Xhalt, X2);
if (conf.page_table) {
code.MOV(Xpagetable, std::bit_cast<u64>(conf.page_table));
code.MOV(Xpagetable, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.MOV(Xfastmem, *conf.fastmem_pointer);
@ -434,7 +434,7 @@ void A64AddressSpace::EmitPrelude() {
code.MOV(Xstate, X1);
code.MOV(Xhalt, X2);
if (conf.page_table) {
code.MOV(Xpagetable, std::bit_cast<u64>(conf.page_table));
code.MOV(Xpagetable, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.MOV(Xfastmem, *conf.fastmem_pointer);
@ -492,9 +492,9 @@ void A64AddressSpace::EmitPrelude() {
code.align(8);
code.l(l_this);
code.dx(std::bit_cast<u64>(this));
code.dx(mcl::bit_cast<u64>(this));
code.l(l_addr);
code.dx(std::bit_cast<u64>(Common::FptrCast(fn)));
code.dx(mcl::bit_cast<u64>(Common::FptrCast(fn)));
}
prelude_info.return_from_run_code = code.xptr<void*>();
@ -522,7 +522,7 @@ void A64AddressSpace::EmitPrelude() {
code.align(8);
code.l(l_return_to_dispatcher);
code.dx(std::bit_cast<u64>(prelude_info.return_to_dispatcher));
code.dx(mcl::bit_cast<u64>(prelude_info.return_to_dispatcher));
prelude_info.end_of_prelude = code.offset();
@ -544,7 +544,7 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
.check_halt_on_memory_access = conf.check_halt_on_memory_access,
.page_table_pointer = std::bit_cast<u64>(conf.page_table),
.page_table_pointer = mcl::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = conf.page_table_address_space_bits,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
.silently_mirror_page_table = conf.silently_mirror_page_table,

7
src/dynarmic/src/dynarmic/backend/arm64/abi.h

@ -17,6 +17,7 @@
#include "dynarmic/common/assert.h"
#include <oaknut/oaknut.hpp>
#include "dynarmic/common/always_false.h"
namespace Dynarmic::Backend::Arm64 {
@ -36,8 +37,7 @@ constexpr auto Rscratch0() {
} else if constexpr (bitsize == 64) {
return Xscratch0;
} else {
// TODO: This codepath is regarded as "takeable" on gcc12
return Xscratch0; //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<bitsize>>);
}
}
@ -48,8 +48,7 @@ constexpr auto Rscratch1() {
} else if constexpr (bitsize == 64) {
return Xscratch1;
} else {
// TODO: This codepath is regarded as "takeable" on gcc12
return Xscratch1; //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<bitsize>>);
}
}

13
src/dynarmic/src/dynarmic/backend/arm64/address_space.cpp

@ -1,14 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <cstdio>
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/backend/arm64/a64_address_space.h"
#include "dynarmic/backend/arm64/a64_jitstate.h"
@ -16,7 +13,7 @@
#include "dynarmic/backend/arm64/devirtualize.h"
#include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/stack_layout.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/common/llvm_disassemble.h"
#include "dynarmic/interface/exclusive_monitor.h"
@ -102,7 +99,7 @@ void AddressSpace::ClearCache() {
void AddressSpace::DumpDisassembly() const {
for (u32* ptr = mem.ptr(); ptr < code.xptr<u32*>(); ptr++) {
std::printf("%s", Common::DisassembleAArch64(*ptr, std::bit_cast<u64>(ptr)).c_str());
std::printf("%s", Common::DisassembleAArch64(*ptr, mcl::bit_cast<u64>(ptr)).c_str());
}
}
@ -319,7 +316,7 @@ void AddressSpace::RelinkForDescriptor(IR::LocationDescriptor target_descriptor,
FakeCall AddressSpace::FastmemCallback(u64 host_pc) {
{
const auto host_ptr = std::bit_cast<CodePtr>(host_pc);
const auto host_ptr = mcl::bit_cast<CodePtr>(host_pc);
const auto entry_point = ReverseGetEntryPoint(host_ptr);
if (!entry_point) {

13
src/dynarmic/src/dynarmic/backend/arm64/devirtualize.h

@ -8,8 +8,7 @@
#pragma once
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/common/common_types.h"
#include <mcl/type_traits/function_info.hpp>
@ -24,7 +23,7 @@ struct DevirtualizedCall {
template<auto mfp>
DevirtualizedCall DevirtualizeWindows(mcl::class_type<decltype(mfp)>* this_) {
static_assert(sizeof(mfp) == 8);
return DevirtualizedCall{std::bit_cast<u64>(mfp), reinterpret_cast<u64>(this_)};
return DevirtualizedCall{mcl::bit_cast<u64>(mfp), reinterpret_cast<u64>(this_)};
}
// https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst#representation-of-pointer-to-member-function
@ -35,16 +34,16 @@ DevirtualizedCall DevirtualizeDefault(mcl::class_type<decltype(mfp)>* this_) {
u64 ptr;
// LSB is discriminator for if function is virtual. Other bits are this adjustment.
u64 adj;
} mfp_struct = std::bit_cast<MemberFunctionPointer>(mfp);
} mfp_struct = mcl::bit_cast<MemberFunctionPointer>(mfp);
static_assert(sizeof(MemberFunctionPointer) == 16);
static_assert(sizeof(MemberFunctionPointer) == sizeof(mfp));
u64 fn_ptr = mfp_struct.ptr;
u64 this_ptr = std::bit_cast<u64>(this_) + (mfp_struct.adj >> 1);
u64 this_ptr = mcl::bit_cast<u64>(this_) + (mfp_struct.adj >> 1);
if (mfp_struct.adj & 1) {
u64 vtable = std::bit_cast<u64>(this_ptr);
fn_ptr = std::bit_cast<u64>(vtable + fn_ptr);
u64 vtable = mcl::bit_cast_pointee<u64>(this_ptr);
fn_ptr = mcl::bit_cast_pointee<u64>(vtable + fn_ptr);
}
return DevirtualizedCall{fn_ptr, this_ptr};
}

12
src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_a64.cpp

@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <oaknut/oaknut.hpp>
#include "dynarmic/backend/arm64/a64_jitstate.h"
@ -499,7 +495,7 @@ template<>
void EmitIR<IR::Opcode::A64GetTPIDR>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto Xvalue = ctx.reg_alloc.WriteX(inst);
RegAlloc::Realize(Xvalue);
code.MOV(Xscratch0, std::bit_cast<u64>(ctx.conf.tpidr_el0));
code.MOV(Xscratch0, mcl::bit_cast<u64>(ctx.conf.tpidr_el0));
code.LDR(Xvalue, Xscratch0);
}
@ -507,7 +503,7 @@ template<>
void EmitIR<IR::Opcode::A64GetTPIDRRO>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto Xvalue = ctx.reg_alloc.WriteX(inst);
RegAlloc::Realize(Xvalue);
code.MOV(Xscratch0, std::bit_cast<u64>(ctx.conf.tpidrro_el0));
code.MOV(Xscratch0, mcl::bit_cast<u64>(ctx.conf.tpidrro_el0));
code.LDR(Xvalue, Xscratch0);
}
@ -516,7 +512,7 @@ void EmitIR<IR::Opcode::A64SetTPIDR>(oaknut::CodeGenerator& code, EmitContext& c
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
auto Xvalue = ctx.reg_alloc.ReadX(args[0]);
RegAlloc::Realize(Xvalue);
code.MOV(Xscratch0, std::bit_cast<u64>(ctx.conf.tpidr_el0));
code.MOV(Xscratch0, mcl::bit_cast<u64>(ctx.conf.tpidr_el0));
code.STR(Xvalue, Xscratch0);
}

11
src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_memory.cpp

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@ -10,8 +7,8 @@
#include <optional>
#include <utility>
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <oaknut/oaknut.hpp>
#include "dynarmic/backend/arm64/abi.h"
@ -551,7 +548,7 @@ void FastmemEmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::In
FastmemPatchInfo{
.marker = marker,
.fc = FakeCall{
.call_pc = std::bit_cast<u64>(code.xptr<void*>()),
.call_pc = mcl::bit_cast<u64>(code.xptr<void*>()),
},
.recompile = ctx.conf.recompile_on_fastmem_failure,
});
@ -601,7 +598,7 @@ void FastmemEmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::I
FastmemPatchInfo{
.marker = marker,
.fc = FakeCall{
.call_pc = std::bit_cast<u64>(code.xptr<void*>()),
.call_pc = mcl::bit_cast<u64>(code.xptr<void*>()),
},
.recompile = ctx.conf.recompile_on_fastmem_failure,
});

26
src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector.cpp

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@ -15,6 +12,7 @@
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/common/always_false.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
@ -45,7 +43,7 @@ static void EmitTwoOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, IR:
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qoperand->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -68,7 +66,7 @@ static void EmitTwoOpArrangedWiden(oaknut::CodeGenerator& code, EmitContext& ctx
} else if constexpr (size == 32) {
emit(Qresult->D2(), Qoperand->toD().S2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -83,7 +81,7 @@ static void EmitTwoOpArrangedNarrow(oaknut::CodeGenerator& code, EmitContext& ct
} else if constexpr (size == 64) {
emit(Qresult->toD().S2(), Qoperand->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -106,7 +104,7 @@ static void EmitTwoOpArrangedPairWiden(oaknut::CodeGenerator& code, EmitContext&
} else if constexpr (size == 32) {
emit(Qresult->D2(), Qoperand->S4());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -121,7 +119,7 @@ static void EmitTwoOpArrangedLower(oaknut::CodeGenerator& code, EmitContext& ctx
} else if constexpr (size == 32) {
emit(Qresult->toD().S2(), Qoperand->toD().S2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -149,7 +147,7 @@ static void EmitThreeOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, I
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qa->D2(), Qb->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -174,7 +172,7 @@ static void EmitThreeOpArrangedWiden(oaknut::CodeGenerator& code, EmitContext& c
} else if constexpr (size == 64) {
emit(Qresult->Q1(), Qa->toD().D1(), Qb->toD().D1());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -197,7 +195,7 @@ static void EmitThreeOpArrangedLower(oaknut::CodeGenerator& code, EmitContext& c
} else if constexpr (size == 32) {
emit(Qresult->toD().S2(), Qa->toD().S2(), Qb->toD().S2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -219,7 +217,7 @@ static void EmitSaturatedAccumulate(oaknut::CodeGenerator&, EmitContext& ctx, IR
} else if constexpr (size == 64) {
emit(Qaccumulator->D2(), Qoperand->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
}
@ -240,7 +238,7 @@ static void EmitImmShift(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* ins
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qoperand->D2(), shift_amount);
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
}
@ -268,7 +266,7 @@ static void EmitReduce(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst,
} else if constexpr (size == 64) {
emit(Vresult, Qoperand->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
}

21
src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_floating_point.cpp

@ -6,8 +6,7 @@
* SPDX-License-Identifier: 0BSD
*/
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <mcl/mp/metavalue/lift_value.hpp>
#include <mcl/mp/typelist/cartesian_product.hpp>
#include <mcl/mp/typelist/get.hpp>
@ -15,6 +14,7 @@
#include <mcl/mp/typelist/list.hpp>
#include <mcl/mp/typelist/lower_to_tuple.hpp>
#include <mcl/type_traits/function_info.hpp>
#include <mcl/type_traits/integer_of_size.hpp>
#include <oaknut/oaknut.hpp>
#include "dynarmic/backend/arm64/a32_jitstate.h"
@ -24,7 +24,8 @@
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/always_false.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/common/fp/fpsr.h"
#include "dynarmic/common/fp/info.h"
@ -83,7 +84,7 @@ static void EmitTwoOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, IR:
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qa->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -111,7 +112,7 @@ static void EmitThreeOpArranged(oaknut::CodeGenerator& code, EmitContext& ctx, I
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qa->D2(), Qb->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -134,7 +135,7 @@ static void EmitFMA(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* ins
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qm->D2(), Qn->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -156,7 +157,7 @@ static void EmitFromFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Ins
} else if constexpr (size == 64) {
emit(Qto->D2(), Qfrom->D2(), fbits);
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
});
}
@ -178,7 +179,7 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst)
} else if constexpr (fsize == 64) {
return Qto->D2();
} else {
return Qto->D2(); //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<fsize>>);
}
}();
auto Vfrom = [&] {
@ -187,7 +188,7 @@ void EmitToFixed(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst)
} else if constexpr (fsize == 64) {
return Qfrom->D2();
} else {
return Qfrom->D2(); //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<fsize>>);
}
}();
@ -270,7 +271,7 @@ static void EmitTwoOpFallbackWithoutRegAlloc(oaknut::CodeGenerator& code, EmitCo
ABI_PushRegisters(code, ABI_CALLER_SAVE & ~(1ull << Qresult.index()), stack_size);
code.MOV(Xscratch0, std::bit_cast<u64>(fn));
code.MOV(Xscratch0, mcl::bit_cast<u64>(fn));
code.ADD(X0, SP, 0 * 16);
code.ADD(X1, SP, 1 * 16);
code.MOV(X2, fpcr);

6
src/dynarmic/src/dynarmic/backend/arm64/emit_arm64_vector_saturation.cpp

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@ -15,6 +12,7 @@
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/common/always_false.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
@ -41,7 +39,7 @@ static void Emit(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst, EmitF
} else if constexpr (size == 64) {
emit(Qresult->D2(), Qa->D2(), Qb->D2());
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<size>>);
}
}

15
src/dynarmic/src/dynarmic/backend/arm64/reg_alloc.cpp

@ -11,10 +11,10 @@
#include <algorithm>
#include <array>
#include <iterator>
#include <bit>
#include <numeric>
#include "dynarmic/common/assert.h"
#include <mcl/bit/bit_field.hpp>
#include <mcl/bit_cast.hpp>
#include <mcl/mp/metavalue/lift_value.hpp>
#include "dynarmic/common/common_types.h"
@ -22,6 +22,7 @@
#include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/verbose_debugging_output.h"
#include "dynarmic/common/always_false.h"
namespace Dynarmic::Backend::Arm64 {
@ -245,7 +246,7 @@ void RegAlloc::AssertNoMoreUses() const {
}
void RegAlloc::EmitVerboseDebuggingOutput() {
code.MOV(X19, std::bit_cast<u64>(&PrintVerboseDebuggingOutputLine)); // Non-volatile register
code.MOV(X19, mcl::bit_cast<u64>(&PrintVerboseDebuggingOutputLine)); // Non-volatile register
const auto do_location = [&](HostLocInfo& info, HostLocType type, size_t index) {
using namespace oaknut::util;
@ -300,7 +301,7 @@ int RegAlloc::GenerateImmediate(const IR::Value& value) {
return 0;
} else {
return 0;//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<kind>>);
}
}
@ -369,7 +370,7 @@ int RegAlloc::RealizeReadImpl(const IR::Value& value) {
} else if constexpr (required_kind == HostLoc::Kind::Flags) {
ASSERT_FALSE("A simple read from flags is likely a logic error.");
} else {
return 0;//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<required_kind>>);
}
}
@ -394,7 +395,7 @@ int RegAlloc::RealizeWriteImpl(const IR::Inst* value) {
flags.SetupLocation(value);
return 0;
} else {
return 0; //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<kind>>);
}
}
@ -415,7 +416,7 @@ int RegAlloc::RealizeReadWriteImpl(const IR::Value& read_value, const IR::Inst*
} else if constexpr (kind == HostLoc::Kind::Flags) {
ASSERT_FALSE("Incorrect function for ReadWrite of flags");
} else {
return write_loc; //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<kind>>);
}
}

20
src/dynarmic/src/dynarmic/backend/exception_handler.h

@ -11,17 +11,19 @@
#include <functional>
#include <memory>
#include <optional>
#include <mcl/macro/architecture.hpp>
#include "dynarmic/common/common_types.h"
#if defined(ARCHITECTURE_x86_64)
#if defined(MCL_ARCHITECTURE_X86_64)
namespace Dynarmic::Backend::X64 {
class BlockOfCode;
} // namespace Dynarmic::Backend::X64
#elif defined(ARCHITECTURE_arm64)
#elif defined(MCL_ARCHITECTURE_ARM64)
namespace oaknut {
class CodeBlock;
} // namespace oaknut
#elif defined(ARCHITECTURE_riscv64)
#elif defined(MCL_ARCHITECTURE_RISCV)
namespace Dynarmic::Backend::RV64 {
class CodeBlock;
} // namespace Dynarmic::Backend::RV64
@ -31,16 +33,16 @@ class CodeBlock;
namespace Dynarmic::Backend {
#if defined(ARCHITECTURE_x86_64)
#if defined(MCL_ARCHITECTURE_X86_64)
struct FakeCall {
u64 call_rip;
u64 ret_rip;
};
#elif defined(ARCHITECTURE_arm64)
#elif defined(MCL_ARCHITECTURE_ARM64)
struct FakeCall {
u64 call_pc;
};
#elif defined(ARCHITECTURE_riscv64)
#elif defined(MCL_ARCHITECTURE_RISCV)
struct FakeCall {
};
#else
@ -52,11 +54,11 @@ public:
ExceptionHandler();
~ExceptionHandler();
#if defined(ARCHITECTURE_x86_64)
#if defined(MCL_ARCHITECTURE_X86_64)
void Register(X64::BlockOfCode& code);
#elif defined(ARCHITECTURE_arm64)
#elif defined(MCL_ARCHITECTURE_ARM64)
void Register(oaknut::CodeBlock& mem, std::size_t mem_size);
#elif defined(ARCHITECTURE_riscv64)
#elif defined(MCL_ARCHITECTURE_RISCV)
void Register(RV64::CodeBlock& mem, std::size_t mem_size);
#else
# error "Invalid architecture"

9
src/dynarmic/src/dynarmic/backend/exception_handler_macos.cpp

@ -19,7 +19,8 @@
#include <fmt/format.h>
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <mcl/macro/architecture.hpp>
#include "dynarmic/common/common_types.h"
#include "dynarmic/backend/exception_handler.h"
@ -145,7 +146,7 @@ kern_return_t MachHandler::HandleRequest(x86_thread_state64_t* ts) {
FakeCall fc = iter->cb(ts->__rip);
ts->__rsp -= sizeof(u64);
*std::bit_cast<u64*>(ts->__rsp) = fc.ret_rip;
*mcl::bit_cast<u64*>(ts->__rsp) = fc.ret_rip;
ts->__rip = fc.call_rip;
return KERN_SUCCESS;
@ -270,13 +271,13 @@ ExceptionHandler::~ExceptionHandler() = default;
#if defined(ARCHITECTURE_x86_64)
void ExceptionHandler::Register(X64::BlockOfCode& code) {
const u64 code_begin = std::bit_cast<u64>(code.getCode());
const u64 code_begin = mcl::bit_cast<u64>(code.getCode());
const u64 code_end = code_begin + code.GetTotalCodeSize();
impl = std::make_unique<Impl>(code_begin, code_end);
}
#elif defined(ARCHITECTURE_arm64)
void ExceptionHandler::Register(oaknut::CodeBlock& mem, std::size_t size) {
const u64 code_begin = std::bit_cast<u64>(mem.ptr());
const u64 code_begin = mcl::bit_cast<u64>(mem.ptr());
const u64 code_end = code_begin + size;
impl = std::make_unique<Impl>(code_begin, code_end);
}

2
src/dynarmic/src/dynarmic/backend/exception_handler_macos_mig.c

@ -3,6 +3,8 @@
* SPDX-License-Identifier: 0BSD
*/
#include <mcl/macro/architecture.hpp>
#if defined(ARCHITECTURE_x86_64)
# include "dynarmic/backend/x64/mig/mach_exc_server.c"
#elif defined(ARCHITECTURE_arm64)

16
src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp

@ -27,7 +27,7 @@
#else
# error "Invalid architecture"
#endif
#include <numeric>
#include <mcl/bit_cast.hpp>
namespace Dynarmic::Backend {
@ -122,7 +122,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
if (auto const iter = sig_handler->FindCodeBlockInfo(CTX_RIP); iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->second.cb(CTX_RIP);
CTX_RSP -= sizeof(u64);
*std::bit_cast<u64*>(CTX_RSP) = fc.ret_rip;
*mcl::bit_cast<u64*>(CTX_RSP) = fc.ret_rip;
CTX_RIP = fc.call_rip;
return;
}
@ -187,17 +187,17 @@ private:
ExceptionHandler::ExceptionHandler() = default;
ExceptionHandler::~ExceptionHandler() = default;
#if defined(ARCHITECTURE_x86_64)
#if defined(MCL_ARCHITECTURE_X86_64)
void ExceptionHandler::Register(X64::BlockOfCode& code) {
impl = std::make_unique<Impl>(std::bit_cast<u64>(code.getCode()), code.GetTotalCodeSize());
impl = std::make_unique<Impl>(mcl::bit_cast<u64>(code.getCode()), code.GetTotalCodeSize());
}
#elif defined(ARCHITECTURE_arm64)
#elif defined(MCL_ARCHITECTURE_ARM64)
void ExceptionHandler::Register(oaknut::CodeBlock& mem, std::size_t size) {
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr()), size);
impl = std::make_unique<Impl>(mcl::bit_cast<u64>(mem.ptr()), size);
}
#elif defined(ARCHITECTURE_riscv64)
#elif defined(MCL_ARCHITECTURE_RISCV)
void ExceptionHandler::Register(RV64::CodeBlock& mem, std::size_t size) {
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
impl = std::make_unique<Impl>(mcl::bit_cast<u64>(mem.ptr<u64>()), size);
}
#else
# error "Invalid architecture"

2
src/dynarmic/src/dynarmic/backend/exception_handler_windows.cpp

@ -6,6 +6,8 @@
* SPDX-License-Identifier: 0BSD
*/
#include <mcl/macro/architecture.hpp>
#if defined(ARCHITECTURE_x86_64)
# include "dynarmic/backend/x64/exception_handler_windows.cpp"
#elif defined(ARCHITECTURE_arm64)

7
src/dynarmic/src/dynarmic/backend/riscv64/reg_alloc.cpp

@ -15,6 +15,7 @@
#include <mcl/mp/metavalue/lift_value.hpp>
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/always_false.h"
namespace Dynarmic::Backend::RV64 {
@ -163,7 +164,7 @@ u32 RegAlloc::GenerateImmediate(const IR::Value& value) {
} else if constexpr (kind == HostLoc::Kind::Fpr) {
UNIMPLEMENTED();
} else {
//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<kind>>);
}
return 0;
@ -226,7 +227,7 @@ u32 RegAlloc::RealizeReadImpl(const IR::Value& value) {
fprs[new_location_index].realized = true;
return new_location_index;
} else {
return 0; //static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<required_kind>>);
}
}
@ -253,7 +254,7 @@ u32 RegAlloc::RealizeWriteImpl(const IR::Inst* value) {
setup_location(fprs[new_location_index]);
return new_location_index;
} else {
return 0;//static_assert(false);
static_assert(Common::always_false_v<mcl::mp::lift_value<required_kind>>);
}
}

4
src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64_memory.cpp

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@ -13,6 +10,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_emit_x64.h"

5
src/dynarmic/src/dynarmic/backend/x64/a32_interface.cpp

@ -9,12 +9,11 @@
#include <functional>
#include <memory>
#include <mutex>
#include <bit>
#include <boost/icl/interval_set.hpp>
#include <fmt/format.h>
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <mcl/scope_exit.hpp>
#include "dynarmic/common/common_types.h"
@ -48,7 +47,7 @@ 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, std::bit_cast<u64>(conf.page_table));
code.mov(code.r14, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.mov(code.r13, *conf.fastmem_pointer);

1
src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.cpp

@ -13,6 +13,7 @@
#include "dynarmic/common/assert.h"
#include <mcl/scope_exit.hpp>
#include "dynarmic/common/common_types.h"
#include <mcl/type_traits/integer_of_size.hpp>
#include <boost/container/static_vector.hpp>
#include "dynarmic/backend/x64/a64_jitstate.h"

4
src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64_memory.cpp

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
@ -13,6 +10,7 @@
#include <fmt/format.h>
#include <fmt/ostream.h>
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a64_emit_x64.h"

5
src/dynarmic/src/dynarmic/backend/x64/a64_interface.cpp

@ -9,11 +9,10 @@
#include <cstring>
#include <memory>
#include <mutex>
#include <bit>
#include <boost/icl/interval_set.hpp>
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include <mcl/scope_exit.hpp>
#include "dynarmic/backend/x64/a64_emit_x64.h"
@ -44,7 +43,7 @@ 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, std::bit_cast<u64>(conf.page_table));
code.mov(code.r14, mcl::bit_cast<u64>(conf.page_table));
}
if (conf.fastmem_pointer) {
code.mov(code.r13, *conf.fastmem_pointer);

2
src/dynarmic/src/dynarmic/backend/x64/block_of_code.h

@ -23,7 +23,7 @@
#include "dynarmic/backend/x64/constant_pool.h"
#include "dynarmic/backend/x64/host_feature.h"
#include "dynarmic/backend/x64/jitstate_info.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/interface/halt_reason.h"
#include "dynarmic/ir/cond.h"

12
src/dynarmic/src/dynarmic/backend/x64/devirtualize.h

@ -10,8 +10,8 @@
#include <cstring>
#include <utility>
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/common/common_types.h"
#include <mcl/type_traits/function_info.hpp>
@ -42,7 +42,7 @@ ArgCallback DevirtualizeGeneric(mcl::class_type<decltype(mfp)>* this_) {
template<auto mfp>
ArgCallback DevirtualizeWindows(mcl::class_type<decltype(mfp)>* this_) {
static_assert(sizeof(mfp) == 8);
return ArgCallback{std::bit_cast<u64>(mfp), reinterpret_cast<u64>(this_)};
return ArgCallback{mcl::bit_cast<u64>(mfp), reinterpret_cast<u64>(this_)};
}
template<auto mfp>
@ -53,7 +53,7 @@ ArgCallback DevirtualizeItanium(mcl::class_type<decltype(mfp)>* this_) {
u64 ptr;
/// The required adjustment to `this`, prior to the call.
u64 adj;
} mfp_struct = std::bit_cast<MemberFunctionPointer>(mfp);
} mfp_struct = mcl::bit_cast<MemberFunctionPointer>(mfp);
static_assert(sizeof(MemberFunctionPointer) == 16);
static_assert(sizeof(MemberFunctionPointer) == sizeof(mfp));
@ -61,8 +61,8 @@ ArgCallback DevirtualizeItanium(mcl::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 = std::bit_cast<u64>(this_ptr);
fn_ptr = std::bit_cast<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};
}

162
src/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp

@ -18,13 +18,14 @@
#include <mcl/mp/typelist/list.hpp>
#include <mcl/mp/typelist/lower_to_tuple.hpp>
#include "dynarmic/common/common_types.h"
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#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/type_util.h"
#include "dynarmic/common/cast_util.h"
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/common/fp/fpsr.h"
#include "dynarmic/common/fp/info.h"
@ -35,8 +36,22 @@
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#define FCODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
#define ICODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
namespace Dynarmic::Backend::X64 {
@ -90,7 +105,7 @@ void ForceDenormalsToZero(BlockOfCode& code, std::initializer_list<Xbyak::Xmm> t
for (const Xbyak::Xmm& xmm : to_daz) {
code.movaps(xmm0, code.Const(xword, fsize == 32 ? f32_non_sign_mask : f64_non_sign_mask));
code.andps(xmm0, xmm);
if (fsize == 32) {
if constexpr (fsize == 32) {
code.pcmpgtd(xmm0, code.Const(xword, f32_smallest_normal - 1));
} else if (code.HasHostFeature(HostFeature::SSE42)) {
code.pcmpgtq(xmm0, code.Const(xword, f64_smallest_normal - 1));
@ -105,11 +120,13 @@ void ForceDenormalsToZero(BlockOfCode& code, std::initializer_list<Xbyak::Xmm> t
template<size_t fsize>
void DenormalsAreZero(BlockOfCode& code, EmitContext& ctx, std::initializer_list<Xbyak::Xmm> to_daz) {
if (ctx.FPCR().FZ())
if (ctx.FPCR().FZ()) {
ForceDenormalsToZero<fsize>(code, to_daz);
}
}
void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm xmm_value, Xbyak::Xmm xmm_scratch, size_t fsize) {
template<size_t fsize>
void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm xmm_value, Xbyak::Xmm xmm_scratch) {
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
constexpr u32 nan_to_zero = FixupLUT(FpFixup::PosZero,
FpFixup::PosZero);
@ -124,7 +141,8 @@ void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm xmm_value, Xbyak::Xmm xmm_scratch,
}
}
void ForceToDefaultNaN(BlockOfCode& code, Xbyak::Xmm result, size_t fsize) {
template<size_t fsize>
void ForceToDefaultNaN(BlockOfCode& code, Xbyak::Xmm result) {
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
const Xbyak::Opmask nan_mask = k1;
FCODE(vfpclasss)(nan_mask, result, u8(FpClass::QNaN | FpClass::SNaN));
@ -190,7 +208,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 = Common::UnsignedIntegerN<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);
@ -218,7 +236,7 @@ void EmitPostProcessNaNs(BlockOfCode& code, Xbyak::Xmm result, Xbyak::Xmm op1, X
}
constexpr size_t shift = fsize == 32 ? 0 : 48;
if (fsize == 32) {
if constexpr (fsize == 32) {
code.movd(tmp.cvt32(), xmm0);
} else {
// We do this to avoid requiring 64-bit immediates
@ -234,7 +252,7 @@ void EmitPostProcessNaNs(BlockOfCode& code, Xbyak::Xmm result, Xbyak::Xmm op1, X
// op1 == QNaN && op2 == SNaN <<< The problematic case
// op1 == QNaN && op2 == Inf
if (fsize == 32) {
if constexpr (fsize == 32) {
code.movd(tmp.cvt32(), op2);
code.shl(tmp.cvt32(), 32 - mantissa_msb_bit);
} else {
@ -273,7 +291,7 @@ void FPTwoOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
// Do nothing
} else if (ctx.FPCR().DN()) {
ForceToDefaultNaN(code, result, fsize);
ForceToDefaultNaN<fsize>(code, result);
} else {
PostProcessNaN<fsize>(code, result, xmm0);
}
@ -284,7 +302,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 = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -299,7 +317,7 @@ void FPThreeOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst, Function fn)
}
if (!ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
ForceToDefaultNaN(code, result, fsize);
ForceToDefaultNaN<fsize>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
@ -343,7 +361,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 = Common::UnsignedIntegerN<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);
@ -369,7 +387,7 @@ void EmitX64::EmitFPAbs64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
void FPNeg(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<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);
@ -424,7 +442,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
FCODE(ucomis)(result, operand);
code.jz(*equal, code.T_NEAR);
if (is_max) {
if constexpr (is_max) {
FCODE(maxs)(result, operand);
} else {
FCODE(mins)(result, operand);
@ -436,7 +454,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.L(*equal);
code.jp(nan);
if (is_max) {
if constexpr (is_max) {
code.andps(result, operand);
} else {
code.orps(result, operand);
@ -459,7 +477,7 @@ static void EmitFPMinMax(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize, bool is_max>
static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) noexcept {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT default_nan = FP::FPInfo<FPT>::DefaultNaN();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -484,7 +502,7 @@ static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::
tmp.setBit(fsize);
const auto move_to_tmp = [=, &code](const Xbyak::Xmm& xmm) {
if (fsize == 32) {
if constexpr (fsize == 32) {
code.movd(tmp.cvt32(), xmm);
} else {
code.movq(tmp.cvt64(), xmm);
@ -495,7 +513,7 @@ static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::
FCODE(ucomis)(op1, op2);
code.jz(*z, code.T_NEAR);
if (is_max) {
if constexpr (is_max) {
FCODE(maxs)(op2, op1);
} else {
FCODE(mins)(op2, op1);
@ -509,7 +527,7 @@ static inline void EmitFPMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::
code.L(*z);
code.jp(nan);
if (is_max) {
if constexpr (is_max) {
code.andps(op2, op1);
} else {
code.orps(op2, op1);
@ -611,12 +629,12 @@ void EmitX64::EmitFPMul64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize, bool negate_product>
static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
const auto fallback_fn = negate_product ? &FP::FPMulSub<FPT> : &FP::FPMulAdd<FPT>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (fsize != 16) {
if constexpr (fsize != 16) {
const bool needs_rounding_correction = ctx.FPCR().FZ();
const bool needs_nan_correction = !ctx.FPCR().DN();
@ -625,13 +643,13 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
const Xbyak::Xmm operand3 = ctx.reg_alloc.UseXmm(args[2]);
if (negate_product) {
if constexpr (negate_product) {
FCODE(vfnmadd231s)(result, operand2, operand3);
} else {
FCODE(vfmadd231s)(result, operand2, operand3);
}
if (ctx.FPCR().DN()) {
ForceToDefaultNaN(code, result, fsize);
ForceToDefaultNaN<fsize>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
@ -647,7 +665,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm result = ctx.reg_alloc.ScratchXmm();
code.movaps(result, operand1);
if (negate_product) {
if constexpr (negate_product) {
FCODE(vfnmadd231s)(result, operand2, operand3);
} else {
FCODE(vfmadd231s)(result, operand2, operand3);
@ -668,8 +686,9 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
} else {
UNREACHABLE();
}
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, fsize);
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<fsize>(code, result);
}
code.L(*end);
ctx.deferred_emits.emplace_back([=, &code, &ctx] {
@ -750,7 +769,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.ptest(operand2, xmm0);
code.jnz(op2_done);
code.vorps(result, operand2, xmm0);
if (negate_product) {
if constexpr (negate_product) {
code.xorps(result, code.Const(xword, FP::FPInfo<FPT>::sign_mask));
}
code.jmp(*end);
@ -766,7 +785,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
// at this point, all SNaNs have been handled
// if op1 was not a QNaN and op2 is, negate the result
if (negate_product) {
if constexpr (negate_product) {
FCODE(ucomis)(operand1, operand1);
code.jp(*end);
FCODE(ucomis)(operand2, operand2);
@ -787,7 +806,7 @@ static void EmitFPMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseScratchXmm(args[1]);
const Xbyak::Xmm operand3 = ctx.reg_alloc.UseXmm(args[2]);
if (negate_product) {
if constexpr (negate_product) {
code.xorps(operand2, code.Const(xword, FP::FPInfo<FPT>::sign_mask));
}
FCODE(muls)(operand2, operand3);
@ -838,7 +857,7 @@ void EmitX64::EmitFPMulSub64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
@ -898,9 +917,9 @@ void EmitX64::EmitFPMulX64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRecipEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
if (fsize != 16) {
if constexpr (fsize != 16) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_ReducedErrorFP)) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const Xbyak::Xmm operand = ctx.reg_alloc.UseXmm(args[0]);
@ -909,7 +928,7 @@ static void EmitFPRecipEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
FCODE(vrcp14s)(result, operand, operand);
} else {
if (fsize == 32) {
if constexpr (fsize == 32) {
code.rcpss(result, operand);
} else {
code.cvtsd2ss(result, operand);
@ -944,7 +963,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 = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, args[0]);
@ -967,11 +986,11 @@ void EmitX64::EmitFPRecipExponent64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (fsize != 16) {
if constexpr (fsize != 16) {
if (code.HasHostFeature(HostFeature::FMA) && ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
Xbyak::Label end, fallback;
@ -1104,9 +1123,9 @@ void EmitX64::EmitFPRoundInt64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
if (fsize != 16) {
if constexpr (fsize != 16) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_ReducedErrorFP)) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const Xbyak::Xmm operand = ctx.reg_alloc.UseXmm(args[0]);
@ -1115,7 +1134,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) {
FCODE(vrsqrt14s)(result, operand, operand);
} else {
if (fsize == 32) {
if constexpr (fsize == 32) {
code.rsqrtss(result, operand);
} else {
code.cvtsd2ss(result, operand);
@ -1161,7 +1180,7 @@ static void EmitFPRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* i
bool needs_fallback = false;
code.L(*bad_values);
if (fsize == 32) {
if constexpr (fsize == 32) {
code.movd(tmp, operand);
if (!ctx.FPCR().FZ()) {
@ -1283,11 +1302,11 @@ void EmitX64::EmitFPRSqrtEstimate64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
if (fsize != 16) {
if constexpr (fsize != 16) {
if (code.HasHostFeature(HostFeature::FMA | HostFeature::AVX) && ctx.HasOptimization(OptimizationFlag::Unsafe_InaccurateNaN)) {
const Xbyak::Xmm operand1 = ctx.reg_alloc.UseXmm(args[0]);
const Xbyak::Xmm operand2 = ctx.reg_alloc.UseXmm(args[1]);
@ -1466,8 +1485,9 @@ void EmitX64::EmitFPHalfToDouble(EmitContext& ctx, IR::Inst* inst) {
// Double-conversion here is acceptable as this is expanding precision.
code.vcvtph2ps(result, value);
code.vcvtps2pd(result, result);
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, 64);
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<64>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
return;
@ -1489,8 +1509,9 @@ void EmitX64::EmitFPHalfToSingle(EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm value = ctx.reg_alloc.UseXmm(args[0]);
code.vcvtph2ps(result, value);
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, 32);
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<32>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
return;
@ -1498,22 +1519,23 @@ void EmitX64::EmitFPHalfToSingle(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst, args[0]);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
code.mov(code.ABI_PARAM3.cvt32(), u32(rounding_mode));
code.mov(code.ABI_PARAM3.cvt32(), static_cast<u32>(rounding_mode));
code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPConvert<u32, u16>);
}
void EmitX64::EmitFPSingleToDouble(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const auto rounding_mode = FP::RoundingMode(args[1].GetImmediateU8());
const auto rounding_mode = static_cast<FP::RoundingMode>(args[1].GetImmediateU8());
// We special-case the non-IEEE-defined ToOdd rounding mode.
if (rounding_mode == ctx.FPCR().RMode() && rounding_mode != FP::RoundingMode::ToOdd) {
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
code.cvtss2sd(result, result);
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, 64);
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<64>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.HostCall(inst, args[0]);
@ -1531,9 +1553,12 @@ void EmitX64::EmitFPSingleToHalf(EmitContext& ctx, IR::Inst* inst) {
if (code.HasHostFeature(HostFeature::F16C) && !ctx.FPCR().AHP() && !ctx.FPCR().FZ16()) {
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, 32);
code.vcvtps2ph(result, result, u8(*round_imm));
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<32>(code, result);
}
code.vcvtps2ph(result, result, static_cast<u8>(*round_imm));
ctx.reg_alloc.DefineValue(inst, result);
return;
}
@ -1561,18 +1586,21 @@ void EmitX64::EmitFPDoubleToHalf(EmitContext& ctx, IR::Inst* inst) {
void EmitX64::EmitFPDoubleToSingle(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const auto rounding_mode = FP::RoundingMode(args[1].GetImmediateU8());
const auto rounding_mode = static_cast<FP::RoundingMode>(args[1].GetImmediateU8());
// We special-case the non-IEEE-defined ToOdd rounding mode.
if (rounding_mode == ctx.FPCR().RMode() && rounding_mode != FP::RoundingMode::ToOdd) {
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
code.cvtsd2ss(result, result);
if (ctx.FPCR().DN())
ForceToDefaultNaN(code, result, 32);
if (ctx.FPCR().DN()) {
ForceToDefaultNaN<32>(code, result);
}
ctx.reg_alloc.DefineValue(inst, result);
} else {
ctx.reg_alloc.HostCall(inst, args[0]);
code.mov(code.ABI_PARAM2.cvt32(), ctx.FPCR().Value());
code.mov(code.ABI_PARAM3.cvt32(), u32(rounding_mode));
code.mov(code.ABI_PARAM3.cvt32(), static_cast<u32>(rounding_mode));
code.lea(code.ABI_PARAM4, code.ptr[code.ABI_JIT_PTR + code.GetJitStateInfo().offsetof_fpsr_exc]);
code.CallFunction(&FP::FPConvert<u32, u64>);
}
@ -1587,7 +1615,7 @@ void EmitX64::EmitFPDoubleToSingle(EmitContext& ctx, IR::Inst* inst) {
/// Better than spamming thousands of templates aye?
template<size_t fsize>
static u64 EmitFPToFixedThunk(u64 input, FP::FPSR& fpsr, FP::FPCR fpcr, u32 extra_args) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto const unsigned_ = ((extra_args >> 24) & 0xff) != 0;
auto const isize = ((extra_args >> 16) & 0xff);
auto const rounding = FP::RoundingMode((extra_args >> 8) & 0xff);
@ -1602,7 +1630,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const size_t fbits = args[1].GetImmediateU8();
const auto rounding_mode = FP::RoundingMode(args[2].GetImmediateU8());
if (fsize != 16) {
if constexpr (fsize != 16) {
const auto round_imm = ConvertRoundingModeToX64Immediate(rounding_mode);
// cvttsd2si truncates during operation so rounding (and thus SSE4.1) not required
@ -1612,7 +1640,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const Xbyak::Xmm src = ctx.reg_alloc.UseScratchXmm(args[0]);
const Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr().cvt64();
if (fsize == 64) {
if constexpr (fsize == 64) {
if (fbits != 0) {
const u64 scale_factor = static_cast<u64>((fbits + 1023) << 52);
code.mulsd(src, code.Const(xword, scale_factor));
@ -1634,13 +1662,13 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.cvtss2sd(src, src);
}
if (isize == 64) {
if constexpr (isize == 64) {
const Xbyak::Xmm scratch = ctx.reg_alloc.ScratchXmm();
if (!unsigned_) {
SharedLabel saturate_max = GenSharedLabel(), end = GenSharedLabel();
ZeroIfNaN(code, src, scratch, 64);
ZeroIfNaN<64>(code, src, scratch);
code.movsd(scratch, code.Const(xword, f64_max_s64_lim));
code.comisd(scratch, src);
@ -1678,11 +1706,11 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
code.sar(result2, 63);
code.or_(result, result2);
}
} else if (isize == 32) {
} else if constexpr (isize == 32) {
if (!unsigned_) {
const Xbyak::Xmm scratch = ctx.reg_alloc.ScratchXmm();
ZeroIfNaN(code, src, scratch, 64);
ZeroIfNaN<64>(code, src, scratch);
code.minsd(src, code.Const(xword, f64_max_s32));
// maxsd not required as cvttsd2si results in 0x8000'0000 when out of range
code.cvttsd2si(result.cvt32(), src); // 32 bit gpr
@ -1695,7 +1723,7 @@ static void EmitFPToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
} else {
const Xbyak::Xmm scratch = ctx.reg_alloc.ScratchXmm();
ZeroIfNaN(code, src, scratch, 64);
ZeroIfNaN<64>(code, src, scratch);
code.maxsd(src, code.Const(xword, unsigned_ ? f64_min_u16 : f64_min_s16));
code.minsd(src, code.Const(xword, unsigned_ ? f64_max_u16 : f64_max_s16));
code.cvttsd2si(result, src); // 64 bit gpr

87
src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc

@ -4,7 +4,6 @@
*/
#include <mcl/macro/concatenate_tokens.hpp>
#include "dynarmic/common/type_util.h"
#define AxxEmitX64 CONCATENATE_TOKENS(Axx, EmitX64)
#define AxxEmitContext CONCATENATE_TOKENS(Axx, EmitContext)
@ -16,11 +15,14 @@ using Vector = std::array<u64, 2>;
}
std::optional<AxxEmitX64::DoNotFastmemMarker> AxxEmitX64::ShouldFastmem(AxxEmitContext& ctx, IR::Inst* inst) const {
if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem())
if (!conf.fastmem_pointer || !exception_handler.SupportsFastmem()) {
return std::nullopt;
}
const auto marker = std::make_tuple(ctx.Location(), inst->GetName());
if (do_not_fastmem.count(marker) > 0)
if (do_not_fastmem.count(marker) > 0) {
return std::nullopt;
}
return marker;
}
@ -56,12 +58,16 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
// Neither fastmem nor page table: Use callbacks
if constexpr (bitsize == 128) {
ctx.reg_alloc.HostCall(nullptr, {}, args[1]);
if (ordered) code.mfence();
if (ordered) {
code.mfence();
}
code.CallFunction(memory_read_128);
ctx.reg_alloc.DefineValue(inst, xmm1);
} else {
ctx.reg_alloc.HostCall(inst, {}, args[1]);
if (ordered) code.mfence();
if (ordered) {
code.mfence();
}
Devirtualize<callback>(conf.callbacks).EmitCall(code);
code.ZeroExtendFrom(bitsize, code.ABI_RETURN);
}
@ -96,10 +102,10 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) {
code.call(wrapped_fn);
fastmem_patch_info.emplace(
std::bit_cast<u64>(location),
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
std::bit_cast<u64>(code.getCurr()),
std::bit_cast<u64>(wrapped_fn),
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
@ -147,7 +153,9 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(nullptr, {}, args[1], args[2]);
Devirtualize<callback>(conf.callbacks).EmitCall(code);
}
if (ordered) code.mfence();
if (ordered) {
code.mfence();
}
EmitCheckMemoryAbort(ctx, inst);
return;
}
@ -181,10 +189,10 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) {
code.call(wrapped_fn);
fastmem_patch_info.emplace(
std::bit_cast<u64>(location),
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
std::bit_cast<u64>(code.getCurr()),
std::bit_cast<u64>(wrapped_fn),
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_fastmem_failure,
});
@ -215,7 +223,7 @@ void AxxEmitX64::EmitExclusiveReadMemory(AxxEmitContext& ctx, IR::Inst* inst) {
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
if constexpr (bitsize != 128) {
using T = Common::UnsignedIntegerN<bitsize>;
using T = mcl::unsigned_integer_of_size<bitsize>;
ctx.reg_alloc.HostCall(inst, {}, args[1]);
@ -282,14 +290,16 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0));
code.mov(code.ABI_PARAM1, reinterpret_cast<u64>(&conf));
if constexpr (bitsize != 128) {
using T = Common::UnsignedIntegerN<bitsize>;
using T = mcl::unsigned_integer_of_size<bitsize>;
code.CallLambda(
[](AxxUserConfig& conf, Axx::VAddr vaddr, T value) -> u32 {
return conf.global_monitor->DoExclusiveOperation<T>(conf.processor_id, vaddr,
[&](T expected) -> bool {
return (conf.callbacks->*callback)(vaddr, value, expected);
}) ? 0 : 1;
[&](T expected) -> bool {
return (conf.callbacks->*callback)(vaddr, value, expected);
})
? 0
: 1;
});
if (ordered) {
code.mfence();
@ -301,9 +311,11 @@ void AxxEmitX64::EmitExclusiveWriteMemory(AxxEmitContext& ctx, IR::Inst* inst) {
code.CallLambda(
[](AxxUserConfig& conf, Axx::VAddr vaddr, Vector& value) -> u32 {
return conf.global_monitor->DoExclusiveOperation<Vector>(conf.processor_id, vaddr,
[&](Vector expected) -> bool {
return (conf.callbacks->*callback)(vaddr, value, expected);
}) ? 0 : 1;
[&](Vector expected) -> bool {
return (conf.callbacks->*callback)(vaddr, value, expected);
})
? 0
: 1;
});
if (ordered) {
code.mfence();
@ -344,7 +356,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
EmitExclusiveLock(code, conf, tmp, tmp2.cvt32());
code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(1));
code.mov(tmp, std::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id)));
code.mov(tmp, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id)));
code.mov(qword[tmp], vaddr);
const auto fastmem_marker = ShouldFastmem(ctx, inst);
@ -357,10 +369,10 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
const auto location = EmitReadMemoryMov<bitsize>(code, value_idx, src_ptr, ordered);
fastmem_patch_info.emplace(
std::bit_cast<u64>(location),
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
std::bit_cast<u64>(code.getCurr()),
std::bit_cast<u64>(wrapped_fn),
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_exclusive_fastmem_failure,
});
@ -378,7 +390,7 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in
code.call(wrapped_fn);
}
code.mov(tmp, std::bit_cast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id)));
code.mov(tmp, mcl::bit_cast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id)));
EmitWriteMemoryMov<bitsize>(code, tmp, value_idx, false);
EmitExclusiveUnlock(code, conf, tmp, tmp2.cvt32());
@ -425,7 +437,7 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
SharedLabel end = GenSharedLabel();
code.mov(tmp, std::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id)));
code.mov(tmp, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, conf.processor_id)));
code.mov(status, u32(1));
code.cmp(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0));
code.je(*end, code.T_NEAR);
@ -435,7 +447,7 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
EmitExclusiveTestAndClear(code, conf, vaddr, tmp, rax);
code.mov(code.byte[code.ABI_JIT_PTR + offsetof(AxxJitState, exclusive_state)], u8(0));
code.mov(tmp, std::bit_cast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id)));
code.mov(tmp, mcl::bit_cast<u64>(GetExclusiveMonitorValuePointer(conf.global_monitor, conf.processor_id)));
if constexpr (bitsize == 128) {
code.mov(rax, qword[tmp + 0]);
@ -463,20 +475,25 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
const auto location = code.getCurr();
if constexpr (bitsize == 128) {
code.lock(); code.cmpxchg16b(ptr[dest_ptr]);
code.lock();
code.cmpxchg16b(ptr[dest_ptr]);
} else {
switch (bitsize) {
case 8:
code.lock(); code.cmpxchg(code.byte[dest_ptr], value.cvt8());
code.lock();
code.cmpxchg(code.byte[dest_ptr], value.cvt8());
break;
case 16:
code.lock(); code.cmpxchg(word[dest_ptr], value.cvt16());
code.lock();
code.cmpxchg(word[dest_ptr], value.cvt16());
break;
case 32:
code.lock(); code.cmpxchg(dword[dest_ptr], value.cvt32());
code.lock();
code.cmpxchg(dword[dest_ptr], value.cvt32());
break;
case 64:
code.lock(); code.cmpxchg(qword[dest_ptr], value.cvt64());
code.lock();
code.cmpxchg(qword[dest_ptr], value.cvt64());
break;
default:
UNREACHABLE();
@ -489,10 +506,10 @@ void AxxEmitX64::EmitExclusiveWriteMemoryInline(AxxEmitContext& ctx, IR::Inst* i
code.call(wrapped_fn);
fastmem_patch_info.emplace(
std::bit_cast<u64>(location),
mcl::bit_cast<u64>(location),
FastmemPatchInfo{
std::bit_cast<u64>(code.getCurr()),
std::bit_cast<u64>(wrapped_fn),
mcl::bit_cast<u64>(code.getCurr()),
mcl::bit_cast<u64>(wrapped_fn),
*fastmem_marker,
conf.recompile_on_exclusive_fastmem_failure,
});

12
src/dynarmic/src/dynarmic/backend/x64/emit_x64_memory.h

@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2022 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#include <numeric>
#include <bit>
#include <mcl/bit_cast.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/a32_emit_x64.h"
@ -346,7 +342,7 @@ void EmitExclusiveLock(BlockOfCode& code, const UserConfig& conf, Xbyak::Reg64 p
return;
}
code.mov(pointer, std::bit_cast<u64>(GetExclusiveMonitorLockPointer(conf.global_monitor)));
code.mov(pointer, mcl::bit_cast<u64>(GetExclusiveMonitorLockPointer(conf.global_monitor)));
EmitSpinLockLock(code, pointer, tmp);
}
@ -356,7 +352,7 @@ void EmitExclusiveUnlock(BlockOfCode& code, const UserConfig& conf, Xbyak::Reg64
return;
}
code.mov(pointer, std::bit_cast<u64>(GetExclusiveMonitorLockPointer(conf.global_monitor)));
code.mov(pointer, mcl::bit_cast<u64>(GetExclusiveMonitorLockPointer(conf.global_monitor)));
EmitSpinLockUnlock(code, pointer, tmp);
}
@ -373,7 +369,7 @@ void EmitExclusiveTestAndClear(BlockOfCode& code, const UserConfig& conf, Xbyak:
continue;
}
Xbyak::Label ok;
code.mov(pointer, std::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, processor_index)));
code.mov(pointer, mcl::bit_cast<u64>(GetExclusiveMonitorAddressPointer(conf.global_monitor, processor_index)));
code.cmp(qword[pointer], vaddr);
code.jne(ok, code.T_NEAR);
code.mov(qword[pointer], tmp);

7
src/dynarmic/src/dynarmic/backend/x64/emit_x64_saturation.cpp

@ -11,14 +11,13 @@
#include "dynarmic/common/assert.h"
#include <mcl/bit/bit_field.hpp>
#include "dynarmic/common/common_types.h"
#include <mcl/type_traits/integer_of_size.hpp>
#include "dynarmic/backend/x64/block_of_code.h"
#include "dynarmic/backend/x64/emit_x64.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
#include "dynarmic/common/fp/util.h"
#include "dynarmic/common/type_util.h"
namespace Dynarmic::Backend::X64 {
@ -39,7 +38,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
Xbyak::Reg addend = ctx.reg_alloc.UseGpr(args[1]).changeBit(size);
Xbyak::Reg overflow = ctx.reg_alloc.ScratchGpr().changeBit(size);
constexpr u64 int_max = static_cast<u64>((std::numeric_limits<Common::SignedIntegerN<size>>::max)());
constexpr u64 int_max = static_cast<u64>((std::numeric_limits<mcl::signed_integer_of_size<size>>::max)());
if constexpr (size < 64) {
code.xor_(overflow.cvt32(), overflow.cvt32());
code.bt(result.cvt32(), size - 1);
@ -83,7 +82,7 @@ void EmitUnsignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst
Xbyak::Reg op_result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(size);
Xbyak::Reg addend = ctx.reg_alloc.UseScratchGpr(args[1]).changeBit(size);
constexpr u64 boundary = op == Op::Add ? (std::numeric_limits<Common::UnsignedIntegerN<size>>::max)() : 0;
constexpr u64 boundary = op == Op::Add ? (std::numeric_limits<mcl::unsigned_integer_of_size<size>>::max)() : 0;
if constexpr (op == Op::Add) {
code.add(op_result, addend);

58
src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp

@ -20,6 +20,7 @@
#include <mcl/mp/typelist/list.hpp>
#include <mcl/mp/typelist/lower_to_tuple.hpp>
#include <mcl/type_traits/function_info.hpp>
#include <mcl/type_traits/integer_of_size.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/abi.h"
@ -30,14 +31,27 @@
#include "dynarmic/common/fp/info.h"
#include "dynarmic/common/fp/op.h"
#include "dynarmic/common/fp/util.h"
#include "dynarmic/common/type_util.h"
#include "dynarmic/common/lut_from_list.h"
#include "dynarmic/interface/optimization_flags.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#define FCODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
#define ICODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (fsize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
namespace Dynarmic::Backend::X64 {
@ -62,7 +76,7 @@ void MaybeStandardFPSCRValue(BlockOfCode& code, EmitContext& ctx, bool fpcr_cont
template<size_t fsize, template<typename> class Indexer, size_t narg>
struct NaNHandler {
public:
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
using function_type = void (*)(std::array<VectorArray<FPT>, narg>&, FP::FPCR);
@ -144,33 +158,33 @@ Xbyak::Address GetVectorOf(BlockOfCode& code) {
template<size_t fsize>
Xbyak::Address GetNaNVector(BlockOfCode& code) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
return GetVectorOf<fsize, FP::FPInfo<FPT>::DefaultNaN()>(code);
}
template<size_t fsize>
Xbyak::Address GetNegativeZeroVector(BlockOfCode& code) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
return GetVectorOf<fsize, FP::FPInfo<FPT>::Zero(true)>(code);
}
template<size_t fsize>
Xbyak::Address GetNonSignMaskVector(BlockOfCode& code) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT non_sign_mask = FP::FPInfo<FPT>::exponent_mask | FP::FPInfo<FPT>::mantissa_mask;
return GetVectorOf<fsize, non_sign_mask>(code);
}
template<size_t fsize>
Xbyak::Address GetSmallestNormalVector(BlockOfCode& code) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
constexpr FPT smallest_normal_number = FP::FPValue<FPT, false, FP::FPInfo<FPT>::exponent_min, 1>();
return GetVectorOf<fsize, smallest_normal_number>(code);
}
template<size_t fsize, bool sign, int exponent, Common::UnsignedIntegerN<fsize> value>
template<size_t fsize, bool sign, int exponent, mcl::unsigned_integer_of_size<fsize> value>
Xbyak::Address GetVectorOf(BlockOfCode& code) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
return GetVectorOf<fsize, FP::FPValue<FPT, sign, exponent, value>()>(code);
}
@ -1071,7 +1085,7 @@ static void EmitFPVectorMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::I
if (code.HasHostFeature(HostFeature::AVX)) {
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
// result = xmm_a == SNaN || xmm_b == QNaN
{
@ -1144,7 +1158,7 @@ static void EmitFPVectorMinMaxNumeric(BlockOfCode& code, EmitContext& ctx, IR::I
}
MaybeStandardFPSCRValue(code, ctx, fpcr_controlled, [&] {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
// result = xmm_a == SNaN || xmm_b == QNaN
{
@ -1300,7 +1314,7 @@ static void EmitFPVectorMulAddFallback(VectorArray<FPT>& result, const VectorArr
template<size_t fsize>
void EmitFPVectorMulAdd(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
const auto fallback_fn = [](VectorArray<FPT>& result, const VectorArray<FPT>& addend, const VectorArray<FPT>& op1, const VectorArray<FPT>& op2, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < result.size(); i++) {
@ -1411,7 +1425,7 @@ void EmitX64::EmitFPVectorMulAdd64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitFPVectorMulX(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const bool fpcr_controlled = args[2].GetImmediateU1();
@ -1477,7 +1491,7 @@ void EmitX64::EmitFPVectorMulX64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
void FPVectorNeg(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<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);
@ -1530,7 +1544,7 @@ void EmitX64::EmitFPVectorPairedAddLower64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitRecipEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
if constexpr (fsize != 16) {
if (ctx.HasOptimization(OptimizationFlag::Unsafe_ReducedErrorFP)) {
@ -1576,7 +1590,7 @@ void EmitX64::EmitFPVectorRecipEstimate64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitRecipStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
const auto fallback_fn = [](VectorArray<FPT>& result, const VectorArray<FPT>& op1, const VectorArray<FPT>& op2, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < result.size(); i++) {
@ -1700,7 +1714,7 @@ void EmitFPVectorRoundInt(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
}
// Do not make a LUT out of this, let the compiler do it's thing
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
switch (rounding) {
case FP::RoundingMode::ToNearest_TieEven:
exact
@ -1746,7 +1760,7 @@ void EmitX64::EmitFPVectorRoundInt64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitRSqrtEstimate(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
const auto fallback_fn = [](VectorArray<FPT>& result, const VectorArray<FPT>& operand, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < result.size(); i++) {
@ -1838,7 +1852,7 @@ void EmitX64::EmitFPVectorRSqrtEstimate64(EmitContext& ctx, IR::Inst* inst) {
template<size_t fsize>
static void EmitRSqrtStepFused(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
using FPT = Common::UnsignedIntegerN<fsize>;
using FPT = mcl::unsigned_integer_of_size<fsize>;
const auto fallback_fn = [](VectorArray<FPT>& result, const VectorArray<FPT>& op1, const VectorArray<FPT>& op2, FP::FPCR fpcr, FP::FPSR& fpsr) {
for (size_t i = 0; i < result.size(); i++) {
@ -2112,7 +2126,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
FCODE(orp)(src, exceed_unsigned);
}
} else {
using FPT = Common::UnsignedIntegerN<fsize>; // WORKAROUND: For issue 678 on MSVC
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
constexpr u64 integer_max = FPT((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
@ -2136,7 +2150,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
static const auto lut = Common::GenerateLookupTableFromList([]<typename I>(I) {
using FPT = Common::UnsignedIntegerN<fsize>; // WORKAROUND: For issue 678 on MSVC
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
return std::pair{
mp::lower_to_tuple_v<I>,
Common::FptrCast([](VectorArray<FPT>& output, const VectorArray<FPT>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {

19
src/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_saturation.cpp

@ -14,8 +14,23 @@
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"
#define FCODE(NAME) [&](auto... args) { if (esize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
#define ICODE(NAME) [&](auto... args) { if (esize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
#define FCODE(NAME) \
[&code](auto... args) { \
if constexpr (esize == 32) { \
code.NAME##s(args...); \
} else { \
code.NAME##d(args...); \
} \
}
#define ICODE(NAME) \
[&code](auto... args) { \
if constexpr (esize == 32) { \
code.NAME##d(args...); \
} else { \
code.NAME##q(args...); \
} \
}
namespace Dynarmic::Backend::X64 {

8
src/dynarmic/src/dynarmic/backend/x64/exception_handler_windows.cpp

@ -13,7 +13,7 @@
#include <vector>
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/common/common_types.h"
#include "dynarmic/backend/exception_handler.h"
@ -184,20 +184,20 @@ struct ExceptionHandler::Impl final {
// Our 3rd argument is a PCONTEXT.
// If not within our codeblock, ignore this exception.
code.mov(code.rax, Safe::Negate(std::bit_cast<u64>(code.getCode())));
code.mov(code.rax, Safe::Negate(mcl::bit_cast<u64>(code.getCode())));
code.add(code.rax, code.qword[code.ABI_PARAM3 + Xbyak::RegExp(offsetof(CONTEXT, Rip))]);
code.cmp(code.rax, static_cast<u32>(code.GetTotalCodeSize()));
code.ja(exception_handler_without_cb);
code.lea(code.rsp, code.ptr[code.rsp - 8]);
code.mov(code.ABI_PARAM1, std::bit_cast<u64>(&cb));
code.mov(code.ABI_PARAM1, mcl::bit_cast<u64>(&cb));
code.mov(code.ABI_PARAM2, code.ABI_PARAM3);
code.CallLambda(
[](const std::function<FakeCall(u64)>& cb_, PCONTEXT ctx) {
FakeCall fc = cb_(ctx->Rip);
ctx->Rsp -= sizeof(u64);
*std::bit_cast<u64*>(ctx->Rsp) = fc.ret_rip;
*mcl::bit_cast<u64*>(ctx->Rsp) = fc.ret_rip;
ctx->Rip = fc.call_rip;
});
code.add(code.rsp, 8);

9
src/dynarmic/src/dynarmic/backend/x64/perf_map.h

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@ -9,8 +6,8 @@
#pragma once
#include <string_view>
#include <bit>
#include <numeric>
#include <mcl/bit_cast.hpp>
namespace Dynarmic::Backend::X64 {
@ -20,7 +17,7 @@ void PerfMapRegister(const void* start, const void* end, std::string_view friend
template<typename T>
void PerfMapRegister(T start, const void* end, std::string_view friendly_name) {
detail::PerfMapRegister(std::bit_cast<const void*>(start), end, friendly_name);
detail::PerfMapRegister(mcl::bit_cast<const void*>(start), end, friendly_name);
}
void PerfMapClear();

2
src/dynarmic/src/dynarmic/backend/x64/reg_alloc.cpp

@ -11,10 +11,10 @@
#include <algorithm>
#include <numeric>
#include <utility>
#include <bit>
#include <fmt/ostream.h>
#include "dynarmic/common/assert.h"
#include <mcl/bit_cast.hpp>
#include <xbyak/xbyak.h>
#include "dynarmic/backend/x64/abi.h"

13
src/dynarmic/src/dynarmic/common/always_false.h

@ -0,0 +1,13 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2023 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
namespace Dynarmic::Common {
template<typename T>
inline constexpr bool always_false_v = false;
} // namespace Dynarmic::Common

45
src/dynarmic/src/dynarmic/common/assert.h

@ -16,33 +16,38 @@ template<typename... Ts>
// Temporary until MCL is fully removed
#ifndef ASSERT_MSG
# define ASSERT_MSG(_a_, ...) do if (!(_a_)) [[unlikely]] assert_terminate(#_a_, __VA_ARGS__); while(0)
#define ASSERT_MSG(_a_, ...) \
([&]() { \
if (!(_a_)) [[unlikely]] { \
assert_terminate(#_a_, __VA_ARGS__); \
} \
}())
#endif
#ifndef ASSERT_FALSE
# define ASSERT_FALSE(...) assert_terminate("false", __VA_ARGS__)
#define ASSERT_FALSE(...) \
([&]() { \
assert_terminate("false", __VA_ARGS__); \
}())
#endif
#ifndef ASSERT
# define ASSERT(_a_) ASSERT_MSG(_a_, "")
#define ASSERT(_a_) ASSERT_MSG(_a_, "")
#endif
#ifndef UNREACHABLE
# ifdef _MSC_VER
# define UNREACHABLE() ASSERT_FALSE("unreachable")
# else
# define UNREACHABLE() __builtin_unreachable();
# endif
#define UNREACHABLE() ASSERT_MSG(false, "unreachable")
#endif
#ifdef _DEBUG
# ifndef DEBUG_ASSERT
# define DEBUG_ASSERT(_a_) ASSERT(_a_)
# endif
# ifndef DEBUG_ASSERT_MSG
# define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
# endif
#ifndef DEBUG_ASSERT
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
#endif
#ifndef DEBUG_ASSERT_MSG
#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
#endif
#else // not debug
# ifndef DEBUG_ASSERT
# define DEBUG_ASSERT(_a_)
# endif
# ifndef DEBUG_ASSERT_MSG
# define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
# endif
#ifndef DEBUG_ASSERT
#define DEBUG_ASSERT(_a_)
#endif
#ifndef DEBUG_ASSERT_MSG
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...)
#endif
#endif

18
src/dynarmic/src/dynarmic/common/cast_util.h

@ -0,0 +1,18 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <mcl/type_traits/function_info.hpp>
namespace Dynarmic::Common {
/// Cast a lambda into an equivalent function pointer.
template<class Function>
inline auto FptrCast(Function f) noexcept {
return static_cast<mcl::equivalent_function_type<Function>*>(f);
}
} // namespace Dynarmic::Common

4
src/dynarmic/src/dynarmic/common/fp/util.h

@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
@ -9,7 +6,6 @@
#pragma once
#include <optional>
#include <cstdint>
#include "dynarmic/common/fp/fpcr.h"
#include "dynarmic/common/fp/info.h"

5
src/dynarmic/src/dynarmic/common/llvm_disassemble.cpp

@ -7,7 +7,7 @@
*/
#include <string>
#include <bit>
#include <fmt/format.h>
#ifdef DYNARMIC_USE_LLVM
@ -16,6 +16,7 @@
#endif
#include "dynarmic/common/assert.h"
#include <mcl/bit_cast.hpp>
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/llvm_disassemble.h"
@ -52,7 +53,7 @@ std::string DisassembleX64(const void* begin, const void* end) {
LLVMDisasmDispose(llvm_ctx);
#else
result += fmt::format("(recompile with DYNARMIC_USE_LLVM=ON to disassemble the generated x86_64 code)\n");
result += fmt::format("start: {:016x}, end: {:016x}\n", std::bit_cast<u64>(begin), std::bit_cast<u64>(end));
result += fmt::format("start: {:016x}, end: {:016x}\n", mcl::bit_cast<u64>(begin), mcl::bit_cast<u64>(end));
#endif
return result;

31
src/dynarmic/src/dynarmic/common/type_util.h

@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
* Copyright (c) 2018 MerryMage
* SPDX-License-Identifier: 0BSD
*/
#pragma once
#include <mcl/type_traits/function_info.hpp>
namespace Dynarmic::Common {
/// Cast a lambda into an equivalent function pointer.
template<class Function>
inline auto FptrCast(Function f) noexcept {
return static_cast<mcl::equivalent_function_type<Function>*>(f);
}
namespace Detail {
template<std::size_t size> struct IntegerOfSize {};
template<> struct IntegerOfSize<8> { using U = std::uint8_t; using S = std::int8_t; };
template<> struct IntegerOfSize<16> { using U = std::uint16_t; using S = std::int16_t; };
template<> struct IntegerOfSize<32> { using U = std::uint32_t; using S = std::int32_t; };
template<> struct IntegerOfSize<64> { using U = std::uint64_t; using S = std::int64_t; };
}
template<size_t N> using UnsignedIntegerN = typename Detail::IntegerOfSize<N>::U;
template<size_t N> using SignedIntegerN = typename Detail::IntegerOfSize<N>::S;
} // namespace Dynarmic::Common

2
src/dynarmic/src/dynarmic/ir/ir_emitter.cpp

@ -11,7 +11,7 @@
#include <vector>
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/ir/opcodes.h"

10
src/dynarmic/src/dynarmic/ir/ir_emitter.h

@ -12,7 +12,7 @@
#include "dynarmic/common/common_types.h"
#include "dynarmic/common/assert.h"
#include <numeric>
#include <mcl/bit_cast.hpp>
#include "dynarmic/ir/opcodes.h"
#include "dynarmic/ir/acc_type.h"
@ -2931,19 +2931,19 @@ public:
}
void CallHostFunction(void (*fn)(void)) {
Inst(Opcode::CallHostFunction, Imm64(std::bit_cast<u64>(fn)), Value{}, Value{}, Value{});
Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast<u64>(fn)), Value{}, Value{}, Value{});
}
void CallHostFunction(void (*fn)(u64), const U64& arg1) {
Inst(Opcode::CallHostFunction, Imm64(std::bit_cast<u64>(fn)), arg1, Value{}, Value{});
Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast<u64>(fn)), arg1, Value{}, Value{});
}
void CallHostFunction(void (*fn)(u64, u64), const U64& arg1, const U64& arg2) {
Inst(Opcode::CallHostFunction, Imm64(std::bit_cast<u64>(fn)), arg1, arg2, Value{});
Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast<u64>(fn)), arg1, arg2, Value{});
}
void CallHostFunction(void (*fn)(u64, u64, u64), const U64& arg1, const U64& arg2, const U64& arg3) {
Inst(Opcode::CallHostFunction, Imm64(std::bit_cast<u64>(fn)), arg1, arg2, arg3);
Inst(Opcode::CallHostFunction, Imm64(mcl::bit_cast<u64>(fn)), arg1, arg2, arg3);
}
void SetTerm(const Terminal& terminal) {

1
src/dynarmic/tests/test_generator.cpp

@ -17,6 +17,7 @@
#include <vector>
#include <mcl/bit/swap.hpp>
#include <mcl/macro/architecture.hpp>
#include "dynarmic/common/common_types.h"
#include "./A32/testenv.h"

Loading…
Cancel
Save