This is the mail archive of the binutils@sourceware.org mailing list for the binutils 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]

powerpc gas built on 64-bit host


On Sat, May 26, 2007 at 10:13:49AM +1000, Paul Mackerras wrote:
> I *think* this is a toolchain bug.  The issue is that an asm
> instruction "rlwinm 10,10,0,~(1<<15)" fails to assemble because of the
> high bits set in the 64-bit value of ~(1<<15), even though there is
> explicitly -m32 on the gcc command line.

Yes, I agree that this is a problem since the expression ~(1<<15) is
perfectly OK when gas is built on a 32-bit host.

When I went to fix this, I noticed some other minor bugs in our range
checking..

	* config/tc-ppc.c (ppc_insert_operand): Truncate sign bits in
	top 32 bits of 64 bit value if so doing results in passing
	range check.  Rewrite sign extension fudges similarly.  Enable
	fudges for powerpc64 too.  Report user value if range check
	fails rather than fudged value.  Negate PPC_OPERAND_NEGATIVE
	range rather than value, also to report user value on failure.

Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.121
diff -u -p -r1.121 tc-ppc.c
--- gas/config/tc-ppc.c	2 May 2007 11:24:16 -0000	1.121
+++ gas/config/tc-ppc.c	26 May 2007 14:02:19 -0000
@@ -86,9 +86,6 @@ static bfd_boolean reg_names_p = TARGET_
 
 static bfd_boolean register_name PARAMS ((expressionS *));
 static void ppc_set_cpu PARAMS ((void));
-static unsigned long ppc_insert_operand
-  PARAMS ((unsigned long insn, const struct powerpc_operand *operand,
-	   offsetT val, char *file, unsigned int line));
 static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro));
 static void ppc_byte PARAMS ((int));
 
@@ -1507,15 +1504,13 @@ ppc_cleanup ()
 /* Insert an operand value into an instruction.  */
 
 static unsigned long
-ppc_insert_operand (insn, operand, val, file, line)
-     unsigned long insn;
-     const struct powerpc_operand *operand;
-     offsetT val;
-     char *file;
-     unsigned int line;
+ppc_insert_operand (unsigned long insn,
+		    const struct powerpc_operand *operand,
+		    offsetT val,
+		    char *file,
+		    unsigned int line)
 {
   long min, max, right;
-  offsetT test;
 
   max = operand->bitm;
   right = max & -max;
@@ -1526,35 +1521,44 @@ ppc_insert_operand (insn, operand, val, 
       if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
 	max = (max >> 1) & -right;
       min = ~max & -right;
-
-      if (!ppc_obj64)
-	{
-	  /* Some people write 32 bit hex constants with the sign
-	     extension done by hand.  This shouldn't really be
-	     valid, but, to permit this code to assemble on a 64
-	     bit host, we sign extend the 32 bit value.  */
-	  if (val > 0
-	      && (val & (offsetT) 0x80000000) != 0
-	      && (val & (offsetT) 0xffffffff) == val)
-	    {
-	      val -= 0x80000000;
-	      val -= 0x80000000;
-	    }
-	}
     }
 
   if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
     max++;
 
   if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
-    test = - val;
-  else
-    test = val;
-
-  if ((min <= max && (test < (offsetT) min || test > (offsetT) max))
-      || (test & (right - 1)) != 0)
-    as_bad_value_out_of_range (_("operand"),
-			       test, (offsetT) min, (offsetT) max, file, line);
+    {
+      long tmp = min;
+      min = -max;
+      max = -tmp;
+    }
+
+  if (min <= max)
+    {
+      /* Some people write constants with the sign extension done by
+	 hand but only up to 32 bits.  This shouldn't really be valid,
+	 but, to permit this code to assemble on a 64-bit host, we
+	 sign extend the 32-bit value to 64 bits if so doing makes the
+	 value valid.  */
+      if (val > max
+	  && (offsetT) (val - 0x80000000 - 0x80000000) >= min
+	  && (offsetT) (val - 0x80000000 - 0x80000000) <= max
+	  && ((val - 0x80000000 - 0x80000000) & (right - 1)) == 0)
+	val = val - 0x80000000 - 0x80000000;
+
+      /* Similarly, people write expressions like ~(1<<15), and expect
+	 this to be OK for a 32-bit unsigned value.  */
+      else if (val < min
+	       && (offsetT) (val + 0x80000000 + 0x80000000) >= min
+	       && (offsetT) (val + 0x80000000 + 0x80000000) <= max
+	       && ((val + 0x80000000 + 0x80000000) & (right - 1)) == 0)
+	val = val + 0x80000000 + 0x80000000;
+
+      else if (val < min
+	       || val > max
+	       || (val & (right - 1)) != 0)
+	as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
+    }
 
   if (operand->insert)
     {

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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