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

Checking out PR4483 (constant overflow on PPC, problems compiling Linux kernel)


I tried to compile the Linux kernel on PowerPC, and I ran into a problem 
someone previously reports (PR4483, 
http://gcc.gnu.org/ml/gcc-prs/2001-10/msg00105.html).  I've played 
around with it some, and it looks like a constant is overflowing in the 
gcse stage.  The PR has a testcase in it.

In the situation, an INSN references two other registers that are 
constants (one is 0xffffffff80000000, the other is 42) and subtracts the 
second from the first (MINUS code).  In validate_replace_rtx_1 
(recog.c), it replaces the registers with constants, then adds them. 
 This results in a constant 0xffffffff7fffffd6, which is obviously now 
too negative to fit into an SI register.  The original constant was 
positive (0x80000000UL in the source).  Since constants don't have 
modes, the addition code doesn't handle this (and it doesn't look like 
it cares, anyway).

I have attached a patch that adds a PowerPC production to truncate a 
constant that is too large that goes into a register.  However, I'm not 
sure if this is the right way to handle this, but it at least works 
around the problem.  The  main production that handles this won't work 
because it checks for constant overflows.

I compiled the Linux kernel (after working around a few small problems 
there) successfully.  However, it crashed at startup :-(.

-Corey
Index: config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.26
diff -u -r1.26 rs6000-protos.h
--- rs6000-protos.h	2001/11/04 02:40:39	1.26
+++ rs6000-protos.h	2001/11/27 17:45:11
@@ -70,6 +70,7 @@
 extern int current_file_function_operand PARAMS ((rtx, enum machine_mode));
 extern int input_operand PARAMS ((rtx, enum machine_mode));
 extern int small_data_operand PARAMS ((rtx, enum machine_mode));
+extern int large_SI_int_operand PARAMS ((rtx, enum machine_mode));
 extern int constant_pool_expr_p PARAMS ((rtx));
 extern int toc_relative_expr_p PARAMS ((rtx));
 extern int expand_block_move PARAMS ((rtx[]));
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.242
diff -u -r1.242 rs6000.c
--- rs6000.c	2001/11/24 06:44:10	1.242
+++ rs6000.c	2001/11/27 17:45:39
@@ -883,6 +883,23 @@
 	  || GET_CODE (op) == LABEL_REF);
 }
 
+/* Return 1 if the operand is a constant that is larger than can fit
+   into a 32-bit register. */
+int
+large_SI_int_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) != CONST_INT)
+    return 0;
+
+  if ((INTVAL (op) <= ((HOST_WIDE_INT) 2147483647))
+      && (INTVAL (op) >= ((HOST_WIDE_INT) -2147483648LL)))
+    return 0;
+
+  return 1;
+}
+
 /* Return 1 if the operand is a simple references that can be loaded via
    the GOT (labels involving addition aren't allowed).  */
 
Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.143
diff -u -r1.143 rs6000.h
--- rs6000.h	2001/11/22 02:19:56	1.143
+++ rs6000.h	2001/11/27 17:45:52
@@ -2773,6 +2773,7 @@
   {"reg_or_add_cint64_operand", {SUBREG, REG, CONST_INT}},		   \
   {"reg_or_sub_cint64_operand", {SUBREG, REG, CONST_INT}},		   \
   {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
+  {"large_SI_int_operand", {CONST_INT}},				   \
   {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},			   \
   {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},			   \
   {"easy_fp_constant", {CONST_DOUBLE}},					   \
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.140
diff -u -r1.140 rs6000.md
--- rs6000.md	2001/11/24 06:44:11	1.140
+++ rs6000.md	2001/11/27 17:46:41
@@ -7487,6 +7487,33 @@
   operands[3] = GEN_INT (INTVAL (operands[1]) & 0xffff);
 }")
 
+;; This split is used to truncate constant integers that have overflowed
+;; during calculations
+
+(define_split
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+	(match_operand:SI 1 "large_SI_int_operand" ""))]
+  ""
+  [(set (match_dup 0)
+	(match_dup 2))
+   (set (match_dup 0)
+	(ior:SI (match_dup 0)
+		(match_dup 3)))]
+  "
+{
+  HOST_WIDE_INT v = INTVAL (operands[1]);
+
+  operands[3] = GEN_INT (v & 0xffff);
+
+  /* If the constant is negative, then sign extend it, otherwise
+     chop it off. */
+  if (v & 0x80000000) {
+    v = v | (((HOST_WIDE_INT) -1) & (~ (HOST_WIDE_INT) 0xffffffff));
+    operands[2] = GEN_INT (v & (~ (HOST_WIDE_INT) 0xffff));
+  } else
+    operands[2] = GEN_INT (v & 0xffff0000);
+}")
+
 (define_insn "*movsi_internal2"
   [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
 	(compare:CC (match_operand:SI 1 "gpc_reg_operand" "r,r")

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