PPU LLVM: Add FMA accuracy setting (#7874)

* PPU LLVM : Match PS3 for the instructions fmadd, fmadds, fmsub, fmsubs, fnmadd, fnmadds, fnmsub, fnmsubs

Co-authored-by: doesthisusername <yfirestorm@gmail.com>
This commit is contained in:
Eladash 2020-03-31 20:01:10 +03:00 committed by GitHub
parent fc3a134e7d
commit 92f821aeb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 15 deletions

View File

@ -1531,6 +1531,7 @@ extern void ppu_initialize(const ppu_module& info)
enum class ppu_settings : u32
{
non_win32,
accurate_fma,
__bitset_enum_max
};
@ -1540,6 +1541,10 @@ extern void ppu_initialize(const ppu_module& info)
#ifndef _WIN32
settings += ppu_settings::non_win32;
#endif
if (g_cfg.core.ppu_accurate_fma)
{
settings += ppu_settings::accurate_fma;
}
// Write version, hash, CPU, settings
fmt::append(obj_name, "v3-tane-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));

View File

@ -1,5 +1,6 @@
#ifdef LLVM_AVAILABLE
#include "Emu/system_config.h"
#include "PPUTranslator.h"
#include "PPUThread.h"
#include "PPUInterpreter.h"
@ -3878,8 +3879,18 @@ void PPUTranslator::FMADDS(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFPTrunc(m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b), GetType<f32>());
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, b});
}
else
{
result = m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFPTrunc(result, GetType<f32>()));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fr", a, b, c));
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fi", a, b, c));
@ -3896,8 +3907,18 @@ void PPUTranslator::FMSUBS(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFPTrunc(m_ir->CreateFSub(m_ir->CreateFMul(a, c), b), GetType<f32>());
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, m_ir->CreateFNeg(b)});
}
else
{
result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFPTrunc(result, GetType<f32>()));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fr", a, b, c)); // TODO ???
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fi", a, b, c));
@ -3914,8 +3935,18 @@ void PPUTranslator::FNMSUBS(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFPTrunc(m_ir->CreateFNeg(m_ir->CreateFSub(m_ir->CreateFMul(a, c), b)), GetType<f32>());
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, m_ir->CreateFNeg(b)});
}
else
{
result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFNeg(m_ir->CreateFPTrunc(result, GetType<f32>())));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fr", a, b, c)); // TODO ???
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fi", a, b, c));
@ -3932,8 +3963,18 @@ void PPUTranslator::FNMADDS(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFPTrunc(m_ir->CreateFNeg(m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b)), GetType<f32>());
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, b});
}
else
{
result = m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFNeg(m_ir->CreateFPTrunc(result, GetType<f32>())));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fr", a, b, c)); // TODO ???
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadds_get_fi", a, b, c));
@ -4182,7 +4223,17 @@ void PPUTranslator::FMSUB(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, m_ir->CreateFNeg(b)});
}
else
{
result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, result);
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fr", a, b, c)); // TODO ???
@ -4200,7 +4251,17 @@ void PPUTranslator::FMADD(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), { a, c, b });
}
else
{
result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, result);
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fr", a, b, c));
@ -4218,8 +4279,18 @@ void PPUTranslator::FNMSUB(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFNeg(m_ir->CreateFSub(m_ir->CreateFMul(a, c), b));
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, m_ir->CreateFNeg(b)});
}
else
{
result = m_ir->CreateFSub(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFNeg(result));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fr", a, b, c)); // TODO ???
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fi", a, b, c));
@ -4236,8 +4307,18 @@ void PPUTranslator::FNMADD(ppu_opcode_t op)
const auto a = GetFpr(op.fra);
const auto b = GetFpr(op.frb);
const auto c = GetFpr(op.frc);
const auto result = m_ir->CreateFNeg(m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b));
SetFpr(op.frd, result);
llvm::Value* result;
if (g_cfg.core.ppu_accurate_fma)
{
result = m_ir->CreateCall(get_intrinsic<f64>(llvm::Intrinsic::fma), {a, c, b});
}
else
{
result = m_ir->CreateFAdd(m_ir->CreateFMul(a, c), b);
}
SetFpr(op.frd, m_ir->CreateFNeg(result));
//SetFPSCR_FR(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fr", a, b, c)); // TODO ???
//SetFPSCR_FI(Call(GetType<bool>(), m_pure_attr, "__fmadd_get_fi", a, b, c));

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#ifdef LLVM_AVAILABLE

View File

@ -45,6 +45,7 @@ struct cfg_root : cfg::node
cfg::_enum<tsx_usage> enable_TSX{ this, "Enable TSX", tsx_usage::enabled }; // Enable TSX. Forcing this on Haswell/Broadwell CPUs should be used carefully
cfg::_bool spu_accurate_xfloat{ this, "Accurate xfloat", false };
cfg::_bool spu_approx_xfloat{ this, "Approximate xfloat", true };
cfg::_bool ppu_accurate_fma{ this, "PPU Accurate FMA", true }; // Enable accurate FMA for CPUs which do not support it natively (can't be disabled for CPUs which do support it)
cfg::_bool debug_console_mode{ this, "Debug Console Mode", false }; // Debug console emulation, not recommended
cfg::_enum<lib_loading_type> lib_loading{ this, "Lib Loader", lib_loading_type::liblv2only };