This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Crossjumping of tablejumps
> by a loop that goes over all insns, checks each insn for references
> to the literal pool, and checks for each such reference whether it
> contains label1; if so, replaces label1 with label2 in the constant, creates
> a new literal pool entry for the modified constant, and replaces the
> literal pool reference in the insn accordingly?
Hi,
this patch does the replacement of labels as suggested.
The replacement of the labels in pool constant is done is replace_label ().
The patch fixes the testcase and gcc.dg/20030213-1.c.
I hope it finally is correct.
Bootstrapped/regtested x86-64.
Bootstrapped s390, regtesting in progress.
OK for mainline if it passes regtesting?
Josef
2003-03-14 Josef Zlomek <zlomekj at suse dot cz>
* rtl.h (subrtx_p): Renamed to rtx_referenced_p.
(rtx_pair): Added new element update_label_nuses, renamed to
replace_label_data.
* cfgcleanup.c (outgoing_edges_match, try_crossjump_to_edge): Use
replace_label_data instead of rtx_pair.
* loop.c (load_mems): Likewise.
* rtlanal.c (replace_label): Replace label in pool constants and in
INSN_LIST (in REG_LABEL note).
(subrtx_p): Renamed to rtx_referenced_p.
(subrtx_p_1): Renamed to rtx_referenced_p_1, compare the interior of
LABEL_REF with CODE_LABEL, traverse constants from pool.
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.77
diff -c -3 -p -r1.77 cfgcleanup.c
*** cfgcleanup.c 10 Mar 2003 18:32:17 -0000 1.77
--- cfgcleanup.c 14 Mar 2003 17:04:08 -0000
*************** outgoing_edges_match (mode, bb1, bb2)
*** 1271,1280 ****
the jump tables are same too. So disable crossjumping of blocks BB1
and BB2 because when deleting the common insns in the end of BB1
by flow_delete_block () the jump table would be deleted too. */
! /* If LABEL2 is contained in BB1->END do not do anything
because we would loose information when replacing
LABEL1 by LABEL2 and then LABEL2 by LABEL1 in BB1->END. */
! if (label1 != label2 && !subrtx_p (label2, bb1->end))
{
/* Set IDENTICAL to true when the tables are identical. */
bool identical = false;
--- 1271,1280 ----
the jump tables are same too. So disable crossjumping of blocks BB1
and BB2 because when deleting the common insns in the end of BB1
by flow_delete_block () the jump table would be deleted too. */
! /* If LABEL2 is referenced in BB1->END do not do anything
because we would loose information when replacing
LABEL1 by LABEL2 and then LABEL2 by LABEL1 in BB1->END. */
! if (label1 != label2 && !rtx_referenced_p (label2, bb1->end))
{
/* Set IDENTICAL to true when the tables are identical. */
bool identical = false;
*************** outgoing_edges_match (mode, bb1, bb2)
*** 1301,1313 ****
if (identical)
{
! rtx_pair rr;
bool match;
/* Temporarily replace references to LABEL1 with LABEL2
in BB1->END so that we could compare the instructions. */
rr.r1 = label1;
rr.r2 = label2;
for_each_rtx (&bb1->end, replace_label, &rr);
match = insns_match_p (mode, bb1->end, bb2->end);
--- 1301,1314 ----
if (identical)
{
! replace_label_data rr;
bool match;
/* Temporarily replace references to LABEL1 with LABEL2
in BB1->END so that we could compare the instructions. */
rr.r1 = label1;
rr.r2 = label2;
+ rr.update_label_nuses = false;
for_each_rtx (&bb1->end, replace_label, &rr);
match = insns_match_p (mode, bb1->end, bb2->end);
*************** try_crossjump_to_edge (mode, e1, e2)
*** 1459,1470 ****
&& tablejump_p (src2->end, &label2, &table2)
&& label1 != label2)
{
! rtx_pair rr;
rtx insn;
/* Replace references to LABEL1 with LABEL2. */
rr.r1 = label1;
rr.r2 = label2;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
/* Do not replace the label in SRC1->END because when deleting
--- 1460,1472 ----
&& tablejump_p (src2->end, &label2, &table2)
&& label1 != label2)
{
! replace_label_data rr;
rtx insn;
/* Replace references to LABEL1 with LABEL2. */
rr.r1 = label1;
rr.r2 = label2;
+ rr.update_label_nuses = true;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
/* Do not replace the label in SRC1->END because when deleting
Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.447
diff -c -3 -p -r1.447 loop.c
*** loop.c 10 Mar 2003 17:23:44 -0000 1.447
--- loop.c 14 Mar 2003 17:04:09 -0000
*************** load_mems (loop)
*** 10137,10145 ****
{
/* Now, we need to replace all references to the previous exit
label with the new one. */
! rtx_pair rr;
rr.r1 = end_label;
rr.r2 = label;
for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
{
--- 10137,10146 ----
{
/* Now, we need to replace all references to the previous exit
label with the new one. */
! replace_label_data rr;
rr.r1 = end_label;
rr.r2 = label;
+ rr.update_label_nuses = true;
for (p = loop->start; p != loop->end; p = NEXT_INSN (p))
{
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.387
diff -c -3 -p -r1.387 rtl.h
*** rtl.h 10 Mar 2003 17:23:44 -0000 1.387
--- rtl.h 14 Mar 2003 17:04:09 -0000
*************** extern rtx set_unique_reg_note PARAMS (
*** 1596,1606 ****
#define single_set_1(I) single_set_2 (I, PATTERN (I))
/* Structure used for passing data to REPLACE_LABEL. */
! typedef struct rtx_pair
{
rtx r1;
rtx r2;
! } rtx_pair;
extern int rtx_addr_can_trap_p PARAMS ((rtx));
extern bool nonzero_address_p PARAMS ((rtx));
--- 1596,1607 ----
#define single_set_1(I) single_set_2 (I, PATTERN (I))
/* Structure used for passing data to REPLACE_LABEL. */
! typedef struct replace_label_data
{
rtx r1;
rtx r2;
! bool update_label_nuses;
! } replace_label_data;
extern int rtx_addr_can_trap_p PARAMS ((rtx));
extern bool nonzero_address_p PARAMS ((rtx));
*************** extern rtx replace_rtx PARAMS ((rtx, r
*** 1662,1668 ****
extern rtx replace_regs PARAMS ((rtx, rtx *, unsigned int,
int));
extern int replace_label PARAMS ((rtx *, void *));
! extern int subrtx_p PARAMS ((rtx, rtx));
extern bool tablejump_p PARAMS ((rtx, rtx *, rtx *));
extern int computed_jump_p PARAMS ((rtx));
typedef int (*rtx_function) PARAMS ((rtx *, void *));
--- 1663,1669 ----
extern rtx replace_regs PARAMS ((rtx, rtx *, unsigned int,
int));
extern int replace_label PARAMS ((rtx *, void *));
! extern int rtx_referenced_p PARAMS ((rtx, rtx));
extern bool tablejump_p PARAMS ((rtx, rtx *, rtx *));
extern int computed_jump_p PARAMS ((rtx));
typedef int (*rtx_function) PARAMS ((rtx *, void *));
Index: rtlanal.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtlanal.c,v
retrieving revision 1.148
diff -c -3 -p -r1.148 rtlanal.c
*** rtlanal.c 10 Mar 2003 17:23:44 -0000 1.148
--- rtlanal.c 14 Mar 2003 17:04:09 -0000
*************** Software Foundation, 59 Temple Place - S
*** 38,44 ****
static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
static void set_of_1 PARAMS ((rtx, rtx, void *));
static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
! static int subrtx_p_1 PARAMS ((rtx *, void *));
static int computed_jump_p_1 PARAMS ((rtx));
static void parms_set PARAMS ((rtx, rtx, void *));
static bool hoist_test_store PARAMS ((rtx, rtx, regset));
--- 38,44 ----
static int global_reg_mentioned_p_1 PARAMS ((rtx *, void *));
static void set_of_1 PARAMS ((rtx, rtx, void *));
static void insn_dependent_p_1 PARAMS ((rtx, rtx, void *));
! static int rtx_referenced_p_1 PARAMS ((rtx *, void *));
static int computed_jump_p_1 PARAMS ((rtx));
static void parms_set PARAMS ((rtx, rtx, void *));
static bool hoist_test_store PARAMS ((rtx, rtx, regset));
*************** replace_regs (x, reg_map, nregs, replace
*** 2793,2799 ****
}
/* Replace occurrences of the old label in *X with the new one.
! DATA is an rtx_pair containing the old and new labels, respectively. */
int
replace_label (x, data)
--- 2793,2799 ----
}
/* Replace occurrences of the old label in *X with the new one.
! DATA is a REPLACE_LABEL_DATA containing the old and new labels. */
int
replace_label (x, data)
*************** replace_label (x, data)
*** 2801,2851 ****
void *data;
{
rtx l = *x;
! rtx old_label = ((rtx_pair *) data)->r1;
! rtx new_label = ((rtx_pair *) data)->r2;
if (l == NULL_RTX)
return 0;
/* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
field. This is not handled by for_each_rtx because it doesn't
handle unprinted ('0') fields. */
if (GET_CODE (l) == JUMP_INSN && JUMP_LABEL (l) == old_label)
JUMP_LABEL (l) = new_label;
-
- if (GET_CODE (l) != LABEL_REF)
- return 0;
-
- if (XEXP (l, 0) != old_label)
- return 0;
! XEXP (l, 0) = new_label;
! ++LABEL_NUSES (new_label);
! --LABEL_NUSES (old_label);
return 0;
}
! /* Return RTX_EQUAL_P (*PX, SUBX). If *PX and SUBX are not equal
! FOR_EACH_RTX continues traversing, if they are equal FOR_EACH_RTX
! stops traversing and returns the same value as this function. */
static int
! subrtx_p_1 (px, subx)
! rtx *px;
! void *subx;
{
! return rtx_equal_p (*px, (rtx) subx);
}
! /* Return true if SUBX is equal to some subexpression of X. */
int
! subrtx_p (subx, x)
! rtx subx;
rtx x;
{
! return for_each_rtx (&x, subrtx_p_1, subx);
}
/* If INSN is a jump to jumptable insn rturn true and store the label (which
--- 2801,2898 ----
void *data;
{
rtx l = *x;
! rtx tmp;
! rtx old_label = ((replace_label_data *) data)->r1;
! rtx new_label = ((replace_label_data *) data)->r2;
! bool update_label_nuses = ((replace_label_data *) data)->update_label_nuses;
if (l == NULL_RTX)
return 0;
+ if (GET_CODE (l) == MEM
+ && (tmp = XEXP (l, 0)) != NULL_RTX
+ && GET_CODE (tmp) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (tmp))
+ {
+ rtx c = get_pool_constant (tmp);
+ if (rtx_referenced_p (old_label, c))
+ {
+ rtx new_c, new_l;
+ replace_label_data *d = (replace_label_data *) data;
+
+ /* Create a copy of constant C; replace the label inside
+ but do not update LABEL_NUSES because uses in constant pool
+ are not counted. */
+ new_c = copy_rtx (c);
+ d->update_label_nuses = false;
+ for_each_rtx (&new_c, replace_label, data);
+ d->update_label_nuses = update_label_nuses;
+
+ /* Add the new constant NEW_C to constant pool and replace
+ the old reference to constant by new reference. */
+ new_l = force_const_mem (get_pool_mode (tmp), new_c);
+ *x = replace_rtx (l, l, new_l);
+ }
+ return 0;
+ }
+
/* If this is a JUMP_INSN, then we also need to fix the JUMP_LABEL
field. This is not handled by for_each_rtx because it doesn't
handle unprinted ('0') fields. */
if (GET_CODE (l) == JUMP_INSN && JUMP_LABEL (l) == old_label)
JUMP_LABEL (l) = new_label;
! if ((GET_CODE (l) == LABEL_REF
! || GET_CODE (l) == INSN_LIST)
! && XEXP (l, 0) == old_label)
! {
! XEXP (l, 0) = new_label;
! if (update_label_nuses)
! {
! ++LABEL_NUSES (new_label);
! --LABEL_NUSES (old_label);
! }
! return 0;
! }
return 0;
}
! /* When *BODY is equal to X or X is directly referenced by *BODY
! return nonzero, thus FOR_EACH_RTX stops traversing and returns nonzero
! too, otherwise FOR_EACH_RTX continues traversing *BODY. */
static int
! rtx_referenced_p_1 (body, x)
! rtx *body;
! void *x;
{
! rtx y = (rtx) x;
!
! if (*body == NULL_RTX)
! return y == NULL_RTX;
!
! /* Return true if a label_ref *BODY refers to label Y. */
! if (GET_CODE (*body) == LABEL_REF && GET_CODE (y) == CODE_LABEL)
! return XEXP (*body, 0) == y;
!
! /* If *BODY is a reference to pool constant traverse the constant. */
! if (GET_CODE (*body) == SYMBOL_REF
! && CONSTANT_POOL_ADDRESS_P (*body))
! return rtx_referenced_p (y, get_pool_constant (*body));
!
! /* By default, compare the RTL expressions. */
! return rtx_equal_p (*body, y);
}
! /* Return true if X is referenced in BODY. */
int
! rtx_referenced_p (x, body)
rtx x;
+ rtx body;
{
! return for_each_rtx (&body, rtx_referenced_p_1, x);
}
/* If INSN is a jump to jumptable insn rturn true and store the label (which