This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFA] Small enhancements to value_binop
- From: Paul Hilfinger <Hilfinger at adacore dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 16 Jan 2008 05:29:48 -0500 (EST)
- Subject: [RFA] Small enhancements to value_binop
- Reply-to: Hilfinger at adacore dot com
This patch contains a couple of changes we introduced into valarith.c
for Ada that have generic applicability:
1. Exponentiation of integral types currently uses floating-point arithmetic
(pow). Since 64-bit integral types have more significant bits than
double-precision IEEE floating point, this can cause errors for large
results. We introduced a couple of exponentiation routines.
2. We extended BINOP_MIN and BINOP_MAX to floating point.
I've also included a new testcase for these additions.
OK?
Paul Hilfinger
Adacore, Inc.
gdb/ChangeLog entries:
2008-01-16 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.
(uninteger_pow): New function.
gdb/testsuite/ChangeLog entries:
2008-01-16 Paul N. Hilfinger <hilfinger@adacore.com>
* gdb.ada/exprs: New test program.
* gdb.ada/exprs.exp: New testcase.
Index: current-public.160/gdb/valarith.c
--- current-public.160/gdb/valarith.c Wed, 16 Jan 2008 01:52:39 -0800 hilfingr
+++ current-public.160(w)/gdb/valarith.c Tue, 15 Jan 2008 02:39:32 -0800 hilfingr
@@ -742,6 +742,66 @@ value_concat (struct value *arg1, struct
}
+/* 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
@@ -897,6 +957,14 @@ value_binop (struct value *arg1, struct
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."));
}
@@ -978,14 +1046,15 @@ value_binop (struct value *arg1, struct
}
/* 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;
}
@@ -1007,9 +1076,10 @@ value_binop (struct value *arg1, struct
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))
@@ -1037,10 +1107,7 @@ value_binop (struct value *arg1, struct
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:
@@ -1159,10 +1226,7 @@ value_binop (struct value *arg1, struct
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:
Index: current-public.160/gdb/testsuite/gdb.ada/exprs.exp
--- current-public.160/gdb/testsuite/gdb.ada/exprs.exp Wed, 16 Jan 2008 02:02:51 -0800 hilfingr ()
+++ current-public.160(w)/gdb/testsuite/gdb.ada/exprs.exp Wed, 16 Jan 2008 02:02:36 -0800 hilfingr (GdbPub/Z/c/32_exprs.exp 644)
@@ -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 <http://www.gnu.org/licenses/>.
+
+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"
Index: current-public.160/gdb/testsuite/gdb.ada/exprs/p.adb
--- current-public.160/gdb/testsuite/gdb.ada/exprs/p.adb Wed, 16 Jan 2008 02:02:51 -0800 hilfingr ()
+++ current-public.160(w)/gdb/testsuite/gdb.ada/exprs/p.adb Tue, 15 Jan 2008 01:44:27 -0800 hilfingr (GdbPub/Z/c/33_p.adb 644)
@@ -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 <http://www.gnu.org/licenses/>.
+
+-- 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;