void sankoff_canonize (elt_p ep, int * cm) { int i; int j; int state; int newe; int newbeta; int mincost=infinity,state_w_mincost=0; sankoff_get_min_state(ep,&mincost,&state_w_mincost); int num_states = ep->num_states; for (i=0;i<num_states;i++) { state = sankoff_get_state(ep,i); newe = (is_infinity(state)) ? infinity : state-mincost; sankoff_set_e(ep,i,newe); } int best; int thise; for (i=0;i<num_states;i++) { newbeta = infinity; for (j=num_states-1;j>=0;j--) { thise = sankoff_get_e(ep,j); best = (is_infinity(thise)) ? thise : thise + sankoff_return_value(cm,num_states,num_states,i,j); store_min(best,&newbeta); } sankoff_set_beta(ep,i,newbeta); } return; }
__inline int #elif __clang__ int #else inline int #endif cost_plus (int a, int b) { if ((is_infinity(a))||(is_infinity(b))) return infinity; else return(a+b); }
__inline int #elif __clang__ int #else inline int #endif cost_less_or_equal (int a, int b) { if (is_infinity(a)) return 0; else if (is_infinity(b)) return 1; else return (a<=b); }
void ieee_floatt::extract_base10( mp_integer &_fraction, mp_integer &_exponent) const { if(is_zero() || is_NaN() || is_infinity()) { _fraction=_exponent=0; return; } _exponent=exponent; _fraction=fraction; // adjust exponent _exponent-=spec.f; // now make it base 10 if(_exponent>=0) { _fraction*=power(2, _exponent); _exponent=0; } else // _exponent<0 { // 10/2=5 -- this makes it base 10 _fraction*=power(5, -_exponent); } // try to re-normalize while((_fraction%10)==0) { _fraction/=10; ++_exponent; } }
inline int_adapter operator-(const int_adapter<rhs_type>& rhs)const { if(is_special() || rhs.is_special()) { if (is_nan() || rhs.is_nan()) { return int_adapter::not_a_number(); } if((is_pos_inf(value_) && rhs.is_pos_inf(rhs.as_number())) || (is_neg_inf(value_) && rhs.is_neg_inf(rhs.as_number())) ) { return int_adapter::not_a_number(); } if (is_infinity()) { return *this; } if (rhs.is_pos_inf(rhs.as_number())) { return int_adapter::neg_infinity(); } if (rhs.is_neg_inf(rhs.as_number())) { return int_adapter::pos_infinity(); } } return int_adapter<int_type>(value_ - rhs.as_number()); }
float_utilst::unbiased_floatt float_utilst::unpack(const bvt &src) { assert(src.size()==spec.width()); unbiased_floatt result; result.sign=sign_bit(src); result.fraction=get_fraction(src); result.fraction.push_back(is_normal(src)); // add hidden bit result.exponent=get_exponent(src); assert(result.exponent.size()==spec.e); // unbias the exponent literalt denormal=bv_utils.is_zero(result.exponent); result.exponent= bv_utils.select(denormal, bv_utils.build_constant(-spec.bias()+1, spec.e), sub_bias(result.exponent)); result.infinity=is_infinity(src); result.zero=is_zero(src); result.NaN=is_NaN(src); return result; }
static mlval to_string(mlval arg) { char buffer[40]; size_t length; mlval string; double x = GETREAL (FIELD (arg,0)); int prec = CINT (FIELD (arg,1)); if (isnan(x)) strcpy (buffer,"nan"); else if (is_infinity (x)) if (x > 0.0) strcpy (buffer,"inf"); else strcpy (buffer,"~inf"); else { size_t i, plus = 0; int point = 0; sprintf(buffer, "%.*G", prec, x); length = strlen(buffer); for(i=0; i<length; ++i) { char c = buffer[i]; if(c == '-') buffer[i] = '~'; else if(c == '.' || c == 'E') point = 1; else if(c == '+') plus = i; } if(plus) { for(i=plus; i<length; ++i) buffer[i] = buffer[i+1]; length--; } if(!point) { buffer[length++] = '.'; buffer[length++] = '0'; buffer[length] = '\0'; } } length = strlen (buffer); string = allocate_string(length+1); strcpy(CSTRING(string), buffer); return(string); }
__inline int #elif __clang__ int #else inline int #endif cost_minus (int a, int b) { if (is_infinity(a)) { assert(!(is_infinity(b))); return INT_MAX; } else if (is_infinity(b)) { return 0; } else return(a-b); }
int_adapter operator-(int_type rhs) const { if (is_nan()) { return int_adapter<int_type>(not_a_number()); } if (is_infinity()) { return *this; } return int_adapter<int_type>(value_ - rhs); }
// Floating Negative Multiply-Sub static void fnmsub(ThreadState *state, Instruction instr) { double a, b, c, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vximz = is_infinity(a * c) && is_zero(c); state->fpscr.vxisi = is_infinity(a * c) || is_infinity(c); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b) || is_signalling_nan(c); d = -((a * c) - b); updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
static void fsubGeneric(ThreadState *state, Instruction instr) { double a, b, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; state->fpscr.vxisi = is_infinity(a) && is_infinity(b); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b); d = static_cast<Type>(a - b); updateFPSCR(state); d = checkNan<Type>(d, a, b); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
int_adapter operator-(const int_adapter& rhs) const { if (is_nan() || rhs.is_nan()) { return int_adapter<int_type>(not_a_number()); } if (is_infinity()) { return *this; } if (rhs.is_infinity()) { return rhs; } return int_adapter<int_type>(value_ - rhs.value_); }
int_adapter operator+(const int_type rhs) const { if(is_special()) { if (is_nan()) { return int_adapter<int_type>(not_a_number()); } if (is_infinity()) { return *this; } } return int_adapter<int_type>(value_ + rhs); }
void sankoff_print_int_array (char * str, int * arr, int size) { printf("%s,",str); int i, tmp; for (i=0;i<size;i++) { tmp = arr[i]; if(is_infinity(tmp)) printf ("inf,"); else printf("%d,",tmp); } printf("\n"); fflush(stdout); }
// should templatize this to be consistant with op +- int_adapter operator%(const int_adapter& rhs)const { if(this->is_special() || rhs.is_special()) { if(is_infinity() && rhs.is_infinity()) { return int_adapter<int_type>(not_a_number()); } if(rhs != 0) { return mult_div_specials(rhs); } else { // let divide by zero blow itself up return int_adapter<int_type>(value_ % rhs.value_); } } return int_adapter<int_type>(value_ % rhs.value_); }
/// Sets *this to the next representable number closer to plus infinity (greater /// = true) or minus infinity (greater = false). void ieee_floatt::next_representable(bool greater) { if(is_NaN()) return; bool old_sign=get_sign(); if(is_zero()) { unpack(1); set_sign(!greater); return; } if(is_infinity()) { if(get_sign()==greater) { make_fltmax(); set_sign(old_sign); } return; } bool dir; if(greater) dir=!get_sign(); else dir=get_sign(); set_sign(false); mp_integer old=pack(); if(dir) ++old; else --old; unpack(old); // sign change impossible (zero case caught earler) set_sign(old_sign); }
// Floating Multiply-Add Single static void fmadds(ThreadState *state, Instruction instr) { double a, b, c, d; a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(b) || is_signalling_nan(c); state->fpscr.vxisi = is_infinity(a * c) || is_infinity(c); state->fpscr.vximz = is_infinity(a * c) && is_zero(c); d = a * c; if (is_nan(d)) { if (is_nan(a)) { d = make_quiet(a); } else if (is_nan(b)) { d = make_quiet(b); } else if (is_nan(c)) { d = make_quiet(c); } else { d = make_nan<double>(); } } else { if (is_infinity(d) && is_infinity(b) && !(is_infinity(a) || is_infinity(c))) { d = b; } else { d = d + b; if (is_nan(d)) { if (is_nan(b)) { d = make_quiet(b); } else { d = make_nan<double>(); } } } } updateFPSCR(state); updateFPRF(state, d); state->fpr[instr.frD].paired0 = static_cast<float>(d); if (instr.rc) { updateFloatConditionRegister(state); } }
static void fmulGeneric(ThreadState *state, Instruction instr) { double a, c, d; a = state->fpr[instr.frA].paired0; c = state->fpr[instr.frC].paired0; state->fpscr.vximz = is_infinity(a) && is_zero(c); state->fpscr.vxsnan = is_signalling_nan(a) || is_signalling_nan(c); d = static_cast<Type>(a * c); updateFPSCR(state); d = checkNan<Type>(d, a, c); updateFPRF(state, d); state->fpr[instr.frD].paired0 = d; if (instr.rc) { updateFloatConditionRegister(state); } }
inline S generalized_mean(I first, I last, T p) { // Check for well known cases. if (p == -1) return harmonic_mean(first, last); if (p == 0) return geometric_mean(first, last); if (p == 1) return arithmetic_mean(first, last); if (p == 2) return quadratic_mean(first, last); if (p == 3) return cubic_mean(first, last); // Either handle the infinity case or compute the generalized // value. if (is_infinity(p)) return generalized_mean_inf(first, last, p); else return generalized_mean_non_inf(first, last, p); }
void ieee_floatt::extract_base2( mp_integer &_fraction, mp_integer &_exponent) const { if(is_zero() || is_NaN() || is_infinity()) { _fraction=_exponent=0; return; } _exponent=exponent; _fraction=fraction; // adjust exponent _exponent-=spec.f; // try to integer-ize while((_fraction%2)==0) { _fraction/=2; ++_exponent; } }
int runTests(const std::string &path) { uint32_t testsFailed = 0, testsPassed = 0; auto baseAddress = cpu::VirtualAddress { 0x02000000u }; auto basePhysicalAddress = cpu::PhysicalAddress { 0x50000000u }; auto codeSize = 2048u; cpu::allocateVirtualAddress(baseAddress, codeSize); cpu::mapMemory(baseAddress, basePhysicalAddress, codeSize, cpu::MapPermission::ReadWrite); Instruction bclr = encodeInstruction(InstructionID::bclr); bclr.bo = 0x1f; mem::write(baseAddress.getAddress() + 4, bclr.value); auto ec = std::error_code { }; for (auto itr = std::filesystem::directory_iterator { "/tests", ec }; itr != end(itr); ++itr) { std::ifstream file(itr->path().string(), std::ifstream::in | std::ifstream::binary); cereal::BinaryInputArchive cerealInput(file); TestFile testFile; // Parse test file with cereal testFile.name = itr->path().filename().string(); cerealInput(testFile); // Run tests for (auto &test : testFile.tests) { bool failed = false; if (!TEST_FMADDSUB) { auto data = espresso::decodeInstruction(test.instr); switch (data->id) { case InstructionID::fmadd: case InstructionID::fmadds: case InstructionID::fmsub: case InstructionID::fmsubs: case InstructionID::fnmadd: case InstructionID::fnmadds: case InstructionID::fnmsub: case InstructionID::fnmsubs: failed = true; break; } if (failed) { continue; } } // Setup core state from test input cpu::CoreRegs *state = cpu::this_core::state(); memset(state, 0, sizeof(cpu::CoreRegs)); state->cia = 0; state->nia = baseAddress.getAddress(); state->xer = test.input.xer; state->cr = test.input.cr; state->fpscr = test.input.fpscr; state->ctr = test.input.ctr; for (auto i = 0; i < 4; ++i) { state->gpr[i + 3] = test.input.gpr[i]; state->fpr[i + 1].paired0 = test.input.fr[i]; } // Execute test mem::write(baseAddress.getAddress(), test.instr.value); cpu::clearInstructionCache(); cpu::this_core::executeSub(); // Check XER (all bits) if (state->xer.value != test.output.xer.value) { gLog->error("Test failed, xer expected {:08X} found {:08X}", test.output.xer.value, state->xer.value); failed = true; } // Check Condition Register (all bits) if (state->cr.value != test.output.cr.value) { gLog->error("Test failed, cr expected {:08X} found {:08X}", test.output.cr.value, state->cr.value); failed = true; } // Check FPSCR if (TEST_FPSCR) { if (!TEST_FPSCR_FR) { state->fpscr.fr = 0; test.output.fpscr.fr = 0; } if (!TEST_FPSCR_UX) { state->fpscr.ux = 0; test.output.fpscr.ux = 0; } auto state_fpscr = state->fpscr.value; auto test_fpscr = test.output.fpscr.value; if (state_fpscr != test_fpscr) { gLog->error("Test failed, fpscr {:08X} found {:08X}", test.output.fpscr.value, state->fpscr.value); compareFPSCR(test.input.fpscr, state->fpscr, test.output.fpscr); failed = true; } } // Check CTR if (state->ctr != test.output.ctr) { gLog->error("Test failed, ctr expected {:08X} found {:08X}", test.output.ctr, state->ctr); failed = true; } // Check all GPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::GPR_BASE; auto value = state->gpr[reg]; auto expected = test.output.gpr[i]; if (value != expected) { gLog->error("Test failed, r{} expected {:08X} found {:08X}", reg, expected, value); failed = true; } } // Check all FPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::FPR_BASE; auto value = state->fpr[reg].value; auto expected = test.output.fr[i]; if (!is_nan(value) && !is_nan(expected) && !is_infinity(value) && !is_infinity(expected)) { double dval = value / expected; if (dval < 0.999 || dval > 1.001) { gLog->error("Test failed, f{} expected {:16f} found {:16f}", reg, expected, value); failed = true; } } else { if (is_nan(value) && is_nan(expected)) { auto bits = get_float_bits(value); bits.sign = get_float_bits(expected).sign; value = bits.v; } if (bit_cast<uint64_t>(value) != bit_cast<uint64_t>(expected)) { gLog->error("Test failed, f{} expected {:16X} found {:16X}", reg, bit_cast<uint64_t>(expected), bit_cast<uint64_t>(value)); failed = true; } } } if (failed) { Disassembly dis; // Print disassembly disassemble(test.instr, dis, baseAddress.getAddress()); gLog->debug(dis.text); // Print all test fields gLog->debug("{:08x} Input Hardware Interp", test.instr.value); for (auto field : dis.instruction->read) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->write) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->flags) { printTestField(field, test.instr, &test.input, &test.output, state); } gLog->debug(""); ++testsFailed; } else { ++testsPassed; } } } if (testsFailed) { gLog->error("Failed {} of {} tests.", testsFailed, testsFailed + testsPassed); } return testsFailed; }
void ieee_floatt::next_representable(bool greater) { if(is_NaN()) return; bool old_sign = get_sign(); if(is_zero()) { unpack(1); set_sign(!greater); return; } if(is_infinity()) { if(get_sign() == greater) { make_fltmax(); set_sign(old_sign); } return; } bool dir; if(greater) { if(get_sign()) dir = false; else dir = true; } else { if(get_sign()) dir = true; else dir = false; } set_sign(false); mp_integer old = pack(); if(dir) ++old; else --old; unpack(old); //sign change impossible (zero case caught earler) set_sign(old_sign); //mp_integer new_exp = exponent; //mp_integer new_frac = fraction + dir; //std::cout << exponent << ":" << fraction << std::endl; //std::cout << new_exp << ":" << new_frac << std::endl; //if(get_sign()) // new_frac.negate(); //new_exp -= spec.f; //build(new_frac, new_exp); }
//! check to see if time is a special value bool is_special() const { return(is_not_a_date_time() || is_infinity()); }
static mlval fmt (mlval arg) { char buffer[40]; size_t length; mlval string; mlval format = FIELD (arg, 0); double x = GETREAL (FIELD (arg,1)); int prec = 0; /* Check the precision first */ if (format != EXACT_FORMAT) { int format_type = CINT (FIELD (format, 0)); int min_prec = 0; /* Minimum precision is 0 for SCI and FIX, 1 for GEN. */ if (format_type == GEN_FORMAT) min_prec = 1; if (FIELD (format,1) == MLINT (0)) { /* Argument is NONE => Default precision. */ prec = -1; } else { prec = CINT (FIELD (FIELD (format,1),1)); if (prec < min_prec) exn_raise(perv_exn_ref_size); } } if (isnan (x)) strcpy (buffer,"nan"); else if (is_infinity (x)) if (x > 0.0) strcpy (buffer,"+inf"); else strcpy (buffer,"-inf"); else if (format == EXACT_FORMAT) { /* EXACT conversion required */ /* Note that this doesn't do the right thing with NaN's, but */ /* this should be taken care of on the ML side of things */ int dec; int sign; char * ptr = buffer; char * digits = dtoa (x,0,100,&dec,&sign,NULL); char * dptr = digits; if (sign) *ptr++ = '~'; *ptr++ = '0'; *ptr++ = '.'; /* Don't copy null byte here */ while (*dptr) *ptr++=*dptr++; if (dec != 0){ *ptr++ = 'E'; if (dec < 0) { dec = -dec; *ptr++ = '~'; } /* Now add the exponent */ sprintf (ptr,"%d",dec); ptr += strlen (ptr); } *ptr++ = '\000'; freedtoa (digits); } else { /* Now we have to decipher the format */ size_t i, plus = 0; int point = 0; int format_type = CINT (FIELD (format,0)); if (format_type == FIX_FORMAT) /* FIX */ sprintf (buffer, "%.*f", prec < 0 ? 6 : prec, x); else if (format_type == GEN_FORMAT) /* GEN */ sprintf (buffer, "%.*G", prec < 0 ? 12 : prec,x); else if (format_type == SCI_FORMAT) /* SCI */ sprintf (buffer, "%.*E", prec < 0 ? 6 : prec, x); else sprintf(buffer, "%.18G", x); length = strlen(buffer); /* Now check for correct printing of negative zeroes */ if (x == 0.0) { switch (check_neg_zero(&x)) { case 2: /* -0.0 */ /* May need to modify the output here */ if (*buffer != '-') { /* Yes, we do need to modify */ if (*buffer == '+') { *buffer = '-'; } else { for (i = length+1; i > 0; i--) { buffer[i] = buffer[i-1]; /* Move the characters along the buffer */ }; length++; *buffer = '-'; } } case 0: /* Not actually 0.0 at all */ case 1: /* +0.0 */ default: /* This shouldn't happen */ /* No action required here */ break; } } for(i=0; i<length; ++i) { char c = buffer[i]; if(c == '-') buffer[i] = '~'; else if(c == '.' || c == 'E') point = i; else if(c == '+') plus = i; } /* Win32 screws up G format by printing too many digits */ /* in the exponent. So we contract that part if necessary */ if (point && buffer[point] == 'E') { char c = buffer[point+1]; if (c == '+' || c == '~') point++; if (buffer[point+1] == '0' && isdigit(buffer[point+2]) && isdigit(buffer[point+3])) { buffer[point+1] = buffer[point+2]; buffer[point+2] = buffer[point+3]; buffer[point+3] = '\0'; } } if(plus) { for(i=plus; i<length; ++i) buffer[i] = buffer[i+1]; length--; } if(!point && (format_type != GEN_FORMAT) && !(format_type == FIX_FORMAT && prec == 0)) { buffer[length++] = '.'; buffer[length++] = '0'; buffer[length] = '\0'; } } length = strlen (buffer); string = allocate_string(length+1); strcpy(CSTRING(string), buffer); return(string); }
static bool fmaSingle(cpu::Core *state, Instruction instr, float *result) { double a, b, c; if (slotAB == 0) { a = state->fpr[instr.frA].paired0; b = state->fpr[instr.frB].paired0; } else { a = state->fpr[instr.frA].paired1; b = state->fpr[instr.frB].paired1; } if (slotC == 0) { c = state->fpr[instr.frC].paired0; } else { c = state->fpr[instr.frC].paired1; } const double addend = (flags & FMASubtract) ? -b : b; const bool vxsnan = is_signalling_nan(a) || is_signalling_nan(b) || is_signalling_nan(c); const bool vximz = (is_infinity(a) && is_zero(c)) || (is_zero(a) && is_infinity(c)); const bool vxisi = (!vximz && !is_nan(a) && !is_nan(c) && (is_infinity(a) || is_infinity(c)) && is_infinity(b) && (std::signbit(a) ^ std::signbit(c)) != std::signbit(addend)); state->fpscr.vxsnan |= vxsnan; state->fpscr.vxisi |= vxisi; state->fpscr.vximz |= vximz; if ((vxsnan || vxisi || vximz) && state->fpscr.ve) { return false; } float d; if (is_nan(a)) { d = make_quiet(truncate_double(a)); } else if (is_nan(b)) { d = make_quiet(truncate_double(b)); } else if (is_nan(c)) { d = make_quiet(truncate_double(c)); } else if (vxisi || vximz) { d = make_nan<float>(); } else { if (slotC == 0) { roundForMultiply(&a, &c); // Not necessary for slot 1. } double d64 = std::fma(a, c, addend); if (state->fpscr.rn == espresso::FloatingPointRoundMode::Nearest) { d = roundFMAResultToSingle(d64, a, addend, c); } else { d = static_cast<float>(d64); } if (possibleUnderflow<float>(d)) { const int oldRound = fegetround(); fesetround(FE_TOWARDZERO); volatile double addendTemp = addend; volatile float dummy; dummy = (float)std::fma(a, c, addendTemp); fesetround(oldRound); } if (flags & FMANegate) { d = -d; } } *result = d; return true; }
static bool psArithSingle(cpu::Core *state, Instruction instr, float *result) { double a, b; if (slotA == 0) { a = state->fpr[instr.frA].paired0; } else { a = state->fpr[instr.frA].paired1; } if (slotB == 0) { b = state->fpr[op == PSMul ? instr.frC : instr.frB].paired0; } else { b = state->fpr[op == PSMul ? instr.frC : instr.frB].paired1; } const bool vxsnan = is_signalling_nan(a) || is_signalling_nan(b); bool vxisi, vximz, vxidi, vxzdz, zx; switch (op) { case PSAdd: vxisi = is_infinity(a) && is_infinity(b) && std::signbit(a) != std::signbit(b); vximz = false; vxidi = false; vxzdz = false; zx = false; break; case PSSub: vxisi = is_infinity(a) && is_infinity(b) && std::signbit(a) == std::signbit(b); vximz = false; vxidi = false; vxzdz = false; zx = false; break; case PSMul: vxisi = false; vximz = (is_infinity(a) && is_zero(b)) || (is_zero(a) && is_infinity(b)); vxidi = false; vxzdz = false; zx = false; break; case PSDiv: vxisi = false; vximz = false; vxidi = is_infinity(a) && is_infinity(b); vxzdz = is_zero(a) && is_zero(b); zx = !(vxzdz || vxsnan) && is_zero(b); break; } state->fpscr.vxsnan |= vxsnan; state->fpscr.vxisi |= vxisi; state->fpscr.vximz |= vximz; state->fpscr.vxidi |= vxidi; state->fpscr.vxzdz |= vxzdz; state->fpscr.zx |= zx; const bool vxEnabled = (vxsnan || vxisi || vximz || vxidi || vxzdz) && state->fpscr.ve; const bool zxEnabled = zx && state->fpscr.ze; if (vxEnabled || zxEnabled) { return false; } float d; if (is_nan(a)) { d = make_quiet(truncate_double(a)); } else if (is_nan(b)) { d = make_quiet(truncate_double(b)); } else if (vxisi || vximz || vxidi || vxzdz) { d = make_nan<float>(); } else { switch (op) { case PSAdd: d = static_cast<float>(a + b); break; case PSSub: d = static_cast<float>(a - b); break; case PSMul: if (slotB == 0) { roundForMultiply(&a, &b); // Not necessary for slot 1. } d = static_cast<float>(a * b); break; case PSDiv: d = static_cast<float>(a / b); break; } if (possibleUnderflow<float>(d)) { const int oldRound = fegetround(); fesetround(FE_TOWARDZERO); volatile double bTemp = b; volatile float dummy; switch (op) { case PSAdd: dummy = static_cast<float>(a + bTemp); break; case PSSub: dummy = static_cast<float>(a - bTemp); break; case PSMul: dummy = static_cast<float>(a * bTemp); break; case PSDiv: dummy = static_cast<float>(a / bTemp); break; } fesetround(oldRound); } } *result = d; return true; }
bool is_special() const { return(is_infinity() || is_nan()); }
bool runTests(const std::string &path) { uint32_t testsFailed = 0, testsPassed = 0; uint32_t baseAddress = mem::MEM2Base; Instruction bclr = encodeInstruction(InstructionID::bclr); bclr.bo = 0x1f; mem::write(baseAddress + 4, bclr.value); fs::FileSystem filesystem; fs::FolderEntry entry; fs::HostPath base = path; filesystem.mountHostFolder("/tests", base, fs::Permissions::Read); auto folder = filesystem.openFolder("/tests"); while (folder->read(entry)) { std::ifstream file(base.join(entry.name).path(), std::ifstream::in | std::ifstream::binary); cereal::BinaryInputArchive cerealInput(file); TestFile testFile; // Parse test file with cereal testFile.name = entry.name; cerealInput(testFile); // Run tests gLog->info("Checking {}", testFile.name); for (auto &test : testFile.tests) { bool failed = false; if (!TEST_FMADDSUB) { auto data = espresso::decodeInstruction(test.instr); switch (data->id) { case InstructionID::fmadd: case InstructionID::fmadds: case InstructionID::fmsub: case InstructionID::fmsubs: case InstructionID::fnmadd: case InstructionID::fnmadds: case InstructionID::fnmsub: case InstructionID::fnmsubs: failed = true; break; } if (failed) { continue; } } // Setup core state from test input cpu::CoreRegs *state = cpu::this_core::state(); memset(state, 0, sizeof(cpu::CoreRegs)); state->cia = 0; state->nia = baseAddress; state->xer = test.input.xer; state->cr = test.input.cr; state->fpscr = test.input.fpscr; state->ctr = test.input.ctr; for (auto i = 0; i < 4; ++i) { state->gpr[i + 3] = test.input.gpr[i]; state->fpr[i + 1].paired0 = test.input.fr[i]; } // Execute test mem::write(baseAddress, test.instr.value); cpu::jit::clearCache(); cpu::this_core::executeSub(); // Check XER (all bits) if (state->xer.value != test.output.xer.value) { gLog->error("Test failed, xer expected {:08X} found {:08X}", test.output.xer.value, state->xer.value); failed = true; } // Check Condition Register (all bits) if (state->cr.value != test.output.cr.value) { gLog->error("Test failed, cr expected {:08X} found {:08X}", test.output.cr.value, state->cr.value); failed = true; } // Check FPSCR if (TEST_FPSCR) { if (!TEST_FPSCR_FR) { state->fpscr.fr = 0; test.output.fpscr.fr = 0; } if (!TEST_FPSCR_UX) { state->fpscr.ux = 0; test.output.fpscr.ux = 0; } auto state_fpscr = state->fpscr.value; auto test_fpscr = test.output.fpscr.value; if (state_fpscr != test_fpscr) { gLog->error("Test failed, fpscr {:08X} found {:08X}", test.output.fpscr.value, state->fpscr.value); compareFPSCR(test.input.fpscr, state->fpscr, test.output.fpscr); failed = true; } } // Check CTR if (state->ctr != test.output.ctr) { gLog->error("Test failed, ctr expected {:08X} found {:08X}", test.output.ctr, state->ctr); failed = true; } // Check all GPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::GPR_BASE; auto value = state->gpr[reg]; auto expected = test.output.gpr[i]; if (value != expected) { gLog->error("Test failed, r{} expected {:08X} found {:08X}", reg, expected, value); failed = true; } } // Check all FPR for (auto i = 0; i < 4; ++i) { auto reg = i + hwtest::FPR_BASE; auto value = state->fpr[reg].value; auto expected = test.output.fr[i]; if (!is_nan(value) && !is_nan(expected) && !is_infinity(value) && !is_infinity(expected)) { double dval = value / expected; if (dval < 0.999 || dval > 1.001) { gLog->error("Test failed, f{} expected {:16f} found {:16f}", reg, expected, value); failed = true; } } else { if (is_nan(value) && is_nan(expected)) { auto bits = get_float_bits(value); bits.sign = get_float_bits(expected).sign; value = bits.v; } if (bit_cast<uint64_t>(value) != bit_cast<uint64_t>(expected)) { gLog->error("Test failed, f{} expected {:16X} found {:16X}", reg, bit_cast<uint64_t>(expected), bit_cast<uint64_t>(value)); failed = true; } } } if (failed) { Disassembly dis; // Print disassembly disassemble(test.instr, dis, baseAddress); gLog->debug(dis.text); // Print all test fields gLog->debug("{:08x} Input Hardware Interp", test.instr.value); for (auto field : dis.instruction->read) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->write) { printTestField(field, test.instr, &test.input, &test.output, state); } for (auto field : dis.instruction->flags) { printTestField(field, test.instr, &test.input, &test.output, state); } gLog->debug(""); ++testsFailed; } else { ++testsPassed; } } } gLog->info("Passed: {}, Failed: {}", testsPassed, testsFailed); return true; }