/* * Copyright (c) 1982 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)bignum1.c 5.1 (Berkeley) 4/30/85"; #endif not lint #include #include #include "as.h" /* * Construct a floating point number */ Bignum as_atof(numbuf, radix, ovfp) char *numbuf; int radix; Ovf *ovfp; { Bignum number; extern int errno; double atof(); number = Znumber; errno = 0; switch(radix){ case TYPF: case TYPD: number.num_tag = TYPD; *ovfp = 0; number.num_num.numFd_float.Fd_value = atof(numbuf); break; case TYPG: case TYPH: number = bigatof(numbuf, radix); break; } if (errno == ERANGE && passno == 2){ yywarning("Floating conversion over/underflowed\n"); } return(number); } /* * Construct an integer. */ Bignum as_atoi(ccp, radix, ovfp) reg char *ccp; /* character cp */ int radix; Ovf *ovfp; { reg chptr bcp; chptr tcp; reg int i; int val; Bignum n_n; Bignum t_n; int sign; Ovf ovf; ovf = 0; sign = 0; for (; *ccp; ccp++){ switch(*ccp){ case '0': case '+': continue; case '-': sign ^= 1; continue; } break; } n_n = Znumber; t_n = Znumber; bcp = CH_FIELD(n_n); (void)numclear(bcp); tcp = CH_FIELD(t_n); (void)numclear(tcp); for (; *ccp; ccp++){ switch(*ccp){ case '8': case '9': if (radix < 10) goto done; /*FALLTHROUGH*/ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': val = *ccp - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': if (radix < 16) goto done; val = *ccp - 'A' + 10; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (radix < 16) goto done; val = *ccp - 'a' + 10; break; default: goto done; } switch(radix){ case 8: ovf |= numshift(3, bcp, bcp); break; case 16: ovf |= numshift(4, bcp, bcp); break; case 10: ovf |= numshift(1, tcp, bcp); ovf |= numshift(3, bcp, bcp); ovf |= numaddv(bcp, tcp, bcp); break; } ovf |= numaddd(bcp, bcp, val); } done: ; ovf |= posovf(bcp); if (sign){ if (ovf & OVF_MAXINT) { ovf &= ~(OVF_MAXINT | OVF_POSOVF); } else { ovf |= numnegate(bcp, bcp); } } /* * find the highest set unit of the number */ val = sign ? -1 : 0; for (i = 0; i < CH_N; i++){ if (bcp[i] == val) break; } { static u_char tagtab[4][16] = { { TYPB, TYPW, TYPL, TYPL, TYPQ, TYPQ, TYPQ, TYPQ, TYPO, TYPO, TYPO, TYPO, TYPO, TYPO, TYPO, TYPO}, { TYPW, TYPL, TYPQ, TYPQ, TYPO, TYPO, TYPO, TYPO}, { 0 }, { TYPL, TYPQ, TYPO, TYPO } }; /* * i indexes to the null chunk; make it point to the * last non null chunk */ i -= 1; if (i < 0) i = 0; n_n.num_tag = tagtab[HOC][i]; assert(n_n.num_tag != 0, "Botch width computation"); } *ovfp = ovf; return(n_n); } Ovf posovf(src) reg chptr src; { reg int i; Ovf overflow = 0; if (src[HOC] & SIGNBIT) overflow = OVF_POSOVF; if (src[HOC] == SIGNBIT){ for (i = HOC - 1; i >= 0; --i){ if (src[i] != 0) return(overflow); } overflow |= OVF_MAXINT; } return(overflow); } /* * check if the number is clear */ int isclear(dst) reg chptr dst; { return(!isunequal(dst, CH_FIELD(Znumber))); } int isunequal(src1, src2) reg chptr src1, src2; { reg int i; i = CH_N; do{ if (*src1++ != *src2++) return(i); }while(--i); return(0); } Ovf numclear(dst) reg chptr dst; { reg int i; i = CH_N; do{ *dst++ = 0; }while(--i); return(0); } Ovf numshift(n, dst, src) int n; reg chptr dst, src; { reg int i; reg u_int carryi, carryo; reg u_int mask; reg u_int value; i = CH_N; if (n == 0){ do{ *dst++ = *src++; } while(--i); return(0); } carryi = 0; mask = ONES(n); if (n > 0){ do{ value = *src++; carryo = (value >> (CH_BITS - n)) & mask; value <<= n; value &= ~mask; *dst++ = value | carryi; carryi = carryo; } while (--i); return(carryi ? OVF_LSHIFT : 0); } else { n = -n; src += CH_N; dst += CH_N; do{ value = *--src; carryo = value & mask; value >>= n; value &= ONES(CH_BITS - n); *--dst = value | carryi; carryi = carryo << (CH_BITS - n); } while (--i); return(carryi ? OVF_LSHIFT : 0); } } Ovf numaddd(dst, src1, val) chptr dst, src1; int val; { static Bignum work; work.num_uchar[0] = val; return (numaddv(dst, src1, CH_FIELD(work))); } Ovf numaddv(dst, src1, src2) reg chptr dst, src1, src2; { reg int i; reg int carry; reg u_int A,B,value; carry = 0; i = CH_N; do{ A = *src1++; B = *src2++; value = A + B + carry; *dst++ = value; carry = 0; if (value < A || value < B) carry = 1; } while (--i); return(carry ? OVF_ADDV : 0); } Ovf numnegate(dst, src) chptr dst, src; { Ovf ovf; ovf = num1comp(dst, src) ; ovf |= numaddd(dst, dst, 1); return(ovf); } Ovf num1comp(dst, src) reg chptr dst, src; { reg int i; i = CH_N; do{ *dst++ = ~ *src++; }while (--i); return(0); } /* * Determine if floating point numbers are * capable of being represented as a one byte immediate literal constant * If it is, then stuff the value into *valuep. * argtype is how the instruction will interpret the number. */ int slitflt(number, argtype, valuep) Bignum number; /* number presented */ int argtype; /* what the instruction expects */ int *valuep; { #define EXPPREC 3 #define MANTPREC 3 int mask; reg int i; Bignum unpacked; Ovf ovf; *valuep = 0; if (!ty_float[argtype]) return(0); unpacked = bignumunpack(number, &ovf); assert(ovf == 0, "overflow in unpacking floating #!?"); if (unpacked.num_sign) return(0); if (unpacked.num_exponent < 0) return(0); if (unpacked.num_exponent > ONES(EXPPREC)) return(0); for (i = 0; i < HOC; i++){ if (CH_FIELD(unpacked)[i]) return(0); } if ((CH_FIELD(unpacked)[HOC]) & ONES(CH_BITS - MANTPREC)) return(0); *valuep = (unpacked.num_exponent & ONES(EXPPREC)) << MANTPREC; mask = (CH_FIELD(unpacked)[HOC]) >> (CH_BITS - MANTPREC); mask &= ONES(MANTPREC); *valuep |= mask; *valuep &= ONES(MANTPREC + EXPPREC); return(1); } #ifndef STANDALONE /* * Output a big number to txtfil * Called only when passno == 2 * * The conversion specifies the width of the number to be written out. * The width is supplied from either an initialized data directive * (for example .float, .double), or from the operand size * defined by an operator. * If the number is of type quad or octal, * we just write it out; this allows one to specify bit * patterns for floating point numbers. * If the number is one of the floating types and the conversion * is not the same type, then we complain, but do the conversion anyway. * The conversion is strict. */ bignumwrite(number, toconv) Bignum number; int toconv; /* one of TYP[QO FDGH] */ { reg u_int *bp; if (passno != 2) return; bp = &number.num_uint[0]; switch(number.num_tag){ case TYPB: case TYPW: case TYPL: case TYPQ: case TYPO: number = intconvert(number, toconv); break; default: number = floatconvert(number, toconv); break; } bwrite((char *)bp, ty_nbyte[toconv], txtfil); } #endif STANDALONE