diff options
author | Paul N. Hilfinger <hilfinger@adacore.com> | 2008-01-30 07:28:16 +0000 |
---|---|---|
committer | Paul N. Hilfinger <hilfinger@adacore.com> | 2008-01-30 07:28:16 +0000 |
commit | d118ef8764180584e6b42b38d8c68c18bf8c83c4 (patch) | |
tree | 7b0451b86d7f4eb95586ba07e83e7629ee40c041 /gdb/valarith.c | |
parent | d56d46f5c7560a45f3a1c6101893ca84969c98a9 (diff) | |
download | gdb-d118ef8764180584e6b42b38d8c68c18bf8c83c4.zip gdb-d118ef8764180584e6b42b38d8c68c18bf8c83c4.tar.gz gdb-d118ef8764180584e6b42b38d8c68c18bf8c83c4.tar.bz2 |
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.c | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/gdb/valarith.c b/gdb/valarith.c index 2fa435d..e69aaa6 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: |