[committed 3.4/3.5] Fix large frame support for PA 64-bit

John David Anglin dave@hiauly1.hia.nrc.ca
Tue Jan 20 23:08:00 GMT 2004


This patch fixes these two testsuite failures:

FAIL: gcc.c-torture/compile/20031023-1.c (test for excess errors)
FAIL: gcc.c-torture/compile/20031023-2.c (test for excess errors)

These failures are caused by a failure to handle the reloads needed
to handle large frames on hppa64-hp-hpux11.x.  We were also generating
incorrect code for saving and restoring registers in large frames.

The patch provides two principal fixes:

  1) We now use HOST_WIDE_INT types for frame sizes and offsets.

  2) emit_move_sequence has been improved to allow it to load an
     arbitrary 64-bit constant when generating 64-bit code.  This
     proved to be the simplest way to handle the "reloads" for large
     frame offsets.  We still force "large" constants to memory
     before reload.

Tested with no regressions on hppa64-hp-hpux11.11, hppa2.0w-hp-hpux11.11
and hppa-unknown-linux-gnu.  Installed to 3.4 and trunk.

Now, if somebody wants to donate a little extra memory for an A500,
I can really test this ;-)

Dave
-- 
J. David Anglin                                  dave.anglin@nrc-cnrc.gc.ca
National Research Council of Canada              (613) 990-0752 (FAX: 952-6602)

2004-01-20  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>

	* pa-protos.h (compute_frame_size): Use HOST_WIDE_INT for frame sizes.
	* pa.c (store_reg, store_reg_modify, load_reg, set_reg_plus_d):
	Likewise.  Handle frames larger than 0x7fffffff on 64-bit ports.
	(emit_move_sequence): Check scratch_reg first in various if statements.
	Extend source simplification to handle all 64-bit CONST_INTs.
	(pa_output_function_prologue): Use HOST_WIDE_INT_PRINT_DEC for printing
	frame size.
	(hppa_expand_prologue, hppa_expand_epilogue): Use HOST_WIDE_INT for
	frame offset calculations.
	* pa.h (NEW_HP_ASSEMBLER): add comment.
	(MAX_LEGIT_64BIT_CONST_INT, MIN_LEGIT_64BIT_CONST_INT,
	LEGITIMATE_64BIT_CONST_INT_P): Define.
	(LEGITIMATE_CONSTANT_P): Use LEGITIMATE_64BIT_CONST_INT_P.  Treat
	any CONST_INT as legitimate during and after reload when generating
	64-bit code.
	(VAL_32_BITS_P, INT_32_BITS): Define.
	(LEGITIMIZE_RELOAD_ADDRESS): Handle large frame offsets.

Index: config/pa/pa-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/pa/pa-protos.h,v
retrieving revision 1.29
diff -u -3 -p -r1.29 pa-protos.h
--- config/pa/pa-protos.h	14 Dec 2003 07:26:18 -0000	1.29
+++ config/pa/pa-protos.h	20 Jan 2004 15:37:42 -0000
@@ -137,7 +137,7 @@ extern struct rtx_def *hppa_builtin_save
 
 extern void override_options (void);
 extern void output_ascii (FILE *, const char *, int);
-extern int compute_frame_size (int, int *);
+extern HOST_WIDE_INT compute_frame_size (HOST_WIDE_INT, int *);
 extern int and_mask_p (unsigned HOST_WIDE_INT);
 extern int cint_ok_for_move (HOST_WIDE_INT);
 extern void hppa_expand_prologue (void);
Index: config/pa/pa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/pa/pa.c,v
retrieving revision 1.236
diff -u -3 -p -r1.236 pa.c
--- config/pa/pa.c	18 Jan 2004 22:37:29 -0000	1.236
+++ config/pa/pa.c	20 Jan 2004 15:37:49 -0000
@@ -107,10 +107,10 @@ static int compute_movstr_length (rtx);
 static int compute_clrstr_length (rtx);
 static bool pa_assemble_integer (rtx, unsigned int, int);
 static void remove_useless_addtr_insns (int);
-static void store_reg (int, int, int);
-static void store_reg_modify (int, int, int);
-static void load_reg (int, int, int);
-static void set_reg_plus_d (int, int, int, int);
+static void store_reg (int, HOST_WIDE_INT, int);
+static void store_reg_modify (int, int, HOST_WIDE_INT);
+static void load_reg (int, HOST_WIDE_INT, int);
+static void set_reg_plus_d (int, int, HOST_WIDE_INT, int);
 static void pa_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void update_total_code_bytes (int);
 static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT);
@@ -1552,13 +1552,13 @@ emit_move_sequence (rtx *operands, enum 
   /* Handle secondary reloads for loads/stores of FP registers from
      REG+D addresses where D does not fit in 5 bits, including
      (subreg (mem (addr))) cases.  */
-  if (fp_reg_operand (operand0, mode)
+  if (scratch_reg
+      && fp_reg_operand (operand0, mode)
       && ((GET_CODE (operand1) == MEM
 	   && !memory_address_p (DFmode, XEXP (operand1, 0)))
 	  || ((GET_CODE (operand1) == SUBREG
 	       && GET_CODE (XEXP (operand1, 0)) == MEM
-	       && !memory_address_p (DFmode, XEXP (XEXP (operand1, 0), 0)))))
-      && scratch_reg)
+	       && !memory_address_p (DFmode, XEXP (XEXP (operand1, 0), 0))))))
     {
       if (GET_CODE (operand1) == SUBREG)
 	operand1 = XEXP (operand1, 0);
@@ -1585,14 +1585,14 @@ emit_move_sequence (rtx *operands, enum 
 			      gen_rtx_MEM (mode, scratch_reg)));
       return 1;
     }
-  else if (fp_reg_operand (operand1, mode)
+  else if (scratch_reg
+	   && fp_reg_operand (operand1, mode)
 	   && ((GET_CODE (operand0) == MEM
 		&& ! memory_address_p (DFmode, XEXP (operand0, 0)))
 	       || ((GET_CODE (operand0) == SUBREG)
 		   && GET_CODE (XEXP (operand0, 0)) == MEM
 		   && !memory_address_p (DFmode,
-			   		 XEXP (XEXP (operand0, 0), 0))))
-	   && scratch_reg)
+			   		 XEXP (XEXP (operand0, 0), 0)))))
     {
       if (GET_CODE (operand0) == SUBREG)
 	operand0 = XEXP (operand0, 0);
@@ -1623,15 +1623,15 @@ emit_move_sequence (rtx *operands, enum 
   /* Handle secondary reloads for loads of FP registers from constant
      expressions by forcing the constant into memory.
 
-     use scratch_reg to hold the address of the memory location.
+     Use scratch_reg to hold the address of the memory location.
 
      The proper fix is to change PREFERRED_RELOAD_CLASS to return
      NO_REGS when presented with a const_int and a register class
      containing only FP registers.  Doing so unfortunately creates
      more problems than it solves.   Fix this for 2.5.  */
-  else if (fp_reg_operand (operand0, mode)
+  else if (scratch_reg
 	   && CONSTANT_P (operand1)
-	   && scratch_reg)
+	   && fp_reg_operand (operand0, mode))
     {
       rtx xoperands[2];
 
@@ -1653,14 +1653,14 @@ emit_move_sequence (rtx *operands, enum 
     }
   /* Handle secondary reloads for SAR.  These occur when trying to load
      the SAR from memory, FP register, or with a constant.  */
-  else if (GET_CODE (operand0) == REG
+  else if (scratch_reg
+	   && GET_CODE (operand0) == REG
 	   && REGNO (operand0) < FIRST_PSEUDO_REGISTER
 	   && REGNO_REG_CLASS (REGNO (operand0)) == SHIFT_REGS
 	   && (GET_CODE (operand1) == MEM
 	       || GET_CODE (operand1) == CONST_INT
 	       || (GET_CODE (operand1) == REG
-		   && FP_REG_CLASS_P (REGNO_REG_CLASS (REGNO (operand1)))))
-	   && scratch_reg)
+		   && FP_REG_CLASS_P (REGNO_REG_CLASS (REGNO (operand1))))))
     {
       /* D might not fit in 14 bits either; for such cases load D into
 	 scratch reg.  */
@@ -1971,16 +1971,19 @@ emit_move_sequence (rtx *operands, enum 
 	  return 1;
 	}
       else if (GET_CODE (operand1) != CONST_INT
-	       || ! cint_ok_for_move (INTVAL (operand1)))
+	       || !cint_ok_for_move (INTVAL (operand1)))
 	{
-	  rtx extend = NULL_RTX;
-	  rtx temp;
+	  rtx insn, temp;
+	  rtx op1 = operand1;
+	  HOST_WIDE_INT value = INTVAL (operand1);
+	  HOST_WIDE_INT insv = 0;
+	  int insert = 0;
 
-	  if (TARGET_64BIT && GET_CODE (operand1) == CONST_INT
+	  if (TARGET_64BIT
+	      && GET_CODE (operand1) == CONST_INT
 	      && HOST_BITS_PER_WIDE_INT > 32
 	      && GET_MODE_BITSIZE (GET_MODE (operand0)) > 32)
 	    {
-	      HOST_WIDE_INT val = INTVAL (operand1);
 	      HOST_WIDE_INT nval;
 
 	      /* Extract the low order 32 bits of the value and sign extend.
@@ -1988,19 +1991,21 @@ emit_move_sequence (rtx *operands, enum 
 		 can use the original value as-is.  If the new value is
 		 different, we use it and insert the most-significant 32-bits
 		 of the original value into the final result.  */
-	      nval = ((val & (((HOST_WIDE_INT) 2 << 31) - 1))
+	      nval = ((value & (((HOST_WIDE_INT) 2 << 31) - 1))
 		      ^ ((HOST_WIDE_INT) 1 << 31)) - ((HOST_WIDE_INT) 1 << 31);
-	      if (val != nval)
+	      if (value != nval)
 		{
 #if HOST_BITS_PER_WIDE_INT > 32
-		  extend = GEN_INT (val >> 32);
+		  insv = value >= 0 ? value >> 32 : ~(~value >> 32);
 #endif
+		  insert = 1;
+		  value = nval;
 		  operand1 = GEN_INT (nval);
 		}
 	    }
 
 	  if (reload_in_progress || reload_completed)
-	    temp = operand0;
+	    temp = scratch_reg ? scratch_reg : operand0;
 	  else
 	    temp = gen_reg_rtx (mode);
 
@@ -2008,7 +2013,8 @@ emit_move_sequence (rtx *operands, enum 
 	     because PLUS uses an 11-bit immediate and the insn sequence
 	     generated is not as efficient as the one using HIGH/LO_SUM.  */
 	  if (GET_CODE (operand1) == CONST_INT
-	      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+	      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+	      && !insert)
 	    {
 	      /* Directly break constant into high and low parts.  This
 		 provides better optimization opportunities because various
@@ -2016,7 +2022,6 @@ emit_move_sequence (rtx *operands, enum 
 		 We use a 14-bit signed low part except when the addition
 		 of 0x4000 to the high part might change the sign of the
 		 high part.  */
-	      HOST_WIDE_INT value = INTVAL (operand1);
 	      HOST_WIDE_INT low = value & 0x3fff;
 	      HOST_WIDE_INT high = value & ~ 0x3fff;
 
@@ -2040,11 +2045,60 @@ emit_move_sequence (rtx *operands, enum 
 	      operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
 	    }
 
-	  emit_move_insn (operands[0], operands[1]);
+	  insn = emit_move_insn (operands[0], operands[1]);
 
-	  if (extend != NULL_RTX)
-	    emit_insn (gen_insv (operands[0], GEN_INT (32), const0_rtx,
-				 extend));
+	  /* Now insert the most significant 32 bits of the value
+	     into the register.  When we don't have a second register
+	     available, it could take up to nine instructions to load
+	     a 64-bit integer constant.  Prior to reload, we force
+	     constants that would take more than three instructions
+	     to load to the constant pool.  During and after reload,
+	     we have to handle all possible values.  */
+	  if (insert)
+	    {
+	      /* Use a HIGH/LO_SUM/INSV sequence if we have a second
+		 register and the value to be inserted is outside the
+		 range that can be loaded with three depdi instructions.  */
+	      if (temp != operand0 && (insv >= 16384 || insv < -16384))
+		{
+		  operand1 = GEN_INT (insv);
+
+		  emit_insn (gen_rtx_SET (VOIDmode, temp,
+					  gen_rtx_HIGH (mode, operand1)));
+		  emit_move_insn (temp, gen_rtx_LO_SUM (mode, temp, operand1));
+		  emit_insn (gen_insv (operand0, GEN_INT (32),
+				       const0_rtx, temp));
+		}
+	      else
+		{
+		  int len = 5, pos = 27;
+
+		  /* Insert the bits using the depdi instruction.  */
+		  while (pos >= 0)
+		    {
+		      HOST_WIDE_INT v5 = ((insv & 31) ^ 16) - 16;
+		      HOST_WIDE_INT sign = v5 < 0;
+
+		      /* Left extend the insertion.  */
+		      insv = (insv >= 0 ? insv >> len : ~(~insv >> len));
+		      while (pos > 0 && (insv & 1) == sign)
+			{
+			  insv = (insv >= 0 ? insv >> 1 : ~(~insv >> 1));
+			  len += 1;
+			  pos -= 1;
+			}
+
+		      emit_insn (gen_insv (operand0, GEN_INT (len),
+					   GEN_INT (pos), GEN_INT (v5)));
+
+		      len = pos > 0 && pos < 5 ? pos : 5;
+		      pos -= len;
+		    }
+		}
+	    }
+
+	  REG_NOTES (insn)
+	    = gen_rtx_EXPR_LIST (REG_EQUAL, op1, REG_NOTES (insn));
 
 	  return 1;
 	}
@@ -3334,8 +3388,8 @@ remove_useless_addtr_insns (int check_no
 /* Global variables set by output_function_prologue().  */
 /* Size of frame.  Need to know this to emit return insns from
    leaf procedures.  */
-static int actual_fsize;
-static int local_fsize, save_fregs;
+static HOST_WIDE_INT actual_fsize, local_fsize;
+static int save_fregs;
 
 /* Emit RTL to store REG at the memory location specified by BASE+DISP.
    Handle case where DISP > 8k by using the add_high_const patterns.
@@ -3344,7 +3398,7 @@ static int local_fsize, save_fregs;
    in %r1.  There is code in expand_hppa_{prologue,epilogue} that knows this.*/
 
 static void
-store_reg (int reg, int disp, int base)
+store_reg (int reg, HOST_WIDE_INT disp, int base)
 {
   rtx insn, dest, src, basereg;
 
@@ -3355,11 +3409,33 @@ store_reg (int reg, int disp, int base)
       dest = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
       insn = emit_move_insn (dest, src);
     }
+  else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
+    {
+      rtx delta = GEN_INT (disp);
+      rtx tmpreg = gen_rtx_REG (Pmode, 1);
+
+      emit_move_insn (tmpreg, delta);
+      emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
+      dest = gen_rtx_MEM (word_mode, tmpreg);
+      insn = emit_move_insn (dest, src);
+      if (DO_FRAME_NOTES)
+	{
+	  REG_NOTES (insn)
+	    = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+		gen_rtx_SET (VOIDmode,
+			     gen_rtx_MEM (word_mode,
+					  gen_rtx_PLUS (word_mode, basereg,
+							delta)),
+                             src),
+                REG_NOTES (insn));
+	}
+    }
   else
     {
       rtx delta = GEN_INT (disp);
       rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
       rtx tmpreg = gen_rtx_REG (Pmode, 1);
+
       emit_move_insn (tmpreg, high);
       dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
       insn = emit_move_insn (dest, src);
@@ -3384,11 +3460,11 @@ store_reg (int reg, int disp, int base)
    add MOD to BASE.  MOD must be <= 8k.  */
 
 static void
-store_reg_modify (int base, int reg, int mod)
+store_reg_modify (int base, int reg, HOST_WIDE_INT mod)
 {
   rtx insn, basereg, srcreg, delta;
 
-  if (! VAL_14_BITS_P (mod))
+  if (!VAL_14_BITS_P (mod))
     abort ();
 
   basereg = gen_rtx_REG (Pmode, base);
@@ -3431,7 +3507,7 @@ store_reg_modify (int base, int reg, int
    There is code in expand_hppa_{prologue,epilogue} that knows about this.  */
 
 static void
-set_reg_plus_d (int reg, int base, int disp, int note)
+set_reg_plus_d (int reg, int base, HOST_WIDE_INT disp, int note)
 {
   rtx insn;
 
@@ -3440,25 +3516,35 @@ set_reg_plus_d (int reg, int base, int d
       insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
 			     plus_constant (gen_rtx_REG (Pmode, base), disp));
     }
+  else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
+    {
+      rtx basereg = gen_rtx_REG (Pmode, base);
+      rtx delta = GEN_INT (disp);
+      rtx tmpreg = gen_rtx_REG (Pmode, 1);
+
+      emit_move_insn (tmpreg, delta);
+      insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
+			     gen_rtx_PLUS (Pmode, tmpreg, basereg));
+    }
   else
     {
       rtx basereg = gen_rtx_REG (Pmode, base);
       rtx delta = GEN_INT (disp);
+      rtx tmpreg = gen_rtx_REG (Pmode, 1);
 
-      emit_move_insn (gen_rtx_REG (Pmode, 1),
+      emit_move_insn (tmpreg,
 		      gen_rtx_PLUS (Pmode, basereg,
 				    gen_rtx_HIGH (Pmode, delta)));
       insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
-			     gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 1),
-					     delta));
+			     gen_rtx_LO_SUM (Pmode, tmpreg, delta));
     }
 
   if (DO_FRAME_NOTES && note)
     RTX_FRAME_RELATED_P (insn) = 1;
 }
 
-int
-compute_frame_size (int size, int *fregs_live)
+HOST_WIDE_INT
+compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
 {
   int freg_saved = 0;
   int i, j;
@@ -3562,7 +3648,7 @@ pa_output_function_prologue (FILE *file,
   /* hppa_expand_prologue does the dirty work now.  We just need
      to output the assembler directives which denote the start
      of a function.  */
-  fprintf (file, "\t.CALLINFO FRAME=%d", actual_fsize);
+  fprintf (file, "\t.CALLINFO FRAME=" HOST_WIDE_INT_PRINT_DEC, actual_fsize);
   if (regs_ever_live[2])
     fputs (",CALLS,SAVE_RP", file);
   else
@@ -3603,8 +3689,9 @@ void
 hppa_expand_prologue (void)
 {
   int merge_sp_adjust_with_store = 0;
-  int size = get_frame_size ();
-  int i, offset;
+  HOST_WIDE_INT size = get_frame_size ();
+  HOST_WIDE_INT offset;
+  int i;
   rtx insn, tmpreg;
 
   gr_saved = 0;
@@ -3668,8 +3755,8 @@ hppa_expand_prologue (void)
 		 So instead use stwm to store at *sp and post-increment the
 		 stack pointer as an atomic operation.  Then increment sp to
 		 finish allocating the new frame.  */
-	      int adjust1 = 8192 - 64;
-	      int adjust2 = actual_fsize - adjust1;
+	      HOST_WIDE_INT adjust1 = 8192 - 64;
+	      HOST_WIDE_INT adjust2 = actual_fsize - adjust1;
 
 	      store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
 	      set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
@@ -3901,26 +3988,39 @@ hppa_expand_prologue (void)
    Handle case where DISP > 8k by using the add_high_const patterns.  */
 
 static void
-load_reg (int reg, int disp, int base)
+load_reg (int reg, HOST_WIDE_INT disp, int base)
 {
-  rtx src, dest, basereg;
+  rtx dest = gen_rtx_REG (word_mode, reg);
+  rtx basereg = gen_rtx_REG (Pmode, base);
+  rtx src;
 
-  dest = gen_rtx_REG (word_mode, reg);
-  basereg = gen_rtx_REG (Pmode, base);
   if (VAL_14_BITS_P (disp))
+    src = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
+  else if (TARGET_64BIT && !VAL_32_BITS_P (disp))
     {
-      src = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
-      emit_move_insn (dest, src);
+      rtx delta = GEN_INT (disp);
+      rtx tmpreg = gen_rtx_REG (Pmode, 1);
+
+      emit_move_insn (tmpreg, delta);
+      if (TARGET_DISABLE_INDEXING)
+	{
+	  emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
+	  src = gen_rtx_MEM (word_mode, tmpreg);
+	}
+      else
+	src = gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, tmpreg, basereg));
     }
   else
     {
       rtx delta = GEN_INT (disp);
       rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
       rtx tmpreg = gen_rtx_REG (Pmode, 1);
+
       emit_move_insn (tmpreg, high);
       src = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
-      emit_move_insn (dest, src);
     }
+
+  emit_move_insn (dest, src);
 }
 
 /* Update the total code bytes output to the text section.  */
@@ -4006,9 +4106,10 @@ void
 hppa_expand_epilogue (void)
 {
   rtx tmpreg;
-  int offset, i;
+  HOST_WIDE_INT offset;
+  HOST_WIDE_INT ret_off = 0;
+  int i;
   int merge_sp_adjust_with_load = 0;
-  int ret_off = 0;
 
   /* We will use this often.  */
   tmpreg = gen_rtx_REG (word_mode, 1);
Index: config/pa/pa.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/pa/pa.h,v
retrieving revision 1.208
diff -u -3 -p -r1.208 pa.h
--- config/pa/pa.h	20 Dec 2003 17:24:15 -0000	1.208
+++ config/pa/pa.h	20 Jan 2004 15:37:50 -0000
@@ -646,7 +646,6 @@ extern struct rtx_def *hppa_pic_save_rtx
    to IN.  If it can be done directly NO_REGS is returned. 
 
   Avoid doing any work for the common case calls.  */
-
 #define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
   ((CLASS == BASE_REG_CLASS && GET_CODE (IN) == REG		\
     && REGNO (IN) < FIRST_PSEUDO_REGISTER)			\
@@ -1223,16 +1222,36 @@ extern int may_call_alloca;
    || GET_CODE (X) == HIGH) 						\
    && (reload_in_progress || reload_completed || ! symbolic_expression_p (X)))
 
-/* Include all constant integers and constant doubles, but not
-   floating-point, except for floating-point zero.
-
-   Reject LABEL_REFs if we're not using gas or the new HP assembler. 
+/* A C expression that is nonzero if we are using the new HP assembler.  */
 
-   ?!? For now also reject CONST_DOUBLES in 64bit mode.  This will need
-   further work.  */
 #ifndef NEW_HP_ASSEMBLER
 #define NEW_HP_ASSEMBLER 0
 #endif
+
+/* The macros below define the immediate range for CONST_INTS on
+   the 64-bit port.  Constants in this range can be loaded in three
+   instructions using a ldil/ldo/depdi sequence.  Constants outside
+   this range are forced to the constant pool prior to reload.  */
+
+#define MAX_LEGIT_64BIT_CONST_INT ((HOST_WIDE_INT) 32 << 31)
+#define MIN_LEGIT_64BIT_CONST_INT ((HOST_WIDE_INT) -32 << 31)
+#define LEGITIMATE_64BIT_CONST_INT_P(X) \
+  ((X) >= MIN_LEGIT_64BIT_CONST_INT && (X) < MAX_LEGIT_64BIT_CONST_INT)
+
+/* A C expression that is nonzero if X is a legitimate constant for an
+   immediate operand.
+
+   We include all constant integers and constant doubles, but not
+   floating-point, except for floating-point zero.  We reject LABEL_REFs
+   if we're not using gas or the new HP assembler. 
+
+   In 64-bit mode, we reject CONST_DOUBLES.  We also reject CONST_INTS
+   that need more than three instructions to load prior to reload.  This
+   limit is somewhat arbitrary.  It takes three instructions to load a
+   CONST_INT from memory but two are memory accesses.  It may be better
+   to increase the allowed range for CONST_INTS.  We may also be able
+   to handle CONST_DOUBLES.  */
+
 #define LEGITIMATE_CONSTANT_P(X)				\
   ((GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT			\
     || (X) == CONST0_RTX (GET_MODE (X)))			\
@@ -1240,8 +1259,8 @@ extern int may_call_alloca;
    && !(TARGET_64BIT && GET_CODE (X) == CONST_DOUBLE)		\
    && !(TARGET_64BIT && GET_CODE (X) == CONST_INT		\
 	&& !(HOST_BITS_PER_WIDE_INT <= 32			\
-	     || (INTVAL (X) >= (HOST_WIDE_INT) -32 << 31	\
-		 && INTVAL (X) < (HOST_WIDE_INT) 32 << 31)	\
+	     || (reload_in_progress || reload_completed)	\
+	     || LEGITIMATE_64BIT_CONST_INT_P (INTVAL (X))	\
 	     || cint_ok_for_move (INTVAL (X))))			\
    && !function_label_operand (X, VOIDmode))
 
@@ -1425,6 +1444,15 @@ extern int may_call_alloca;
 #define VAL_14_BITS_P(X) ((unsigned HOST_WIDE_INT)(X) + 0x2000 < 0x4000)
 #define INT_14_BITS(X) VAL_14_BITS_P (INTVAL (X))
 
+#if HOST_BITS_PER_WIDE_INT > 32
+#define VAL_32_BITS_P(X) \
+  ((unsigned HOST_WIDE_INT)(X) + ((unsigned HOST_WIDE_INT) 1 << 31)    \
+   < (unsigned HOST_WIDE_INT) 2 << 31)
+#else
+#define VAL_32_BITS_P(X) 1
+#endif
+#define INT_32_BITS(X) VAL_32_BITS_P (INTVAL (X))
+
 /* These are the modes that we allow for scaled indexing.  */
 #define MODE_OK_FOR_SCALED_INDEXING_P(MODE) \
   ((TARGET_64BIT && (MODE) == DImode)					\
@@ -1557,14 +1585,13 @@ extern int may_call_alloca;
    There may be more opportunities to improve code with this hook.  */
 #define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) 	\
 do { 									\
-  int offset, newoffset, mask;						\
+  long offset, newoffset, mask;						\
   rtx new, temp = NULL_RTX;						\
 									\
   mask = (GET_MODE_CLASS (MODE) == MODE_FLOAT				\
 	  ? (TARGET_PA_20 && !TARGET_ELF32 ? 0x3fff : 0x1f) : 0x3fff);	\
 									\
-  if (optimize								\
-      && GET_CODE (AD) == PLUS)						\
+  if (optimize && GET_CODE (AD) == PLUS)				\
     temp = simplify_binary_operation (PLUS, Pmode,			\
 				      XEXP (AD, 0), XEXP (AD, 1));	\
 									\
@@ -1583,16 +1610,14 @@ do { 									\
       else								\
 	newoffset = offset & ~mask;					\
 									\
-      if (newoffset != 0						\
-	  && VAL_14_BITS_P (newoffset))					\
+      if (newoffset != 0 && VAL_14_BITS_P (newoffset))			\
 	{								\
-									\
 	  temp = gen_rtx_PLUS (Pmode, XEXP (new, 0),			\
 			       GEN_INT (newoffset));			\
 	  AD = gen_rtx_PLUS (Pmode, temp, GEN_INT (offset - newoffset));\
 	  push_reload (XEXP (AD, 0), 0, &XEXP (AD, 0), 0,		\
-			     BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,	\
-			     (OPNUM), (TYPE));				\
+		       BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,		\
+		       (OPNUM), (TYPE));				\
 	  goto WIN;							\
 	}								\
     }									\



More information about the Gcc-patches mailing list