This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
double max case labels in switch
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 21 Nov 2001 23:53:35 +1030
- Subject: 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,