This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] Small enhancements to value_binop


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;



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]