* real.h: Don't define REAL_INFINITY or REAL_IS_NOT_DOUBLE.
Always make REAL_VALUE_TYPE a struct containing an array of
HOST_WIDE_INT, not a double. Tidy up the code deciding how
big it is. Don't declare or use union real_extract.
* emit-rtl.c (init_emit_once), varasm.c (immed_real_const_1,
decode_rtx_const, output_constant_pool), config/a29k/a29k.c
(print_operand), config/arm/arm.c (output_move_double),
config/arm/arm.md (consttable_4, consttable_8),
config/romp/romp.c (output_fpops), config/s390/s390.h
(ASM_OUTPUT_SPECIAL_POOL_ENTRY), config/xtensa/xtensa.c
(xtensa_output_literal): Don't use union real_extract.
* config/dsp16xx/dsp16xx.c (print_operand), config/i860/i860.c
(sfmode_constant_to_ulong), config/ns32k/merlin.h
(PRINT_OPERAND), config/ns32k/ns32k.c (print_operand),
config/pdp11/pdp11.h (PRINT_OPERAND), config/we32k/we32k.h
(PRINT_OPERAND): Don't use local version of union
real_extract.
* config/convex/convex.c (check_float_value), config/vax/vax.c
(vax_float_literal), config/m88k/m88k.md (divdf3),
config/dsp16xx/dsp16xx.md (fixuns_trunchfhi2),
config/pdp11/pdp11.c (output_move_quad): Don't do host
arithmetic on target floating point quantities.
* config/a29k/a29k.md, config/dsp16xx/dsp16xx.c
(output_dsp16xx_float_const): Don't test HOST_FLOAT_FORMAT.
* fold-const.c (fold), simplify-rtx.c (simplify_binary_real):
Use MODE_HAS_INFINITIES rather than #ifdef REAL_INFINITY.
* real.c (earith): Test INFINITY rather than REAL_INFINITY;
NANS implies INFINITY, so can drop #ifdef NANS inside #ifndef
INFINITY.
* print-rtl.c (print_rtx): Disable code which needs
floating-point emulator.
* libgcc2.c: Include float.h and use DBL_MANT_DIG,
FLT_MANT_DIG, to define DF_SIZE and SF_SIZE, rather than
depending on HOST_FLOAT_FORMAT to be defined properly.
* ch/grant.c, cp/error.c: Always use REAL_VALUE_TO_DECIMAL;
don't test REAL_IS_NOT_DOUBLE.
* config/1750a/1750a.c (get_double, float_label): Delete.
(print_operand): Delete huge commented-out chunk. Use
REAL_VALUE_TO_DECIMAL.
* config/1750a/1750a-protos.h: Delete prototypes of deleted
functions.
* config/convex/convex.h: Always set TARGET_FLOAT_FORMAT to
IEEE_FLOAT_FORMAT.
* config/i370/i370.h (PRINT_OPERAND [TARGET_HLASM version]):
Use REAL_VALUE_TO_DECIMAL as ELF version does.
* config/m88k/m88k.c (real_power_of_2_operand,
legitimize_operand): Take the REAL_VALUE_TYPE and/or union
real_extract out of the union; run the input through
REAL_VALUE_TO_TARGET_DOUBLE, then plug the pair of longwords
from that into the union.
* config/pdp11/pdp11.c (output_move_double): Rearrange
parentheses to make automatic indenter happy.
* doc/tm.texi (Cross-compilation): Rename node to "Floating
Point" and rewrite to describe current situation. Also adjust
documentation of REAL_VALUE_TO_TARGET_SINGLE and friends to
match code.
* doc/rtl.texi: Adjust cross reference.
From-SVN: r51210
+2002-03-22 Zack Weinberg <zack@codesourcery.com>
+
+ * real.h: Don't define REAL_INFINITY or REAL_IS_NOT_DOUBLE.
+ Always make REAL_VALUE_TYPE a struct containing an array of
+ HOST_WIDE_INT, not a double. Tidy up the code deciding how
+ big it is. Don't declare or use union real_extract.
+
+ * emit-rtl.c (init_emit_once), varasm.c (immed_real_const_1,
+ decode_rtx_const, output_constant_pool), config/a29k/a29k.c
+ (print_operand), config/arm/arm.c (output_move_double),
+ config/arm/arm.md (consttable_4, consttable_8),
+ config/romp/romp.c (output_fpops), config/s390/s390.h
+ (ASM_OUTPUT_SPECIAL_POOL_ENTRY), config/xtensa/xtensa.c
+ (xtensa_output_literal): Don't use union real_extract.
+
+ * config/dsp16xx/dsp16xx.c (print_operand), config/i860/i860.c
+ (sfmode_constant_to_ulong), config/ns32k/merlin.h
+ (PRINT_OPERAND), config/ns32k/ns32k.c (print_operand),
+ config/pdp11/pdp11.h (PRINT_OPERAND), config/we32k/we32k.h
+ (PRINT_OPERAND): Don't use local version of union
+ real_extract.
+
+ * config/convex/convex.c (check_float_value), config/vax/vax.c
+ (vax_float_literal), config/m88k/m88k.md (divdf3),
+ config/dsp16xx/dsp16xx.md (fixuns_trunchfhi2),
+ config/pdp11/pdp11.c (output_move_quad): Don't do host
+ arithmetic on target floating point quantities.
+
+ * config/a29k/a29k.md, config/dsp16xx/dsp16xx.c
+ (output_dsp16xx_float_const): Don't test HOST_FLOAT_FORMAT.
+
+ * fold-const.c (fold), simplify-rtx.c (simplify_binary_real):
+ Use MODE_HAS_INFINITIES rather than #ifdef REAL_INFINITY.
+
+ * real.c (earith): Test INFINITY rather than REAL_INFINITY;
+ NANS implies INFINITY, so can drop #ifdef NANS inside #ifndef
+ INFINITY.
+ * print-rtl.c (print_rtx): Disable code which needs
+ floating-point emulator.
+ * libgcc2.c: Include float.h and use DBL_MANT_DIG,
+ FLT_MANT_DIG, to define DF_SIZE and SF_SIZE, rather than
+ depending on HOST_FLOAT_FORMAT to be defined properly.
+
+ * config/1750a/1750a.c (get_double, float_label): Delete.
+ (print_operand): Delete huge commented-out chunk. Use
+ REAL_VALUE_TO_DECIMAL.
+ * config/1750a/1750a-protos.h: Delete prototypes of deleted
+ functions.
+ * config/convex/convex.h: Always set TARGET_FLOAT_FORMAT to
+ IEEE_FLOAT_FORMAT.
+ * config/i370/i370.h (PRINT_OPERAND [TARGET_HLASM version]):
+ Use REAL_VALUE_TO_DECIMAL as ELF version does.
+ * config/m88k/m88k.c (real_power_of_2_operand,
+ legitimize_operand): Take the REAL_VALUE_TYPE and/or union
+ real_extract out of the union; run the input through
+ REAL_VALUE_TO_TARGET_DOUBLE, then plug the pair of longwords
+ from that into the union.
+ * config/pdp11/pdp11.c (output_move_double): Rearrange
+ parentheses to make automatic indenter happy.
+
+ * doc/tm.texi (Cross-compilation): Rename node to "Floating
+ Point" and rewrite to describe current situation. Also adjust
+ documentation of REAL_VALUE_TO_TARGET_SINGLE and friends to
+ match code.
+ * doc/rtl.texi: Adjust cross reference.
+
2002-03-22 Bob Wilson <bob.wilson@acm.org>
* config/xtensa/xtensa-protos.h (non_acc_reg_operand): Remove.
2002-03-22 Neil Booth <neil@daikokuya.demon.co.uk>
- * cpphash.h (struct cpp_reader): Remove mls_line and mls_col.
- * cpplex.c (unterminated): Delete.
- (parse_string): No string literal may extend over multiple
- lines. Suppress the error when preprocessing assembly.
+ * cpphash.h (struct cpp_reader): Remove mls_line and mls_col.
+ * cpplex.c (unterminated): Delete.
+ (parse_string): No string literal may extend over multiple
+ lines. Suppress the error when preprocessing assembly.
* cppmain.c (scan_translation_unit): Strings are single-line.
- * doc/cpp.texi: Update to match.
+ * doc/cpp.texi: Update to match.
2002-03-22 Jakub Jelinek <jakub@redhat.com>
2002-03-18 Mark Mitchell <mark@codesourcery.com>
- * calls.c (precompute_arguments): Do not assume that temporaries
+ * calls.c (precompute_arguments): Do not assume that temporaries
can be destroyed after expanding the argument.
(expand_call): Likewise.
+2002-03-22 Zack Weinberg <zack@codesourcery.com>
+
+ * grant.c: Always use REAL_VALUE_TO_DECIMAL; don't test
+ REAL_IS_NOT_DOUBLE.
+
2002-03-12 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* decl.c (chill_tree_code_type, chill_tree_code_length,
return result;
case REAL_CST:
-#ifndef REAL_IS_NOT_DOUBLE
- sprintf (wrk, "%.20g", TREE_REAL_CST (val));
-#else
REAL_VALUE_TO_DECIMAL (TREE_REAL_CST (val), "%.20g", wrk);
-#endif
APPEND (result, wrk);
return result;
extern const char *movcnt_regno_adjust PARAMS ((rtx *));
extern const char *mod_regno_adjust PARAMS ((const char *, rtx *));
extern void notice_update_cc PARAMS ((rtx));
-extern double get_double PARAMS ((rtx));
extern int memop_valid PARAMS ((rtx));
extern int mov_memory_operand PARAMS ((rtx, enum machine_mode));
extern int small_nonneg_const PARAMS ((rtx, enum machine_mode));
extern void print_operand_address PARAMS ((FILE *, rtx));
#endif /* RTX_CODE */
-extern char *float_label PARAMS ((int, double));
extern const char *branch_or_jump PARAMS ((const char *, int));
extern int find_jmplbl PARAMS ((int));
extern int one_bit_set_p PARAMS ((int));
return (rtx) 0;
}
-
-double
-get_double (x)
- rtx x;
-{
- union
- {
- double d;
- long i[2];
- }
- du;
-
- du.i[0] = CONST_DOUBLE_LOW (x);
- du.i[1] = CONST_DOUBLE_HIGH (x);
- return du.d;
-}
-
-char *
-float_label (code, value)
- int code;
- double value;
-{
- static char label[32];
- char *p;
-
- label[0] = code;
- p = label + 1;
- sprintf (p, "%f", value);
- while (*p)
- {
- *p = (*p == '+') ? 'p' :
- (*p == '-') ? 'm' : *p;
- p++;
- }
- return xstrdup (label);
-}
-
-
const char *
movcnt_regno_adjust (op)
rtx *op;
break;
case CONST_DOUBLE:
-/* {
- double value = get_double (x);
- char fltstr[32];
- sprintf (fltstr, "%f", value);
+ {
+ REAL_VALUE_TYPE r;
+ char buf[30];
- if (letter == 'D' || letter == 'E')
- {
- int i, found = 0;
- for (i = 0; i <= datalbl_ndx; i++)
- if (strcmp (fltstr, datalbl[i].value) == 0)
- {
- found = 1;
- break;
- }
- if (!found)
- {
- strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
- datalbl[i].name = float_label (letter, value);
- datalbl[i].size = (letter == 'E') ? 3 : 2;
- check_section (Konst);
- fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
- (letter == 'E' ? "ef" : "f"), fltstr);
- check_section (Normal);
- }
- }
- else if (letter == 'F' || letter == 'G')
- {
- int i, found = 0;
- for (i = 0; i <= datalbl_ndx; i++)
- if (strcmp (fltstr, datalbl[i].value) == 0)
- {
- found = 1;
- break;
- }
- if (!found)
- {
- fprintf (stderr,
- "float value %f not found upon label reference\n", value);
- strcpy (datalbl[i = ++datalbl_ndx].value, fltstr);
- datalbl[i].name = float_label (letter, value);
- datalbl[i].size = (letter == 'G') ? 3 : 2;
- check_section (Konst);
- fprintf (file, "K%s \tdata%s %s ;p_o\n", datalbl[i].name,
- (letter == 'G' ? "ef" : "f"), fltstr);
- check_section (Normal);
- }
- fprintf (file, "%s ;P_O 'F'", datalbl[i].name);
- }
- else
- fprintf (file, " %s ;P_O cst_dbl ", fltstr);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ REAL_VALUE_TO_DECIMAL (r, "%f", buf);
+
+ fputs (buf, file);
}
- */
- fprintf (file, "%f", get_double (x));
break;
case CONST_INT:
case 'L':
if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{
- union real_extract u;
+ REAL_VALUE_TYPE r;
+ char s[30];
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
- fprintf (file, "$double1(%.20e)", u.d);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", s);
+
+ fprintf (file, "$double1(%s)", s);
}
else if (GET_CODE (x) == REG)
fprintf (file, "%s", reg_names[REGNO (x) + 1]);
else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == SUBREG
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == CONST_DOUBLE)
{
- union real_extract u;
+ REAL_VALUE_TYPE r;
+ char s[30];
if (GET_MODE (SUBREG_REG (XEXP (x, 0))) == SFmode)
fprintf (file, "$float");
else
fprintf (file, "$double%d",
- (SUBREG_BYTE (XEXP (x, 0)) / GET_MODE_SIZE (GET_MODE (x))));
- memcpy ((char *) &u,
- (char *) &CONST_DOUBLE_LOW (SUBREG_REG (XEXP (x, 0))), sizeof u);
- fprintf (file, "(%.20e)", u.d);
+ (SUBREG_BYTE (XEXP (x, 0)) / GET_MODE_SIZE (GET_MODE (x))));
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", s);
+ fprintf (file, "(%s)", s);
}
else if (GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
- union real_extract u;
+ REAL_VALUE_TYPE r;
+ char s[30];
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
- fprintf (file, "$%s(%.20e)",
- GET_MODE (x) == SFmode ? "float" : "double0", u.d);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", s);
+ fprintf (file, "$%s(%s)",
+ GET_MODE (x) == SFmode ? "float" : "double0", s);
}
else
(define_split
[(set (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "float_const_operand" ""))]
- "HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT"
+ ""
[(set (match_dup 0)
(match_dup 1))]
"
{
if (GET_MODE (operands[1]) == DFmode)
{
+ REAL_VALUE_TYPE r;
long l[2];
- union real_extract u;
- memcpy (&u, &CONST_DOUBLE_LOW (operands[1]), sizeof (u));
- REAL_VALUE_TO_TARGET_DOUBLE (u.d, l);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+ REAL_VALUE_TO_TARGET_DOUBLE (r, l);
otherops[1] = GEN_INT (l[1]);
operands[1] = GEN_INT (l[0]);
}
{
case MODE_FLOAT:
{
- union real_extract u;
- memcpy (&u, &CONST_DOUBLE_LOW (operands[0]), sizeof u);
- assemble_real (u.d, GET_MODE (operands[0]), BITS_PER_WORD);
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
+ assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
break;
}
default:
{
case MODE_FLOAT:
{
- union real_extract u;
- memcpy (&u, &CONST_DOUBLE_LOW (operands[0]), sizeof u);
- assemble_real (u.d, GET_MODE (operands[0]), BITS_PER_WORD);
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[0]);
+ assemble_real (r, GET_MODE (operands[0]), BITS_PER_WORD);
break;
}
default:
TYPE_MODE (sizetype));
}
\f
-#if _IEEE_FLOAT_
-#define MAX_FLOAT 3.4028234663852886e+38
-#define MIN_FLOAT 1.1754943508222875e-38
+#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+#define MAX_FLOAT "3.4028234663852886e+38"
+#define MIN_FLOAT "1.1754943508222875e-38"
#else
-#define MAX_FLOAT 1.7014117331926443e+38
-#define MIN_FLOAT 2.9387358770557188e-39
+#define MAX_FLOAT "1.7014117331926443e+38"
+#define MIN_FLOAT "2.9387358770557188e-39"
#endif
int
int overflow;
{
REAL_VALUE_TYPE d = *dp;
+ REAL_VALUE_TYPE maxfloat = REAL_VALUE_ATOF (MAX_FLOAT, mode);
+ REAL_VALUE_TYPE minfloat = REAL_VALUE_ATOF (MIN_FLOAT, mode);
+ REAL_VALUE_TYPE neg_maxfloat = REAL_VALUE_NEGATE (maxfloat);
+ REAL_VALUE_TYPE neg_minfloat = REAL_VALUE_NEGATE (minfloat);
if (overflow)
{
- *dp = MAX_FLOAT;
+ *dp = maxfloat;
return 1;
}
if (mode == SFmode)
{
- if (d > MAX_FLOAT)
+ if (REAL_VALUES_LESS (maxfloat, d))
{
- *dp = MAX_FLOAT;
+ *dp = maxfloat;
return 1;
}
- else if (d < -MAX_FLOAT)
+ else if (REAL_VALUES_LESS (d, neg_maxfloat))
{
- *dp = -MAX_FLOAT;
+ *dp = neg_maxfloat;
return 1;
}
- else if ((d > 0 && d < MIN_FLOAT) || (d < 0 && d > -MIN_FLOAT))
+ else if ((REAL_VALUES_LESS (dconst0, d)
+ && REAL_VALUES_LESS (d, minfloat))
+ || (REAL_VALUES_LESS (d, dconst0)
+ && REAL_VALUES_LESS (neg_minfloat, d)))
{
- *dp = 0.0;
+ *dp = dconst0;
return 1;
}
}
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
switch (GET_MODE (x)) {
case DFmode:
-#if 0 /* doesn't work, produces dfloats */
REAL_VALUE_TO_TARGET_DOUBLE (d, u);
-#else
- {
- union { double d; int i[2]; } t;
- t.d = d;
- u[0] = t.i[0];
- u[1] = t.i[1];
- }
-#endif
if (code == 'u')
fprintf (file, "#%#lx", u[0]);
else if (code == 'v')
#define BRANCH_COST 0
-/* Convex uses VAX or IEEE floats.
- Follow the host format. */
-#define TARGET_FLOAT_FORMAT HOST_FLOAT_FORMAT
+/* Convex uses VAX or IEEE floats. Default to IEEE. */
+#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
/* Check a `double' value for validity for a particular machine mode. */
#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
fprintf (file, HOST_WIDE_INT_PRINT_HEX, (val >> 16) & 0xffff);
else
output_addr_const(file, op);
- }
+ }
else if (code == CONST_DOUBLE && GET_MODE(op) != DImode)
- {
- union { double d; int i[2]; } u;
- union { float f; int i; } u1;
- u.i[0] = CONST_DOUBLE_LOW (op);
- u.i[1] = CONST_DOUBLE_HIGH (op);
- u1.f = u.d;
- fprintf (file, "0x%x", u1.i);
- }
+ {
+ long l;
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ REAL_VALUE_TO_TARGET_SINGLE (r, l);
+ fprintf (file, "0x%x", l);
+ }
else if (code == CONST)
{
rtx addr = XEXP (op, 0);
{
rtx src = operands[1];
-#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
REAL_VALUE_TYPE d;
long value;
operands[1] = GEN_INT (value);
output_asm_insn ("%u0=%U1\n\t%w0=%H1", operands);
-#else
- fatal_error ("inline float constants not supported on this host");
-#endif
}
static int
rtx reg3 = gen_reg_rtx (HImode);
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
- REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31);
+ REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (dconst1, 31);
if (reg1) /* turn off complaints about unreached code */
{
} \
else \
{ \
- /* hack alert -- this prints wildly incorrect values */ \
- /* when run in cross-compiler mode. See ELF section */ \
- /* for suggested fix */ \
- union { double d; int i[2]; } u; \
- u.i[0] = CONST_DOUBLE_LOW (XV); \
- u.i[1] = CONST_DOUBLE_HIGH (XV); \
+ char buf[50]; \
+ REAL_VALUE_TYPE rval; \
+ REAL_VALUE_FROM_CONST_DOUBLE(rval, XV); \
+ REAL_VALUE_TO_DECIMAL (rval, HOST_WIDE_INT_PRINT_DEC, buf); \
if (GET_MODE (XV) == SFmode) \
{ \
mvs_page_lit += 4; \
- fprintf (FILE, "=E'%.9G'", u.d); \
+ fprintf (FILE, "=E'%s'", buf); \
} \
else \
+ if (GET_MODE (XV) == DFmode) \
{ \
mvs_page_lit += 8; \
- fprintf (FILE, "=D'%.18G'", u.d); \
+ fprintf (FILE, "=D'%s'", buf); \
+ } \
+ else /* VOIDmode !?!? strange but true ... */ \
+ { \
+ mvs_page_lit += 8; \
+ fprintf (FILE, "=XL8'%08X%08X'", \
+ CONST_DOUBLE_HIGH (XV), CONST_DOUBLE_LOW (XV)); \
} \
} \
break; \
rtx x;
{
REAL_VALUE_TYPE d;
- union { float f; unsigned long i; } u2;
+ unsigned long l;
if (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != SFmode)
abort ();
-#if TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT
- error IEEE emulation needed
-#endif
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
- u2.f = d;
- return u2.i;
+ REAL_VALUE_TO_TARGET_SINGLE (d, l);
+ return l;
}
\f
/* This function generates the assembly code for function entry.
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
+ REAL_VALUE_TYPE d;
union {
- REAL_VALUE_TYPE d;
- int i[sizeof (REAL_VALUE_TYPE) / sizeof (int)];
+ long l[2];
struct { /* IEEE double precision format */
unsigned sign : 1;
unsigned exponent : 11;
if (GET_CODE (op) != CONST_DOUBLE)
return 0;
- u.i[0] = CONST_DOUBLE_LOW (op);
- u.i[1] = CONST_DOUBLE_HIGH (op);
+ REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+ REAL_VALUE_TO_TARGET_DOUBLE (d, u.l);
if (u.s.mantissa1 != 0 || u.s.mantissa2 != 0 /* not a power of two */
|| u.s.exponent == 0 /* constant 0.0 */
enum machine_mode mode;
{
rtx temp;
+ REAL_VALUE_TYPE r;
union {
- union real_extract r;
+ long l[2];
struct { /* IEEE double precision format */
unsigned sign : 1;
unsigned exponent : 11;
if (GET_CODE (op) == CONST_DOUBLE)
{
- memcpy (&u.r, &CONST_DOUBLE_LOW (op), sizeof u);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ REAL_VALUE_TO_TARGET_DOUBLE (r, u.l);
if (u.d.exponent != 0x7ff /* NaN */
&& u.d.mantissa2 == 0 /* Mantissa fits */
&& (u.s.exponent1 == 0x8 || u.s.exponent1 == 0x7) /* Exponent fits */
operands[1] = legitimize_operand (operands[1], DFmode);
if (real_power_of_2_operand (operands[2], DFmode))
{
- union real_extract u;
- memcpy (&u, &CONST_DOUBLE_LOW (operands[2]), sizeof u);
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[2]);
+ if (!exact_real_inverse (DFmode, &r))
+ abort ();
emit_insn (gen_muldf3 (operands[0], operands[1],
- CONST_DOUBLE_FROM_REAL_VALUE (1.0/u.d, DFmode)));
+ CONST_DOUBLE_FROM_REAL_VALUE (r, DFmode)));
DONE;
}
else if (! register_operand (operands[2], DFmode))
#ifdef UTEK_ASM
#undef PRINT_OPERAND
-#define PRINT_OPERAND(FILE, X, CODE) \
-{ if (CODE == '$') putc('$', FILE); \
+#define PRINT_OPERAND(FILE, X, CODE) do { \
+ if (CODE == '$') putc('$', FILE); \
else if (CODE == '?'); \
else if (GET_CODE (X) == CONST_INT) \
fprintf(FILE, "$%d", INTVAL(X)); \
} \
} \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) \
- if (GET_MODE (X) == DFmode) \
- { union { double d; int i[2]; } u; \
- u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
- fprintf (FILE, "$0d%.20e", u.d); } \
- else { union { double d; int i[2]; } u; \
- u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
- fprintf (FILE, "$0f%.20e", u.d); } \
- else output_addr_const (FILE, X); }
+ { \
+ char buf[50]; \
+ REAL_VALUE_TYPE rval; \
+ REAL_VALUE_FROM_CONST_DOUBLE(rval, XV); \
+ REAL_VALUE_TO_DECIMAL (rval, "%.20e", buf); \
+ if (GET_MODE (XV) == SFmode) \
+ fprintf (FILE, "$0e%s", buf); \
+ else if (GET_MODE (XV) == DFmode) \
+ fprintf (FILE, "$0d%s", buf); \
+ else \
+ abort(); \
+ } \
+ else output_addr_const (FILE, X); \
+} while (0)
#endif /* UTEK_ASM */
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
{
+ REAL_VALUE_TYPE r;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ PUT_IMMEDIATE_PREFIX (file);
if (GET_MODE (x) == DFmode)
{
- union { double d; int i[2]; } u;
- u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
- PUT_IMMEDIATE_PREFIX (file);
#ifdef SEQUENT_ASM
/* Sequent likes its floating point constants as integers */
- fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);
+ fprintf (file, "0Dx%08x%08x",
+ CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
#else
+ char s[30];
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", s);
#ifdef ENCORE_ASM
- fprintf (file, "0f%.20e", u.d);
+ fprintf (file, "0f%s", s);
#else
- fprintf (file, "0d%.20e", u.d);
+ fprintf (file, "0d%s", s);
#endif
#endif
}
else
- {
- union { double d; int i[2]; } u;
- u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x);
- PUT_IMMEDIATE_PREFIX (file);
+ {
#ifdef SEQUENT_ASM
- /* We have no way of winning if we can't get the bits
- for a sequent floating point number. */
-#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
- abort ();
-#endif
- {
- union { float f; long l; } uu;
- uu.f = u.d;
- fprintf (file, "0Fx%08lx", uu.l);
- }
+ long l;
+ REAL_VALUE_TO_TARGET_SINGLE (r, l);
+ fprintf (file, "0Fx%08lx", l);
#else
- fprintf (file, "0f%.20e", u.d);
+ char s[30];
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", s);
+ fprintf (file, "0f%s", s);
#endif
}
}
if (REG_P (operands[1]))
optype1 = REGOP;
- else if (CONSTANT_P (operands[1]))
+ else if (CONSTANT_P (operands[1])
#if 0
- || GET_CODE (operands[1]) == CONST_DOUBLE)
+ || GET_CODE (operands[1]) == CONST_DOUBLE
#endif
+ )
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
{
if (GET_CODE(operands[1]) == CONST_DOUBLE)
{
- union { double d; int i[2]; } u;
- u.i[0] = CONST_DOUBLE_LOW (operands[1]);
- u.i[1] = CONST_DOUBLE_HIGH (operands[1]);
-
- if (u.d == 0.0)
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+
+ if (REAL_VALUES_EQUAL (r, dconst0))
return "{clrd|clrf} %0";
}
else if (GET_CODE (X) == MEM) \
output_address (XEXP (X, 0)); \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != SImode) \
- { union { double d; int i[2]; } u; \
- u.i[0] = CONST_DOUBLE_LOW (X); u.i[1] = CONST_DOUBLE_HIGH (X); \
- fprintf (FILE, "#%.20e", u.d); } \
+ { REAL_VALUE_TYPE r; \
+ char buf[30]; \
+ REAL_VALUE_FROM_CONST_DOUBLE (r, X); \
+ REAL_VALUE_TO_DECIMAL (r, "%.20e", buf); \
+ fprintf (FILE, "#%s", buf); } \
else { putc ('$', FILE); output_addr_const_pdp11 (FILE, X); }}
\f
/* Print a memory address as an operand to reference that memory location. */
size_so_far += 4;
if (GET_CODE (immed[i]) == CONST_DOUBLE)
{
- union real_extract u;
-
- memcpy (&u, &CONST_DOUBLE_LOW (immed[i]), sizeof u);
- assemble_real (u.d, GET_MODE (immed[i]),
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, immed[i]);
+ assemble_real (r, GET_MODE (immed[i]),
GET_MODE_ALIGNMENT (GET_MODE (immed[i])));
}
else
if (GET_CODE (EXP) != CONST_DOUBLE) \
abort (); \
\
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (EXP), sizeof u); \
- assemble_real (u.d, MODE, ALIGN); \
+ REAL_VALUE_FROM_CONST_DOUBLE (r, EXP); \
+ assemble_real (r, MODE, ALIGN); \
break; \
\
case MODE_INT: \
register rtx c;
{
register enum machine_mode mode;
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+ REAL_VALUE_TYPE r, s;
int i;
- union {double d; int i[2];} val;
-#endif
if (GET_CODE (c) != CONST_DOUBLE)
return 0;
|| c == const_tiny_rtx[(int) mode][2])
return 1;
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+ REAL_VALUE_FROM_CONST_DOUBLE (r, c);
- val.i[0] = CONST_DOUBLE_LOW (c);
- val.i[1] = CONST_DOUBLE_HIGH (c);
+ for (i = 0; i < 7; i++)
+ {
+ int x = 1 << i;
+ REAL_VALUE_FROM_INT (s, x, 0, mode);
- for (i = 0; i < 7; i ++)
- if (val.d == 1 << i || val.d == 1 / (1 << i))
- return 1;
-#endif
+ if (REAL_VALUES_EQUAL (r, s))
+ return 1;
+ if (!exact_real_inverse (mode, &s))
+ abort ();
+ if (REAL_VALUES_EQUAL (r, s))
+ return 1;
+ }
return 0;
}
output_address (XEXP (X, 0)); \
else if (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) == SFmode) \
{ \
- union { double d; long l[2]; } dtem; \
- union { float f; long l; } ftem; \
+ REAL_VALUE_TYPE r; \
+ long l; \
\
- dtem.l[0] = CONST_DOUBLE_LOW (X); \
- dtem.l[1] = CONST_DOUBLE_HIGH (X); \
- ftem.f = dtem.d; \
- fprintf(FILE, "&0x%lx", ftem.l); \
+ REAL_VALUE_FROM_CONST_DOUBLE (r, X); \
+ REAL_VALUE_TO_TARGET_SINGLE (r, l); \
+ fprintf (FILE, "&0x%lx", l); \
} \
else { putc ('&', FILE); output_addr_const (FILE, X); }}
\f
int labelno;
{
long value_long[2];
- union real_extract u;
+ REAL_VALUE_TYPE r;
int size;
fprintf (file, "\t.literal .LC%u, ", (unsigned) labelno);
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
switch (mode)
{
case SFmode:
- REAL_VALUE_TO_TARGET_SINGLE (u.d, value_long[0]);
- fprintf (file, "0x%08lx\t\t# %.12g (float)\n", value_long[0], u.d);
+ REAL_VALUE_TO_TARGET_SINGLE (r, value_long[0]);
+ fprintf (file, "0x%08lx\n", value_long[0]);
break;
case DFmode:
- REAL_VALUE_TO_TARGET_DOUBLE (u.d, value_long);
- fprintf (file, "0x%08lx, 0x%08lx # %.20g (double)\n",
- value_long[0], value_long[1], u.d);
+ REAL_VALUE_TO_TARGET_DOUBLE (r, value_long);
+ fprintf (file, "0x%08lx, 0x%08lx\n",
+ value_long[0], value_long[1]);
break;
default:
+2002-03-22 Zack Weinberg <zack@codesourcery.com>
+
+ * error.c: Always use REAL_VALUE_TO_DECIMAL; don't test
+ REAL_IS_NOT_DOUBLE.
+
2002-03-22 Jeff Knaggs <jknaggs@redhat.com>
* typeck.c (expand_ptrmemfunc_cst): Scale idx down to an index
break;
case REAL_CST:
-#ifndef REAL_IS_NOT_DOUBLE
- sprintf (digit_buffer, "%g", TREE_REAL_CST (t));
-#else
{
const unsigned char *p = (const unsigned char *) &TREE_REAL_CST (t);
size_t i;
for (i = 0; i < sizeof TREE_REAL_CST (t); i++)
sprintf (digit_buffer + 2 + 2*i, "%02x", *p++);
}
-#endif
output_add_string (scratch_buffer, digit_buffer);
break;
If the constant is floating point (regardless of its precision), then
the number of integers used to store the value depends on the size of
-@code{REAL_VALUE_TYPE} (@pxref{Cross-compilation}). The integers
+@code{REAL_VALUE_TYPE} (@pxref{Floating Point}). The integers
represent a floating point number, but not precisely in the target
machine's or host machine's floating point format. To convert them to
the precise bit pattern used by the target machine, use the macro
* PIC:: Macros for position independent code.
* Assembler Format:: Defining how to write insns and pseudo-ops to output.
* Debugging Info:: Defining the format of debugging output.
-* Cross-compilation:: Handling floating point for cross-compilers.
+* Floating Point:: Handling floating point for cross-compilers.
* Mode Switching:: Insertion of mode-switching instructions.
* Target Attributes:: Defining target-specific uses of @code{__attribute__}.
* Misc:: Everything else.
@findex REAL_VALUE_TO_TARGET_DOUBLE
@findex REAL_VALUE_TO_TARGET_LONG_DOUBLE
These translate @var{x}, of type @code{REAL_VALUE_TYPE}, to the target's
-floating point representation, and store its bit pattern in the array of
-@code{long int} whose address is @var{l}. The number of elements in the
-output array is determined by the size of the desired target floating
-point data type: 32 bits of it go in each @code{long int} array
-element. Each array element holds 32 bits of the result, even if
-@code{long int} is wider than 32 bits on the host machine.
+floating point representation, and store its bit pattern in the variable
+@var{l}. For @code{REAL_VALUE_TO_TARGET_SINGLE}, this variable should
+be a simple @code{long int}. For the others, it should be an array of
+@code{long int}. The number of elements in this array is determined by
+the size of the desired target floating point data type: 32 bits of it
+go in each @code{long int} array element. Each array element holds 32
+bits of the result, even if @code{long int} is wider than 32 bits on the
+host machine.
The array element values are designed so that you can print them out
using @code{fprintf} in the order they should appear in the target
@code{OVERRIDE_OPTIONS}.
@end table
-@node Cross-compilation
+@node Floating Point
@section Cross Compilation and Floating Point
@cindex cross compilation and floating point
@cindex floating point and cross compilation
-While all modern machines use 2's complement representation for integers,
+While all modern machines use twos-complement representation for integers,
there are a variety of representations for floating point numbers. This
means that in a cross-compiler the representation of floating point numbers
in the compiled program may be different from that used in the machine
doing the compilation.
-@findex atof
Because different representation systems may offer different amounts of
-range and precision, the cross compiler cannot safely use the host
-machine's floating point arithmetic. Therefore, floating point constants
-must be represented in the target machine's format. This means that the
-cross compiler cannot use @code{atof} to parse a floating point constant;
-it must have its own special routine to use instead. Also, constant
-folding must emulate the target machine's arithmetic (or must not be done
-at all).
-
-The macros in the following table are provided by @file{real.h} for the
-compiler to use. All parts of the compiler which generate or optimize
+range and precision, all floating point constants must be represented in
+the target machine's format. Therefore, the cross compiler cannot
+safely use the host machine's floating point arithmetic; it must emulate
+the target's arithmetic. To ensure consistency, GCC always uses
+emulation to work with floating point values, even when the host and
+target floating point formats are identical.
+
+The following macros are provided by @file{real.h} for the compiler to
+use. All parts of the compiler which generate or optimize
floating-point calculations must use these macros. They may evaluate
their operands more than once, so operands must not have side effects.
-@table @code
-@findex REAL_VALUE_TYPE
-@item REAL_VALUE_TYPE
-A macro for the C data type to be used to hold a floating point value
-in the target machine's format. Typically this would be a
-@code{struct} containing an array of @code{int}.
-
-@findex REAL_VALUES_EQUAL
-@item REAL_VALUES_EQUAL (@var{x}, @var{y})
-A macro for a C expression which compares for equality the two values,
-@var{x} and @var{y}, both of type @code{REAL_VALUE_TYPE}.
-
-@findex REAL_VALUES_LESS
-@item REAL_VALUES_LESS (@var{x}, @var{y})
-A macro for a C expression which tests whether @var{x} is less than
-@var{y}, both values being of type @code{REAL_VALUE_TYPE} and
-interpreted as floating point numbers in the target machine's
-representation.
-
-@findex REAL_VALUE_LDEXP
+@defmac REAL_VALUE_TYPE
+The C data type to be used to hold a floating point value in the target
+machine's format. Typically this is a @code{struct} containing an
+array of @code{HOST_WIDE_INT}, but all code should treat it as an opaque
+quantity.
+@end defmac
+
+@deftypefn Macro int REAL_VALUES_EQUAL (REAL_VALUE_TYPE @var{x}, REAL_VALUE_TYPE @var{y})
+Compares for equality the two values, @var{x} and @var{y}. If the target
+floating point format supports negative zeroes and/or NaNs,
+@samp{REAL_VALUES_EQUAL (-0.0, 0.0)} is true, and
+@samp{REAL_VALUES_EQUAL (NaN, NaN)} is false.
+@end deftypefn
+
+@deftypefn Macro int REAL_VALUES_LESS (REAL_VALUE_TYPE @var{x}, REAL_VALUE_TYPE @var{y})
+Tests whether @var{x} is less than @var{y}.
+@end deftypefn
+
@findex ldexp
-@item REAL_VALUE_LDEXP (@var{x}, @var{scale})
-A macro for a C expression which performs the standard library
-function @code{ldexp}, but using the target machine's floating point
-representation. Both @var{x} and the value of the expression have
-type @code{REAL_VALUE_TYPE}. The second argument, @var{scale}, is an
-integer.
-
-@findex REAL_VALUE_FIX
-@item REAL_VALUE_FIX (@var{x})
-A macro whose definition is a C expression to convert the target-machine
-floating point value @var{x} to a signed integer. @var{x} has type
-@code{REAL_VALUE_TYPE}.
-
-@findex REAL_VALUE_UNSIGNED_FIX
-@item REAL_VALUE_UNSIGNED_FIX (@var{x})
-A macro whose definition is a C expression to convert the target-machine
-floating point value @var{x} to an unsigned integer. @var{x} has type
-@code{REAL_VALUE_TYPE}.
-
-@findex REAL_VALUE_RNDZINT
-@item REAL_VALUE_RNDZINT (@var{x})
-A macro whose definition is a C expression to round the target-machine
-floating point value @var{x} towards zero to an integer value (but still
-as a floating point number). @var{x} has type @code{REAL_VALUE_TYPE},
-and so does the value.
-
-@findex REAL_VALUE_UNSIGNED_RNDZINT
-@item REAL_VALUE_UNSIGNED_RNDZINT (@var{x})
-A macro whose definition is a C expression to round the target-machine
-floating point value @var{x} towards zero to an unsigned integer value
-(but still represented as a floating point number). @var{x} has type
-@code{REAL_VALUE_TYPE}, and so does the value.
-
-@findex REAL_VALUE_ATOF
-@item REAL_VALUE_ATOF (@var{string}, @var{mode})
-A macro for a C expression which converts @var{string}, an expression of
-type @code{char *}, into a floating point number in the target machine's
-representation for mode @var{mode}. The value has type
-@code{REAL_VALUE_TYPE}.
-
-@findex REAL_INFINITY
-@item REAL_INFINITY
-Define this macro if infinity is a possible floating point value, and
-therefore division by 0 is legitimate.
-
-@findex REAL_VALUE_ISINF
-@findex isinf
-@item REAL_VALUE_ISINF (@var{x})
-A macro for a C expression which determines whether @var{x}, a floating
-point value, is infinity. The value has type @code{int}.
-By default, this is defined to call @code{isinf}.
-
-@findex REAL_VALUE_ISNAN
-@findex isnan
-@item REAL_VALUE_ISNAN (@var{x})
-A macro for a C expression which determines whether @var{x}, a floating
-point value, is a ``nan'' (not-a-number). The value has type
-@code{int}. By default, this is defined to call @code{isnan}.
-
-@findex REAL_ARITHMETIC
-@item REAL_ARITHMETIC (@var{output}, @var{code}, @var{x}, @var{y})
-A macro for a C statement which calculates an arithmetic operation of
-the two floating point values @var{x} and @var{y}, both of type
-@code{REAL_VALUE_TYPE} in the target machine's representation, to
-produce a result of the same type and representation which is stored
-in @var{output} (which will be a variable).
-
-The operation to be performed is specified by @var{code}, a tree code
-which will always be one of the following: @code{PLUS_EXPR},
-@code{MINUS_EXPR}, @code{MULT_EXPR}, @code{RDIV_EXPR},
-@code{MAX_EXPR}, @code{MIN_EXPR}.
-
-@cindex overflow while constant folding
-If overflow happens, the macro expansion executes the statement
-@code{return 0;}, which indicates the inability to perform the
-arithmetic operation requested.
-
-@findex REAL_VALUE_NEGATE
-@item REAL_VALUE_NEGATE (@var{x})
-A macro for a C expression which returns the negative of the floating
-point value @var{x}. Both @var{x} and the value of the expression
-have type @code{REAL_VALUE_TYPE} and are in the target machine's
-floating point representation.
-
-There is no way for this macro to report overflow, since overflow
-can't happen in the negation operation.
-
-@findex REAL_VALUE_TRUNCATE
-@item REAL_VALUE_TRUNCATE (@var{mode}, @var{x})
-A macro for a C expression which converts the floating point value
-@var{x} to mode @var{mode}.
-
-Both @var{x} and the value of the expression are in the target machine's
-floating point representation and have type @code{REAL_VALUE_TYPE}.
-However, the value should have an appropriate bit pattern to be output
-properly as a floating constant whose precision accords with mode
-@var{mode}.
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_LDEXP (REAL_VALUE_TYPE @var{x}, int @var{scale})
+Multiplies @var{x} by 2 raised to the power @var{scale}.
+@end deftypefn
+
+@deftypefn Macro HOST_WIDE_INT REAL_VALUE_FIX (REAL_VALUE_TYPE @var{x})
+Truncates @var{x} to a signed integer, rounding toward zero.
+@end deftypefn
+
+@deftypefn Macro {unsigned HOST_WIDE_INT} REAL_VALUE_UNSIGNED_FIX (REAL_VALUE_TYPE @var{x})
+Truncates @var{x} to an unsigned integer, rounding toward zero. If
+@var{x} is negative, returns zero.
+@end deftypefn
+
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_RNDZINT (REAL_VALUE_TYPE @var{x})
+Rounds the target-machine floating point value @var{x} towards zero to an
+integer value, but leaves it represented as a floating point number.
+@end deftypefn
-There is no way for this macro to report overflow.
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_UNSIGNED_RNDZINT (REAL_VALUE_TYPE @var{x})
+Rounds the target-machine floating point value @var{x} towards zero to an
+unsigned integer value, but leaves it represented as a floating point
+number. If @var{x} is negative, returns (positive) zero.
+@end deftypefn
-@findex REAL_VALUE_TO_INT
-@item REAL_VALUE_TO_INT (@var{low}, @var{high}, @var{x})
-A macro for a C expression which converts a floating point value
-@var{x} into a double-precision integer which is then stored into
-@var{low} and @var{high}, two variables of type @var{int}.
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_ATOF (const char *@var{string}, enum machine_mode @var{mode})
+Converts @var{string} into a floating point number in the target machine's
+representation for mode @var{mode}. This routine can handle both
+decimal and hexadecimal floating point constants, using the syntax
+defined by the C language for both.
+@end deftypefn
-@item REAL_VALUE_FROM_INT (@var{x}, @var{low}, @var{high}, @var{mode})
+@deftypefn Macro int REAL_VALUE_ISINF (REAL_VALUE_TYPE @var{x})
+Determines whether @var{x} represents infinity (positive or negative).
+@end deftypefn
+
+@deftypefn Macro int REAL_VALUE_ISNAN (REAL_VALUE_TYPE @var{x})
+Determines whether @var{x} represents a ``NaN'' (not-a-number).
+@end deftypefn
+
+@deftypefn Macro void REAL_ARITHMETIC (REAL_VALUE_TYPE @var{output}, enum tree_code @var{code}, REAL_VALUE_TYPE @var{x}, REAL_VALUE_TYPE @var{y})
+Calculates an arithmetic operation on the two floating point values
+@var{x} and @var{y}, storing the result in @var{output} (which must be a
+variable).
+
+The operation to be performed is specified by @var{code}. Only the
+following codes are supported: @code{PLUS_EXPR}, @code{MINUS_EXPR},
+@code{MULT_EXPR}, @code{RDIV_EXPR}, @code{MAX_EXPR}, @code{MIN_EXPR}.
+
+If @code{REAL_ARITHMETIC} is asked to evaluate division by zero and the
+target's floating point format cannot represent infinity, it will call
+@code{abort}. Callers should check for this situation first, using
+@code{MODE_HAS_INFINITIES}. @xref{Storage Layout}.
+@end deftypefn
+
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_NEGATE (REAL_VALUE_TYPE @var{x})
+Returns the negative of the floating point value @var{x}.
+@end deftypefn
+
+@deftypefn Macro REAL_VALUE_TYPE REAL_VALUE_TRUNCATE (REAL_VALUE_TYPE @var{mode}, enum machine_mode @var{x})
+Truncates the floating point value @var{x} to fit in @var{mode}. The
+return value is still a full-size @code{REAL_VALUE_TYPE}, but it has an
+appropriate bit pattern to be output asa floating constant whose
+precision accords with mode @var{mode}.
+@end deftypefn
+
+@deftypefn Macro void REAL_VALUE_TO_INT (HOST_WIDE_INT @var{low}, HOST_WIDE_INT @var{high}, REAL_VALUE_TYPE @var{x})
+Converts a floating point value @var{x} into a double-precision integer
+which is then stored into @var{low} and @var{high}. If the value is not
+integral, it is truncated.
+@end deftypefn
+
+@deftypefn Macro void REAL_VALUE_FROM_INT (REAL_VALUE_TYPE @var{x}, HOST_WIDE_INT @var{low}, HOST_WIDE_INT @var{high}, enum machine_mode @var{mode})
@findex REAL_VALUE_FROM_INT
-A macro for a C expression which converts a double-precision integer
-found in @var{low} and @var{high}, two variables of type @var{int},
-into a floating point value which is then stored into @var{x}.
-The value is in the target machine's representation for mode @var{mode}
-and has the type @code{REAL_VALUE_TYPE}.
-@end table
+Converts a double-precision integer found in @var{low} and @var{high},
+into a floating point value which is then stored into @var{x}. The
+value is truncated to fit in mode @var{mode}.
+@end deftypefn
@node Mode Switching
@section Mode Switching Instructions
for (i = 0; i <= 2; i++)
{
+ REAL_VALUE_TYPE *r =
+ (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2);
+
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
rtx tem = rtx_alloc (CONST_DOUBLE);
- union real_extract u;
-
- /* Zero any holes in a structure. */
- memset ((char *) &u, 0, sizeof u);
- u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2;
-
- /* Avoid trailing garbage in the rtx. */
- if (sizeof (u) < sizeof (HOST_WIDE_INT))
- CONST_DOUBLE_LOW (tem) = 0;
- if (sizeof (u) < 2 * sizeof (HOST_WIDE_INT))
- CONST_DOUBLE_HIGH (tem) = 0;
-
- memcpy (&CONST_DOUBLE_LOW (tem), &u, sizeof u);
+
+ /* Can't use CONST_DOUBLE_FROM_REAL_VALUE here; that uses the
+ tables we're setting up right now. */
+ memcpy (&CONST_DOUBLE_LOW (tem), r, sizeof (REAL_VALUE_TYPE));
CONST_DOUBLE_CHAIN (tem) = NULL_RTX;
PUT_MODE (tem, mode);
goto binary;
case RDIV_EXPR:
- /* In most cases, do nothing with a divide by zero. */
-#ifndef REAL_INFINITY
- if (TREE_CODE (arg1) == REAL_CST && real_zerop (arg1))
+ /* Don't touch a floating-point divide by zero unless the mode
+ of the constant can represent infinity. */
+ if (TREE_CODE (arg1) == REAL_CST
+ && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1)))
+ && real_zerop (arg1))
return t;
-#endif
/* (-A) / (-B) -> A / B */
if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == NEGATE_EXPR)
#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
#define DI_SIZE (sizeof (DWtype) * BITS_PER_UNIT)
-/* Define codes for all the float formats that we know of. Note
- that this is copied from real.h. */
+/* GCC guarantees this header exists at this point. */
+#include <float.h>
-#define UNKNOWN_FLOAT_FORMAT 0
-#define IEEE_FLOAT_FORMAT 1
-#define VAX_FLOAT_FORMAT 2
-#define IBM_FLOAT_FORMAT 3
-
-/* Default to IEEE float if not specified. Nearly all machines use it. */
-#ifndef HOST_FLOAT_FORMAT
-#define HOST_FLOAT_FORMAT IEEE_FLOAT_FORMAT
-#endif
-
-#if HOST_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-#define DF_SIZE 53
-#define SF_SIZE 24
-#endif
-
-#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
-#define DF_SIZE 56
-#define SF_SIZE 24
-#endif
-
-#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
-#define DF_SIZE 56
-#define SF_SIZE 24
-#endif
+#define DF_SIZE DBL_MANT_DIG
+#define SF_SIZE FLT_MANT_DIG
SFtype
__floatdisf (DWtype u)
fputc (']', outfile);
break;
-#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && MAX_LONG_DOUBLE_TYPE_SIZE == 64
+#if 0
+ /* It would be nice to do this, but it would require real.o to
+ be linked into the MD-generator programs. Maybe we should
+ do that. -zw 2002-03-03 */
case CONST_DOUBLE:
if (FLOAT_MODE_P (GET_MODE (in_rtx)))
{
- double val;
+ REAL_VALUE_TYPE val;
+ char s[30];
+
REAL_VALUE_FROM_CONST_DOUBLE (val, in_rtx);
- fprintf (outfile, " [%.16g]", val);
+ REAL_VALUE_TO_DECIMAL (val, "%.16g", s);
+ fprintf (outfile, " [%s]", s);
}
break;
#endif
break;
case RDIV_EXPR:
-#ifndef REAL_INFINITY
+#ifndef INFINITY
if (ecmp (d2, ezero) == 0)
- {
-#ifdef NANS
- enan (v, eisneg (d1) ^ eisneg (d2));
- break;
-#else
abort ();
#endif
- }
-#endif
ediv (d2, d1, v); /* d1/d2 */
break;
#define INTEL_EXTENDED_IEEE_FORMAT 0
#endif
-#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-#define REAL_INFINITY
-#endif
-
/* If FLOAT_WORDS_BIG_ENDIAN and HOST_FLOAT_WORDS_BIG_ENDIAN are not defined
in the header files, then this implies the word-endianness is the same as
for integers. */
/* **** Start of software floating point emulator interface macros **** */
-/* Support 80-bit extended real XFmode if LONG_DOUBLE_TYPE_SIZE
- has been defined to be 96 in the tm.h machine file. */
-#if (MAX_LONG_DOUBLE_TYPE_SIZE == 96)
-#define REAL_IS_NOT_DOUBLE
-typedef struct {
- HOST_WIDE_INT r[(11 + sizeof (HOST_WIDE_INT))/(sizeof (HOST_WIDE_INT))];
-} realvaluetype;
-#define REAL_VALUE_TYPE realvaluetype
-
-#else /* no XFmode support */
-
-#if (MAX_LONG_DOUBLE_TYPE_SIZE == 128)
-
-#define REAL_IS_NOT_DOUBLE
-typedef struct {
- HOST_WIDE_INT r[(19 + sizeof (HOST_WIDE_INT))/(sizeof (HOST_WIDE_INT))];
-} realvaluetype;
-#define REAL_VALUE_TYPE realvaluetype
-
-#else /* not TFmode */
-
-#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-/* If no XFmode support, then a REAL_VALUE_TYPE is 64 bits wide
- but it is not necessarily a host machine double. */
-#define REAL_IS_NOT_DOUBLE
+/* REAL_VALUE_TYPE is an array of the minimum number of HOST_WIDE_INTs
+ required to hold MAX_LONG_DOUBLE_TYPE_SIZE bits. */
+#define N (MAX_LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)
+#define S sizeof (HOST_WIDE_INT)
typedef struct {
- HOST_WIDE_INT r[(7 + sizeof (HOST_WIDE_INT))/(sizeof (HOST_WIDE_INT))];
-} realvaluetype;
-#define REAL_VALUE_TYPE realvaluetype
-#else
-/* If host and target formats are compatible, then a REAL_VALUE_TYPE
- is actually a host machine double. */
-#define REAL_VALUE_TYPE double
-#endif
-
-#endif /* no TFmode support */
-#endif /* no XFmode support */
+ HOST_WIDE_INT r[N/S + (N%S ? 1 : 0)]; /* round up */
+} REAL_VALUE_TYPE;
+#undef N
+#undef S
extern unsigned int significand_size PARAMS ((enum machine_mode));
extern REAL_VALUE_TYPE dconst2;
extern REAL_VALUE_TYPE dconstm1;
-/* Union type used for extracting real values from CONST_DOUBLEs
- or putting them in. */
-
-union real_extract
-{
- REAL_VALUE_TYPE d;
- HOST_WIDE_INT i[sizeof (REAL_VALUE_TYPE) / sizeof (HOST_WIDE_INT)];
-};
-
/* Given a CONST_DOUBLE in FROM, store into TO the value it represents. */
/* Function to return a real value (not a tree node)
from a given integer constant. */
union tree_node *));
#define REAL_VALUE_FROM_CONST_DOUBLE(to, from) \
-do { union real_extract u; \
- memcpy (&u, &CONST_DOUBLE_LOW ((from)), sizeof u); \
- to = u.d; } while (0)
+ memcpy (&(to), &CONST_DOUBLE_LOW ((from)), sizeof (REAL_VALUE_TYPE))
/* Return a CONST_DOUBLE with value R and mode M. */
f0 = real_value_truncate (args->mode, f0);
f1 = real_value_truncate (args->mode, f1);
-#ifndef REAL_INFINITY
- if (args->code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
+ if (args->code == DIV
+ && !MODE_HAS_INFINITIES (args->mode)
+ && REAL_VALUES_EQUAL (f1, dconst0))
{
args->result = 0;
return;
}
-#endif
REAL_ARITHMETIC (value, rtx_to_tree_code (args->code), f0, f1);
value = real_value_truncate (args->mode, value);
REAL_VALUE_TYPE d;
enum machine_mode mode;
{
- union real_extract u;
rtx r;
- /* Get the desired `double' value as a sequence of ints
- since that is how they are stored in a CONST_DOUBLE. */
-
- u.d = d;
-
/* Detect special cases. Check for NaN first, because some ports
(specifically the i386) do not emit correct ieee-fp code by default, and
thus will generate a core dump here if we pass a NaN to REAL_VALUES_EQUAL
else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst2, d))
return CONST2_RTX (mode);
- if (sizeof u == sizeof (HOST_WIDE_INT))
- return immed_double_const (u.i[0], 0, mode);
- if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
- return immed_double_const (u.i[0], u.i[1], mode);
+ if (sizeof (REAL_VALUE_TYPE) == sizeof (HOST_WIDE_INT))
+ return immed_double_const (d.r[0], 0, mode);
+ if (sizeof (REAL_VALUE_TYPE) == 2 * sizeof (HOST_WIDE_INT))
+ return immed_double_const (d.r[0], d.r[1], mode);
/* The rest of this function handles the case where
a float value requires more than 2 ints of space.
If one is found, return it. */
if (cfun != 0)
for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r))
- if (! memcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u)
+ if (! memcmp ((char *) &CONST_DOUBLE_LOW (r), (char *) &d, sizeof d)
&& GET_MODE (r) == mode)
return r;
freed memory. */
r = rtx_alloc (CONST_DOUBLE);
PUT_MODE (r, mode);
- memcpy ((char *) &CONST_DOUBLE_LOW (r), (char *) &u, sizeof u);
+ memcpy ((char *) &CONST_DOUBLE_LOW (r), (char *) &d, sizeof d);
/* If we aren't inside a function, don't put r on the
const_double_chain. */
ENUM_BITFIELD(kind) kind : 16;
ENUM_BITFIELD(machine_mode) mode : 16;
union {
- union real_extract du;
+ REAL_VALUE_TYPE du;
struct addr_const addr;
struct {HOST_WIDE_INT high, low;} di;
if (GET_MODE (x) != VOIDmode)
{
value->mode = GET_MODE (x);
- memcpy ((char *) &value->un.du,
- (char *) &CONST_DOUBLE_LOW (x), sizeof value->un.du);
+ REAL_VALUE_FROM_CONST_DOUBLE (value->un.du, x);
}
else
{
{
struct pool_constant *pool;
rtx x;
- union real_extract u;
+ REAL_VALUE_TYPE r;
/* It is possible for gcc to call force_const_mem and then to later
discard the instructions which refer to the constant. In such a
if (GET_CODE (x) != CONST_DOUBLE)
abort ();
- memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (x), sizeof u);
- assemble_real (u.d, pool->mode, pool->align);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ assemble_real (r, pool->mode, pool->align);
break;
case MODE_INT:
for (i = 0; i < units; i++)
{
elt = CONST_VECTOR_ELT (x, i);
- memcpy ((char *) &u,
- (char *) &CONST_DOUBLE_LOW (elt),
- sizeof u);
- assemble_real (u.d, GET_MODE_INNER (pool->mode), pool->align);
+ REAL_VALUE_FROM_CONST_DOUBLE (r, elt);
+ assemble_real (r, GET_MODE_INNER (pool->mode), pool->align);
}
}
break;