/****************************** Intel Confidential ******************************/ // MACH #include "ki.h" #ifndef WIN32_OR_WIN64 #include #include #include #endif #include "fepublic.h" #include "fehelper.h" #include "festate.h" // MACH #ifdef WIN32_OR_WIN64 // MACH #include // MACH #endif // ************************************************************* // The functions fp_reg_read_hi() and fp_reg_read_lo() // Take a packed floating-point register, // Reads the hi (or lo) part // Returns a register-biased number with implicit made explicit. // ************************************************************* EM_uint64_t fp_concatenate(EM_uint_t hi_val, EM_uint_t lo_val) { return( ((EM_uint64_t)hi_val <<32) | ((EM_uint64_t)lo_val & CONST_FORMAT(0x00000000FFFFFFFF )) ); } EM_uint_t fp_extract_bits( EM_uint64_t input_value, unsigned int hi_bound, unsigned int lo_bound) { EM_uint64_t value; if(lo_bound >63) return(0x00000000); value = (input_value >> lo_bound) & ~(CONST_FORMAT(0xFFFFFFFFFFFFFFFF) << (hi_bound - lo_bound + 1)); return((EM_uint_t)value); } INLINE EM_fp_reg_type fp_reg_read_hi(EM_uint_t freg) { EM_fp_reg_type tmp_freg = FR[freg]; EM_memory_type mem; if (freg == 0) return (FP_ZERO); else if (freg == 1) { return (FP_NEG_ZERO); } else { mem.uint_32.uvalue = (EM_uint_t)(tmp_freg.significand >> 32); tmp_freg = fp_mem_to_fr_format(mem, 4, 0); return (tmp_freg); } } INLINE EM_fp_reg_type fp_reg_read_lo(EM_uint_t freg) { EM_fp_reg_type tmp_freg = FR[freg]; EM_memory_type mem; EM_uint64_t tmp_val; EM_uint_t tmp32_val; if (freg == 0) return (FP_ZERO); else if (freg == 1) { return (FP_ZERO); } else { tmp_val = (tmp_freg.significand & CONST_FORMAT(0x00000000ffffffff)); tmp32_val = (EM_uint_t)tmp_val; mem.uint_32.uvalue = tmp32_val; tmp_freg = fp_mem_to_fr_format(mem, 4, 0); return (tmp_freg); } } #undef fp_reg_read_hi #undef fp_reg_read_lo #define fp_reg_read_hi(f2) fp82_reg_read_hi(ps,f2) #define fp_reg_read_lo(f3) fp82_reg_read_lo(ps,f3) // *********************************************************** // fp_fr_to_mem_format() // ************************************************************ EM_memory_type fp_fr_to_mem_format( EM_fp_reg_type freg, EM_uint_t size, EM_uint_t integer_form) { EM_memory_type tmp_mem; EM_uint64_t tmp_significand; switch(size) { case 4: tmp_mem.fp_single.sign = freg.sign; if (freg.exponent == 0) tmp_mem.fp_single.exponent = 0; else if ((freg.significand>>63) == 0) tmp_mem.fp_single.exponent = 0; else if (freg.exponent == FP_REG_EXP_ONES) tmp_mem.fp_single.exponent = FP_SGL_EXP_ONES; else tmp_mem.fp_single.exponent = ((freg.exponent >> (FP_REG_EXP_WIDTH-1) & 1) << (FP_SGL_EXP_WIDTH-1)) |( freg.exponent & FP_SGL_BIAS); tmp_mem.fp_single.significand = (EM_uint_t)((freg.significand <<1) >>(63-22)); break; case 8: /* double */ if (integer_form) tmp_mem.uint_64.uvalue = freg.significand; else { /* !integer_form */ tmp_mem.fp_double.sign = freg.sign; if (freg.exponent == 0) tmp_mem.fp_double.exponent = 0; else if ((freg.significand>>63) == 0) tmp_mem.fp_double.exponent = 0; else if (freg.exponent == FP_REG_EXP_ONES) tmp_mem.fp_double.exponent = FP_DBL_EXP_ONES; else tmp_mem.fp_double.exponent = ((freg.exponent >> (FP_REG_EXP_WIDTH-1) & 1) << (FP_DBL_EXP_WIDTH-1)) |( freg.exponent & FP_DBL_BIAS); tmp_significand = (freg.significand <<1) >> (63-51); tmp_mem.fp_double.significand_hi = (EM_uint_t)((tmp_significand >> 32) & CONST_FORMAT( 0x00000000ffffffff)); tmp_mem.fp_double.significand_lo = (EM_uint_t)(tmp_significand & CONST_FORMAT( 0x00000000ffffffff)); } break; case 10: /* double extended */ tmp_mem.fp_double_extended.sign = freg.sign; if (freg.exponent == 0) { /* Zero or (Pseudo-)Denormal */ tmp_mem.fp_double_extended.exponent = 0; } else if (freg.exponent == FP_REG_EXP_ONES) { /* Inf/NaN/NatVAL */ tmp_mem.fp_double_extended.exponent = FP_EXT_EXP_ONES; } else { /* Normal or Unnormal */ tmp_mem.fp_double_extended.exponent = ((freg.exponent >> (FP_REG_EXP_WIDTH-1) & 1) << (FP_EXT_EXP_WIDTH-1)) |( freg.exponent & FP_EXT_BIAS); } memcpy(tmp_mem.fp_double_extended.significand, &freg.significand, 8); break; case 16: /* spill */ tmp_mem.fp_spill_fill.reserved1 = 0; tmp_mem.fp_spill_fill.reserved2 = 0; tmp_mem.fp_spill_fill.sign = freg.sign; tmp_mem.fp_spill_fill.exponent = freg.exponent; tmp_mem.fp_spill_fill.significand = freg.significand; break; } return (tmp_mem); } INLINE EM_memory_type fr_to_mem4_bias_adjust(EM_fp_reg_type freg) { EM_memory_type tmp_mem; tmp_mem.fp_single.sign = freg.sign; if (freg.exponent == 0) tmp_mem.fp_single.exponent = 0; else if (freg.exponent == FP_REG_EXP_ONES) tmp_mem.fp_single.exponent = FP_SGL_EXP_ONES; else if ((freg.significand>>63) == 0) tmp_mem.fp_single.exponent = (EM_uint_t) (((EM_int_t)freg.exponent) - FP_REG_BIAS + FP_SGL_BIAS - 1); else tmp_mem.fp_single.exponent = (EM_uint_t) (((EM_int_t)freg.exponent) - FP_REG_BIAS + FP_SGL_BIAS); tmp_mem.fp_single.significand = (EM_uint_t) ( (freg.significand<<(64-62-1))>>(40+64-62-1)); return (tmp_mem); } // ***************************************************** // helper functions definitions // ***************************************************** INLINE EM_boolean_t fp_equal(EM_fp_reg_type fr1, EM_fp_reg_type fr2) { EM_fp_dp_type fp_dp1; EM_fp_dp_type fp_dp2; if ( fp_is_nan(fr1) || fp_is_nan(fr2) || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) ) return (0); fp_dp1 = fp_fr_to_dp(fr1); fp_dp2 = fp_fr_to_dp(fr2); if ( (fp_dp1.sign == fp_dp2.sign ) && (fp_dp1.exponent == fp_dp2.exponent ) && (fp_dp1.significand.hi == fp_dp2.significand.hi) && (fp_dp1.significand.lo == fp_dp2.significand.lo) ) return (1); else if ( fp_is_zero_dp(fp_dp1) && fp_is_zero_dp(fp_dp2) ) return (1); else return (0); } INLINE EM_boolean_t fp_less_than( EM_fp_reg_type fr1, EM_fp_reg_type fr2) { EM_fp_dp_type fp_dp1; EM_fp_dp_type fp_dp2; if ( fp_is_nan(fr1) || fp_is_nan(fr2) || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) ) return (0); fp_dp1 = fp_fr_to_dp(fr1); fp_dp2 = fp_fr_to_dp(fr2); if (fp_is_neg_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) { if (!fp_is_zero_dp(fp_dp1) || !fp_is_zero_dp(fp_dp2) ) return (1); /* for non-zero's neg is lt pos */ else return (0); /* zeros are equal */ } else if (fp_is_pos_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) { return (0); /* pos is not lt neg */ } else if (fp_is_neg_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) { if (fp_dp1.exponent > fp_dp2.exponent) return (1); /* fp_dp1 much less than fp_dp2 */ else if ((fp_dp1.exponent == fp_dp2.exponent) && (fp_U128_gt(fp_dp1.significand, fp_dp2.significand))) return (1); /* fp_dp1 just less than fp_dp2 */ else return (0); } else if (fp_is_pos_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) { if (fp_dp1.exponent < fp_dp2.exponent) return (1); /* fp_dp1 much less than fp_dp2 */ else if ((fp_dp1.exponent == fp_dp2.exponent) && (fp_U128_lt(fp_dp1.significand, fp_dp2.significand))) return (1); /* fp_dp1 just less than fp_dp2 */ else return (0); } else { return (0); // MACH ADDED } } INLINE EM_boolean_t fp_lesser_or_equal(EM_fp_reg_type fr1, EM_fp_reg_type fr2) { EM_fp_dp_type fp_dp1; EM_fp_dp_type fp_dp2; if ( fp_is_nan(fr1) || fp_is_nan(fr2) || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) ) return (0); fp_dp1 = fp_fr_to_dp(fr1); fp_dp2 = fp_fr_to_dp(fr2); if (fp_is_neg_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) { return (1); /* for non-zero's and zeros's neg is le pos */ } else if (fp_is_pos_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) { if (fp_is_zero_dp(fp_dp1) && fp_is_zero_dp(fp_dp2)) return (1); /* zero's are le */ else return (0); /* pos is not lt neg */ } else if (fp_is_neg_dp(fp_dp1) && fp_is_neg_dp(fp_dp2)) { if (fp_dp1.exponent > fp_dp2.exponent) return (1); /* fp_dp1 much less than fp_dp2 */ else if ((fp_dp1.exponent == fp_dp2.exponent) && (fp_U128_ge(fp_dp1.significand, fp_dp2.significand))) return (1); /* fp_dp1 just less than or equal fp_dp2 */ else return (0); } else if (fp_is_pos_dp(fp_dp1) && fp_is_pos_dp(fp_dp2)) { if (fp_dp1.exponent < fp_dp2.exponent) return (1); /* fp_dp1 much less than fp_dp2 */ else if ((fp_dp1.exponent == fp_dp2.exponent) && (fp_U128_le(fp_dp1.significand, fp_dp2.significand))) return (1); /* fp_dp1 just less than or equal fp_dp2 */ else return (0); } else { return (0); // MACH ADDED } } INLINE EM_boolean_t fp_unordered(EM_fp_reg_type fr1, EM_fp_reg_type fr2) { if ( fp_is_nan(fr1) || fp_is_nan(fr2) || fp_is_unsupported(fr1) || fp_is_unsupported(fr2) ) return (1); else return (0); } EM_uint_t fp82_fp_decode_fault(EM_tmp_fp_env_type tmp_fp_env) { EM_uint_t tmp_ret = 0; if (!tmp_fp_env.simd) { // MACH ADDED if (tmp_fp_env.em_faults.swa) return (8); else if (tmp_fp_env.em_faults.v) return (1); else if (tmp_fp_env.em_faults.z) return (4); else if (tmp_fp_env.em_faults.d) return (2); else { tmp_ret = 0; return (0); // MACH ADDED } } else { // **************************************************** // hi_faults are recorded in the low four bits of temp_ret. // lo_faults are recorded in the high four bits of temp_ret. // **************************************************** if (tmp_fp_env.hi_faults.swa) tmp_ret = 8; else if (tmp_fp_env.hi_faults.v) tmp_ret = 1; else if (tmp_fp_env.hi_faults.z) tmp_ret = 4; else if (tmp_fp_env.hi_faults.d) tmp_ret = 2; if (tmp_fp_env.lo_faults.swa) tmp_ret |= 8<<4; else if (tmp_fp_env.lo_faults.v) tmp_ret |= 1<<4; else if (tmp_fp_env.lo_faults.z) tmp_ret |= 4<<4; else if (tmp_fp_env.lo_faults.d) tmp_ret |= 2<<4; return (tmp_ret); } } EM_uint_t fp82_fp_decode_trap(EM_tmp_fp_env_type tmp_fp_env) { EM_uint_t tmp_ret; if (!tmp_fp_env.simd) { tmp_ret = (tmp_fp_env.ebc <<15 | tmp_fp_env.fpa <<14 | tmp_fp_env.em_traps.i<<13 | tmp_fp_env.em_traps.un<<12 | tmp_fp_env.em_traps.o<<11 ); // MACH } else { tmp_ret = 0; if(tmp_fp_env.hi_traps.i || tmp_fp_env.hi_traps.un || tmp_fp_env.hi_traps.o ) { // MACH tmp_ret = tmp_fp_env.hi_fpa <<14 | tmp_fp_env.hi_traps.i<<13 | tmp_fp_env.hi_flags.i<<13 | tmp_fp_env.hi_traps.un<<12 | tmp_fp_env.hi_traps.o<<11; // MACH } if(tmp_fp_env.lo_traps.i || tmp_fp_env.lo_traps.un || tmp_fp_env.lo_traps.o ) { // MACH tmp_ret |= tmp_fp_env.lo_fpa <<10 | tmp_fp_env.lo_traps.i<<9 | tmp_fp_env.lo_flags.i<<9 | tmp_fp_env.lo_traps.un<<8 | tmp_fp_env.lo_traps.o<<7; // MACH } } return (tmp_ret); } void fp_decode_environment( EM_opcode_pc_type pc, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_sf_type tmp_sf; if (sf == sfS0) { tmp_sf.controls.ftz = FPSR.sf0_controls_ftz; tmp_sf.controls.wre = FPSR.sf0_controls_wre; tmp_sf.controls.pc = FPSR.sf0_controls_pc; tmp_sf.controls.rc = FPSR.sf0_controls_rc; tmp_sf.controls.td = FPSR.sf0_controls_td; } else if (sf == sfS1) { tmp_sf.controls.ftz = FPSR.sf1_controls_ftz; tmp_sf.controls.wre = FPSR.sf1_controls_wre; tmp_sf.controls.pc = FPSR.sf1_controls_pc; tmp_sf.controls.rc = FPSR.sf1_controls_rc; tmp_sf.controls.td = FPSR.sf1_controls_td; } else if (sf == sfS2) { tmp_sf.controls.ftz = FPSR.sf2_controls_ftz; tmp_sf.controls.wre = FPSR.sf2_controls_wre; tmp_sf.controls.pc = FPSR.sf2_controls_pc; tmp_sf.controls.rc = FPSR.sf2_controls_rc; tmp_sf.controls.td = FPSR.sf2_controls_td; } else if (sf == sfS3) { tmp_sf.controls.ftz = FPSR.sf3_controls_ftz; tmp_sf.controls.wre = FPSR.sf3_controls_wre; tmp_sf.controls.pc = FPSR.sf3_controls_pc; tmp_sf.controls.rc = FPSR.sf3_controls_rc; tmp_sf.controls.td = FPSR.sf3_controls_td; } else { tmp_sf.controls.ftz = 0; tmp_sf.controls.wre = 1; tmp_sf.controls.pc = sf_double_extended; tmp_sf.controls.rc = rc_rn; tmp_sf.controls.td = 1; } if (sf == sf_none) { tmp_fp_env->controls.vd = 0; tmp_fp_env->controls.dd = 0; tmp_fp_env->controls.zd = 0; tmp_fp_env->controls.od = 0; tmp_fp_env->controls.ud = 0; tmp_fp_env->controls.id = 0; } else if (tmp_sf.controls.td ) { tmp_fp_env->controls.vd = 1; tmp_fp_env->controls.dd = 1; tmp_fp_env->controls.zd = 1; tmp_fp_env->controls.od = 1; tmp_fp_env->controls.ud = 1; tmp_fp_env->controls.id = 1; } else { tmp_fp_env->controls.vd = FPSR.traps_vd; tmp_fp_env->controls.dd = FPSR.traps_dd; tmp_fp_env->controls.zd = FPSR.traps_zd; tmp_fp_env->controls.od = FPSR.traps_od; tmp_fp_env->controls.ud = FPSR.traps_ud; tmp_fp_env->controls.id = FPSR.traps_id; } if (pc == pc_none) { tmp_fp_env->ss = ss_double_extended_64; tmp_fp_env->es = es_seventeen_bits; tmp_fp_env->simd = 0; } else if (pc == pc_simd) { tmp_fp_env->ss = ss_single_24; tmp_fp_env->es = es_eight_bits; tmp_fp_env->simd = 1; if (tmp_sf.controls.wre) tmp_sf.controls.wre = 0; tmp_fp_env->hi_flags.v = 0; tmp_fp_env->hi_flags.d = 0; tmp_fp_env->hi_flags.z = 0; tmp_fp_env->hi_flags.o = 0; tmp_fp_env->hi_flags.un = 0; tmp_fp_env->hi_flags.i = 0; tmp_fp_env->lo_flags.v = 0; tmp_fp_env->lo_flags.d = 0; tmp_fp_env->lo_flags.z = 0; tmp_fp_env->lo_flags.o = 0; tmp_fp_env->lo_flags.un = 0; tmp_fp_env->lo_flags.i = 0; } else if (pc == pc_s) { tmp_fp_env->ss = ss_single_24; tmp_fp_env->simd = 0; if (tmp_sf.controls.wre) tmp_fp_env->es = es_seventeen_bits; else tmp_fp_env->es = es_eight_bits; } else if (pc == pc_d) { tmp_fp_env->ss = ss_double_53; tmp_fp_env->simd = 0; if (tmp_sf.controls.wre) tmp_fp_env->es = es_seventeen_bits; else tmp_fp_env->es = es_eleven_bits; } else if (pc == pc_sf) { tmp_fp_env->simd = 0; if (tmp_sf.controls.pc == sf_single) tmp_fp_env->ss = ss_single_24; else if (tmp_sf.controls.pc == sf_double) tmp_fp_env->ss = ss_double_53; else if (tmp_sf.controls.pc == sf_double_extended) tmp_fp_env->ss = ss_double_extended_64; if (tmp_sf.controls.wre) tmp_fp_env->es = es_seventeen_bits; else tmp_fp_env->es = es_fifteen_bits; } if (sf == sf_none) { tmp_fp_env->rc = rc_rz; tmp_fp_env->ftz = 0; } else { tmp_fp_env->rc = tmp_sf.controls.rc; tmp_fp_env->ftz = tmp_sf.controls.ftz && tmp_fp_env->controls.ud; } tmp_fp_env->flags.v = 0; tmp_fp_env->flags.d = 0; tmp_fp_env->flags.z = 0; tmp_fp_env->flags.o = 0; tmp_fp_env->flags.un = 0; tmp_fp_env->flags.i = 0; tmp_fp_env->ebc = 0; tmp_fp_env->mdl = 0; tmp_fp_env->mdh = 0; tmp_fp_env->em_faults.v = 0; tmp_fp_env->em_faults.d = 0; tmp_fp_env->em_faults.z = 0; tmp_fp_env->em_faults.swa = 0; tmp_fp_env->em_traps.i = 0; tmp_fp_env->em_traps.o = 0; tmp_fp_env->em_traps.un = 0; tmp_fp_env->fpa = 0; tmp_fp_env->hi_faults.v = 0; tmp_fp_env->hi_faults.d = 0; tmp_fp_env->hi_faults.z = 0; tmp_fp_env->hi_faults.swa = 0; tmp_fp_env->hi_traps.i = 0; tmp_fp_env->hi_traps.o = 0; tmp_fp_env->hi_traps.un = 0; tmp_fp_env->hi_fpa = 0; tmp_fp_env->lo_faults.v = 0; tmp_fp_env->lo_faults.d = 0; tmp_fp_env->lo_faults.z = 0; tmp_fp_env->lo_faults.swa = 0; tmp_fp_env->lo_traps.i = 0; tmp_fp_env->lo_traps.o = 0; tmp_fp_env->lo_traps.un = 0; tmp_fp_env->lo_fpa = 0; return; } #undef fp_decode_environment #define fp_decode_environment(arg1, arg2, arg3) \ fp82_fp_decode_environment(ps, arg1, arg2, arg3) // **************************************************** // Returns // 1: if a specified register is <= disabled limit and dfl is 1 // 0: if a specified register is > disabled limit and dfh is 1 // The disabled limit is 31 after ACR106. // ***************************************************** EM_uint_t fp_reg_disabled( EM_uint_t f1, EM_uint_t f2, EM_uint_t f3, EM_uint_t f4) { EM_uint_t tmp_ret; EM_uint_t disabled_limit; tmp_ret=0; disabled_limit = 31; if ( ((f1 >= 2) && (f1 <=disabled_limit) && (PSR.dfl)) || ((f2 >= 2) && (f2 <=disabled_limit) && (PSR.dfl)) || ((f3 >= 2) && (f3 <=disabled_limit) && (PSR.dfl)) || ((f4 >= 2) && (f4 <=disabled_limit) && (PSR.dfl)) ) tmp_ret |= (1<<0); if ( ((f1 > disabled_limit) && (f1 <= 127) && (PSR.dfh)) || ((f2 > disabled_limit) && (f2 <= 127) && (PSR.dfh)) || ((f3 > disabled_limit) && (f3 <= 127) && (PSR.dfh)) || ((f4 > disabled_limit) && (f4 <= 127) && (PSR.dfh)) ) tmp_ret |= (1<<1); return(tmp_ret); } INLINE EM_boolean_t fp_is_nan_or_inf(EM_fp_reg_type tmp_res) { if (fp_is_nan(tmp_res) || fp_is_inf(tmp_res)) return (1); else return (0); } INLINE EM_fp_reg_type fp_dp_to_fr(EM_fp_dp_type tmp_res) { EM_fp_reg_type tmp_ret; /* MACH FIX CMPLR BUG tmp_ret.sign = tmp_res.sign; */ if (tmp_res.exponent == FP_DP_EXP_ONES) tmp_ret.exponent = FP_REG_EXP_ONES; else if (tmp_res.exponent == 0) tmp_ret.exponent = 0; else tmp_ret.exponent = (EM_uint_t)(((EM_int_t)tmp_res.exponent) - FP_DP_BIAS + FP_REG_BIAS); tmp_ret.sign = tmp_res.sign; /* MACH FIX CMPLR BUG */ tmp_ret.significand = tmp_res.significand.hi; return (tmp_ret); } // *************************************************************** // fp_add() // Adds a dp value to an freg value // Returns a dp value // *************************************************************** INLINE EM_fp_dp_type fp_add(EM_fp_dp_type fp_dp, EM_fp_reg_type fr2, EM_tmp_fp_env_type tmp_fp_env) // fp_dp has been normalized and fr2 may not be normalized { EM_fp_dp_type tmp_res; EM_uint256_t tmp_a, tmp_b, tmp_c; EM_int_t exp_diff; EM_uint_t normalize_count; // all cases which might have faulted have been screened out // we still may trap on overflow, underflow and/or inexact later if (fp_is_zero_dp(fp_dp) && (fp_is_zero(fr2) || fp_is_pseudo_zero(fr2))) { /* correctly signed zero */ tmp_res = fp_fr_to_dp(FP_ZERO); if (fp_dp.sign == fr2.sign) { tmp_res.sign = fr2.sign; } else if (tmp_fp_env.rc == rc_rm) { tmp_res.sign = 1; } else { tmp_res.sign = 0; } return(tmp_res); } else if (fp_is_inf_dp(fp_dp)) { /* correctly signed infinity */ return(fp_dp); } else if (fp_is_inf(fr2)) { /* correctly signed infinity */ return(fp_fr_to_dp(fr2)); } else if( fp_is_zero_dp(fp_dp)) { return(fp_fr_to_dp(fr2)); } else if( fp_is_zero(fr2) || fp_is_pseudo_zero(fr2) ) { return(fp_dp); } else { /* we have non-all-zeros and non-all-ones exponents in both operands */ exp_diff = (((EM_int_t)fp_dp.exponent) - FP_DP_BIAS ) - (((EM_int_t)fr2.exponent) - FP_REG_BIAS); tmp_res.sign = fp_dp.sign; tmp_a = fp_U128_to_U256(fp_dp.significand); tmp_a = fp_U256_lsh(tmp_a,64); tmp_b = fp_U64_to_U256(fr2.significand); tmp_b = fp_U256_lsh(tmp_b,128); if (exp_diff >= 0) { tmp_res.exponent = fp_dp.exponent; tmp_c = fp_U256_rsh(tmp_b,exp_diff); tmp_res.sticky = !fp_U256_eq(tmp_b,fp_U256_lsh(tmp_c,exp_diff)); tmp_b = tmp_c; if(fp_dp.sign != fr2.sign) { /* add sticky */ if (tmp_res.sticky) tmp_b = fp_U256_inc(tmp_b); if (fp_dp.sign) tmp_a = fp_U256_neg(tmp_a); if (fr2.sign) tmp_b = fp_U256_neg(tmp_b); } } else { tmp_res.exponent = fp_dp.exponent - exp_diff; tmp_c = fp_U256_rsh(tmp_a,-exp_diff); tmp_res.sticky = !fp_U256_eq(tmp_a,fp_U256_lsh(tmp_c,-exp_diff)); tmp_a = tmp_c; if(fp_dp.sign != fr2.sign) { /* add sticky */ if (tmp_res.sticky) tmp_a = fp_U256_inc(tmp_a); if (fp_dp.sign) tmp_a = fp_U256_neg(tmp_a); if (fr2.sign) tmp_b = fp_U256_neg(tmp_b); } } tmp_c = fp_U256_add(tmp_a, tmp_b); if (fp_dp.sign != fr2.sign) { if (tmp_c.hh != 0) { tmp_res.sign = 1; tmp_c = fp_U256_neg(tmp_c); } else { tmp_res.sign = 0; } } if (!fp_U256_eq(tmp_c,U256_0)) { normalize_count = fp_U256_lead0(tmp_c); tmp_res.exponent -= (normalize_count - 64); tmp_res.significand = fp_U256_to_U128( fp_U256_rsh( fp_U256_lsh(tmp_c, normalize_count), 128 ) ); if(normalize_count > 128) { tmp_res.sticky |= !fp_U256_eq( fp_U256_rsh( fp_U128_to_U256(tmp_res.significand), normalize_count-128 ), tmp_c ); } else { tmp_res.sticky |= !fp_U256_eq( fp_U256_lsh( fp_U128_to_U256(tmp_res.significand), 128-normalize_count ), tmp_c ); } } else { if (fp_dp.sign == fr2.sign) tmp_res.sign = fp_dp.sign; else if (tmp_fp_env.rc == rc_rm) tmp_res.sign = 1; else tmp_res.sign = 0; tmp_res.exponent = 0; tmp_res.significand = U128_0; } return(tmp_res); } } // ******************************************************************* // IEEE rounds // ******************************************************************* INLINE EM_uint_t fp_single(EM_fp_reg_type freg) { EM_memory_type tmp_mem; tmp_mem = fp_fr_to_mem_format(freg, 4, 0); return (tmp_mem.uint_32.uvalue); } INLINE void fp_ieee_to_hilo( EM_simd_hilo hilo, EM_tmp_fp_env_type *tmp_fp_env) { if(hilo == high) { tmp_fp_env->hi_flags.o = tmp_fp_env->flags.o; tmp_fp_env->flags.o = 0; tmp_fp_env->hi_flags.un = tmp_fp_env->flags.un; // MACH tmp_fp_env->flags.un = 0; // MACH tmp_fp_env->hi_flags.i = tmp_fp_env->flags.i; tmp_fp_env->flags.i = 0; tmp_fp_env->hi_traps.o = tmp_fp_env->em_traps.o; tmp_fp_env->em_traps.o = 0; tmp_fp_env->hi_traps.un = tmp_fp_env->em_traps.un; // MACH tmp_fp_env->em_traps.un = 0; // MACH tmp_fp_env->hi_traps.i = tmp_fp_env->em_traps.i; tmp_fp_env->em_traps.i = 0; tmp_fp_env->hi_faults.d = tmp_fp_env->em_faults.d; tmp_fp_env->em_faults.d = 0; tmp_fp_env->hi_faults.z = tmp_fp_env->em_faults.z; tmp_fp_env->em_faults.z = 0; tmp_fp_env->hi_faults.v = tmp_fp_env->em_faults.v; tmp_fp_env->em_faults.v = 0; tmp_fp_env->hi_fpa = tmp_fp_env->fpa; tmp_fp_env->fpa = 0; } else { tmp_fp_env->lo_flags.o = tmp_fp_env->flags.o; tmp_fp_env->flags.o = 0; tmp_fp_env->lo_flags.un = tmp_fp_env->flags.un; // MACH tmp_fp_env->flags.un = 0; // MACH tmp_fp_env->lo_flags.i = tmp_fp_env->flags.i; tmp_fp_env->flags.i = 0; tmp_fp_env->lo_traps.o = tmp_fp_env->em_traps.o; tmp_fp_env->em_traps.o = 0; tmp_fp_env->lo_traps.un = tmp_fp_env->em_traps.un; // MACH tmp_fp_env->em_traps.un = 0; // MACH tmp_fp_env->lo_traps.i = tmp_fp_env->em_traps.i; tmp_fp_env->em_traps.i = 0; tmp_fp_env->lo_faults.d = tmp_fp_env->em_faults.d; tmp_fp_env->em_faults.d = 0; tmp_fp_env->lo_faults.z = tmp_fp_env->em_faults.z; tmp_fp_env->em_faults.z = 0; tmp_fp_env->lo_faults.v = tmp_fp_env->em_faults.v; tmp_fp_env->em_faults.v = 0; tmp_fp_env->lo_fpa = tmp_fp_env->fpa; tmp_fp_env->fpa = 0; } } EM_fp_reg_type fp_ieee_round( EM_fp_dp_type fp_dp, EM_tmp_fp_env_type *tmp_fp_env) { const EM_uint_t FPA[64] = { 0,0,0,1, 0,0,1,1, 0,0,0,1, 0,0,1,1, /* Nearest */ 0,0,0,0, 0,0,0,0, 0,1,1,1, 0,1,1,1, /* -inf */ 0,1,1,1, 0,1,1,1, 0,0,0,0, 0,0,0,0, /* +inf */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* Zero */ }; EM_fp_reg_type tmp_rtn; EM_fp_dp_type tmp_res, tmp_unbounded_round; EM_int_t cnt, tmp_shift; EM_uint_t e_max, e_min, tmp_unbounded_ebc = 0, tmp_unbounded_fpa = 0; EM_uint128_t significand_mask; EM_uint128_t significand_even; EM_uint128_t significand_round; EM_uint128_t significand_not_mask; EM_uint128_t significand_sticky; /************************************************ SETUP set e_max, e_min Note that the exponents are still dp-biased. *************************************************/ if (tmp_fp_env->es == es_eight_bits) { e_max = FP_DP_BIAS + FP_SGL_BIAS; e_min = FP_DP_BIAS - FP_SGL_BIAS + 1; } else if (tmp_fp_env->es == es_eleven_bits) { e_max = FP_DP_BIAS + FP_DBL_BIAS; e_min = FP_DP_BIAS - FP_DBL_BIAS + 1; } else if (tmp_fp_env->es == es_fifteen_bits) { e_max = FP_DP_BIAS + FP_EXT_BIAS; e_min = FP_DP_BIAS - FP_EXT_BIAS + 1; } else if (tmp_fp_env->es == es_seventeen_bits) { e_max = FP_DP_BIAS + FP_REG_BIAS; e_min = FP_DP_BIAS - FP_REG_BIAS + 1; } /************************************************ SETUP set significand_mask, significand_even, significand_round significand_not_mask, significand_sticky *************************************************/ if( tmp_fp_env->ss == ss_single_24) { significand_mask = U128_0xFFFFFF00000000000000000000000000; significand_even = U128_0x00000100000000000000000000000000; significand_round = U128_0x00000080000000000000000000000000; significand_not_mask = U128_0x000000FFFFFFFFFFFFFFFFFFFFFFFFFF; significand_sticky = U128_0x0000007FFFFFFFFFFFFFFFFFFFFFFFFF; } else if( tmp_fp_env->ss == ss_double_53) { significand_mask = U128_0xFFFFFFFFFFFFF8000000000000000000; significand_even = U128_0x00000000000008000000000000000000; significand_round = U128_0x00000000000004000000000000000000; significand_not_mask = U128_0x00000000000007FFFFFFFFFFFFFFFFFF; significand_sticky = U128_0x00000000000003FFFFFFFFFFFFFFFFFF; } else if( tmp_fp_env->ss == ss_double_extended_64) { significand_mask = U128_0xFFFFFFFFFFFFFFFF0000000000000000; significand_even = U128_0x00000000000000010000000000000000; significand_round = U128_0x00000000000000008000000000000000; significand_not_mask = U128_0x0000000000000000FFFFFFFFFFFFFFFF; significand_sticky = U128_0x00000000000000007FFFFFFFFFFFFFFF; } /*************************************************** INPUT CHECK Inf? ****************************************************/ if ( fp_is_inf_dp(fp_dp) ) { tmp_res = fp_dp; tmp_res.significand = fp_U128_band(tmp_res.significand, significand_mask); tmp_rtn = fp_dp_to_fr(tmp_res); return(tmp_rtn); /*************************************************** INPUT CHECK Nan? ****************************************************/ } else if ( fp_is_nan_dp(fp_dp) ) { tmp_res = fp_dp; tmp_res.significand = fp_U128_band(tmp_res.significand, significand_mask); tmp_rtn = fp_dp_to_fr(tmp_res); return(tmp_rtn); /*************************************************** INPUT CHECK Zero? ****************************************************/ } else if ( fp_is_zero_dp(fp_dp) ) { if ( (fp_dp.sticky) && (tmp_fp_env->rc == rc_rm) ) tmp_rtn.sign = 1; else if ( (fp_dp.sticky) && (tmp_fp_env->rc != rc_rm) ) tmp_rtn.sign = 0; else tmp_rtn.sign = fp_dp.sign; tmp_rtn.exponent = fp_dp.exponent; tmp_rtn.significand = 0; return(tmp_rtn); /****************************************************** INPUT CHECK Answer is finite and non-zero. *******************************************************/ } else { tmp_res.sign = fp_dp.sign; tmp_res.exponent = fp_dp.exponent; tmp_res.sticky = fp_dp.sticky; /****************************************************** UNBOUNDED SETUP Set cnt -- depends on rounding control, +/-, even/odd, round?, sticky? Set sticky to be either round or sticky *******************************************************/ cnt = (tmp_fp_env->rc<<4) | (fp_dp.sign<<3); cnt |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand, /* even */ significand_even)) << 2; cnt |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand, /* round */ significand_round)) << 1; tmp_res.sticky |= !fp_U128_eq(U128_0, fp_U128_band(fp_dp.significand, /* sticky */ significand_sticky)); cnt |= tmp_res.sticky; tmp_res.sticky |= ((cnt&2) != 0); /* round and sticky */ /************************************************************************* UNBOUNDED ROUNDING If necessary, round the significand This is the FIRST (or UNBOUNDED) rounding If rounding the significand results in a carry out of the significand, inc exponent and set significand to 10..0 else mask out lower bits of significand **************************************************************************/ if (FPA[cnt]) { tmp_res.significand = fp_U128_bor(fp_dp.significand, significand_not_mask); tmp_res.significand = fp_U128_inc(tmp_res.significand); if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* carry out */ tmp_res.exponent++; tmp_res.significand = U128_0x80000000000000000000000000000000; } } else { tmp_res.significand = fp_U128_band(fp_dp.significand, significand_mask); } /************************************************************************* UNBOUNDED ROUNDING If significand = 0, set exponent to 0. CAN THIS EVER HAPPEN IF tmp_res IS NORMALIZED? **************************************************************************/ if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* underflow -> zero */ tmp_res.exponent = 0; } /************************************************************************* UNBOUNDED Save the result of the FIRST ROUNDING in tmp_unbounded_round. Then, set i flag. **************************************************************************/ tmp_unbounded_round.sign = tmp_res.sign; tmp_unbounded_round.significand = tmp_res.significand; tmp_unbounded_round.exponent = tmp_res.exponent; tmp_unbounded_round.sticky = tmp_res.sticky; tmp_unbounded_fpa = FPA[cnt]; if ( ((tmp_unbounded_round.exponent>>17)&1) ^ ((tmp_unbounded_round.exponent>>16)&1) ) tmp_unbounded_ebc = 1; tmp_fp_env->flags.i = tmp_res.sticky; /************************************************************ HUGE if HUGE, set o_flag; if o traps enabled, also set o_trap, ebc, fpa then if i_flag set, set i_trap and return tmp_unbounded_round with mod17 exponent; the fp_dp_to_fr() mods the exponent. (sometimes inappropriately called the wrapped value) else set set tmp_res to max or inf, set i_flag if i traps enabled, set i_trap, fpa return tmp_res *************************************************************/ if ( tmp_res.exponent > e_max ) { /* huge */ tmp_fp_env->flags.o = 1; if ( !tmp_fp_env->controls.od) { tmp_fp_env->ebc = tmp_unbounded_ebc; tmp_fp_env->fpa = tmp_unbounded_fpa; tmp_fp_env->em_traps.o = 1; if(tmp_fp_env->flags.i) { tmp_fp_env->em_traps.i = 1; } return(fp_dp_to_fr(tmp_unbounded_round)); } else { tmp_res = fp_max_or_infinity(fp_dp.sign, tmp_fp_env, e_max, significand_mask); tmp_fp_env->flags.i = 1; /**************************************************************** The IEEE standard specifies (7.5) that if you overflow without enabling O traps, then inexact is always set. Hence, the above assignment. *****************************************************************/ if ( !tmp_fp_env->controls.id ) { tmp_fp_env->em_traps.i = 1; tmp_fp_env->fpa = fp_is_inf_dp(tmp_res); tmp_fp_env->ebc = 0; } return(fp_dp_to_fr(tmp_res)); } /************************************************************ TINY If MERCED_RTL, return unbounded, rounded result with mod17 exponent *************************************************************/ } else if ( tmp_res.exponent < e_min ) { /* tiny */ /************************************************************ TINY Undo the rounding. *************************************************************/ tmp_res.sign = fp_dp.sign; tmp_res.exponent = fp_dp.exponent; tmp_res.sticky = fp_dp.sticky; /************************************************************ TINY Calculate the shift to bring exponent to e_min if shift >=128 and significand is not zero, set sticky and clear significand else do the shift and set sticky if lost bits from significand *************************************************************/ tmp_shift = ((EM_int_t)e_min) - ((EM_int_t)fp_dp.exponent); tmp_res.exponent += tmp_shift; if (tmp_shift >= 128) { tmp_res.sticky |= !fp_U128_eq( fp_dp.significand, U128_0); tmp_res.significand = U128_0; } else { tmp_res.sticky |= !fp_U128_eq( U128_0, fp_U128_lsh( fp_dp.significand, (128-tmp_shift))); tmp_res.significand = fp_U128_rsh(fp_dp.significand, tmp_shift); } /****************************************************** TINY SETUP Set cnt -- depends on rounding control, +/-, even/odd, round?, sticky? Set sticky to be either round or sticky *******************************************************/ cnt = (tmp_fp_env->rc<<4) | (tmp_res.sign<<3); /* even */ cnt |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand, significand_even)) << 2; /* round */ cnt |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand, significand_round)) << 1; /* sticky */ tmp_res.sticky |= !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand, significand_sticky)); cnt |= tmp_res.sticky; tmp_res.sticky |= ((cnt&2) != 0); /* round and sticky */ /************************************************************************* TINY ROUNDING -- answer is in tmp_res If necessary, round the significand This is the SECOND (as opposed to the FIRST or UNBOUNDED) rounding If rounding the significand results in a carry out of the significand, inc exponent and set significand to 10..0 else mask out lower bits of significand **************************************************************************/ if (FPA[cnt]) { tmp_res.significand = fp_U128_bor(tmp_res.significand, significand_not_mask); tmp_res.significand = fp_U128_inc(tmp_res.significand); if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* carry out */ tmp_res.exponent++; tmp_res.significand = U128_0x80000000000000000000000000000000; } } else { tmp_res.significand = fp_U128_band(tmp_res.significand, significand_mask); } /****************************************************** TINY ROUNDING If significand = 0, set exponent to 0. Then, or in new sticky to the i flag *******************************************************/ if ( fp_U128_eq(tmp_res.significand, U128_0) ) { /* underflow to 0 */ tmp_res.exponent = 0; } tmp_fp_env->flags.i |= tmp_res.sticky; /****************************************************** TINY Set underflow, if inexact. *******************************************************/ if( tmp_fp_env->flags.i ) tmp_fp_env->flags.un = 1; /* tiny and inexact */ // MACH /****************************************************** TINY If u traps enabled, set u_flag, u_trap, ebc, fpa, and possibly i_trap return unbounded result with mod17 exponent; the fp_dp_to_fr() mods the exponent. else if ftz set i_flag, set u_flag, clear ebc, clear fpa if inexact set i_trap else if inexact trap and inexact set fpa, set i_trap set tmp_rtn (freg) to tmp_res (fp_dp). tmp_rtn now has the result of the SECOND rounding. Do not return tmp_res yet, because we may have to make a canonical double_ext denormal. *******************************************************/ tmp_fp_env->fpa = FPA[cnt]; if (!tmp_fp_env->controls.ud) { tmp_fp_env->flags.un = 1; // MACH tmp_fp_env->em_traps.un = 1; // MACH tmp_fp_env->ebc = tmp_unbounded_ebc; tmp_fp_env->fpa = tmp_unbounded_fpa; tmp_fp_env->flags.i = tmp_unbounded_round.sticky; if(tmp_fp_env->flags.i) { tmp_fp_env->em_traps.i = 1; } return(fp_dp_to_fr(tmp_unbounded_round)); } else { if (tmp_fp_env->ftz) { tmp_res.exponent = 0; tmp_res.significand = U128_0; tmp_res.sticky = 1; tmp_fp_env->flags.i = 1; tmp_fp_env->flags.un = 1; // MACH tmp_fp_env->ebc = 0; tmp_fp_env->fpa = 0; if (!tmp_fp_env->controls.id) { tmp_fp_env->em_traps.i = 1; } } else { if (!tmp_fp_env->controls.id && tmp_fp_env->flags.i) { tmp_fp_env->fpa = FPA[cnt]; tmp_fp_env->em_traps.i = 1; } } } tmp_rtn = fp_dp_to_fr(tmp_res); /****************************************************** TINY if double_extended, set tmp_rtn to canonical denormal return result of SECOND ROUNDING *******************************************************/ if ( (tmp_fp_env->es == es_fifteen_bits) && (tmp_rtn.exponent == 0x0C001) &&((tmp_rtn.significand & U64_0x8000000000000000) == 0) ) { /* canonical double-extended denormal */ tmp_rtn.exponent = 0x00000; } return(tmp_rtn); /****************************************************** NOT HUGE, NOT TINY if i traps enabled and i flag, set i_trap set fpa *******************************************************/ } else { if (!tmp_fp_env->controls.id && tmp_fp_env->flags.i) { tmp_fp_env->fpa = tmp_unbounded_fpa; tmp_fp_env->em_traps.i = 1; } tmp_rtn = fp_dp_to_fr(tmp_unbounded_round); /****************************************************** NOT HUGE, NOT TINY if double_extended, set tmp_rtn to canonical denormal return result of FIRST rounding *******************************************************/ if ( (tmp_fp_env->es == es_fifteen_bits) && (tmp_rtn.exponent == 0x0C001) &&((tmp_rtn.significand & U64_0x8000000000000000) == 0) ) { /* canonical double-extended denormal */ tmp_rtn.exponent = 0x00000; } return(tmp_rtn); } /* end of not huge, not tiny */ } /* end of infinitely precise and nonzero */ } #undef fp_ieee_round #define fp_ieee_round(arg1, arg2) fp82_fp_ieee_round(ps, arg1, arg2) // ******************************************************************* // fp_ieee_round_sp() // Takes a dp register value (which is the hi or lo of a simd) // Rounds to single precision, setting flags // Returns the value as a single-precision memory format value // ******************************************************************** EM_uint_t fp_ieee_round_sp( EM_fp_dp_type fp_dp, EM_simd_hilo hilo, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type fp_reg; EM_memory_type tmp_mem; fp_reg = fp_ieee_round( fp_dp, tmp_fp_env); fp_ieee_to_hilo(hilo, tmp_fp_env); if( tmp_fp_env->hi_traps.un || tmp_fp_env->hi_traps.o || tmp_fp_env->lo_traps.un || tmp_fp_env->lo_traps.o ) { // MACH tmp_mem = fr_to_mem4_bias_adjust(fp_reg); return (tmp_mem.uint_32.uvalue); } else { return (fp_single(fp_reg)); } } #undef fp_ieee_round_sp #define fp_ieee_round_sp(arg1, arg2, arg3) \ fp82_fp_ieee_round_sp(ps, arg1, arg2, arg3) EM_fp_reg_type fp_ieee_rnd_to_int( EM_fp_reg_type fr1, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_dp_type tmp_res; EM_tmp_fp_env_type tmp_fp_env_local; tmp_res = fp_fr_to_dp(fr1); memcpy ((char *)(&tmp_fp_env_local), (char *)tmp_fp_env, sizeof (EM_tmp_fp_env_type)); if (tmp_res.exponent < FP_DP_INTEGER_EXP) { if (tmp_res.sign) { tmp_res = fp_add(tmp_res, FP_NEG_2_TO_63, *tmp_fp_env); tmp_res = fp_fr_to_dp(fp_ieee_round( tmp_res, tmp_fp_env)); tmp_res = fp_add(tmp_res, FP_POS_2_TO_63, *tmp_fp_env); return(fp_ieee_round( tmp_res, &tmp_fp_env_local)); } else { tmp_res = fp_add(tmp_res, FP_POS_2_TO_63, *tmp_fp_env); tmp_res = fp_fr_to_dp(fp_ieee_round( tmp_res, tmp_fp_env)); tmp_res = fp_add(tmp_res, FP_NEG_2_TO_63, *tmp_fp_env); return(fp_ieee_round( tmp_res, &tmp_fp_env_local)); } } else return (fr1); } #undef fp_ieee_rnd_to_int #define fp_ieee_rnd_to_int(arg1,arg2) \ fp82_fp_ieee_rnd_to_int(ps, arg1, arg2) EM_fp_reg_type fp_ieee_rnd_to_int_sp( EM_fp_reg_type fr1, EM_simd_hilo hilo, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_fix; EM_tmp_fp_env_type tmp_fp_env_save; tmp_fp_env_save = *tmp_fp_env; tmp_fp_env->ss = ss_double_extended_64; tmp_fp_env->es = es_seventeen_bits; tmp_fix = fp_ieee_rnd_to_int(fr1, tmp_fp_env); fp_ieee_to_hilo(hilo, tmp_fp_env); tmp_fp_env->ss = tmp_fp_env_save.ss; tmp_fp_env->es = tmp_fp_env_save.es; return(tmp_fix); } // *************************************************************** // Exception fault checks // ***************************************************************** // **************************************************************** // fcmp_exception_fault_check() // ***************************************************************** INLINE void fcmp_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_opcode_frel_type frel, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type fr2, fr3; fr2 = FR[f2]; fr3 = FR[f3]; fp_decode_environment( pc_none, sf, tmp_fp_env ); if (fp_software_assistance_required(ps, op_fcmp, fr2, fr3)) { tmp_fp_env->em_faults.swa = 1; } if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) { if (fp_is_snan(fr2) || fp_is_snan(fr3) || (frel == frelLT) || (frel == frelNLT) || (frel == frelLE) || (frel == frelNLE)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) { tmp_fp_env->flags.d = 1; if(!tmp_fp_env->controls.dd) tmp_fp_env->em_faults.d = 1; } } // **************************************************************** // fpcmp_exception_fault_check() // ***************************************************************** INLINE void fpcmp_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_opcode_frel_type frel, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_fr2 = FR[f2], tmp_fr3 = FR[f3]; fp_decode_environment( pc_simd, sf, tmp_fp_env ); // *********** // high // ************ tmp_fr2 = fp_reg_read_hi(f2); tmp_fr3 = fp_reg_read_hi(f3); if (fp_software_assistance_required(ps, op_fpcmp, tmp_fr2, tmp_fr3)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { if ((fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || (frel == frelLT) || (frel == frelNLT) || (frel == frelLE) || (frel == frelNLE))) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->hi_faults.d = 1; } // *********** // low // ************ tmp_fr2 = fp_reg_read_lo(f2); tmp_fr3 = fp_reg_read_lo(f3); if (fp_software_assistance_required(ps, op_fpcmp, tmp_fr2, tmp_fr3)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { if ((fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || (frel == frelLT) || (frel == frelNLT) || (frel == frelLE) || (frel == frelNLE))) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->lo_faults.d = 1; } return; } // ******************************************************************* // fcvt_exception_fault_check() // ******************************************************************** INLINE EM_fp_reg_type fcvt_exception_fault_check( EM_fp_reg_specifier f2, EM_opcode_sf_type sf, EM_boolean_t signed_form, EM_boolean_t trunc_form, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_res, fr2; EM_tmp_fp_env_type tmp_fp_env_local; fr2 = FR[f2]; fp_decode_environment( pc_none, sf, tmp_fp_env ); if (trunc_form) tmp_fp_env->rc = rc_rz; tmp_res = fp_reg_read(fr2); memcpy ((char *)(&tmp_fp_env_local), (char *)tmp_fp_env, sizeof (EM_tmp_fp_env_type)); tmp_res = fp_ieee_rnd_to_int( tmp_res, &tmp_fp_env_local); if( signed_form && fp_software_assistance_required(ps, op_fcvt_fx, fr2)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } else if( !signed_form && fp_software_assistance_required(ps, op_fcvt_fxu, fr2)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } if (fp_is_unsupported(fr2)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_nan(fr2)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2; } else if ( signed_form && (!fp_lesser_or_equal(FP_NEG_2_TO_63, tmp_res) || !fp_less_than(tmp_res,FP_POS_2_TO_63)) ) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->em_faults.v = 1; } else if ( !signed_form && (!fp_lesser_or_equal(FP_ZERO, tmp_res) || !fp_less_than(tmp_res,FP_POS_2_TO_64)) ) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->em_faults.v = 1; tmp_res = FP_QNAN; } else if (fp_is_unorm(fr2)) { tmp_fp_env->flags.d = 1; if( !tmp_fp_env->controls.dd) tmp_fp_env->em_faults.d = 1; } return (tmp_res); } // ******************************************************************* // fpcvt_exception_fault_check() // ******************************************************************** EM_pair_fp_reg_type fpcvt_exception_fault_check( EM_fp_reg_specifier f2, EM_opcode_sf_type sf, EM_boolean_t signed_form, EM_boolean_t trunc_form, EM_tmp_fp_env_type *tmp_fp_env) { EM_tmp_fp_env_type tmp_fp_env_local; EM_pair_fp_reg_type tmp_reg_pair; EM_fp_reg_type tmp_fr2 = FR[f2]; fp_decode_environment( pc_simd, sf, tmp_fp_env ); tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.lo = FP_ZERO; if (trunc_form) tmp_fp_env->rc = rc_rz; // ************* // high // ************** tmp_fr2 = fp_reg_read_hi(f2); tmp_fp_env_local = *tmp_fp_env; tmp_fp_env_local.ss = ss_double_extended_64; tmp_fp_env_local.es = es_seventeen_bits; tmp_reg_pair.hi = fp_ieee_rnd_to_int( tmp_fr2, &tmp_fp_env_local); if ( signed_form && fp_software_assistance_required(ps, op_fpcvt_fx, tmp_fr2)) { tmp_fp_env->hi_faults.swa = 1; } else if( !signed_form && fp_software_assistance_required(ps, op_fpcvt_fxu, tmp_fr2)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr2)) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (signed_form && (!fp_lesser_or_equal(FP_NEG_2_TO_31, tmp_reg_pair.hi) || !fp_less_than(tmp_reg_pair.hi,FP_POS_2_TO_31)) ) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (!signed_form && (!fp_lesser_or_equal(FP_ZERO, tmp_reg_pair.hi) || !fp_less_than(tmp_reg_pair.hi,FP_POS_2_TO_32)) ) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (fp_is_unorm(tmp_fr2)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->hi_faults.d = 1; } // ************* // low // ************** tmp_fr2 = fp_reg_read_lo(f2); tmp_fp_env_local = *tmp_fp_env; tmp_fp_env_local.ss = ss_double_extended_64; tmp_fp_env_local.es = es_seventeen_bits; tmp_reg_pair.lo = fp_ieee_rnd_to_int( tmp_fr2, &tmp_fp_env_local); if ( signed_form && fp_software_assistance_required(ps, op_fpcvt_fx, tmp_fr2)) { tmp_fp_env->lo_faults.swa = 1; } else if( !signed_form && fp_software_assistance_required(ps, op_fpcvt_fxu, tmp_fr2)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_nan(tmp_fr2)) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (signed_form && (!fp_lesser_or_equal(FP_NEG_2_TO_31, tmp_reg_pair.lo) || !fp_less_than(tmp_reg_pair.lo,FP_POS_2_TO_31)) ) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (!signed_form && (!fp_lesser_or_equal(FP_ZERO, tmp_reg_pair.lo) || !fp_less_than(tmp_reg_pair.lo,FP_POS_2_TO_32)) ) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (fp_is_unorm(tmp_fr2)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->lo_faults.d = 1; } return (tmp_reg_pair); } // ******************************************************************* // fma_exception_fault_check() // ******************************************************************** EM_fp_reg_type fma_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_fp_reg_specifier f4, EM_opcode_pc_type pc, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_res; EM_fp_reg_type fr2, fr3, fr4; // printf ("MACH DEBUG: BEGIN fma_exception_fault_check\n"); fr2 = FR[f2]; fr3 = FR[f3]; fr4 = FR[f4]; // printf ("MACH DEBUG: FR2 = %x %x "LX"\n", fr2.sign, fr2.exponent, fr2.significand); // printf ("MACH DEBUG: FR3 = %x %x "LX"\n", fr3.sign, fr3.exponent, fr3.significand); // printf ("MACH DEBUG: FR4 = %x %x "LX"\n", fr4.sign, fr4.exponent, fr4.significand); fp_decode_environment( pc, sf, tmp_fp_env ); if(f4==1 && f2==0) { if (fp_software_assistance_required(ps, op_fnorm, fr3, *tmp_fp_env)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } } else { if (fp_software_assistance_required(ps, op_fma, fr2, fr3, fr4)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } } tmp_res = FP_ZERO; if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3) || fp_is_unsupported(fr4)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if (fp_is_nan(fr2) || fp_is_nan(fr3) || fp_is_nan(fr4)) { if (fp_is_snan(fr2) || fp_is_snan(fr3) || fp_is_snan(fr4)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->em_faults.v = 1; } if (fp_is_nan(fr4)) tmp_res = fp_is_snan(fr4)?fp_make_quiet_nan(fr4):fr4; else if (fp_is_nan(fr2)) tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2; else if (fp_is_nan(fr3)) tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3; } else if (( fp_is_pos_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_pos_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_neg_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_neg_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_pos_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_pos_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_neg_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_neg_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_neg_inf(fr2) )) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if ((fp_is_inf(fr3) && fp_is_zero(fr4)) || (fp_is_zero(fr3) && fp_is_inf(fr4))) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3) || fp_is_unorm(fr4)) { // printf ("MACH DEBUG: setting the D flag in fma_exception_fault_check\n"); tmp_fp_env->flags.d = 1; if(!tmp_fp_env->controls.dd) { // MACH DEBUG // printf ("MACH DEBUG: setting the D fault in fma_exception_fault_check\n"); tmp_fp_env->em_faults.d = 1; } // MACH DEBUG } return (tmp_res); } // ******************************************************************* // fpma_exception_fault_check() // ******************************************************************** EM_pair_fp_reg_type fpma_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_fp_reg_specifier f4, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_pair_fp_reg_type tmp_reg_pair; EM_fp_reg_type tmp_fr2 = FR[f2], tmp_fr3 = FR[f3], tmp_fr4 = FR[f4]; fp_decode_environment( pc_simd, sf, tmp_fp_env ); tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.lo = FP_ZERO; // ********* // high // ********* tmp_fr2 = fp_reg_read_hi(f2); tmp_fr3 = fp_reg_read_hi(f3); tmp_fr4 = fp_reg_read_hi(f4); if (fp_software_assistance_required(ps, op_fpma, tmp_fr2, tmp_fr3, tmp_fr4)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } if (fp_is_nan(tmp_fr4)) tmp_reg_pair.hi = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4; else if (fp_is_nan(tmp_fr2)) tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; else if (fp_is_nan(tmp_fr3)) tmp_reg_pair.hi = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3; } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) )) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4)) || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->hi_faults.d = 1; } // ********* // low // ********** tmp_fr2 = fp_reg_read_lo(f2); tmp_fr3 = fp_reg_read_lo(f3); tmp_fr4 = fp_reg_read_lo(f4); if (fp_software_assistance_required(ps, op_fpma, tmp_fr2, tmp_fr3, tmp_fr4)) { tmp_fp_env->lo_faults.swa = 1; } if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } if (fp_is_nan(tmp_fr4)) tmp_reg_pair.lo = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4; else if (fp_is_nan(tmp_fr2)) tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; else if (fp_is_nan(tmp_fr3)) tmp_reg_pair.lo = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3; } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) )) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4)) || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->lo_faults.d = 1; } return (tmp_reg_pair); } // ******************************************************************* // fpminmax_exception_fault_check() // No return value // If input contains a NATVAL, just return. // Otherwise set flags appropriately so that fpsr will // be correct or a fault taken in caller. // ******************************************************************** INLINE void fpminmax_exception_fault_check( EM_uint_t f2, EM_uint_t f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_fr2 = FR[f2], tmp_fr3 = FR[f3]; // MACH fp_decode_environment( pc_simd, sf, tmp_fp_env ); // ************ // high // ************ tmp_fr2 = fp_reg_read_hi(f2); tmp_fr3 = fp_reg_read_hi(f3); if (fp_software_assistance_required(ps, op_fpminmax, tmp_fr2, tmp_fr3)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->hi_faults.d = 1; } } // ************ // low // ************ tmp_fr2 = fp_reg_read_lo(f2); tmp_fr3 = fp_reg_read_lo(f3); if (fp_software_assistance_required(ps, op_fpminmax, tmp_fr2, tmp_fr3)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->lo_faults.d = 1; } return; } // ******************************************************************* // fminmax_exception_fault_check() // ******************************************************************* INLINE void fminmax_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type fr2, fr3; fr2 = FR[f2]; fr3 = FR[f3]; fp_decode_environment( pc_none, sf, tmp_fp_env ); if (fp_software_assistance_required(ps, op_fminmax, fr2, fr3)) { tmp_fp_env->em_faults.swa = 1; } if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) { tmp_fp_env->flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->em_faults.d = 1; } } // ******************************************************************* // fms_fnma_() // ******************************************************************* EM_fp_reg_type fms_fnma_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_fp_reg_specifier f4, EM_opcode_pc_type pc, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type fr2, fr3, fr4; EM_fp_reg_type tmp_res; fr2 = FR[f2]; fr3 = FR[f3]; fr4 = FR[f4]; fp_decode_environment( pc, sf, tmp_fp_env ); if (fp_software_assistance_required(ps, op_fms_fnma, fr2, fr3, fr4)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } tmp_res = FP_ZERO; if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3) || fp_is_unsupported(fr4)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if (fp_is_nan(fr2) || fp_is_nan(fr3) || fp_is_nan(fr4)) { if (fp_is_snan(fr2) || fp_is_snan(fr3) || fp_is_snan(fr4)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->em_faults.v = 1; } if (fp_is_nan(fr4)) tmp_res = fp_is_snan(fr4)?fp_make_quiet_nan(fr4):fr4; else if (fp_is_nan(fr2)) tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2; else if (fp_is_nan(fr3)) tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3; } else if (( fp_is_pos_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_pos_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_neg_inf(fr3) && fp_is_pos_non_zero(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_neg_inf(fr3) && fp_is_neg_non_zero(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_pos_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_pos_inf(fr2) ) || ( fp_is_pos_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_neg_non_zero(fr3) && fp_is_pos_inf(fr4) && fp_is_neg_inf(fr2) ) || ( fp_is_neg_non_zero(fr3) && fp_is_neg_inf(fr4) && fp_is_pos_inf(fr2) )) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if ((fp_is_inf(fr3) && fp_is_zero(fr4)) || (fp_is_zero(fr3) && fp_is_inf(fr4))) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; return (tmp_res); } } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3) || fp_is_unorm(fr4)) { tmp_fp_env->flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->em_faults.d = 1; } return (tmp_res); } // ******************************************************************* // fpms_fpnma_exception_fault_check() // ******************************************************************** EM_pair_fp_reg_type fpms_fpnma_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_fp_reg_specifier f4, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_pair_fp_reg_type tmp_reg_pair; EM_fp_reg_type tmp_fr2 = FR[f2], tmp_fr3 = FR[f3], tmp_fr4 = FR[f4]; fp_decode_environment( pc_simd, sf, tmp_fp_env ); tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.lo = FP_ZERO; // *************** // high // *************** tmp_fr2 = fp_reg_read_hi(f2); tmp_fr3 = fp_reg_read_hi(f3); tmp_fr4 = fp_reg_read_hi(f4); if (fp_software_assistance_required(ps, op_fpms_fpnma, tmp_fr2, tmp_fr3, tmp_fr4)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_unsupported(tmp_fr2) || fp_is_unsupported(tmp_fr3) || fp_is_unsupported(tmp_fr4)) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } if (fp_is_nan(tmp_fr4)) tmp_reg_pair.hi = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4; else if (fp_is_nan(tmp_fr2)) tmp_reg_pair.hi = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; else if (fp_is_nan(tmp_fr3)) tmp_reg_pair.hi = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3; } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) )) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4)) || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->hi_faults.v = 1; } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->hi_faults.d = 1; } // *************** // low // *************** tmp_fr2 = fp_reg_read_lo(f2); tmp_fr3 = fp_reg_read_lo(f3); tmp_fr4 = fp_reg_read_lo(f4); if (fp_software_assistance_required(ps, op_fpms_fpnma, tmp_fr2, tmp_fr3, tmp_fr4)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_unsupported(tmp_fr2) || fp_is_unsupported(tmp_fr3) || fp_is_unsupported(tmp_fr4)) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3) || fp_is_nan(tmp_fr4)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3) || fp_is_snan(tmp_fr4)) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } if (fp_is_nan(tmp_fr4)) tmp_reg_pair.lo = fp_is_snan(tmp_fr4)?fp_make_quiet_nan(tmp_fr4):tmp_fr4; else if (fp_is_nan(tmp_fr2)) tmp_reg_pair.lo = fp_is_snan(tmp_fr2)?fp_make_quiet_nan(tmp_fr2):tmp_fr2; else if (fp_is_nan(tmp_fr3)) tmp_reg_pair.lo = fp_is_snan(tmp_fr3)?fp_make_quiet_nan(tmp_fr3):tmp_fr3; } else if (( fp_is_pos_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_pos_non_zero(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_inf(tmp_fr3) && fp_is_neg_non_zero(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) ) || ( fp_is_pos_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_pos_inf(tmp_fr4) && fp_is_neg_inf(tmp_fr2) ) || ( fp_is_neg_non_zero(tmp_fr3) && fp_is_neg_inf(tmp_fr4) && fp_is_pos_inf(tmp_fr2) )) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if ((fp_is_inf(tmp_fr3) && fp_is_zero(tmp_fr4)) || (fp_is_zero(tmp_fr3) && fp_is_inf(tmp_fr4))) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) tmp_fp_env->lo_faults.v = 1; } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3) || fp_is_unorm(tmp_fr4)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) tmp_fp_env->lo_faults.d = 1; } return (tmp_reg_pair); } INLINE EM_fp_dp_type fp_max_or_infinity(EM_uint_t sign, EM_tmp_fp_env_type *tmp_fp_env, EM_uint_t e_max, EM_uint128_t max_significand) { EM_fp_dp_type tmp_res; tmp_res.sign = sign; if (tmp_fp_env->rc == rc_rm) { if (tmp_res.sign) { tmp_res.exponent = FP_DP_EXP_ONES; tmp_res.significand = U128_0x80000000000000000000000000000000; }else { tmp_res.exponent = e_max; tmp_res.significand = max_significand; } } else if (tmp_fp_env->rc == rc_rz) { tmp_res.exponent = e_max; tmp_res.significand = max_significand; } else if (tmp_fp_env->rc == rc_rp) { if (tmp_res.sign) { tmp_res.exponent = e_max; tmp_res.significand = max_significand; }else { tmp_res.exponent = FP_DP_EXP_ONES; tmp_res.significand = U128_0x80000000000000000000000000000000; } } else { tmp_res.exponent = FP_DP_EXP_ONES; tmp_res.significand = U128_0x80000000000000000000000000000000; } return(tmp_res); } INLINE EM_fp_dp_type fp_mul(EM_fp_reg_type fr3, EM_fp_reg_type fr4) { EM_fp_dp_type tmp_res; EM_int_t normalize_count; // all cases which might have faulted have been screened out // we still may trap on overflow, underflow and/or inexact later if (fp_is_zero(fr3) || fp_is_zero(fr4)) { /* correctly signed zero */ tmp_res = fp_fr_to_dp(FP_ZERO); tmp_res.sign = fr3.sign ^ fr4.sign; } else if (fp_is_inf(fr3) || fp_is_inf(fr4)) { /* correctly signed inf*/ tmp_res = fp_fr_to_dp(FP_INFINITY); tmp_res.sign = fr3.sign ^ fr4.sign; } else if (fp_is_pseudo_zero(fr3) || fp_is_pseudo_zero(fr4)) { /* pseudo zero if one operand is a pseudo-zero, return real zero. pz * NaN = Nan, but we already tested for Nan */ tmp_res = fp_fr_to_dp(FP_ZERO); tmp_res.sign = fr3.sign ^ fr4.sign; } else { /* (un)normal * (un)normal */ tmp_res.sign = fr3.sign ^ fr4.sign; tmp_res.exponent = (EM_uint_t)( (((EM_int_t)fr3.exponent)-FP_REG_BIAS) + (((EM_int_t)fr4.exponent)-FP_REG_BIAS) + FP_DP_BIAS); /* x.xxx (64-bits) * y.yyy (64-bits) => zz.zzzzzz (128-bits) */ tmp_res.significand = fp_U64_x_U64_to_U128(fr3.significand, fr4.significand); if (fp_U128_lead0(tmp_res.significand) == 0) { /* 1.xxx (64-bits) * 1.yyy (64-bits) => 1z.zzzzzz (128-bits) */ tmp_res.exponent += 1; /* 1z.zzzzzz => 1.zzzzzzz (128-bits) */ } else if (fp_U128_lead0(tmp_res.significand) == 1) { /* 1.xxx (64-bits) * 1.yyy (64-bits) => 0z.zzzzzz (128-bits) */ tmp_res.significand = fp_U128_lsh(tmp_res.significand,1); /* 0z.zzzzzz => z.zzzzzz0 (128-bits) */ } else { /* 0.xxx (64-bits) * 0.yyy (64-bits) => 00.zzzzzz (128-bits) all unsigned int's */ normalize_count = fp_U128_lead0(tmp_res.significand); tmp_res.exponent -= normalize_count-1; tmp_res.significand = fp_U128_lsh(tmp_res.significand, normalize_count); } } tmp_res.sticky = 0; return(tmp_res); } INLINE EM_fp_reg_type fp_normalize(EM_fp_reg_type freg) { EM_int_t tmp_normalize_count; if (fp_is_nan(freg) || fp_is_inf(freg) || fp_is_normal(freg) || fp_is_unsupported(freg) || fp_is_zero(freg) || fp_is_natval(freg)) return (freg); tmp_normalize_count = fp_U64_lead0(freg.significand); if (tmp_normalize_count == 64) { /* ftz pseudo-zero */ if(freg.exponent) freg.exponent = 0; return (freg); } else if(freg.exponent == 1) { return(freg); } else if ((((EM_int_t)freg.exponent) - tmp_normalize_count) <= 0) { tmp_normalize_count = freg.exponent -1; freg.exponent = 1; freg.significand <<= tmp_normalize_count; return (freg); } else { /* normalize */ freg.exponent -= tmp_normalize_count; freg.significand <<= tmp_normalize_count; return(freg); } } INLINE EM_fp_dp_type fp_normalize_dp(EM_fp_dp_type fp_dp) { EM_int_t tmp_normalize_count; if (fp_is_nan_dp(fp_dp) || fp_is_inf_dp(fp_dp) || fp_is_normal_dp(fp_dp) || fp_is_zero_dp(fp_dp)) return (fp_dp); else if (fp_is_unsupported_dp(fp_dp)) /* unsupported are turned into nans */ return (fp_fr_to_dp(FP_QNAN)); tmp_normalize_count = fp_U128_lead0(fp_dp.significand); if (tmp_normalize_count == 128) { /* ftz pseudo-zero */ if (fp_dp.exponent) fp_dp.exponent = 0; return (fp_dp); } else if ((((EM_int_t)fp_dp.exponent) - tmp_normalize_count) <= 0) { /* ftz register file format (pseudo-)denormals */ fp_dp.exponent = 0; fp_dp.significand = U128_0; return (fp_dp); } else { /* normalize */ fp_dp.exponent -= tmp_normalize_count; fp_dp.significand = fp_U128_lsh(fp_dp.significand, tmp_normalize_count); return(fp_dp); } } EM_fp_dp_type fp82_fp_fr_to_dp(EM_fp_reg_type fr1) { EM_fp_dp_type tmp_res; tmp_res.sign = fr1.sign; if (fr1.exponent == 0) tmp_res.exponent = 0; else if (fr1.exponent == FP_REG_EXP_ONES) tmp_res.exponent = FP_DP_EXP_ONES; else tmp_res.exponent = (EM_uint_t)(((EM_int_t)fr1.exponent) - FP_REG_BIAS + FP_DP_BIAS); tmp_res.significand.hi = fr1.significand; tmp_res.significand.lo = U64_0; tmp_res.sticky = 0; return(fp_normalize_dp(tmp_res)); } // ******************************************************************* // frcpa_exception_fault_check() // ******************************************************************* EM_fp_reg_type frcpa_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type fr2, fr3; EM_fp_reg_type tmp_res; EM_int_t estimated_exponent; fr2 = FR[f2]; fr3 = FR[f3]; fp_decode_environment( pc_none, sf, tmp_fp_env ); if (fp_software_assistance_required(ps, op_frcpa, fr2, fr3) ) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } tmp_res = FP_ZERO; if (fp_is_unsupported(fr2) || fp_is_unsupported(fr3)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_nan(fr2) || fp_is_nan(fr3)) { if (fp_is_snan(fr2) || fp_is_snan(fr3)) { tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } if (fp_is_nan(fr2)) { tmp_res = fp_is_snan(fr2)?fp_make_quiet_nan(fr2):fr2; } else if (fp_is_nan(fr3)) { tmp_res = fp_is_snan(fr3)?fp_make_quiet_nan(fr3):fr3; } } else if ( (fp_is_inf(fr2) && fp_is_inf(fr3)) || ( (fp_is_zero(fr2) || fp_is_pseudo_zero(fr2)) && (fp_is_zero(fr3) || fp_is_pseudo_zero(fr3)) ) ) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if ( ( ( fp_is_normal(fr2) && !fp_is_zero(fr2) ) || ( fp_is_unorm(fr2) && !fp_is_pseudo_zero(fr2) ) ) && ( fp_is_zero(fr3) || fp_is_pseudo_zero(fr3) ) ) { tmp_fp_env->flags.z = 1; tmp_res = FP_INFINITY; tmp_res.sign = fr2.sign ^ fr3.sign; if (!tmp_fp_env->controls.zd) { tmp_fp_env->em_faults.z = 1; } } else if (fp_is_unorm(fr2) || fp_is_unorm(fr3)) { tmp_fp_env->flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->em_faults.d = 1; } } /************************************************************ This is the architecturally mandated swa fault check. The precision of the working type is 17-bit exponent. fp_normalize() will normalize except in the case of a register denormal. In this context, fp_is_unorm() returns 1 if integer bit is 0 and that occurs when fr3.exponent < emin. Note that the estimated exponent is unbiased, because the bias is subtracted out. *************************************************************/ if ( !fp_is_zero(fr2) && fp_is_finite(fr2) && !fp_is_pseudo_zero(fr2) && !fp_is_zero(fr3) && fp_is_finite(fr3) && !fp_is_pseudo_zero(fr3) ) { fr2 = fp_normalize(fp_reg_read(fr2)); fr3 = fp_normalize(fp_reg_read(fr3)); estimated_exponent = (EM_int_t)(fr2.exponent) - (EM_int_t)(fr3.exponent); if ( fp_is_unorm(fr3) || ( fr3.exponent >= (FP_REG_BIAS+FP_REG_BIAS-2) ) || ( estimated_exponent >= ((EM_int_t)(FP_REG_BIAS)) ) || ( estimated_exponent <= (2 - (EM_int_t)FP_REG_BIAS) ) || ( fr2.exponent <= (ss_double_extended_64) ) ) { tmp_fp_env->em_faults.swa = 1; } } return (tmp_res); } // ******************************************************************* // fprcpa_exception_fault_check() // ******************************************************************* EM_pair_fp_reg_type fprcpa_exception_fault_check( EM_fp_reg_specifier f2, EM_fp_reg_specifier f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env, EM_limits_check_fprcpa *limits_check) { EM_pair_fp_reg_type tmp_reg_pair; EM_fp_reg_type tmp_fr2 = FR[f2], tmp_fr3 = FR[f3]; EM_int_t estimated_exponent; fp_decode_environment( pc_simd, sf, tmp_fp_env ); tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.lo = FP_ZERO; // ************ // high // ************ tmp_fr2 = fp_reg_read_hi(f2); tmp_fr3 = fp_reg_read_hi(f3); if (fp_software_assistance_required(ps, op_fprcpa, tmp_fr2, tmp_fr3)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3)) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } if (fp_is_nan(tmp_fr2)) { tmp_reg_pair.hi = fp_is_snan(tmp_fr2) ? fp_make_quiet_nan(tmp_fr2) : tmp_fr2; } else if (fp_is_nan(tmp_fr3)) { tmp_reg_pair.hi = fp_is_snan(tmp_fr3) ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3; } /******************************************************************************* (f2 and f3 are inf) or (f2 and f3 are 0); returns qnan ********************************************************************************/ } else if ( (fp_is_inf(tmp_fr2) && fp_is_inf(tmp_fr3) ) || (fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) ) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } /******************************************************************************* (f2 is non-zero (normal or denormal but not inf) and f3 is zero; returns inf The reason for the "but not inf" is because inf/0 shoudl not set the divide-by-zero flag. ********************************************************************************/ } else if ( !fp_is_inf(tmp_fr2) && !fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) { tmp_fp_env->hi_flags.z = 1; tmp_reg_pair.hi = FP_INFINITY; tmp_reg_pair.hi.sign = tmp_fr2.sign ^ tmp_fr3.sign; if (!tmp_fp_env->controls.zd) { tmp_fp_env->hi_faults.z = 1; } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->hi_faults.d = 1; } } if ( !fp_is_zero(tmp_fr2) && fp_is_finite(tmp_fr2) && !fp_is_zero(tmp_fr3) && fp_is_finite(tmp_fr3) ) { tmp_fr2 = fp_normalize(tmp_fr2); if ( fp_is_unorm(tmp_fr3) ) { limits_check->hi_fr3 = 1; /* recip(fr3_hi) not rep. */ tmp_reg_pair.hi = FP_INFINITY; tmp_reg_pair.hi.sign = tmp_fr3.sign; tmp_fr3 = fp_normalize(tmp_fr3); } else if ( tmp_fr3.exponent >= (FP_REG_BIAS+FP_SGL_BIAS-2) ) { limits_check->hi_fr3 = 1; /* recip(fr3_hi) not rep. */ tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.hi.sign = tmp_fr3.sign; } estimated_exponent = (EM_int_t)tmp_fr2.exponent - (EM_int_t)tmp_fr3.exponent; if ( (estimated_exponent >= (((EM_int_t)(FP_SGL_BIAS))) ) || (estimated_exponent <= (2-((EM_int_t)FP_SGL_BIAS)) ) || (tmp_fr2.exponent <= (ss_single_24+FP_REG_BIAS-FP_SGL_BIAS) ) ) { limits_check->hi_fr2_or_quot = 1; /* hi est. quot. or fr2_hi */ } } // ************ // low // ************ tmp_fr2 = fp_reg_read_lo(f2); tmp_fr3 = fp_reg_read_lo(f3); if (fp_software_assistance_required(ps, op_fprcpa, tmp_fr2, tmp_fr3)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_nan(tmp_fr2) || fp_is_nan(tmp_fr3)) { if (fp_is_snan(tmp_fr2) || fp_is_snan(tmp_fr3)) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } if (fp_is_nan(tmp_fr2)) { tmp_reg_pair.lo = fp_is_snan(tmp_fr2) ? fp_make_quiet_nan(tmp_fr2) : tmp_fr2; } else if (fp_is_nan(tmp_fr3)) { tmp_reg_pair.lo = fp_is_snan(tmp_fr3) ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3; } /******************************************************************************* (f2 and f3 are inf) or (f2 and f3 are 0); returns qnan ********************************************************************************/ } else if ( ( fp_is_inf(tmp_fr2) && fp_is_inf(tmp_fr3) ) || ( fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) ) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } /******************************************************************************* (f2 is non-zero (normal or denormal but not inf) and f3 is zero; returns inf The reason for the "but not inf" is because inf/0 should not set the divide-by-zero flag. ********************************************************************************/ } else if ( !fp_is_inf(tmp_fr2) && !fp_is_zero(tmp_fr2) && fp_is_zero(tmp_fr3) ) { tmp_fp_env->lo_flags.z = 1; tmp_reg_pair.lo = FP_INFINITY; tmp_reg_pair.lo.sign = tmp_fr2.sign ^ tmp_fr3.sign; if (!tmp_fp_env->controls.zd) { tmp_fp_env->lo_faults.z = 1; } } else if (fp_is_unorm(tmp_fr2) || fp_is_unorm(tmp_fr3)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->lo_faults.d = 1; } } if ( !fp_is_zero(tmp_fr2) && fp_is_finite(tmp_fr2) && !fp_is_zero(tmp_fr3) && fp_is_finite(tmp_fr3) ) { tmp_fr2 = fp_normalize(tmp_fr2); if ( fp_is_unorm(tmp_fr3) ) { limits_check->lo_fr3 = 1; /* recip(fr3_lo) not rep. */ tmp_reg_pair.lo = FP_INFINITY; tmp_reg_pair.lo.sign = tmp_fr3.sign; tmp_fr3 = fp_normalize(tmp_fr3); } else if ( tmp_fr3.exponent >= (FP_REG_BIAS+FP_SGL_BIAS-2) ) { limits_check->lo_fr3 = 1; /* recip(fr3_lo) not rep. */ tmp_reg_pair.lo = FP_ZERO; tmp_reg_pair.lo.sign = tmp_fr3.sign; } estimated_exponent = (EM_int_t)tmp_fr2.exponent - (EM_int_t)tmp_fr3.exponent; if ( (estimated_exponent >= (((EM_int_t)(FP_SGL_BIAS))) ) || (estimated_exponent <= (2-((EM_int_t)FP_SGL_BIAS)) ) || (tmp_fr2.exponent <= (ss_single_24+FP_REG_BIAS-FP_SGL_BIAS) ) ) { limits_check->lo_fr2_or_quot = 1; /* lo est. quot. or fr2_lo */ } } return (tmp_reg_pair); } // ******************************************************************* // frsqrta_exception_fault_check() // ******************************************************************* EM_fp_reg_type frsqrta_exception_fault_check( EM_fp_reg_specifier f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env) { EM_fp_reg_type tmp_res, fr3; fr3 = FR[f3]; fp_decode_environment( pc_none, sf, tmp_fp_env ); if (fp_software_assistance_required(ps, op_frsqrta, fr3)) { tmp_fp_env->em_faults.swa = 1; return (FP_ZERO); } tmp_res = FP_ZERO; if (fp_is_unsupported(fr3)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_nan(fr3)) { if(fp_is_snan(fr3)){ tmp_fp_env->flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } tmp_res = fp_is_snan(fr3) ? fp_make_quiet_nan(fr3) : fr3; } else if (fp_is_neg_inf(fr3)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if ( fp_is_neg_non_zero(fr3) && !fp_is_pseudo_zero(fr3)) { tmp_fp_env->flags.v = 1; tmp_res = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->em_faults.v = 1; } } else if (fp_is_unorm(fr3)) { tmp_fp_env->flags.d = 1; if( !tmp_fp_env->controls.dd) { tmp_fp_env->em_faults.d = 1; } } if( (fp_is_pos_non_zero(fr3) && !fp_is_pseudo_zero(fr3) )&& fp_is_finite(fr3)) { fr3 = fp_normalize(fp_reg_read(fr3)); if(fr3.exponent <= ss_double_extended_64) { tmp_fp_env->em_faults.swa = 1; } } return (tmp_res); } // ******************************************************************* // fprsqrta_exception_fault_check() // ******************************************************************* EM_pair_fp_reg_type fprsqrta_exception_fault_check( EM_fp_reg_specifier f3, EM_opcode_sf_type sf, EM_tmp_fp_env_type *tmp_fp_env, EM_limits_check_fprsqrta *limits_check) { EM_pair_fp_reg_type tmp_reg_pair; EM_fp_reg_type tmp_fr3 = FR[f3]; fp_decode_environment( pc_simd, sf, tmp_fp_env ); tmp_reg_pair.hi = FP_ZERO; tmp_reg_pair.lo = FP_ZERO; // ******** // high // ******** tmp_fr3 = fp_reg_read_hi(f3); if (fp_software_assistance_required(ps, op_fprsqrta, tmp_fr3)) { tmp_fp_env->hi_faults.swa = 1; } else if (fp_is_nan(tmp_fr3)) { if (fp_is_snan(tmp_fr3)) { tmp_fp_env->hi_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } tmp_reg_pair.hi = fp_is_snan(tmp_fr3) ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3; } else if (fp_is_neg_inf(tmp_fr3)) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } else if (fp_is_neg_non_zero(tmp_fr3)) { tmp_fp_env->hi_flags.v = 1; tmp_reg_pair.hi = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->hi_faults.v = 1; } } else if (fp_is_unorm(tmp_fr3)) { tmp_fp_env->hi_flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->hi_faults.d = 1; } } if(fp_is_pos_non_zero(tmp_fr3) && fp_is_finite(tmp_fr3)) { tmp_fr3 = fp_normalize(tmp_fr3); if (tmp_fr3.exponent <= (FP_REG_BIAS - FP_SGL_BIAS + ss_single_24)) { limits_check->hi = 1; } else { limits_check->hi = 0; } } // ******** // low // ******** tmp_fr3 = fp_reg_read_lo(f3); if (fp_software_assistance_required(ps, op_fprsqrta, tmp_fr3)) { tmp_fp_env->lo_faults.swa = 1; } else if (fp_is_nan(tmp_fr3)) { if (fp_is_snan(tmp_fr3)) { tmp_fp_env->lo_flags.v = 1; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } tmp_reg_pair.lo = fp_is_snan(tmp_fr3) ? fp_make_quiet_nan(tmp_fr3) : tmp_fr3; } else if (fp_is_neg_inf(tmp_fr3)) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } else if (fp_is_neg_non_zero(tmp_fr3)) { tmp_fp_env->lo_flags.v = 1; tmp_reg_pair.lo = FP_QNAN; if (!tmp_fp_env->controls.vd) { tmp_fp_env->lo_faults.v = 1; } } else if (fp_is_unorm(tmp_fr3)) { tmp_fp_env->lo_flags.d = 1; if (!tmp_fp_env->controls.dd) { tmp_fp_env->lo_faults.d = 1; } } if(fp_is_pos_non_zero(tmp_fr3) && fp_is_finite(tmp_fr3)) { tmp_fr3 = fp_normalize(tmp_fr3); if (tmp_fr3.exponent <= (FP_REG_BIAS - FP_SGL_BIAS + ss_single_24)) { limits_check->lo = 1; } else { limits_check->lo = 0; } } return (tmp_reg_pair); } INLINE EM_boolean_t fp_is_finite(EM_fp_reg_type freg) { if ( fp_is_inf(freg) || fp_is_nan(freg) || fp_is_unsupported(freg) ) { return(0); } else { return(1); } } INLINE EM_boolean_t fp_is_inf(EM_fp_reg_type freg) { if ( (freg.exponent == FP_REG_EXP_ONES) &&(freg.significand == U64_0x8000000000000000) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_inf_dp(EM_fp_dp_type tmp_res) { if ( (tmp_res.exponent == FP_DP_EXP_ONES) && fp_U128_eq(tmp_res.significand, U128_0x80000000000000000000000000000000) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_nan(EM_fp_reg_type freg) { if ( (freg.exponent == FP_REG_EXP_ONES) && ((freg.significand & U64_0x8000000000000000) != 0) && ((freg.significand & U64_0x7FFFFFFFFFFFFFFF) != 0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_nan_dp(EM_fp_dp_type tmp_res) { if ( (tmp_res.exponent == FP_DP_EXP_ONES) && fp_U128_eq(U128_0x80000000000000000000000000000000, fp_U128_band(tmp_res.significand, U128_0x80000000000000000000000000000000)) && !fp_U128_eq(U128_0, fp_U128_band(tmp_res.significand, U128_0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) ) { return (1); } else { return (0); } } INLINE EM_boolean_t fp_is_natval(EM_fp_reg_type freg) { if ( (freg.sign == 0) && (freg.exponent == 0x1FFFE) && (freg.significand == U64_0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_neg_dp(EM_fp_dp_type tmp_res) { if (tmp_res.sign) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_neg_inf(EM_fp_reg_type freg) { if ( (freg.sign == 1) && (freg.exponent == FP_REG_EXP_ONES) && (freg.significand == U64_0x8000000000000000) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_neg_non_zero(EM_fp_reg_type freg) { if ( (freg.sign == 1) && !fp_is_zero(freg) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_normal(EM_fp_reg_type freg) { if ( (freg.exponent != 0) && (freg.exponent != FP_REG_EXP_ONES) && ((freg.significand & U64_0x8000000000000000) != 0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_normal_dp(EM_fp_dp_type tmp_res) { if ( (tmp_res.exponent != 0) && (tmp_res.exponent != FP_DP_EXP_ONES) && fp_U128_eq(U128_0x80000000000000000000000000000000, fp_U128_band(tmp_res.significand, U128_0x80000000000000000000000000000000)) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_pos_dp(EM_fp_dp_type tmp_res) { if (!tmp_res.sign) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_pos_inf(EM_fp_reg_type freg) { if ( (freg.sign == 0) && (freg.exponent == FP_REG_EXP_ONES) && (freg.significand == U64_0x8000000000000000) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_pos_non_zero(EM_fp_reg_type freg) { if ( (freg.sign == 0) && !fp_is_zero(freg) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_pseudo_zero(EM_fp_reg_type freg) { if ( (freg.exponent != 0) && (freg.exponent != FP_REG_EXP_ONES) && (freg.significand == U64_0 && !fp_is_natval (freg)) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_qnan(EM_fp_reg_type freg) { if ( (freg.exponent == FP_REG_EXP_ONES) &&((freg.significand & U64_0xC000000000000000) == U64_0xC000000000000000) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_snan(EM_fp_reg_type freg) { if ( (freg.exponent == FP_REG_EXP_ONES) &&((freg.significand & U64_0xC000000000000000) == U64_0x8000000000000000) &&((freg.significand & U64_0x3FFFFFFFFFFFFFFF) != 0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_unorm(EM_fp_reg_type freg) { if ( ( (freg.exponent != 0) && (freg.exponent != FP_REG_EXP_ONES) &&((freg.significand & U64_0x8000000000000000) == 0) ) /* double-extended pseudo-denormal or double-extended denormal */ || ( (freg.exponent == 0) && (freg.significand != 0) ) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_unorm_dp(EM_fp_dp_type tmp_res) { if ( (tmp_res.exponent != 0) && (tmp_res.exponent != FP_DP_EXP_ONES) &&((tmp_res.significand.hi & U64_0x8000000000000000) == 0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_unsupported(EM_fp_reg_type freg) { if ( fp_is_natval(freg) || fp_is_nan(freg) || fp_is_inf(freg) || fp_is_normal(freg) || fp_is_unorm(freg) || fp_is_zero(freg) ) { return(0); } else { return(1); } } INLINE EM_boolean_t fp_is_unsupported_dp(EM_fp_dp_type tmp_res) { if ( fp_is_nan_dp(tmp_res) || fp_is_inf_dp(tmp_res) || fp_is_normal_dp(tmp_res) || fp_is_unorm_dp(tmp_res) || fp_is_zero_dp(tmp_res) ) { return(0); } else { return(1); } } INLINE EM_boolean_t fp_is_zero(EM_fp_reg_type freg) { if ( (freg.exponent == 0) && (freg.significand == U64_0) ) { return(1); } else { return(0); } } INLINE EM_boolean_t fp_is_zero_dp(EM_fp_dp_type tmp_res) { if ( (tmp_res.exponent == 0) && fp_U128_eq(tmp_res.significand, U128_0) ) { return(1); } else { return(0); } } EM_int_t fp82_fp_U64_lead0(EM_uint64_t value) { EM_int_t tmp_i, offset=0; EM_uint64_t tmp_mask; if( value == U64_0) return(64); tmp_mask = U64_0x8000000000000000; if( (value & U64_0xFFFFFFFF00000000) != U64_0) { if( (value & U64_0xFFFF000000000000) != U64_0) { if( (value & U64_0xFF00000000000000) != U64_0) { for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i); } } } else { /* 0x00FF000000000000 */ value <<= 8; offset += 8; for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } } else { /* 0x0000FFFF00000000 */ value <<= 16; offset += 16; if( (value & U64_0xFF00000000000000) != U64_0) { for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } else { value <<= 8; offset += 8; for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } } } else { /* 0x00000000 FFFFFFFF */ value <<= 32; offset += 32; if( (value & U64_0xFFFF000000000000) != U64_0) { if( (value & U64_0xFF00000000000000) != U64_0) { for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } else { /* 0x00000000 00FF0000 */ value <<= 8; offset += 8; for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } } else { /* 0x00000000 0000FFFF */ value <<= 16; offset += 16; if( (value & U64_0xFF00000000000000) != U64_0) { for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } else { value <<= 8; offset += 8; for (tmp_i=0; tmp_i<8; tmp_i++, tmp_mask>>=1) { if ( (value & tmp_mask) != U64_0 ) { return(tmp_i + offset); } } } } } return(64); // MACH ADDED } EM_int_t fp_U128_lead0(EM_uint128_t value) { EM_int_t tmp_i; tmp_i = fp_U64_lead0(value.hi); if (tmp_i == 64) { tmp_i += fp_U64_lead0(value.lo); } return(tmp_i); } EM_int_t fp82_fp_U256_lead0(EM_uint256_t value) { EM_int_t tmp_i; tmp_i = fp_U64_lead0(value.hh); if (tmp_i == 64) { tmp_i += fp_U64_lead0(value.hl); if (tmp_i == 128) { tmp_i += fp_U64_lead0(value.lh); if (tmp_i == 192) { tmp_i += fp_U64_lead0(value.ll); } } } return(tmp_i); } // ******************************************************************* // fp_mem_to_fr_format() // ******************************************************************* EM_fp_reg_type fp_mem_to_fr_format( EM_memory_type mem, EM_uint_t size, EM_uint_t integer_form) { /****************************************************** integer_form = 0 floating point integer_form = 1 simd, integer *******************************************************/ EM_fp_reg_type tmp_freg; EM_uint64_t tmp_significand, tmp_significand_hi, tmp_significand_lo; switch (size) { case 4:/* single */ tmp_freg.sign = mem.fp_single.sign; if ( (mem.fp_single.exponent == 0) && (mem.fp_single.significand == 0) ) { /* zero */ tmp_freg.exponent = 0; } else if (mem.fp_single.exponent == 0) { /* denormal */ tmp_freg.exponent = (EM_uint_t)(FP_REG_BIAS - FP_SGL_BIAS + 1); } else if (mem.fp_single.exponent == FP_SGL_EXP_ONES) { /* Inf, NaN, NaTVal */ tmp_freg.exponent = FP_REG_EXP_ONES; } else { tmp_freg.exponent = (EM_uint_t) (((EM_int_t)mem.fp_single.exponent) - FP_SGL_BIAS + FP_REG_BIAS); } tmp_freg.significand = (((EM_uint64_t)mem.fp_single.significand)<<40) #ifdef HPC_BUGS | (((mem.fp_single.exponent != U64_0)?U64_1:U64_0)<<63); #else | (((mem.fp_single.exponent != 0)?U64_1:U64_0)<<63); #endif break; case 8: /* double */ if (integer_form) { tmp_freg.sign = 0; tmp_freg.significand = mem.uint_64.uvalue; tmp_freg.exponent = FP_INTEGER_EXP; } else { tmp_freg.sign = mem.fp_double.sign; if ( (mem.fp_double.exponent == 0) && (mem.fp_double.significand_hi == 0) && (mem.fp_double.significand_lo == 0) ){ /* zero */ tmp_freg.exponent = 0; } else if (mem.fp_double.exponent == 0) { /* denormal */ tmp_freg.exponent = (EM_uint_t)(FP_REG_BIAS - FP_DBL_BIAS + 1); } else if (mem.fp_double.exponent == FP_DBL_EXP_ONES) { /* Inf, NaN, NaTVal */ tmp_freg.exponent = FP_REG_EXP_ONES; } else { tmp_freg.exponent = (EM_uint_t) (((EM_int_t)mem.fp_double.exponent) - FP_DBL_BIAS + FP_REG_BIAS); } tmp_significand_lo = ((EM_uint64_t)(mem.fp_double.significand_lo)) ; tmp_significand_hi = (((EM_uint64_t)(mem.fp_double.significand_hi)) << 32); tmp_significand = tmp_significand_lo | tmp_significand_hi; tmp_freg.significand = (tmp_significand<<11) #ifdef HPC_BUGS | (((mem.fp_double.exponent != U64_0)?U64_1:U64_0)<<63); #else | (((mem.fp_double.exponent != 0)?U64_1:U64_0)<<63); #endif } break; case 10: /* double extended */ tmp_freg.sign = mem.fp_double_extended.sign; if (mem.fp_double_extended.exponent == 0) { /* Zero or (Pseudo-)Denormal */ tmp_freg.exponent = 0; } else if (mem.fp_double_extended.exponent == FP_EXT_EXP_ONES) { /* Inf, NaN, NaTVal */ tmp_freg.exponent = FP_REG_EXP_ONES; } else { /* Normal */ tmp_freg.exponent = (EM_uint_t) (((EM_int_t)mem.fp_double_extended.exponent) - FP_EXT_BIAS + FP_REG_BIAS); } memcpy(&tmp_freg.significand, mem.fp_double_extended.significand, 8); break; case 16: /* fill */ tmp_freg.sign = mem.fp_spill_fill.sign; tmp_freg.exponent = mem.fp_spill_fill.exponent; tmp_freg.significand = mem.fp_spill_fill.significand; break; } return (tmp_freg); } INLINE EM_fp_reg_type fp_make_quiet_nan(EM_fp_reg_type freg) { freg.significand |= U64_0x4000000000000000; return (freg); } EM_boolean_t fp82_fp_raise_fault(EM_tmp_fp_env_type tmp_fp_env) { if(tmp_fp_env.simd == 1) { if (tmp_fp_env.lo_faults.swa || tmp_fp_env.lo_faults.v || tmp_fp_env.lo_faults.d || tmp_fp_env.lo_faults.z || tmp_fp_env.hi_faults.swa || tmp_fp_env.hi_faults.v || tmp_fp_env.hi_faults.d || tmp_fp_env.hi_faults.z ) return(1); } else if ( tmp_fp_env.em_faults.swa || tmp_fp_env.em_faults.v || tmp_fp_env.em_faults.d || tmp_fp_env.em_faults.z ) return (1); return (0); } EM_boolean_t fp82_fp_raise_traps(EM_tmp_fp_env_type tmp_fp_env) { if(tmp_fp_env.simd == 1) { if (tmp_fp_env.hi_traps.o || tmp_fp_env.hi_traps.un || tmp_fp_env.hi_traps.i || tmp_fp_env.lo_traps.o || tmp_fp_env.lo_traps.un || tmp_fp_env.lo_traps.i) // MACH return (1); } else if (tmp_fp_env.em_traps.o || tmp_fp_env.em_traps.un || tmp_fp_env.em_traps.i) // MACH return (1); return (0); } INLINE EM_fp_reg_type fp_reg_read(EM_fp_reg_type freg) { EM_fp_reg_type tmp_freg; tmp_freg = freg; /* insert true register file exponent for double-extended (pseudo-)denormal */ if ((tmp_freg.exponent == 0) && (tmp_freg.significand != U64_0)) tmp_freg.exponent=0x0C001; return (tmp_freg); } // ******************************************************************* // fp_update_fpsr() // ******************************************************************* INLINE void fp_update_fpsr( EM_opcode_sf_type sf, EM_tmp_fp_env_type tmp_fp_env ) { if (sf == sf_none) { return; } else if (sf == sfS0) { /******************************************************************* SF0 *******************************************************************/ if(tmp_fp_env.simd == 1) { /* SF0 simd fault: if either hi or low is set, set the s0 flag */ if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) { SET_STATUS_FLAG(FPSR.sf0_flags_v); } if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) { SET_STATUS_FLAG(FPSR.sf0_flags_d); } if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) { SET_STATUS_FLAG(FPSR.sf0_flags_z); } /* SF0 simd trap: if either hi or low is set, set the s0 flag if the flag is over or underflow, also set inexact */ if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) { SET_STATUS_FLAG(FPSR.sf0_flags_o); } if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH SET_STATUS_FLAG(FPSR.sf0_flags_u); } if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) { SET_STATUS_FLAG(FPSR.sf0_flags_i); } } /* end of simd */ else { /* not simd */ /* SF0 non-simd fault: if tmp flag is set and s0 flag is not, set the flag */ if (tmp_fp_env.flags.v) { SET_STATUS_FLAG(FPSR.sf0_flags_v); } if (tmp_fp_env.flags.d) { // printf ("MACH DEBUG: setting the D flag in update_fpsr ()\n"); SET_STATUS_FLAG(FPSR.sf0_flags_d); } if (tmp_fp_env.flags.z) { SET_STATUS_FLAG(FPSR.sf0_flags_z); } /* SF0 non-simd trap: if tmp flag is set, set the flag. if the flag is over or underflow, also check inexact */ if (tmp_fp_env.flags.o) { SET_STATUS_FLAG(FPSR.sf0_flags_o); if ( tmp_fp_env.flags.i) { SET_STATUS_FLAG(FPSR.sf0_flags_i); } } else if (tmp_fp_env.flags.un) { // MACH SET_STATUS_FLAG(FPSR.sf0_flags_u); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf0_flags_i); } } else if (tmp_fp_env.flags.i) { SET_STATUS_FLAG(FPSR.sf0_flags_i); } } /* end of not simd */ } /* end of SF0 */ /******************************************************************* SF1 *******************************************************************/ else if (sf == sfS1) { if(tmp_fp_env.simd == 1) { /* SF1 simd fault: if either hi or low is set, set the s1 flag */ if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) { SET_STATUS_FLAG(FPSR.sf1_flags_v); } if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) { SET_STATUS_FLAG(FPSR.sf1_flags_d); } if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) { SET_STATUS_FLAG(FPSR.sf1_flags_z); } /* SF1 simd trap: if either hi or low is set and the s1 flag is not, set the s1 flag If the flag is over or underflow, also check inexact */ if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) { SET_STATUS_FLAG(FPSR.sf1_flags_o); } if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH SET_STATUS_FLAG(FPSR.sf1_flags_u); } if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) { SET_STATUS_FLAG(FPSR.sf1_flags_i); } } /* end of simd SF1 */ else { /* not simd SF1 */ /* SF1 non-simd fault: if tmp flag is set and s1 flag is not, set the flag */ if (tmp_fp_env.flags.v ) { SET_STATUS_FLAG(FPSR.sf1_flags_v); } if (tmp_fp_env.flags.d ) { SET_STATUS_FLAG(FPSR.sf1_flags_d); } if (tmp_fp_env.flags.z ) { SET_STATUS_FLAG(FPSR.sf1_flags_z); } /* SF1 non-simd traps: if tmp flag is set and s1 flag is not, set the flag. if the flag is over or underflow, also check inexact */ if ( tmp_fp_env.flags.o ) { SET_STATUS_FLAG(FPSR.sf1_flags_o); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf1_flags_i); } } else if (tmp_fp_env.flags.un ) { // MACH SET_STATUS_FLAG(FPSR.sf1_flags_u); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf1_flags_i); } } else if (tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf1_flags_i); } } /*end of not simd SF1 */ } /* end of SF1 */ /******************************************************************* SF2 *******************************************************************/ else if (sf == sfS2) { if(tmp_fp_env.simd == 1) { /* SF2 simd fault: if either hi or low is set and the s2 flag is not, set the s2 flag */ if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) { SET_STATUS_FLAG(FPSR.sf2_flags_v); } if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) { SET_STATUS_FLAG(FPSR.sf2_flags_d); } if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) { SET_STATUS_FLAG(FPSR.sf2_flags_z); } /* SF2 simd trap: if either hi or low is set and the s2 flag is not, set the s2 flag If the flag is over or underflow, also check inexact */ if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) { SET_STATUS_FLAG(FPSR.sf2_flags_o); } if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH SET_STATUS_FLAG(FPSR.sf2_flags_u); } if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) { SET_STATUS_FLAG(FPSR.sf2_flags_i); } } /* end of simd SF2 */ else { /* not simd SF2 */ /* SF2 non-simd fault: if tmp flag is set and s2 flag is not, set the flag */ if (tmp_fp_env.flags.v ) { SET_STATUS_FLAG(FPSR.sf2_flags_v); } if (tmp_fp_env.flags.d ) { SET_STATUS_FLAG(FPSR.sf2_flags_d); } if (tmp_fp_env.flags.z ) { SET_STATUS_FLAG(FPSR.sf2_flags_z); } /* SF2 non-simd traps: if tmp flag is set and s2 flag is not, set the flag. if the flag is over or underflow, also check inexact */ if ( tmp_fp_env.flags.o ) { SET_STATUS_FLAG(FPSR.sf2_flags_o); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf2_flags_i); } } else if (tmp_fp_env.flags.un ) { // MACH SET_STATUS_FLAG(FPSR.sf2_flags_u); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf2_flags_i); } } else if (tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf2_flags_i); } } /* end of not simd SF2 */ } /* end of SF2 */ /******************************************************************* SF3 *******************************************************************/ else if (sf == sfS3) { if(tmp_fp_env.simd == 1) { /* SF3 simd fault: if either hi or low is set and the s3 flag is not, set the s3 flag */ if (tmp_fp_env.hi_flags.v || tmp_fp_env.lo_flags.v) { SET_STATUS_FLAG(FPSR.sf3_flags_v); } if (tmp_fp_env.hi_flags.d || tmp_fp_env.lo_flags.d) { SET_STATUS_FLAG(FPSR.sf3_flags_d); } if (tmp_fp_env.hi_flags.z || tmp_fp_env.lo_flags.z) { SET_STATUS_FLAG(FPSR.sf3_flags_z); } /* SF3 simd trap: if either hi or low is set and the s3 flag is not, set the s3 flag If the flag is over or underflow, also check inexact */ if (tmp_fp_env.hi_flags.o || tmp_fp_env.lo_flags.o) { SET_STATUS_FLAG(FPSR.sf3_flags_o); } if (tmp_fp_env.hi_flags.un || tmp_fp_env.lo_flags.un) { // MACH SET_STATUS_FLAG(FPSR.sf3_flags_u); } if (tmp_fp_env.hi_flags.i || tmp_fp_env.lo_flags.i) { SET_STATUS_FLAG(FPSR.sf3_flags_i); } } /* end of simd SF3 */ else { /* not simd SF3 */ /* SF3 non-simd fault: if tmp flag is set and s3 flag is not, set the flag */ if (tmp_fp_env.flags.v ) { SET_STATUS_FLAG(FPSR.sf3_flags_v); } if (tmp_fp_env.flags.d ) { SET_STATUS_FLAG(FPSR.sf3_flags_d); } if (tmp_fp_env.flags.z ) { SET_STATUS_FLAG(FPSR.sf3_flags_z); } /* SF3 non-simd traps: if tmp flag is set and s3 flag is not, set the flag. if the flag is over or underflow, also check inexact */ if ( tmp_fp_env.flags.o ) { SET_STATUS_FLAG(FPSR.sf3_flags_o); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf3_flags_i); } } else if (tmp_fp_env.flags.un ) { // MACH SET_STATUS_FLAG(FPSR.sf3_flags_u); if ( tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf3_flags_i); } } else if (tmp_fp_env.flags.i ) { SET_STATUS_FLAG(FPSR.sf3_flags_i); } } /* end of not simd SF3 */ } /* end of SF3 */ } /* end of fp_update_fpsr */ INLINE void fp_update_psr(EM_uint_t dest_freg) { EM_uint_t disabled_limit = 31; if ( (dest_freg >= 2) && (dest_freg <= disabled_limit) ){ SET_STATUS_FLAG(PSR.mfl); } else if ( (dest_freg > disabled_limit) ) { SET_STATUS_FLAG(PSR.mfh); } } /* EM_int64_t, EM_uint64_t, EM_uint128_t and EM_uint256_t support routines */ /* 128-bit unsigned int support routines */ EM_boolean_t fp82_fp_U128_eq(EM_uint128_t value1, EM_uint128_t value2) { if ( (value1.hi == value2.hi) && (value1.lo == value2.lo) ) return (1); else return (0); } static INLINE EM_boolean_t fp_U128_ge(EM_uint128_t value1, EM_uint128_t value2) { if (value1.hi > value2.hi) return (1); else if ( (value1.hi == value2.hi) && (value1.lo >= value2.lo) ) return (1); else return (0); } static INLINE EM_boolean_t fp_U128_gt(EM_uint128_t value1, EM_uint128_t value2) { if (value1.hi > value2.hi) return (1); else if ( (value1.hi == value2.hi) && (value1.lo > value2.lo) ) return (1); else return (0); } static INLINE EM_boolean_t fp_U128_le(EM_uint128_t value1, EM_uint128_t value2) { if (value1.hi < value2.hi) return (1); else if ( (value1.hi == value2.hi) && (value1.lo <= value2.lo) ) return (1); else return (0); } EM_boolean_t fp82_fp_U128_lt(EM_uint128_t value1, EM_uint128_t value2) { if (value1.hi < value2.hi) return (1); else if ( (value1.hi == value2.hi) && (value1.lo < value2.lo) ) return (1); else return (0); } EM_uint128_t fp82_fp_U128_lsh(EM_uint128_t value, EM_uint_t count) { EM_uint128_t tmp; if (count == 0) { return(value); } else if (count >= 128) { return (U128_0); } else if (count > 64) { tmp.lo = U64_0; tmp.hi = (value.lo<<(count-64)); return (tmp); } else if (count == 64) { tmp.lo = U64_0; tmp.hi = value.lo; return (tmp); } else if (count > 0) { tmp.lo = (value.lo<>(64-count)) ; return (tmp); } return(value); // MACH ADDED } EM_uint128_t fp82_fp_U128_rsh(EM_uint128_t value, EM_uint_t count) { EM_uint128_t tmp; if (count == 0) { return (value); } else if (count >= 128) { return (U128_0); } else if (count > 64) { tmp.lo = (value.hi>>(count-64)); tmp.hi = U64_0; return (tmp); } else if (count == 64) { tmp.lo = value.hi; tmp.hi = U64_0; return (tmp); } else if (count > 0) { tmp.lo = (value.lo>>count) | (value.hi<<(64-count)); tmp.hi = (value.hi>>count); return (tmp); } return(U128_0); // MACH ADDED } EM_uint128_t fp82_fp_U64_x_U64_to_U128(EM_uint64_t value1, EM_uint64_t value2) { EM_uint128_t tmp_res; EM_uint64_t r0, s0, t0; EM_uint64_t r1, s1, t1; s0 = (value1<<32)>>32; s1 = (value1>>32); t0 = (value2<<32)>>32; t1 = (value2>>32); #ifdef HPC_BUGS s0 = ((EM_uint64_t)( ( ( ((EM_int64_t)s0) << 32 ) >> 32 ) )); s1 = ((EM_uint64_t)( ( ( ((EM_int64_t)s1) << 32 ) >> 32 ) )); t0 = ((EM_uint64_t)( ( ( ((EM_int64_t)t0) << 32 ) >> 32 ) )); t1 = ((EM_uint64_t)( ( ( ((EM_int64_t)t1) << 32 ) >> 32 ) )); #endif tmp_res.lo = s0 * t0; #ifdef HPC_BUGS if(s0 & U64_0x0000000080000000) tmp_res.lo += t0<<32; if(t0 & U64_0x0000000080000000) tmp_res.lo += s0<<32; #endif r0 = s0 * t1; #ifdef HPC_BUGS if(s0 & U64_0x0000000080000000) r0 += t1<<32; if(t1 & U64_0x0000000080000000) r0 += s0<<32; #endif r1 = s1 * t0; #ifdef HPC_BUGS if(s1 & U64_0x0000000080000000) r1 += t0<<32; if(t0 & U64_0x0000000080000000) r1 += s1<<32; #endif tmp_res.hi = s1 * t1; #ifdef HPC_BUGS if(s1 & U64_0x0000000080000000) tmp_res.hi += t1<<32; if(t1 & U64_0x0000000080000000) tmp_res.hi += s1<<32; #endif if ( (tmp_res.lo + (r0<<32)) < tmp_res.lo) tmp_res.hi++; tmp_res.lo += (r0<<32); if ( (tmp_res.lo + (r1<<32)) < tmp_res.lo) tmp_res.hi++; tmp_res.lo += (r1<<32); tmp_res.hi += (r0>>32); tmp_res.hi += (r1>>32); return (tmp_res); } INLINE EM_uint128_t fp_I64_x_I64_to_I128(EM_uint64_t value1, EM_uint64_t value2) { EM_uint128_t tmp_res; EM_uint128_t scratch; tmp_res = fp_U64_x_U64_to_U128(value1, value2); if (value1 & U64_0x8000000000000000) { scratch = fp_U64_to_U128(value2); scratch = fp_U128_lsh(scratch,64); scratch = fp_U128_neg(scratch); tmp_res = fp_U128_add(scratch, tmp_res); } if (value2 & U64_0x8000000000000000) { scratch = fp_U64_to_U128(value1); scratch = fp_U128_lsh(scratch,64); scratch = fp_U128_neg(scratch); tmp_res = fp_U128_add(scratch, tmp_res); } return (tmp_res); } EM_uint128_t fp82_fp_U128_inc(EM_uint128_t value) { EM_uint128_t tmp; /* add one */ tmp.lo = value.lo + 1; tmp.hi = value.hi + (tmp.lo < value.lo); return (tmp); } static INLINE EM_uint128_t fp_U128_neg(EM_uint128_t value) { EM_uint128_t tmp; /* complement */ value.lo = ~value.lo; value.hi = ~value.hi; /* add one */ tmp.lo = value.lo + 1; tmp.hi = value.hi + (tmp.lo < value.lo); return (tmp); } EM_uint128_t fp82_fp_U128_add(EM_uint128_t value1, EM_uint128_t value2) { EM_uint128_t tmp; /* sum */ value2.lo = value1.lo + value2.lo; value2.hi = value1.hi + value2.hi; /* carry */ tmp.lo = 0; tmp.hi = (value2.lo < value1.lo); /* carry propagate adder */ tmp.lo = value2.lo; tmp.hi += value2.hi; return (tmp); } EM_uint128_t fp82_fp_U128_bor(EM_uint128_t value1, EM_uint128_t value2) { EM_uint128_t tmp_res; tmp_res.lo = value1.lo | value2.lo; tmp_res.hi = value1.hi | value2.hi; return (tmp_res); } EM_uint128_t fp82_fp_U128_band(EM_uint128_t value1, EM_uint128_t value2) { EM_uint128_t tmp_res; tmp_res.lo = value1.lo & value2.lo; tmp_res.hi = value1.hi & value2.hi; return (tmp_res); } /* 256-bit unsigned int support routines */ EM_boolean_t fp82_fp_U256_eq(EM_uint256_t value1, EM_uint256_t value2) { if ( (value1.hh == value2.hh) && (value1.hl == value2.hl ) && (value1.lh == value2.lh ) && (value1.ll == value2.ll ) ) return (1); else return (0); } EM_uint256_t fp82_fp_U256_lsh(EM_uint256_t value, EM_uint_t count) { EM_uint256_t tmp; if (count == 0) { return (value); } else if (count >= 256) { return (U256_0); } else if (count > 192) { tmp.ll = U64_0; tmp.lh = U64_0; tmp.hl = U64_0; tmp.hh = (value.ll<<(count-192)); return (tmp); } else if (count == 192) { tmp.ll = U64_0; tmp.lh = U64_0; tmp.hl = U64_0; tmp.hh = value.ll; return (tmp); } else if (count > 128) { tmp.ll = U64_0; tmp.lh = U64_0; tmp.hl = (value.ll<<(count-128)); tmp.hh = (value.lh<<(count-128)) | (value.ll>>(192-count)); return (tmp); } else if (count == 128) { tmp.ll = U64_0; tmp.lh = U64_0; tmp.hl = value.ll; tmp.hh = value.lh; return (tmp); } else if (count > 64) { tmp.ll = U64_0; tmp.lh = (value.ll<<(count-64)); tmp.hl = (value.lh<<(count-64)) | (value.ll>>(128-count)) ; tmp.hh = (value.hl<<(count-64)) | (value.lh>>(128-count)) ; return (tmp); } else if (count == 64) { tmp.ll = 0; tmp.lh = value.ll; tmp.hl = value.lh; tmp.hh = value.hl; return (tmp); } else if (count > 0) { tmp.ll = (value.ll<>(64-count)) ; tmp.hl = (value.hl<>(64-count)) ; tmp.hh = (value.hh<<(count)) | (value.hl>>(64-count)) ; return (tmp); } return(U256_0); // MACH ADDED } EM_uint256_t fp82_fp_U256_rsh(EM_uint256_t value, EM_uint_t count) { EM_uint256_t tmp; if (count == 0) { return (value); } else if (count >= 256) { return (U256_0); } else if (count > 192) { tmp.ll = (value.hh>>(count-192)); tmp.lh = U64_0; tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } else if (count == 192) { tmp.ll = value.hh; tmp.lh = U64_0; tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } else if (count > 128) { tmp.ll = (value.hl>>(count-128)) | (value.hh<<(192-count)); tmp.lh = (value.hh>>(count-128)); tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } else if (count == 128) { tmp.ll = value.hl; tmp.lh = value.hh; tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } else if (count > 64) { tmp.ll = (value.lh>>(count-64)) | (value.hl<<(128-count)); tmp.lh = (value.hl>>(count-64)) | (value.hh<<(128-count)); tmp.hl = (value.hh>>(count-64)); tmp.hh = U64_0; return (tmp); } else if (count == 64) { tmp.ll = value.lh; tmp.lh = value.hl; tmp.hl = value.hh; tmp.hh = U64_0; return (tmp); } else if (count > 0) { tmp.ll = (value.ll>>count) | (value.lh<<(64-count)); tmp.lh = (value.lh>>count) | (value.hl<<(64-count)); tmp.hl = (value.hl>>count) | (value.hh<<(64-count)); tmp.hh = (value.hh>>count); return (tmp); } return(U256_0); // MACH ADDED } EM_uint256_t fp82_fp_U256_inc(EM_uint256_t value) { EM_uint256_t tmp; /* add one */ tmp.ll = value.ll + 1; tmp.lh = value.lh + (tmp.ll < value.ll); tmp.hl = value.hl + (tmp.lh < value.lh); tmp.hh = value.hh + (tmp.hl < value.hl); return (tmp); } static INLINE EM_uint256_t fp_U256_neg(EM_uint256_t value) { EM_uint256_t tmp; /* complement */ value.ll = ~value.ll; value.lh = ~value.lh; value.hl = ~value.hl; value.hh = ~value.hh; /* add one */ tmp.ll = value.ll + 1; tmp.lh = value.lh + (tmp.ll < value.ll); tmp.hl = value.hl + (tmp.lh < value.lh); tmp.hh = value.hh + (tmp.hl < value.hl); return (tmp); } static INLINE EM_uint256_t fp_U256_add(EM_uint256_t value1, EM_uint256_t value2) { EM_uint256_t tmp; /* sum */ value2.ll = value1.ll + value2.ll; value2.lh = value1.lh + value2.lh; value2.hl = value1.hl + value2.hl; value2.hh = value1.hh + value2.hh; /* carry */ tmp.ll = 0; tmp.lh = (value2.ll < value1.ll); tmp.hl = (value2.lh < value1.lh); tmp.hh = (value2.hl < value1.hl); /* c_out = (value2.hh < value1.hh); */ /* carry propagate adder */ tmp.ll = value2.ll; tmp.lh += value2.lh; tmp.hl += value2.hl + (tmp.lh < value2.lh); tmp.hh += value2.hh + (tmp.hl < value2.hl); /* c_out += (tmp.hh < value2.hh); */ return (tmp); } /* Basic Conversion Routines */ INLINE EM_uint128_t fp_U64_to_U128(EM_uint64_t value) { EM_uint128_t tmp; tmp.lo = value; tmp.hi = U64_0; return (tmp); } INLINE EM_uint64_t fp_U128_to_U64(EM_uint128_t value) { EM_uint64_t tmp; tmp = value.lo; return (tmp); } static INLINE EM_uint256_t fp_U64_to_U256(EM_uint64_t value) { EM_uint256_t tmp; tmp.ll = value; tmp.lh = U64_0; tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } static INLINE EM_uint64_t fp_U256_to_U64(EM_uint256_t value) { EM_uint64_t tmp; tmp = value.ll; return (tmp); } EM_uint256_t fp82_fp_U128_to_U256(EM_uint128_t value) { EM_uint256_t tmp; tmp.ll = value.lo; tmp.lh = value.hi; tmp.hl = U64_0; tmp.hh = U64_0; return (tmp); } static INLINE EM_uint128_t fp_U256_to_U128(EM_uint256_t value) { EM_uint128_t tmp; tmp.lo = value.ll; tmp.hi = value.lh; return (tmp); }