This is the mail archive of the gcc-patches@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]

double max case labels in switch


This patch doubles the maximum number of case labels that can be
handled in a switch for those targets that use ADDR_{,DIFF}_VEC and
have JUMP_TABLES_IN_TEXT_SECTION.  eg. hppa-linux-gcc goes from a
maximum of 4095 case labels (addr_vec elts are 8 bytes) to 8191.
Who would write such monster switch statements?  Well, someone sent
me a bug report regarding some automatically generated code with
4500 case labels.

Note that for targets with instruction sizes a multiple of n bytes,
we could fairly easily gain another factor of n by scaling values
stored in insn_lengths.

gcc/ChangeLog
	* final.c (insn_lengths): Make it unsigned.
	(shorten_branches): Use an int temp to calculate insn_lengths[uid],
	and improve overflow check.

Bootstrapped (current 3.0 cvs based) on hppa-linux and powerpc-linux.
Bootstrapped (current 3.1 cvs) i686-linux.

OK for mainline?  And branch?

-- 
Alan Modra

Index: gcc/final.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/final.c,v
retrieving revision 1.222
diff -u -p -r1.222 final.c
--- final.c	2001/11/15 14:58:19	1.222
+++ final.c	2001/11/21 10:43:10
@@ -603,7 +603,7 @@ dbr_sequence_length ()
 /* Arrays for insn lengths, and addresses.  The latter is referenced by
    `insn_current_length'.  */
 
-static short *insn_lengths;
+static unsigned short *insn_lengths;
 
 #ifdef HAVE_ATTR_length
 varray_type insn_addresses_;
@@ -1186,7 +1186,7 @@ shorten_branches (first)
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
-  insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
+  insn_lengths = (unsigned short *) xmalloc (max_uid * sizeof (*insn_lengths));
   insn_lengths_max_uid = max_uid;
   /* Syntax errors can lead to labels being outside of the main insn stream.
      Initialize insn_addresses, so that we get reproducible results.  */
@@ -1280,9 +1280,10 @@ shorten_branches (first)
        insn != 0;
        insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
     {
+      int i_len;
       uid = INSN_UID (insn);
 
-      insn_lengths[uid] = 0;
+      i_len = 0;
 
       if (GET_CODE (insn) == CODE_LABEL)
 	{
@@ -1291,17 +1292,20 @@ shorten_branches (first)
 	    {
 	      int align = 1 << log;
 	      int new_address = (insn_current_address + align - 1) & -align;
-	      insn_lengths[uid] = new_address - insn_current_address;
+	      i_len = new_address - insn_current_address;
 	    }
 	}
 
       INSN_ADDRESSES (uid) = insn_current_address;
 
-      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
-	  || GET_CODE (insn) == CODE_LABEL)
-	continue;
-      if (INSN_DELETED_P (insn))
-	continue;
+      if (GET_CODE (insn) == NOTE
+	  || GET_CODE (insn) == BARRIER
+	  || GET_CODE (insn) == CODE_LABEL
+	  || INSN_DELETED_P (insn))
+	{
+	  insn_lengths[uid] = i_len;
+	  continue;
+	}
 
       body = PATTERN (insn);
       if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
@@ -1313,13 +1317,12 @@ shorten_branches (first)
 	      || 1
 #endif
 	      )
-	    insn_lengths[uid] = (XVECLEN (body,
-					  GET_CODE (body) == ADDR_DIFF_VEC)
-				 * GET_MODE_SIZE (GET_MODE (body)));
+	    i_len = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
+		     * GET_MODE_SIZE (GET_MODE (body)));
 	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
 	}
       else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
-	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
+	i_len = asm_insn_count (body) * insn_default_length (insn);
       else if (GET_CODE (body) == SEQUENCE)
 	{
 	  int i;
@@ -1351,26 +1354,26 @@ shorten_branches (first)
 		  if ((varying_length[inner_uid]
 		       = insn_variable_length_p (inner_insn)) != 0)
 		    varying_length[uid] = 1;
-		  INSN_ADDRESSES (inner_uid) = (insn_current_address
-						+ insn_lengths[uid]);
+		  INSN_ADDRESSES (inner_uid) = insn_current_address + i_len;
 		}
 	      else
 		varying_length[inner_uid] = 0;
-	      insn_lengths[uid] += inner_length;
+	      i_len += inner_length;
 	    }
 	}
       else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
 	{
-	  insn_lengths[uid] = insn_default_length (insn);
+	  i_len = insn_default_length (insn);
 	  varying_length[uid] = insn_variable_length_p (insn);
 	}
 
       /* If needed, do any adjustment.  */
 #ifdef ADJUST_INSN_LENGTH
-      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
-      if (insn_lengths[uid] < 0)
-	fatal_insn ("Negative insn length", insn);
+      ADJUST_INSN_LENGTH (insn, i_len);
 #endif
+      if (i_len < 0 || (unsigned short) i_len != i_len)
+	fatal_insn ("Overflowed insn length", insn);
+      insn_lengths[uid] = i_len;
     }
 
   /* Now loop over all the insns finding varying length insns.  For each,


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