/* $Id: saturn.c,v 1.1.1.10 1995/07/11 22:17:31 alex Exp $ */ /* Subroutines for insn-output.c for GNU compiler. Saturn version. This port, done by Alex T. Ramos in 1994, is the first 4-bit port of GNU CC. Copyright (C) 1987, 1992 Free Software Foundation, Inc This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "config.h" #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" #include "insn-flags.h" #include "output.h" #include "real.h" #include "flags.h" /* Under BSDi, the standard assert() is broken */ #define ASSERT(CONDITION) if(!(CONDITION)) abort(); /* RCS identification info */ char *saturn_md_version = ""; char *saturn_c_version = "$Id: saturn.c,v 1.1.1.10 1995/07/11 22:17:31 alex Exp $"; /* Internal gcc variables */ extern char *reg_names[]; extern int optimize; /* Exported global variables */ int parm_alloc_order[N_REG_PARMS] = PARM_ALLOC_ORDER; rtx cmp_op0 = 0, cmp_op1 = 0; /* Exported functions */ int branch_target(x) rtx x; { return 1; } int arithmetic_register(x) rtx x; { if(REG_P(x) && REGNO(x)>=REG_A && REGNO(x)<=REG_D) return 1; else return 0; } /* Return true if OP is a CONST_INT equal to 1. This is an acceptable operand for inc or dec instructions. */ int immediate_one_operand (op, mode) rtx op; enum machine_mode mode; { return (GET_CODE (op) == CONST_INT && abs (INTVAL (op)) == 1); } /* Return true if OP is a CONST_INT, with OP <= 16. This is an acceptable operand for constant add instructions. */ int immediate_nib_p1_operand (op, mode) rtx op; enum machine_mode mode; { return (GET_CODE (op) == CONST_INT && INTVAL (op) != 0 && abs (INTVAL (op)) <= 16); } int function_arg_regno_p(regno) int regno; { int i; for (i=0; i unroll) { sprintf (template, "push\n\tmove.1 #0,p\n\tmove.5 #$%x,c\n\t" "exg.a a,%%0\n\tadd.a c,a\n\texg.a a,%%0\n\t" "move.1 #7,p\n\tpop", cons & 0xfffff); output_asm_insn (template, ®); return ""; } if (cons>16) { expand_inline_add_const (reg,16); expand_inline_add_const (reg,cons-16); return ""; } else if (cons < -16) { expand_inline_add_const (reg,-16); expand_inline_add_const (reg,cons+16); return ""; } else if (cons == 0) { return ""; } sprintf (template, "%s.a #%d,%%0", cons>0 ? "add" : "sub", abs(cons)); output_asm_insn (template, ®); return ""; } char * expand_inline_add (reg, add) rtx reg, add; { char template [256]; rtx op[2]; switch (GET_CODE (add)) { case CONST: expand_inline_add (reg, XEXP (add, 0)); break; case CONST_INT: expand_inline_add_const (reg, INTVAL (add)); break; case LABEL_REF: case SYMBOL_REF: sprintf (template, "push\n\tmove.1 #0,p\n\tmove.ao #%%1,c\n\t" "exg.a a,%%0\n\tadd.a c,a\n\texg.a a,%%0\n\t" "move.1 #7,p\n\tpop"); op[0] = reg; op[1] = add; output_asm_insn (template, op); break; case PLUS: expand_inline_add (reg, XEXP (add, 0)); expand_inline_add (reg, XEXP (add, 1)); break; default: abort (); } return ""; } void saturn_print_operand_address (file, addr) FILE *file; register rtx addr; { switch (GET_CODE(addr)) { case REG: fprintf (file, "(%s)", reg_names[REGNO (addr)]); break; case SYMBOL_REF: assemble_name (file, XSTR(addr,0)); break; case PLUS: warning ("compiling without optimization not supported"); fprintf (file, "(%s+%d)", reg_names[REGNO (XEXP(addr,0))], INTVAL (XEXP (addr,1))); break; default: abort(); } } /* Print an instruction operand X on file FILE. CODE is the code from the %-spec that requested printing this operand; if `%z3' was used to print operand 3, then CODE is 'z'. */ void saturn_print_operand (file, x, code) FILE *file; rtx x; char code; { if(code == 'm') { /* * print out the next available asm mode for the machine mode * of this operand. This is for instructions that don't care * about bits outside the used width. */ if(GET_MODE(x) == SImode) fputs("a", file); else fputs(mode_fieldspec(x), file); } else switch (GET_CODE (x)) { case REG: fprintf (file, "%s", reg_names[REGNO (x)]); break; case MEM: output_address (XEXP (x, 0)); break; case LABEL_REF: saturn_print_operand (file, XEXP (x, 0), code); break; case CONST: saturn_print_operand (file, XEXP (x, 0), code); break; case CONST_INT: switch(code) { case 'P': if(CONSTANT_P(x)) fputc('#', file); fprintf (file, "%d", INTVAL(x)); break; case 'n': fprintf (file, "%d", -INTVAL(x)); break; case 'L': fprintf (file, "$%x00000000", INTVAL(x) & 0xFFFFFFFFU); break; case 'A': fprintf (file, "$%05x", INTVAL(x) & 0xfffff); break; case 'B': fprintf (file, "$%08x", INTVAL(x) & 0xffffffff); break; case 'C': fprintf (file, "$%04x", INTVAL(x) & 0xffff); break; case 'D': fprintf (file, "$%02x", INTVAL(x) & 0xff); break; default: fprintf (file, "%d", INTVAL(x)); break; } break; case SYMBOL_REF: assemble_name (file, XSTR(x,0)); break; case CODE_LABEL: { char label[32]; ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER(x)); assemble_name (file, label); } break; case PLUS: saturn_print_operand (file, XEXP (x, 0), code); fprintf (file, "+"); saturn_print_operand (file, XEXP (x, 1), code); break; default: abort(); } } void saturn_output_addr_const (file, x, size) FILE *file; rtx x; int size; { char buf[256]; restart: switch (GET_CODE (x)) { case SYMBOL_REF: assemble_name (file, XSTR (x, 0)); break; case LABEL_REF: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0))); assemble_name (file, buf); break; case CODE_LABEL: ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); assemble_name (file, buf); break; case CONST_INT: switch (GET_MODE (x)) { case VOIDmode: switch (size) { case 1: goto size_for_qi; case 2: goto size_for_hi; case 4: goto size_for_si; case 5: goto size_for_pdi; case 8: goto size_for_di; case 16: goto size_for_ti; default: output_operand_lossage ("unknown size const_int operand"); break; } break; size_for_qi: case QImode: if (INTVAL (x) < 0) fprintf (file, "$%x", INTVAL (x) & 0xf); else fprintf (file, "%d", INTVAL (x)); break; size_for_hi: case HImode: if (INTVAL (x) < 0) fprintf (file, "$%x", INTVAL (x) & 0xff); else fprintf (file, "%d", INTVAL (x)); break; size_for_si: case SImode: if (INTVAL (x) < 0) fprintf (file, "$%x", INTVAL (x) & 0xffff); else fprintf (file, "%d", INTVAL (x)); break; size_for_pdi: case PDImode: if (INTVAL (x) < 0) fprintf (file, "$%x", INTVAL (x) & 0xfffff); else fprintf (file, "%d", INTVAL (x)); break; size_for_di: case DImode: if (INTVAL (x) < 0) fprintf (file, #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "$%x", #else "$%lx", #endif INTVAL (x)); else fprintf (file, #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "%d", #else "%ld", #endif INTVAL (x)); break; default: output_operand_lossage ("unknown mode in const_int operand"); break; } break; case CONST: saturn_output_addr_const (file, XEXP (x, 0), size); break; size_for_ti: case CONST_DOUBLE: if (GET_MODE (x) == VOIDmode) { if (CONST_DOUBLE_HIGH (x)) fprintf (file, #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "$%x%08x", #else "$%lx%08lx", #endif CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x)); else if (CONST_DOUBLE_LOW (x) < 0) fprintf (file, #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "$%x", #else "$%lx", #endif CONST_DOUBLE_LOW (x)); else fprintf (file, #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT "%d", #else "%ld", #endif CONST_DOUBLE_LOW (x)); } else output_operand_lossage ("floating constant misused"); break; case PLUS: if (GET_CODE (XEXP (x, 0)) == CONST_INT) { saturn_output_addr_const (file, XEXP (x, 1), size); if (INTVAL (XEXP (x, 0)) >= 0) fprintf (file, "+"); saturn_output_addr_const (file, XEXP (x, 0), size); } else { saturn_output_addr_const (file, XEXP (x, 0), size); if (INTVAL (XEXP (x, 1)) >= 0) fprintf (file, "+"); saturn_output_addr_const (file, XEXP (x, 1), size); } break; case MINUS: x = simplify_subtraction (x); if (GET_CODE (x) != MINUS) goto restart; saturn_output_addr_const (file, XEXP (x, 0), size); fprintf (file, "-"); if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < 0) { fprintf (file, ASM_OPEN_PAREN); saturn_output_addr_const (file, XEXP (x, 1), size); fprintf (file, ASM_CLOSE_PAREN); } else saturn_output_addr_const (file, XEXP (x, 1), size); break; case ZERO_EXTEND: case SIGN_EXTEND: saturn_output_addr_const (file, XEXP (x, 0), size); break; default: output_operand_lossage ("invalid operand expression"); break; } } enum reg_class secondary_reload_class (class, mode, x) enum reg_class class; enum machine_mode mode; rtx x; { ASSERT(!REG_P(x) || REGNO(x)>=0); ASSERT(class>=0 && class= NMSGS)) code = 0; sprintf (errstr, " %s %s error", name, errmsg[code]); if (extra_warnings) warning (errstr); merror = code + 1; } void saturn_real_clear (r) REAL_VALUE_TYPE *r; { r->sign = 1; r->mant = 0; r->esign = 1; r->exp = 0; } void saturn_real_copy (src, dst) REAL_VALUE_TYPE *src; REAL_VALUE_TYPE *dst; { bcopy ((char *)src, (char *)dst, sizeof (REAL_VALUE_TYPE)); } REAL_VALUE_TYPE saturn_real_normalize (e, mode) struct saturn_ereal e; enum machine_mode mode; { REAL_VALUE_TYPE x; unsigned long long t; long exp; long max_exp; if (e.mhi == 0 && e.mlo == 0) { exp = 0; goto pack; } exp = e.esign * e.exp; while (e.mhi < 100000000000000ULL) { /* scale left */ t = e.mlo / 1000000000000000ULL; e.mlo = e.mlo % 1000000000000000ULL; e.mlo *= 10; e.mhi *= 10; e.mhi += t; exp -= 1; } do { while (e.mhi >= 1000000000000000ULL) { /* scale right */ e.mlo /= 10; t = e.mhi % 10; e.mlo += t * 1000000000000000ULL; e.mhi /= 10; exp += 1; } switch (mode) { case SFmode: case DFmode: t = e.mhi % 1000; t /= 100; if (t >= 5) e.mhi += 1000; e.mhi -= e.mhi % 1000; break; default: t = e.mlo / 1000000000000000ULL; if (t >= 5) e.mhi += 1; break; } } while (e.mhi >= 1000000000000000ULL); switch (mode) { case SFmode: case DFmode: max_exp = 499; break; default: max_exp = 49999; break; } if (abs (exp) > max_exp) { if (exp < 0) { saturn_real_error ("real_normalize", UNDERFLOW); e.mhi = 100000000000000ULL; exp = -max_exp; } else { saturn_real_error ("real_normalize", OVERFLOW); switch (mode) { case SFmode: case DFmode: e.mhi = 999999999999000ULL; break; default: e.mhi = 999999999999999ULL; break; } exp = max_exp; } } pack: x.sign = e.sign; x.mant = e.mhi; if (exp < 0) { x.esign = -1; x.exp = -exp; } else { x.esign = 1; x.exp = exp; } return x; } REAL_VALUE_TYPE saturn_real_add (d1, d2) REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; { struct saturn_ereal e, tmp; unsigned long long f; int i, c, t; int sign, shift; long e1, e2; e1 = d1.esign * d1.exp; e2 = d2.esign * d2.exp; if (e1 < e2) { saturn_real_copy (&d1, &tmp); saturn_real_copy (&d2, &d1); saturn_real_copy (&tmp, &d2); } e.exp = d1.exp; e.esign = d1.esign; shift = e.exp - d2.exp; if (shift > 17) { e.sign = d1.sign; e.mhi = d1.mant; e.mlo = 0; } else { /* perform addition */ sign = 0; if (d1.sign != d2.sign) sign = 1; e.sign = d1.sign; f = 1; for (i = shift + 1; i < 16; i++) f *= 10; c = 0; e.mlo = 0; for (i = 0; i < shift; i++) { if (sign) t = c - (d2.mant % 10); else t = c + (d2.mant % 10); c = t / 10; t = t % 10; e.mlo += t * f; d2.mant /= 10; f *= 10; } f = 1; e.mhi = 0; for (i = 0; i < 15; i++) { t = d1.mant % 10; if (sign) t += c - (d2.mant % 10); else t += c + (d2.mant % 10); c = t / 10; t = t % 10; e.mhi += t * f; d1.mant /= 10; d2.mant /= 10; f *= 10; } if (c != 0) { c = c % 10; if (sign) e.sign = -e.sign; e.mhi += c * f; } } /* normalize */ return saturn_real_normalize (e, VOIDmode); } REAL_VALUE_TYPE saturn_real_sub (d1, d2) REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; { d2 = saturn_real_negate (d2); return saturn_real_add (d1, d2); } REAL_VALUE_TYPE saturn_real_mul (d1, d2) REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; { struct saturn_ereal e; long exp; unsigned long h1, l1; unsigned long h2, l2; unsigned long long t1, t2; exp = d1.esign * d1.exp + d2.esign * d2.exp + 2; if (exp < 0) { e.esign = -1; e.exp = -exp; } else { e.esign = 1; e.exp = exp; } e.sign = d1.sign * d2.sign; h1 = (unsigned long)(d1.mant / 100000000ULL); l1 = (unsigned long)(d1.mant % 100000000ULL); h2 = (unsigned long)(d2.mant / 100000000ULL); l2 = (unsigned long)(d2.mant % 100000000ULL); e.mhi = (unsigned long long)h1 * (unsigned long long)h2; e.mlo = (unsigned long long)l1 * (unsigned long long)l2; t1 = (unsigned long long)l1 * (unsigned long long)h2; e.mhi += t1 / 100000000ULL; e.mlo += (t1 % 100000000ULL) * 100000000ULL; if (e.mlo > 10000000000000000ULL) { e.mhi += e.mlo / 10000000000000000ULL; e.mlo = e.mlo % 10000000000000000ULL; } t2 = (unsigned long long)h1 * (unsigned long long)l2; e.mhi += t2 / 100000000ULL; e.mlo += (t2 % 100000000ULL) * 100000000ULL; if (e.mlo > 10000000000000000ULL) { e.mhi += e.mlo / 10000000000000000ULL; e.mlo = e.mlo % 10000000000000000ULL; } return saturn_real_normalize (e, VOIDmode); } REAL_VALUE_TYPE saturn_real_div (d1, d2) REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; { struct saturn_ereal e; int i, t; long exp; e.sign = d1.sign * d2.sign; if (d1.mant == 0) { saturn_real_error ("real_div", SING); e.mhi = 999999999999999ULL; e.mlo = 0; e.esign = 1; e.exp = 49999; return saturn_real_normalize (e); } exp = d1.esign * d1.exp - d2.esign * d2.exp + 14; if (exp < 0) { e.esign = -1; e.exp = -exp; } else { e.esign = 1; e.exp = exp; } e.mhi = d1.mant / d2.mant; d1.mant -= e.mhi * d2.mant; e.mlo = 0; for (i = 0; i < 16; i++) { e.mlo *= 10; d1.mant *= 10; t = d1.mant / d2.mant; e.mlo += t; d1.mant -= t * d2.mant; } return saturn_real_normalize (e, VOIDmode); } REAL_VALUE_TYPE saturn_real_from_ulong (unsigned HOST_WIDE_INT l) { REAL_VALUE_TYPE x; int i; unsigned char data[15]; for (i = 0; i < 16; i++) data[i] = 0; for (i = 0; i < 15; i++) { data[i] = l % 10; l /= 10; if (l == 0) break; } x.sign = 1; x.esign = 1; x.exp = i; x.mant = 0; for (i = x.exp; i >= 0; i--) { x.mant *= 10; x.mant += data[i]; } for (i = x.exp + 1; i < 15; i++) x.mant *= 10; return x; } void saturn_real_to_int (lo, hi, x) HOST_WIDE_INT *lo; HOST_WIDE_INT *hi; REAL_VALUE_TYPE x; { /* UNFINISHED */ *lo = 0; *hi = 0; } void saturn_real_from_int (x, lo, hi) REAL_VALUE_TYPE *x; HOST_WIDE_INT lo; HOST_WIDE_INT hi; { REAL_VALUE_TYPE one, df, dg; int sign; saturn_real_clear (&one); one.mant = 100000000000000ULL; sign = 0; if (hi < 0) { sign = 1; hi = ~hi; if (lo) lo = -lo; else hi += 1; } df = saturn_real_ldexp (one, HOST_BITS_PER_WIDE_INT); dg = saturn_real_from_ulong ((unsigned HOST_WIDE_INT)hi); dg = saturn_real_mul (dg, df); df = saturn_real_from_ulong ((unsigned HOST_WIDE_INT)lo); dg = saturn_real_add (dg, df); if (sign) dg = saturn_real_negate (dg); saturn_real_copy (&dg, x); } void saturn_real_from_uint (x, lo, hi) REAL_VALUE_TYPE *x; unsigned HOST_WIDE_INT lo; unsigned HOST_WIDE_INT hi; { REAL_VALUE_TYPE one, df, dg; saturn_real_clear (&one); one.mant = 1000000000000000ULL; df = saturn_real_ldexp (one, HOST_BITS_PER_WIDE_INT); dg = saturn_real_from_ulong (hi); dg = saturn_real_mul (dg, df); df = saturn_real_from_ulong (lo); dg = saturn_real_add (dg, df); saturn_real_copy (&dg, x); } REAL_VALUE_TYPE saturn_real_from_float (f) HOST_WIDE_INT f; { REAL_VALUE_TYPE r; /* UNFINISHED */ saturn_real_clear (&r); return r; } REAL_VALUE_TYPE saturn_real_from_double (d) HOST_WIDE_INT *d; { REAL_VALUE_TYPE r; /* UNFINISHED */ saturn_real_clear (&r); return r; } long saturn_real_to_float (r) REAL_VALUE_TYPE r; { /* UNFINISHED */ return 0; } void saturn_real_to_double (REAL_VALUE_TYPE r, long *d) { /* UNFINISHED */ d[0] = 0; d[1] = 0; } REAL_VALUE_TYPE saturn_real_negate (x) REAL_VALUE_TYPE x; { x.sign = -x.sign; return x; } REAL_VALUE_TYPE saturn_real_truncate (mode, x) enum machine_mode mode; REAL_VALUE_TYPE x; { struct saturn_ereal e; switch (mode) { case SFmode: case DFmode: e.sign = x.sign; e.mhi = x.mant; e.mlo = 0; e.esign = x.esign; e.exp = x.exp; return saturn_real_normalize (e, mode); default: return x; } } REAL_VALUE_TYPE saturn_real_ldexp (x, n) REAL_VALUE_TYPE x; int n; { REAL_VALUE_TYPE r; saturn_real_clear (&r); while (n) { if (n % 2) r = saturn_real_add (r, x); x = saturn_real_add (x, x); n /= 2; } return r; } int saturn_real_cmp (x, y) REAL_VALUE_TYPE x; REAL_VALUE_TYPE y; { int i; int msign; if (x.sign != y.sign) { if (x.mant != 0 || y.mant != 0) return x.sign; return 0; } /* Same sign. */ if (x.sign == 0) msign = 1; else msign = -1; /* Compare the exponents. */ if (x.esign > y.esign) return msign; else if (x.esign < x.esign) return -msign; else if (x.exp > y.exp) return msign; else if (x.exp < y.exp) return -msign; /* Compare the mantissa. */ if (x.mant > y.mant) return msign; else if (x.mant < y.mant) return -msign; return 0; } #define INVALID_EXP (-7) #define chrtoi(c) ((int)((c) & 0x7f) - (int)'0') REAL_VALUE_TYPE saturn_real_atof (ss, mode) char *ss; enum machine_mode mode; { REAL_VALUE_TYPE r; struct saturn_ereal er; long exp_exp = 0; long neg_exp; long e; int imp_exp = INVALID_EXP; int sign = 1; int exp_sign = 1; int lz_exp = 0; int ptr; int mptr = 0; int exparse = 0; int nonzero = 0; int i; char *s; unsigned char mantissa[31]; for (i = 0; i < 31; i++) mantissa[i] = 0; s = ss; while (*s == ' ') /* skip leading spaces */ ++s; ptr = -1; while (s[++ptr]) { switch (s[ptr]) { case 'E': case 'e': if (exparse) goto error; exparse = 1; if (imp_exp == INVALID_EXP) imp_exp = ptr - 1; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': nonzero = 1; case '0': if (exparse) exp_exp = exp_exp * 10 + chrtoi (s[ptr]); else if (s[ptr] != '0' || nonzero) { if (mptr < 31) mantissa[mptr++] = chrtoi (s[ptr]); else if (imp_exp == INVALID_EXP) imp_exp = ptr - 1; } else --lz_exp; break; case '-': if (exparse) exp_sign = -1; else { sign *= -1; ++s; --ptr; } break; case '+': ++s; --ptr; break; case '.': imp_exp = ptr - 1; break; default: error: saturn_real_error ("real_atof", DOMAIN); saturn_real_clear (&r); return r; } } if (imp_exp == INVALID_EXP) imp_exp = ptr - 1; er.sign = sign; e = imp_exp + exp_sign * exp_exp + lz_exp; if (e < 0) { er.esign = -1; er.exp = -e; } else { er.esign = 1; er.exp = e; } er.mhi = 0; for (i = 0; i < 15; i++) { er.mhi *= 10; er.mhi += mantissa[i]; } er.mlo = 0; for (i = 0; i < 16; i++) { er.mlo *= 10; er.mlo += mantissa[15 + i]; } return saturn_real_normalize (er, mode); } extern void print_real PROTO ((REAL_VALUE_TYPE)); void print_real (r) REAL_VALUE_TYPE r; { char *s, buf[100]; int i; unsigned char data[15]; s = buf; if (r.sign < 0) *s++ = '-'; for (i = 0; i < 15; i++) { data[14 - i] = r.mant % 10; r.mant /= 10; } *s++ = data[0] + '0'; *s++ = '.'; for (i = 1; i < 15; i++) *s++ = data[i] + '0'; *s++ = 'E'; if (r.esign < 0) *s++ = '-'; for (i = 0; i < 5; i++) { data[i] = r.exp % 10; r.exp /= 10; } for (i = 4; i >= 0; i--) *s++ = data[i] + '0'; *s = '\0'; fprintf (stderr, "%s\n", buf); } void saturn_real_to_decimal (r, s) REAL_VALUE_TYPE r; char *s; { int i; unsigned char data[15]; if (r.sign < 0) *s++ = '-'; for (i = 0; i < 15; i++) { data[14 - i] = r.mant % 10; r.mant /= 10; } *s++ = data[0] + '0'; *s++ = '.'; for (i = 1; i < 15; i++) *s++ = data[i] + '0'; s--; while (*s == '0') s--; if (*s != '.') s++; if (r.exp > 0) { *s++ = 'E'; if (r.esign < 0) *s++ = '-'; for (i = 0; i < 5; i++) { data[i] = r.exp % 10; r.exp /= 10; if (r.exp == 0) break; } for ( ; i >= 0; i--) *s++ = data[i] + '0'; } *s = '\0'; } void saturn_real_arith (value, icode, d1, d2) REAL_VALUE_TYPE *value; int icode; REAL_VALUE_TYPE *d1; REAL_VALUE_TYPE *d2; { int code = (enum tree_code) icode; switch (code) { case PLUS_EXPR: /* d1 + d2 */ *value = saturn_real_add (*d1, *d2); break; case MINUS_EXPR: /* d1 - d2 */ *value = saturn_real_sub (*d1, *d2); break; case MULT_EXPR: /* d1 * d2 */ *value = saturn_real_mul (*d1, *d2); break; case RDIV_EXPR: /* d1 / d2 */ *value = saturn_real_div (*d1, *d2); break; case MIN_EXPR: /* min (d1, d2) */ if (saturn_real_cmp (*d1, *d2) < 0) saturn_real_copy (d1, value); else saturn_real_copy (d2, value); break; case MAX_EXPR: /* max (d1, d2) */ if (saturn_real_cmp (*d1, *d2) > 0) saturn_real_copy (d1, value); else saturn_real_copy (d2, value); break; default: saturn_real_clear (value); break; } } int saturn_significand_size (mode) enum machine_mode mode; { switch (mode) { case SFmode: case DFmode: return 39; case TFmode: return 49; default: abort (); } } void saturn_output_ascii(file, string, len) FILE *file; char *string; int len; { size_t n = len; char *p = string; fputs("\ttextr \"", file); while(n--) { if(isprint(*p) && *p!='\\' && *p!='"') fputc(*p, file); else fprintf(file, "\\%03o", *p); ++p; } fputs("\"\n", file); }