diff --git a/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 2994a91e..dfe834fa 100644 --- a/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -1681,7 +1681,7 @@ void EmitX64::EmitFPFixedS32ToSingle(EmitContext& ctx, IR::Inst* inst) { const size_t fbits = args[1].GetImmediateU8(); const FP::RoundingMode rounding_mode = static_cast(args[2].GetImmediateU8()); - if (rounding_mode == ctx.FPCR().RMode()) { + if (rounding_mode == ctx.FPCR().RMode() || ctx.HasOptimization(OptimizationFlag::Unsafe_IgnoreStandardFPCRValue)) { code.cvtsi2ss(result, from); } else { ASSERT(rounding_mode == FP::RoundingMode::ToNearest_TieEven); @@ -1717,7 +1717,7 @@ void EmitX64::EmitFPFixedU32ToSingle(EmitContext& ctx, IR::Inst* inst) { } }; - if (rounding_mode == ctx.FPCR().RMode()) { + if (rounding_mode == ctx.FPCR().RMode() || ctx.HasOptimization(OptimizationFlag::Unsafe_IgnoreStandardFPCRValue)) { op(); } else { ASSERT(rounding_mode == FP::RoundingMode::ToNearest_TieEven); diff --git a/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 3952527b..84de2bf2 100644 --- a/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -58,7 +58,7 @@ template void MaybeStandardFPSCRValue(BlockOfCode& code, EmitContext& ctx, bool fpcr_controlled, Lambda lambda) { const bool switch_mxcsr = ctx.FPCR(fpcr_controlled) != ctx.FPCR(); - if (switch_mxcsr) { + if (switch_mxcsr && !ctx.HasOptimization(OptimizationFlag::Unsafe_IgnoreStandardFPCRValue)) { code.EnterStandardASIMD(); lambda(); code.LeaveStandardASIMD(); diff --git a/src/dynarmic/interface/optimization_flags.h b/src/dynarmic/interface/optimization_flags.h index 143edc5c..df7eee3e 100644 --- a/src/dynarmic/interface/optimization_flags.h +++ b/src/dynarmic/interface/optimization_flags.h @@ -42,6 +42,9 @@ enum class OptimizationFlag : std::uint32_t { /// This is an UNSAFE optimization that causes floating-point instructions to not produce correct NaNs. /// This may also result in inaccurate results when instructions are given certain special values. Unsafe_InaccurateNaN = 0x00040000, + /// This is an UNSAFE optimization that causes ASIMD floating-point instructions to be run with incorrect + /// rounding modes. This may result in inaccurate results with all floating-point ASIMD instructions. + Unsafe_IgnoreStandardFPCRValue = 0x00080000, }; constexpr OptimizationFlag no_optimizations = static_cast(0);