[dynarmic] proper LUT implementation

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2026-04-03 04:11:55 +00:00
parent 501b884661
commit 69ac655a62
5 changed files with 29 additions and 81 deletions

View file

@ -59,7 +59,6 @@ add_library(dynarmic STATIC
common/fp/util.h
common/llvm_disassemble.cpp
common/llvm_disassemble.h
common/lut_from_list.h
common/math_util.cpp
common/math_util.h
common/safe_ops.h

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* This file is part of the dynarmic project.
@ -25,7 +25,6 @@
#include "dynarmic/common/fp/info.h"
#include "dynarmic/common/fp/op.h"
#include "dynarmic/common/fp/rounding_mode.h"
#include "dynarmic/common/lut_from_list.h"
#include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.h"

View file

@ -25,7 +25,6 @@
#include "dynarmic/common/fp/info.h"
#include "dynarmic/common/fp/op.h"
#include "dynarmic/common/fp/rounding_mode.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"

View file

@ -26,7 +26,6 @@
#include "dynarmic/common/fp/op.h"
#include "dynarmic/common/fp/rounding_mode.h"
#include "dynarmic/common/fp/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"
@ -1986,6 +1985,13 @@ void EmitX64::EmitFPVectorToHalf32(EmitContext& ctx, IR::Inst* inst) {
// output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
// }
template<size_t fsize, bool unsigned_, FP::RoundingMode rounding_mode, size_t fbits>
static void EmitFPVectorToFixedThunk(VectorArray<mcl::unsigned_integer_of_size<fsize>>& output, const VectorArray<mcl::unsigned_integer_of_size<fsize>>& input, FP::FPCR fpcr, FP::FPSR& fpsr) {
using FPT = mcl::unsigned_integer_of_size<fsize>;
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
}
template<size_t fsize, bool unsigned_>
void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
const size_t fbits = inst->GetArg(1).GetU8();
@ -2107,29 +2113,29 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(code, inst, src);
return;
}
auto const fpt_fn = [fbits, rounding]{
#define ROUNDING_MODE(CASE) \
else if (rounding == FP::RoundingMode::CASE && fsize == 8 && fbits == 8) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 8>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 16 && fbits == 8) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 8>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 16 && fbits == 16) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 16>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 32 && fbits == 8) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 8>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 32 && fbits == 16) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 16>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 32 && fbits == 32) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 32>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 64 && fbits == 8) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 8>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 64 && fbits == 16) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 16>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 64 && fbits == 32) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 32>; \
else if (rounding == FP::RoundingMode::CASE && fsize == 64 && fbits == 64) return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::CASE, 64>;
using fbits_list = mp::lift_sequence<std::make_index_sequence<fsize + 1>>;
using rounding_list = mp::list<
mp::lift_value<FP::RoundingMode::ToNearest_TieEven>,
mp::lift_value<FP::RoundingMode::TowardsPlusInfinity>,
mp::lift_value<FP::RoundingMode::TowardsMinusInfinity>,
mp::lift_value<FP::RoundingMode::TowardsZero>,
mp::lift_value<FP::RoundingMode::ToNearest_TieAwayFromZero>>;
if (false) { /* ... */ }
ROUNDING_MODE(ToNearest_TieEven)
ROUNDING_MODE(TowardsPlusInfinity)
ROUNDING_MODE(TowardsMinusInfinity)
ROUNDING_MODE(TowardsZero)
ROUNDING_MODE(ToNearest_TieAwayFromZero)
else return &EmitFPVectorToFixedThunk<fsize, unsigned_, FP::RoundingMode::TowardsZero, 64>;
}();
static const auto lut = Common::GenerateLookupTableFromList([]<typename I>(I) {
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) {
constexpr size_t fbits = mp::get<0, I>::value;
constexpr FP::RoundingMode rounding_mode = mp::get<1, I>::value;
for (size_t i = 0; i < output.size(); ++i)
output[i] = FPT(FP::FPToFixed<FPT>(fsize, input[i], fbits, unsigned_, fpcr, rounding_mode, fpsr));
})
};
}, mp::cartesian_product<fbits_list, rounding_list>{});
EmitTwoOpFallback<3>(code, ctx, inst, lut.at(std::make_tuple(fbits, rounding)));
EmitTwoOpFallback<3>(code, ctx, inst, fpt_fn);
}
void EmitX64::EmitFPVectorToSignedFixed16(EmitContext& ctx, IR::Inst* inst) {

View file

@ -1,55 +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 <initializer_list>
#include <map>
#include <type_traits>
#include <mcl/mp/metafunction/apply.hpp>
#include <mcl/mp/typelist/list.hpp>
#include <mcl/type_traits/is_instance_of_template.hpp>
#ifdef _MSC_VER
# include <mcl/mp/typelist/head.hpp>
#endif
namespace Dynarmic::Common {
// prevents this function from printing 56,000 character warning messages
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wno-stack-usage"
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wno-stack-usage"
#endif
template<typename Function, typename... Values>
inline auto GenerateLookupTableFromList(Function f, mcl::mp::list<Values...>) {
#ifdef _MSC_VER
using PairT = std::invoke_result_t<Function, mcl::mp::head<mcl::mp::list<Values...>>>;
#else
using PairT = std::common_type_t<std::invoke_result_t<Function, Values>...>;
#endif
using MapT = mcl::mp::apply<std::map, PairT>;
static_assert(mcl::is_instance_of_template_v<std::pair, PairT>);
const std::initializer_list<PairT> pair_array{f(Values{})...};
return MapT(pair_array.begin(), pair_array.end());
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
} // namespace Dynarmic::Common