/* acc *= op */ static void floatnum_mul(yasm_floatnum *acc, const yasm_floatnum *op) { long expon; wordptr product, op1, op2; long norm_amt; /* Compute the new sign */ acc->sign ^= op->sign; /* Check for multiply by 0 */ if (BitVector_is_empty(acc->mantissa) || BitVector_is_empty(op->mantissa)) { BitVector_Empty(acc->mantissa); acc->exponent = EXP_ZERO; return; } /* Add exponents, checking for overflow/underflow. */ expon = (((int)acc->exponent)-EXP_BIAS) + (((int)op->exponent)-EXP_BIAS); expon += EXP_BIAS; if (expon > EXP_MAX) { /* Overflow; return infinity. */ BitVector_Empty(acc->mantissa); acc->exponent = EXP_INF; return; } else if (expon < EXP_MIN) { /* Underflow; return zero. */ BitVector_Empty(acc->mantissa); acc->exponent = EXP_ZERO; return; } /* Add one to the final exponent, as the multiply shifts one extra time. */ acc->exponent = (unsigned short)(expon+1); /* Allocate space for the multiply result */ product = BitVector_Create((N_int)((MANT_BITS+1)*2), FALSE); /* Allocate 1-bit-longer fields to force the operands to be unsigned */ op1 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); op2 = BitVector_Create((N_int)(MANT_BITS+1), FALSE); /* Make the operands unsigned after copying from original operands */ BitVector_Copy(op1, acc->mantissa); BitVector_MSB(op1, 0); BitVector_Copy(op2, op->mantissa); BitVector_MSB(op2, 0); /* Compute the product of the mantissas */ BitVector_Multiply(product, op1, op2); /* Normalize the product. Note: we know the product is non-zero because * both of the original operands were non-zero. * * Look for the highest set bit, shift to make it the MSB, and adjust * exponent. Don't let exponent go negative. */ norm_amt = (MANT_BITS*2-1)-Set_Max(product); if (norm_amt > (long)acc->exponent) norm_amt = (long)acc->exponent; BitVector_Move_Left(product, (N_int)norm_amt); acc->exponent -= (unsigned short)norm_amt; /* Store the highest bits of the result */ BitVector_Interval_Copy(acc->mantissa, product, 0, MANT_BITS, MANT_BITS); /* Free allocated variables */ BitVector_Destroy(product); BitVector_Destroy(op1); BitVector_Destroy(op2); }
/* Function used by conversion routines to actually perform the conversion. * * ptr -> the array to return the little-endian floating point value into. * flt -> the floating point value to convert. * byte_size -> the size in bytes of the output format. * mant_bits -> the size in bits of the output mantissa. * implicit1 -> does the output format have an implicit 1? 1=yes, 0=no. * exp_bits -> the size in bits of the output exponent. * * Returns 0 on success, 1 if overflow, -1 if underflow. */ static int floatnum_get_common(const yasm_floatnum *flt, /*@out@*/ unsigned char *ptr, N_int byte_size, N_int mant_bits, int implicit1, N_int exp_bits) { long exponent = (long)flt->exponent; wordptr output; charptr buf; unsigned int len; unsigned int overflow = 0, underflow = 0; int retval = 0; long exp_bias = (1<<(exp_bits-1))-1; long exp_inf = (1<<exp_bits)-1; output = BitVector_Create(byte_size*8, TRUE); /* copy mantissa */ BitVector_Interval_Copy(output, flt->mantissa, 0, (N_int)((MANT_BITS-implicit1)-mant_bits), mant_bits); /* round mantissa */ if (BitVector_bit_test(flt->mantissa, (MANT_BITS-implicit1)-(mant_bits+1))) BitVector_increment(output); if (BitVector_bit_test(output, mant_bits)) { /* overflowed, so zero mantissa (and set explicit bit if necessary) */ BitVector_Empty(output); BitVector_Bit_Copy(output, mant_bits-1, !implicit1); /* and up the exponent (checking for overflow) */ if (exponent+1 >= EXP_INF) overflow = 1; else exponent++; } /* adjust the exponent to the output bias, checking for overflow */ exponent -= EXP_BIAS-exp_bias; if (exponent >= exp_inf) overflow = 1; else if (exponent <= 0) underflow = 1; /* underflow and overflow both set!? */ if (underflow && overflow) yasm_internal_error(N_("Both underflow and overflow set")); /* check for underflow or overflow and set up appropriate output */ if (underflow) { BitVector_Empty(output); exponent = 0; if (!(flt->flags & FLAG_ISZERO)) retval = -1; } else if (overflow) { BitVector_Empty(output); exponent = exp_inf; retval = 1; } /* move exponent into place */ BitVector_Chunk_Store(output, exp_bits, mant_bits, (N_long)exponent); /* merge in sign bit */ BitVector_Bit_Copy(output, byte_size*8-1, flt->sign); /* get little-endian bytes */ buf = BitVector_Block_Read(output, &len); if (len < byte_size) yasm_internal_error( N_("Byte length of BitVector does not match bit length")); /* copy to output */ memcpy(ptr, buf, byte_size*sizeof(unsigned char)); /* free allocated resources */ yasm_xfree(buf); BitVector_Destroy(output); return retval; }
void yasm_intnum_get_sized(const yasm_intnum *intn, unsigned char *ptr, size_t destsize, size_t valsize, int shift, int bigendian, int warn) { wordptr op1 = op1static, op2; unsigned char *buf; unsigned int len; size_t rshift = shift < 0 ? (size_t)(-shift) : 0; int carry_in; /* Currently don't support destinations larger than our native size */ if (destsize*8 > BITVECT_NATIVE_SIZE) yasm_internal_error(N_("destination too large")); /* General size warnings */ if (warn<0 && !yasm_intnum_check_size(intn, valsize, rshift, 1)) yasm_warn_set(YASM_WARN_GENERAL, N_("value does not fit in signed %d bit field"), valsize); if (warn>0 && !yasm_intnum_check_size(intn, valsize, rshift, 2)) yasm_warn_set(YASM_WARN_GENERAL, N_("value does not fit in %d bit field"), valsize); /* Read the original data into a bitvect */ if (bigendian) { /* TODO */ yasm_internal_error(N_("big endian not implemented")); } else BitVector_Block_Store(op1, ptr, (N_int)destsize); /* If not already a bitvect, convert value to be written to a bitvect */ op2 = intnum_tobv(op2static, intn); /* Check low bits if right shifting and warnings enabled */ if (warn && rshift > 0) { BitVector_Copy(conv_bv, op2); BitVector_Move_Left(conv_bv, (N_int)(BITVECT_NATIVE_SIZE-rshift)); if (!BitVector_is_empty(conv_bv)) yasm_warn_set(YASM_WARN_GENERAL, N_("misaligned value, truncating to boundary")); } /* Shift right if needed */ if (rshift > 0) { carry_in = BitVector_msb_(op2); while (rshift-- > 0) BitVector_shift_right(op2, carry_in); shift = 0; } /* Write the new value into the destination bitvect */ BitVector_Interval_Copy(op1, op2, (unsigned int)shift, 0, (N_int)valsize); /* Write out the new data */ buf = BitVector_Block_Read(op1, &len); if (bigendian) { /* TODO */ yasm_internal_error(N_("big endian not implemented")); } else memcpy(ptr, buf, destsize); yasm_xfree(buf); }