Implement some more FP instructions in the PPU LLVM recompiler

This commit is contained in:
S Gopal Rajagopal 2014-11-25 02:14:12 +05:30
parent bb1e08a6be
commit a9645eda73
3 changed files with 111 additions and 42 deletions

View file

@ -4192,9 +4192,7 @@ private:
}
}
(u64&)CPU.FPR[frd] = 0xfff8000000000000ull | r;
if(r == 0 && ( (u64&)b & DOUBLE_SIGN )) (u64&)CPU.FPR[frd] |= 0x100000000ull;
(u64&)CPU.FPR[frd] = r;
if(rc) UNK("fctiw.");
}
void FCTIWZ(u32 frd, u32 frb, bool rc)
@ -4232,10 +4230,7 @@ private:
value = (u32)i;
}
(u64&)CPU.FPR[frd] = 0xfff8000000000000ull | value;
if (value == 0 && ( (u64&)b & DOUBLE_SIGN ))
(u64&)CPU.FPR[frd] |= 0x100000000ull;
(u64&)CPU.FPR[frd] = (u64)value;
if(rc) UNK("fctiwz.");
}
void FDIV(u32 frd, u32 fra, u32 frb, bool rc)
@ -4333,7 +4328,7 @@ private:
{
CPU.SetFPSCRException(FPSCR_ZX);
}
CPU.FPR[frd] = static_cast<float>(1.0 / sqrt(CPU.FPR[frb]));
CPU.FPR[frd] = 1.0 / sqrt(CPU.FPR[frb]);
if(rc) UNK("frsqrte.");//CPU.UpdateCR1(CPU.FPR[frd]);
}
void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc)
@ -4458,9 +4453,7 @@ private:
}
}
(u64&)CPU.FPR[frd] = 0xfff8000000000000ull | r;
if(r == 0 && ( (u64&)b & DOUBLE_SIGN )) (u64&)CPU.FPR[frd] |= 0x100000000ull;
(u64&)CPU.FPR[frd] = r;
if(rc) UNK("fctid.");
}
void FCTIDZ(u32 frd, u32 frb, bool rc)
@ -4498,9 +4491,7 @@ private:
r = (u64)i;
}
(u64&)CPU.FPR[frd] = 0xfff8000000000000ull | r;
if(r == 0 && ( (u64&)b & DOUBLE_SIGN )) (u64&)CPU.FPR[frd] |= 0x100000000ull;
(u64&)CPU.FPR[frd] = r;
if(rc) UNK("fctidz.");
}
void FCFID(u32 frd, u32 frb, bool rc)

View file

@ -3991,8 +3991,7 @@ void Compiler::FDIVS(u32 frd, u32 fra, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto res_f64 = m_ir_builder->CreateFDiv(ra_f64, rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4007,8 +4006,7 @@ void Compiler::FSUBS(u32 frd, u32 fra, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto res_f64 = m_ir_builder->CreateFSub(ra_f64, rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4023,8 +4021,7 @@ void Compiler::FADDS(u32 frd, u32 fra, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto res_f64 = m_ir_builder->CreateFAdd(ra_f64, rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4038,8 +4035,7 @@ void Compiler::FSQRTS(u32 frd, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4052,7 +4048,8 @@ void Compiler::FSQRTS(u32 frd, u32 frb, bool rc) {
void Compiler::FRES(u32 frd, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto res_f64 = m_ir_builder->CreateFDiv(ConstantFP::get(m_ir_builder->getDoubleTy(), 1.0), rb_f64);
SetFpr(frd, res_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4067,8 +4064,7 @@ void Compiler::FMULS(u32 frd, u32 fra, u32 frc, bool rc) {
auto rc_f64 = GetFpr(frc);
auto res_f64 = m_ir_builder->CreateFMul(ra_f64, rc_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4084,8 +4080,7 @@ void Compiler::FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
auto rc_f64 = GetFpr(frc);
auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4102,8 +4097,7 @@ void Compiler::FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
rb_f64 = m_ir_builder->CreateFNeg(rb_f64);
auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4121,8 +4115,7 @@ void Compiler::FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64);
res_f64 = m_ir_builder->CreateFNeg(res_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4139,8 +4132,7 @@ void Compiler::FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64);
res_f64 = m_ir_builder->CreateFNeg(res_f64);
auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy());
res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
SetFpr(frd, res_f32);
if (rc) {
// TODO: Implement this
@ -4194,27 +4186,68 @@ void Compiler::MTFSF(u32 flm, u32 frb, bool rc) {
}
void Compiler::FCMPU(u32 crfd, u32 fra, u32 frb) {
InterpreterCall("FCMPU", &PPUInterpreter::FCMPU, crfd, fra, frb);
auto ra_f64 = GetFpr(fra);
auto rb_f64 = GetFpr(frb);
auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64);
auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64);
auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64);
auto cr_i32 = GetCr();
cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false));
SetCr(cr_i32);
// TODO: Set flags / Handle NaN
}
void Compiler::FRSP(u32 frd, u32 frb, bool rc) {
InterpreterCall("FRSP", &PPUInterpreter::FRSP, frd, frb, rc);
auto rb_f64 = GetFpr(frb);
auto res_f32 = m_ir_builder->CreateFPTrunc(rb_f64, m_ir_builder->getFloatTy());
auto res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy());
SetFpr(frd, res_f64);
if (rc) {
// TODO: Implement this
CompilationError("FRSP.");
}
// TODO: Revisit this
// TODO: Set flags
}
void Compiler::FCTIW(u32 frd, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto rb_f64 = GetFpr(frb);
auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0x7FFFFFFF));
auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648));
auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty());
SetFpr(frd, res_i32);
auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty());
res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64);
res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64);
SetFpr(frd, res_i64);
if (rc) {
// TODO: Implement this
CompilationError("FCTIW.");
}
// TODO: Set flags / Handle NaN / Implement Saturation
// TODO: Set flags / Implement rounding modes
//InterpreterCall("FCTIW", &PPUInterpreter::FCTIWZ, frd, frb, rc);
}
void Compiler::FCTIWZ(u32 frd, u32 frb, bool rc) {
//auto rb_f64 = GetFpr(frb);
//auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0x7FFFFFFF));
//auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648));
//auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty());
//auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty());
//res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64);
//res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64);
//SetFpr(frd, res_i64);
//if (rc) {
// // TODO: Implement this
// CompilationError("FCTIWZ.");
//}
// TODO: Set flags
InterpreterCall("FCTIWZ", &PPUInterpreter::FCTIWZ, frd, frb, rc);
}
@ -4274,7 +4307,19 @@ void Compiler::FSQRT(u32 frd, u32 frb, bool rc) {
}
void Compiler::FSEL(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
InterpreterCall("FSEL", &PPUInterpreter::FSEL, frd, fra, frc, frb, rc);
auto ra_f64 = GetFpr(fra);
auto rb_f64 = GetFpr(frb);
auto rc_f64 = GetFpr(frc);
auto cmp_i1 = m_ir_builder->CreateFCmpOGE(ra_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0.0));
auto res_f64 = m_ir_builder->CreateSelect(cmp_i1, rc_f64, rb_f64);
SetFpr(frd, res_f64);
if (rc) {
// TODO: Implement this
CompilationError("FSEL.");
}
// TODO: Set flags
}
void Compiler::FMUL(u32 frd, u32 fra, u32 frc, bool rc) {
@ -4368,7 +4413,16 @@ void Compiler::FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {
}
void Compiler::FCMPO(u32 crfd, u32 fra, u32 frb) {
InterpreterCall("FCMPO", &PPUInterpreter::FCMPO, crfd, fra, frb);
auto ra_f64 = GetFpr(fra);
auto rb_f64 = GetFpr(frb);
auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64);
auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64);
auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64);
auto cr_i32 = GetCr();
cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false));
SetCr(cr_i32);
// TODO: Set flags / Handle NaN
}
void Compiler::FNEG(u32 frd, u32 frb, bool rc) {
@ -4424,7 +4478,11 @@ void Compiler::FABS(u32 frd, u32 frb, bool rc) {
void Compiler::FCTID(u32 frd, u32 frb, bool rc) {
auto rb_f64 = GetFpr(frb);
auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0x7FFFFFFFFFFFFFFFll));
auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808ll));
auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty());
res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64);
res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64);
SetFpr(frd, res_i64);
if (rc) {
@ -4432,10 +4490,25 @@ void Compiler::FCTID(u32 frd, u32 frb, bool rc) {
CompilationError("FCTID.");
}
// TODO: Set flags / Handle NaN / Implement Saturation
// TODO: Set flags / Implement rounding modes
//InterpreterCall("FCTIDZ", &PPUInterpreter::FCTID, frd, frb, rc);
}
void Compiler::FCTIDZ(u32 frd, u32 frb, bool rc) {
//auto rb_f64 = GetFpr(frb);
//auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0x7FFFFFFFFFFFFFFFll));
//auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808ll));
//auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty());
//res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64);
//res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64);
//SetFpr(frd, res_i64);
//if (rc) {
// // TODO: Implement this
// CompilationError("FCTIDZ.");
//}
// TODO: Set flags
InterpreterCall("FCTIDZ", &PPUInterpreter::FCTIDZ, frd, frb, rc);
}

View file

@ -164,7 +164,7 @@ VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &Comp
std::string ret;
for (int i = 0; i < 32; i++) {
ret += fmt::Format("GPR[%02d] = 0x%016llx FPR[%02d] = %16g VPR[%02d] = 0x%s [%s]\n", i, GPR[i], i, FPR[i]._double, i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str());
ret += fmt::Format("GPR[%02d] = 0x%016llx FPR[%02d] = %16g (0x%016llx) VPR[%02d] = 0x%s [%s]\n", i, GPR[i], i, FPR[i]._double, FPR[i]._u64, i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str());
}
for (int i = 0; i < 8; i++) {
@ -663,17 +663,22 @@ void Compiler::RunAllTests() {
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FMSUBS, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNMSUBS, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNMADDS, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FCMPU, 0, 5, 5, 0, 1);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FRSP, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FCTIW, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FCTIWZ, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FDIV, 0, 5, 0, 1, 2, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FSUB, 0, 5, 0, 1, 2, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FADD, 0, 5, 0, 1, 2, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FSQRT, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FSEL, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FMUL, 0, 5, 0, 1, 2, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FRSQRTE, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FMSUB, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FMADD, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNMSUB, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNMADD, 0, 5, 0, 1, 2, 3, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FCMPO, 0, 5, 3, 0, 1);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNEG, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FMR, 0, 5, 0, 1, false);
VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(FNABS, 0, 5, 0, 1, false);