From d118ef8764180584e6b42b38d8c68c18bf8c83c4 Mon Sep 17 00:00:00 2001 From: "Paul N. Hilfinger" Date: Wed, 30 Jan 2008 07:28:16 +0000 Subject: [PATCH] 2008-01-30 Paul N. Hilfinger * 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 * gdb.ada/exprs: New test program. * gdb.ada/exprs.exp: New testcase. --- gdb/ChangeLog | 11 ++++ gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.ada/exprs.exp | 50 +++++++++++++++++ gdb/testsuite/gdb.ada/exprs/p.adb | 41 ++++++++++++++ gdb/valarith.c | 92 ++++++++++++++++++++++++++----- 5 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 gdb/testsuite/gdb.ada/exprs.exp create mode 100644 gdb/testsuite/gdb.ada/exprs/p.adb diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1eecd4bdc8e..67fbd01d3ae 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2008-01-30 Paul N. Hilfinger + + * 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 Vladimir Prus Use vector for varobj_list_children interface. diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 6bc429a62a2..f198e03e7b9 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-01-30 Paul N. Hilfinger + + * gdb.ada/exprs: New test program. + * gdb.ada/exprs.exp: New testcase. + 2008-01-30 Thiago Jung Bauermann * dfp-test.c (DELTA, DELTA_B): New definitions. diff --git a/gdb/testsuite/gdb.ada/exprs.exp b/gdb/testsuite/gdb.ada/exprs.exp new file mode 100644 index 00000000000..0283bb1a705 --- /dev/null +++ b/gdb/testsuite/gdb.ada/exprs.exp @@ -0,0 +1,50 @@ +# Copyright 2005, 2007 Free Software Foundation, Inc. +# +# 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 . + +if $tracelevel then { + strace $tracelevel +} + +load_lib "ada.exp" + +set testdir "exprs" +set testfile "${testdir}/p" +set srcfile ${srcdir}/${subdir}/${testfile}.adb +set binfile ${objdir}/${subdir}/${testfile} + +file mkdir ${objdir}/${subdir}/${testdir} +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set bp_location [gdb_get_line_number "START" ${testdir}/p.adb] +runto "p.adb:$bp_location" + +gdb_test "print X ** Y = Z" \ + "true" \ + "Long_Long_Integer ** Y" + +gdb_test "print long_float'min (long_float (X), 8.0)" \ + "7.0" \ + "long_float'min" + +gdb_test "print long_float'max (long_float (X), 8.0)" \ + "8.0" \ + "long_float'max" diff --git a/gdb/testsuite/gdb.ada/exprs/p.adb b/gdb/testsuite/gdb.ada/exprs/p.adb new file mode 100644 index 00000000000..b342c9878a8 --- /dev/null +++ b/gdb/testsuite/gdb.ada/exprs/p.adb @@ -0,0 +1,41 @@ +-- Copyright 2008 Free Software Foundation, Inc. +-- +-- 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 . + +-- Test Ada additions to core GDB evaluation. + +with System; +with Text_IO; use Text_IO; + +procedure P is + type Int is range System.Min_Int .. System.Max_Int; + + X, Z : Int; + Y : Integer; + +begin + X := 0; + -- Set X to 7 by disguised means lest a future optimizer interfere. + for I in 1 .. 7 loop + X := X + 1; + end loop; + Z := 1; + Y := 0; + while Z < Int'Last / X loop + Z := Z * X; + Y := Y + 1; + end loop; + + Put_Line (Int'Image (X ** Y)); -- START +end P; diff --git a/gdb/valarith.c b/gdb/valarith.c index 2fa435d446d..e69aaa67567 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: -- 2.30.2