0b1afbb37b
While writing the previous patch, I noticed that we're not consistent with the (C) in the copyright header. The maintainers manual prefers having it, though also says it's optional. We have over 10x more files with (C) than without in gdb's code, so I spent a few minutes grepping and fixing. Funny enough, the testsuite has it backwards. I'll leave that for another time. gdb/ 2013-02-12 Pedro Alves <palves@redhat.com> * amd64-darwin-tdep.c: Add (C) after Copyright. * cli/cli-cmds.h: Ditto. * cli/cli-decode.c: Ditto. * cli/cli-decode.h: Ditto. * cli/cli-dump.c: Ditto. * cli/cli-dump.h: Ditto. * cli/cli-interp.c: Ditto. * cli/cli-logging.c: Ditto. * cli/cli-script.c: Ditto. * cli/cli-script.h: Ditto. * cli/cli-setshow.c: Ditto. * cli/cli-setshow.h: Ditto. * cli/cli-utils.c: Ditto. * cli/cli-utils.h: Ditto. * config/alpha/nm-osf3.h: Ditto. * config/djgpp/djconfig.sh: Ditto. * config/i386/nm-fbsd.h: Ditto. * config/i386/nm-i386gnu.h: Ditto. * config/nm-linux.h: Ditto. * config/nm-nto.h: Ditto. * config/rs6000/nm-rs6000.h: Ditto. * config/sparc/nm-sol2.h: Ditto. * darwin-nat-info.c: Ditto. * dfp.c: Ditto. * dfp.h: Ditto. * gdb-demangle.h: Ditto. * i386-darwin-nat.c: Ditto. * i386-darwin-tdep.c: Ditto. * linux-fork.h: Ditto. * m32c-tdep.c: Ditto. * microblaze-linux-tdep.c: Ditto. * microblaze-rom.c: Ditto. * microblaze-tdep.c: Ditto. * microblaze-tdep.h: Ditto. * mips-linux-tdep.h: Ditto. * ppc-ravenscar-thread.c: Ditto. * ppc-ravenscar-thread.h: Ditto. * prologue-value.c: Ditto. * prologue-value.h: Ditto. * ravenscar-thread.c: Ditto. * ravenscar-thread.h: Ditto. * sparc-ravenscar-thread.c: Ditto. * sparc-ravenscar-thread.h: Ditto. * tilegx-linux-tdep.c: Ditto. * unwind_stop_reasons.def: Ditto. * windows-nat.h: Ditto. * xtensa-linux-tdep.c: Ditto. * xtensa-xtregs.c: Ditto. * regformats/regdat.sh: Ditto. * regformats/regdef.h: Ditto. gdb/gdbserver/ 2013-02-12 Pedro Alves <palves@redhat.com> * linux-xtensa-low.c: Ditto. * xtensa-xtregs.c: Ditto.
385 lines
10 KiB
C
385 lines
10 KiB
C
/* Decimal floating point support for GDB.
|
|
|
|
Copyright (C) 2007-2013 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include "defs.h"
|
|
#include "expression.h"
|
|
#include "gdbtypes.h"
|
|
#include "value.h"
|
|
#include "dfp.h"
|
|
|
|
/* The order of the following headers is important for making sure
|
|
decNumber structure is large enough to hold decimal128 digits. */
|
|
|
|
#include "dpd/decimal128.h"
|
|
#include "dpd/decimal64.h"
|
|
#include "dpd/decimal32.h"
|
|
|
|
/* In GDB, we are using an array of gdb_byte to represent decimal values.
|
|
They are stored in host byte order. This routine does the conversion if
|
|
the target byte order is different. */
|
|
static void
|
|
match_endianness (const gdb_byte *from, int len, enum bfd_endian byte_order,
|
|
gdb_byte *to)
|
|
{
|
|
int i;
|
|
|
|
#if WORDS_BIGENDIAN
|
|
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_LITTLE
|
|
#else
|
|
#define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG
|
|
#endif
|
|
|
|
if (byte_order == OPPOSITE_BYTE_ORDER)
|
|
for (i = 0; i < len; i++)
|
|
to[i] = from[len - i - 1];
|
|
else
|
|
for (i = 0; i < len; i++)
|
|
to[i] = from[i];
|
|
|
|
return;
|
|
}
|
|
|
|
/* Helper function to get the appropriate libdecnumber context for each size
|
|
of decimal float. */
|
|
static void
|
|
set_decnumber_context (decContext *ctx, int len)
|
|
{
|
|
switch (len)
|
|
{
|
|
case 4:
|
|
decContextDefault (ctx, DEC_INIT_DECIMAL32);
|
|
break;
|
|
case 8:
|
|
decContextDefault (ctx, DEC_INIT_DECIMAL64);
|
|
break;
|
|
case 16:
|
|
decContextDefault (ctx, DEC_INIT_DECIMAL128);
|
|
break;
|
|
}
|
|
|
|
ctx->traps = 0;
|
|
}
|
|
|
|
/* Check for errors signaled in the decimal context structure. */
|
|
static void
|
|
decimal_check_errors (decContext *ctx)
|
|
{
|
|
/* An error here could be a division by zero, an overflow, an underflow or
|
|
an invalid operation (from the DEC_Errors constant in decContext.h).
|
|
Since GDB doesn't complain about division by zero, overflow or underflow
|
|
errors for binary floating, we won't complain about them for decimal
|
|
floating either. */
|
|
if (ctx->status & DEC_IEEE_854_Invalid_operation)
|
|
{
|
|
/* Leave only the error bits in the status flags. */
|
|
ctx->status &= DEC_IEEE_854_Invalid_operation;
|
|
error (_("Cannot perform operation: %s"),
|
|
decContextStatusToString (ctx));
|
|
}
|
|
}
|
|
|
|
/* Helper function to convert from libdecnumber's appropriate representation
|
|
for computation to each size of decimal float. */
|
|
static void
|
|
decimal_from_number (const decNumber *from, gdb_byte *to, int len)
|
|
{
|
|
decContext set;
|
|
|
|
set_decnumber_context (&set, len);
|
|
|
|
switch (len)
|
|
{
|
|
case 4:
|
|
decimal32FromNumber ((decimal32 *) to, from, &set);
|
|
break;
|
|
case 8:
|
|
decimal64FromNumber ((decimal64 *) to, from, &set);
|
|
break;
|
|
case 16:
|
|
decimal128FromNumber ((decimal128 *) to, from, &set);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Helper function to convert each size of decimal float to libdecnumber's
|
|
appropriate representation for computation. */
|
|
static void
|
|
decimal_to_number (const gdb_byte *from, int len, decNumber *to)
|
|
{
|
|
switch (len)
|
|
{
|
|
case 4:
|
|
decimal32ToNumber ((decimal32 *) from, to);
|
|
break;
|
|
case 8:
|
|
decimal64ToNumber ((decimal64 *) from, to);
|
|
break;
|
|
case 16:
|
|
decimal128ToNumber ((decimal128 *) from, to);
|
|
break;
|
|
default:
|
|
error (_("Unknown decimal floating point type."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Convert decimal type to its string representation. LEN is the length
|
|
of the decimal type, 4 bytes for decimal32, 8 bytes for decimal64 and
|
|
16 bytes for decimal128. */
|
|
void
|
|
decimal_to_string (const gdb_byte *decbytes, int len,
|
|
enum bfd_endian byte_order, char *s)
|
|
{
|
|
gdb_byte dec[16];
|
|
|
|
match_endianness (decbytes, len, byte_order, dec);
|
|
|
|
switch (len)
|
|
{
|
|
case 4:
|
|
decimal32ToString ((decimal32 *) dec, s);
|
|
break;
|
|
case 8:
|
|
decimal64ToString ((decimal64 *) dec, s);
|
|
break;
|
|
case 16:
|
|
decimal128ToString ((decimal128 *) dec, s);
|
|
break;
|
|
default:
|
|
error (_("Unknown decimal floating point type."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Convert the string form of a decimal value to its decimal representation.
|
|
LEN is the length of the decimal type, 4 bytes for decimal32, 8 bytes for
|
|
decimal64 and 16 bytes for decimal128. */
|
|
int
|
|
decimal_from_string (gdb_byte *decbytes, int len, enum bfd_endian byte_order,
|
|
const char *string)
|
|
{
|
|
decContext set;
|
|
gdb_byte dec[16];
|
|
|
|
set_decnumber_context (&set, len);
|
|
|
|
switch (len)
|
|
{
|
|
case 4:
|
|
decimal32FromString ((decimal32 *) dec, string, &set);
|
|
break;
|
|
case 8:
|
|
decimal64FromString ((decimal64 *) dec, string, &set);
|
|
break;
|
|
case 16:
|
|
decimal128FromString ((decimal128 *) dec, string, &set);
|
|
break;
|
|
default:
|
|
error (_("Unknown decimal floating point type."));
|
|
break;
|
|
}
|
|
|
|
match_endianness (dec, len, byte_order, decbytes);
|
|
|
|
/* Check for errors in the DFP operation. */
|
|
decimal_check_errors (&set);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Converts a value of an integral type to a decimal float of
|
|
specified LEN bytes. */
|
|
void
|
|
decimal_from_integral (struct value *from,
|
|
gdb_byte *to, int len, enum bfd_endian byte_order)
|
|
{
|
|
LONGEST l;
|
|
gdb_byte dec[16];
|
|
decNumber number;
|
|
struct type *type;
|
|
|
|
type = check_typedef (value_type (from));
|
|
|
|
if (TYPE_LENGTH (type) > 4)
|
|
/* libdecnumber can convert only 32-bit integers. */
|
|
error (_("Conversion of large integer to a "
|
|
"decimal floating type is not supported."));
|
|
|
|
l = value_as_long (from);
|
|
|
|
if (TYPE_UNSIGNED (type))
|
|
decNumberFromUInt32 (&number, (unsigned int) l);
|
|
else
|
|
decNumberFromInt32 (&number, (int) l);
|
|
|
|
decimal_from_number (&number, dec, len);
|
|
match_endianness (dec, len, byte_order, to);
|
|
}
|
|
|
|
/* Converts a value of a float type to a decimal float of
|
|
specified LEN bytes.
|
|
|
|
This is an ugly way to do the conversion, but libdecnumber does
|
|
not offer a direct way to do it. */
|
|
void
|
|
decimal_from_floating (struct value *from,
|
|
gdb_byte *to, int len, enum bfd_endian byte_order)
|
|
{
|
|
char *buffer;
|
|
|
|
buffer = xstrprintf ("%.30" DOUBLEST_PRINT_FORMAT, value_as_double (from));
|
|
|
|
decimal_from_string (to, len, byte_order, buffer);
|
|
|
|
xfree (buffer);
|
|
}
|
|
|
|
/* Converts a decimal float of LEN bytes to a double value. */
|
|
DOUBLEST
|
|
decimal_to_doublest (const gdb_byte *from, int len, enum bfd_endian byte_order)
|
|
{
|
|
char buffer[MAX_DECIMAL_STRING];
|
|
|
|
/* This is an ugly way to do the conversion, but libdecnumber does
|
|
not offer a direct way to do it. */
|
|
decimal_to_string (from, len, byte_order, buffer);
|
|
return strtod (buffer, NULL);
|
|
}
|
|
|
|
/* Perform operation OP with operands X and Y with sizes LEN_X and LEN_Y
|
|
and byte orders BYTE_ORDER_X and BYTE_ORDER_Y, and store value in
|
|
RESULT with size LEN_RESULT and byte order BYTE_ORDER_RESULT. */
|
|
void
|
|
decimal_binop (enum exp_opcode op,
|
|
const gdb_byte *x, int len_x, enum bfd_endian byte_order_x,
|
|
const gdb_byte *y, int len_y, enum bfd_endian byte_order_y,
|
|
gdb_byte *result, int len_result,
|
|
enum bfd_endian byte_order_result)
|
|
{
|
|
decContext set;
|
|
decNumber number1, number2, number3;
|
|
gdb_byte dec1[16], dec2[16], dec3[16];
|
|
|
|
match_endianness (x, len_x, byte_order_x, dec1);
|
|
match_endianness (y, len_y, byte_order_y, dec2);
|
|
|
|
decimal_to_number (dec1, len_x, &number1);
|
|
decimal_to_number (dec2, len_y, &number2);
|
|
|
|
set_decnumber_context (&set, len_result);
|
|
|
|
switch (op)
|
|
{
|
|
case BINOP_ADD:
|
|
decNumberAdd (&number3, &number1, &number2, &set);
|
|
break;
|
|
case BINOP_SUB:
|
|
decNumberSubtract (&number3, &number1, &number2, &set);
|
|
break;
|
|
case BINOP_MUL:
|
|
decNumberMultiply (&number3, &number1, &number2, &set);
|
|
break;
|
|
case BINOP_DIV:
|
|
decNumberDivide (&number3, &number1, &number2, &set);
|
|
break;
|
|
case BINOP_EXP:
|
|
decNumberPower (&number3, &number1, &number2, &set);
|
|
break;
|
|
default:
|
|
internal_error (__FILE__, __LINE__,
|
|
_("Unknown decimal floating point operation."));
|
|
break;
|
|
}
|
|
|
|
/* Check for errors in the DFP operation. */
|
|
decimal_check_errors (&set);
|
|
|
|
decimal_from_number (&number3, dec3, len_result);
|
|
|
|
match_endianness (dec3, len_result, byte_order_result, result);
|
|
}
|
|
|
|
/* Returns true if X (which is LEN bytes wide) is the number zero. */
|
|
int
|
|
decimal_is_zero (const gdb_byte *x, int len, enum bfd_endian byte_order)
|
|
{
|
|
decNumber number;
|
|
gdb_byte dec[16];
|
|
|
|
match_endianness (x, len, byte_order, dec);
|
|
decimal_to_number (dec, len, &number);
|
|
|
|
return decNumberIsZero (&number);
|
|
}
|
|
|
|
/* Compares two numbers numerically. If X is less than Y then the return value
|
|
will be -1. If they are equal, then the return value will be 0. If X is
|
|
greater than the Y then the return value will be 1. */
|
|
int
|
|
decimal_compare (const gdb_byte *x, int len_x, enum bfd_endian byte_order_x,
|
|
const gdb_byte *y, int len_y, enum bfd_endian byte_order_y)
|
|
{
|
|
decNumber number1, number2, result;
|
|
decContext set;
|
|
gdb_byte dec1[16], dec2[16];
|
|
int len_result;
|
|
|
|
match_endianness (x, len_x, byte_order_x, dec1);
|
|
match_endianness (y, len_y, byte_order_y, dec2);
|
|
|
|
decimal_to_number (dec1, len_x, &number1);
|
|
decimal_to_number (dec2, len_y, &number2);
|
|
|
|
/* Perform the comparison in the larger of the two sizes. */
|
|
len_result = len_x > len_y ? len_x : len_y;
|
|
set_decnumber_context (&set, len_result);
|
|
|
|
decNumberCompare (&result, &number1, &number2, &set);
|
|
|
|
/* Check for errors in the DFP operation. */
|
|
decimal_check_errors (&set);
|
|
|
|
if (decNumberIsNaN (&result))
|
|
error (_("Comparison with an invalid number (NaN)."));
|
|
else if (decNumberIsZero (&result))
|
|
return 0;
|
|
else if (decNumberIsNegative (&result))
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
/* Convert a decimal value from a decimal type with LEN_FROM bytes to a
|
|
decimal type with LEN_TO bytes. */
|
|
void
|
|
decimal_convert (const gdb_byte *from, int len_from,
|
|
enum bfd_endian byte_order_from, gdb_byte *to, int len_to,
|
|
enum bfd_endian byte_order_to)
|
|
{
|
|
decNumber number;
|
|
gdb_byte dec[16];
|
|
|
|
match_endianness (from, len_from, byte_order_from, dec);
|
|
|
|
decimal_to_number (dec, len_from, &number);
|
|
decimal_from_number (&number, dec, len_to);
|
|
|
|
match_endianness (dec, len_to, byte_order_to, to);
|
|
}
|