summaryrefslogtreecommitdiffstats
path: root/gdb/valarith.c
diff options
context:
space:
mode:
authorPaul N. Hilfinger <hilfinger@adacore.com>2008-01-30 07:28:16 +0000
committerPaul N. Hilfinger <hilfinger@adacore.com>2008-01-30 07:28:16 +0000
commitd118ef8764180584e6b42b38d8c68c18bf8c83c4 (patch)
tree7b0451b86d7f4eb95586ba07e83e7629ee40c041 /gdb/valarith.c
parentd56d46f5c7560a45f3a1c6101893ca84969c98a9 (diff)
downloadppe42-binutils-d118ef8764180584e6b42b38d8c68c18bf8c83c4.tar.gz
ppe42-binutils-d118ef8764180584e6b42b38d8c68c18bf8c83c4.zip
2008-01-30 Paul N. Hilfinger <hilfinger@adacore.com>
* valarith.c (value_binop): Add floating-point BINOP_MIN and BINOP_MAX cases. For BINOP_EXP, use length and signedness of left operand only for result, as for shifts. For integral operands to BINOP_EXP, use new integer_pow and uinteger_pow functions so as to get full range of results. (integer_pow): New function. (uinteger_pow): New function. 2008-01-30 Paul N. Hilfinger <hilfinger@adacore.com> * gdb.ada/exprs: New test program. * gdb.ada/exprs.exp: New testcase.
Diffstat (limited to 'gdb/valarith.c')
-rw-r--r--gdb/valarith.c92
1 files changed, 78 insertions, 14 deletions
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 2fa435d446..e69aaa6756 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -743,6 +743,66 @@ value_concat (struct value *arg1, struct value *arg2)
}
+/* Integer exponentiation: V1**V2, where both arguments are
+ integers. Requires V1 != 0 if V2 < 0. Returns 1 for 0 ** 0. */
+static LONGEST
+integer_pow (LONGEST v1, LONGEST v2)
+{
+ if (v2 < 0)
+ {
+ if (v1 == 0)
+ error (_("Attempt to raise 0 to negative power."));
+ else
+ return 0;
+ }
+ else
+ {
+ /* The Russian Peasant's Algorithm */
+ LONGEST v;
+
+ v = 1;
+ for (;;)
+ {
+ if (v2 & 1L)
+ v *= v1;
+ v2 >>= 1;
+ if (v2 == 0)
+ return v;
+ v1 *= v1;
+ }
+ }
+}
+
+/* Integer exponentiation: V1**V2, where both arguments are
+ integers. Requires V1 != 0 if V2 < 0. Returns 1 for 0 ** 0. */
+static ULONGEST
+uinteger_pow (ULONGEST v1, LONGEST v2)
+{
+ if (v2 < 0)
+ {
+ if (v1 == 0)
+ error (_("Attempt to raise 0 to negative power."));
+ else
+ return 0;
+ }
+ else
+ {
+ /* The Russian Peasant's Algorithm */
+ ULONGEST v;
+
+ v = 1;
+ for (;;)
+ {
+ if (v2 & 1L)
+ v *= v1;
+ v2 >>= 1;
+ if (v2 == 0)
+ return v;
+ v1 *= v1;
+ }
+ }
+}
+
/* Obtain decimal value of arguments for binary operation, converting from
other types if one of them is not decimal floating point. */
static void
@@ -898,6 +958,14 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
error (_("Cannot perform exponentiation: %s"), safe_strerror (errno));
break;
+ case BINOP_MIN:
+ v = v1 < v2 ? v1 : v2;
+ break;
+
+ case BINOP_MAX:
+ v = v1 > v2 ? v1 : v2;
+ break;
+
default:
error (_("Integer-only operation on floating point number."));
}
@@ -979,14 +1047,15 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
}
/* Determine type length of the result, and if the operation should
- be done unsigned.
- Use the signedness of the operand with the greater length.
+ be done unsigned. For exponentiation and shift operators,
+ use the length and type of the left operand. Otherwise,
+ use the signedness of the operand with the greater length.
If both operands are of equal length, use unsigned operation
if one of the operands is unsigned. */
- if (op == BINOP_RSH || op == BINOP_LSH)
+ if (op == BINOP_RSH || op == BINOP_LSH || op == BINOP_EXP)
{
- /* In case of the shift operators the type of the result only
- depends on the type of the left operand. */
+ /* In case of the shift operators and exponentiation the type of
+ the result only depends on the type of the left operand. */
unsigned_operation = is_unsigned1;
result_len = promoted_len1;
}
@@ -1008,9 +1077,10 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
if (unsigned_operation)
{
+ LONGEST v2_signed = value_as_long (arg2);
ULONGEST v1, v2, v = 0;
v1 = (ULONGEST) value_as_long (arg1);
- v2 = (ULONGEST) value_as_long (arg2);
+ v2 = (ULONGEST) v2_signed;
/* Truncate values to the type length of the result. */
if (result_len < sizeof (ULONGEST))
@@ -1042,10 +1112,7 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
break;
case BINOP_EXP:
- errno = 0;
- v = pow (v1, v2);
- if (errno)
- error (_("Cannot perform exponentiation: %s"), safe_strerror (errno));
+ v = uinteger_pow (v1, v2_signed);
break;
case BINOP_REM:
@@ -1165,10 +1232,7 @@ value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
break;
case BINOP_EXP:
- errno = 0;
- v = pow (v1, v2);
- if (errno)
- error (_("Cannot perform exponentiation: %s"), safe_strerror (errno));
+ v = integer_pow (v1, v2);
break;
case BINOP_REM:
OpenPOWER on IntegriCloud