This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to implement get_jump_table_offset for VRP (version 2)
- From: John Wehle <john at feith dot com>
- To: rth at redhat dot com
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 7 Dec 2001 11:12:13 -0500 (EST)
- Subject: Patch to implement get_jump_table_offset for VRP (version 2)
[ I commited a slightly tweaked version that has been tested on
Dec Alpha 4.0f, IBM rs6000 AIX 4.3, Solaris 7 SPARC, and
Solaris 7 x86.
Changes:
1) Renamed a couple of variables.
2) Removed LO_SUM handling since there's likely to be
a REG_EQUAL note for the label_ref present which
will be returned by find_last_value.
3) Call find_last_value in one more place in order
to handle the rs6000. ]
get_jump_table_offset is a generic support routine used by VRP
to determine the RTL expression for the offset into the jump
table. It may be useful elsewhere.
This patch (combined with VRP) passes make bootstrap and make check
on Dec Alpha 4.0f, Solaris 7 SPARC, and Solaris 7 x86.
ChangeLog:
Thu Dec 6 12:24:36 EST 2001 John Wehle (john@feith.com)
* rtl.h (get_jump_table_offset): Declare.
* rtlanal.c (get_jump_table_offset): Implement.
Enjoy!
-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/rtl.h.ORIGINAL Fri Nov 30 12:59:45 2001
--- gcc/rtl.h Fri Nov 30 13:03:49 2001
*************** extern int rtx_varies_p PARAMS ((rtx,
*** 1428,1433 ****
--- 1428,1434 ----
extern int rtx_addr_varies_p PARAMS ((rtx, int));
extern HOST_WIDE_INT get_integer_term PARAMS ((rtx));
extern rtx get_related_value PARAMS ((rtx));
+ extern rtx get_jump_table_offset PARAMS ((rtx, rtx *));
extern int reg_mentioned_p PARAMS ((rtx, rtx));
extern int count_occurrences PARAMS ((rtx, rtx, int));
extern int reg_referenced_p PARAMS ((rtx, rtx));
*** gcc/rtlanal.c.ORIGINAL Thu Dec 6 12:18:19 2001
--- gcc/rtlanal.c Mon Dec 3 14:07:54 2001
*************** get_related_value (x)
*** 339,344 ****
--- 339,485 ----
return 0;
}
+ /* Given a tablejump insn INSN, return the RTL expression for the offset
+ into the jump table. If the offset cannot be determined, then return
+ NULL_RTX.
+
+ If EARLIEST is non-zero, it is a pointer to a place where the earliest
+ insn used in locating the offset was found. */
+
+ rtx
+ get_jump_table_offset (insn, earliest)
+ rtx insn;
+ rtx *earliest;
+ {
+ rtx label;
+ rtx table;
+ rtx set;
+ rtx old_insn;
+ rtx x;
+ rtx old_x;
+ rtx y;
+ rtx old_y;
+ int i;
+ int j;
+
+ if (GET_CODE (insn) != JUMP_INSN
+ || ! (label = JUMP_LABEL (insn))
+ || ! (table = NEXT_INSN (label))
+ || GET_CODE (table) != JUMP_INSN
+ || (GET_CODE (PATTERN (table)) != ADDR_VEC
+ && GET_CODE (PATTERN (table)) != ADDR_DIFF_VEC)
+ || ! (set = single_set (insn)))
+ return NULL_RTX;
+
+ x = SET_SRC (set);
+
+ /* Some targets (eg, ARM) emit a tablejump that also
+ contains the out-of-range target. */
+ if (GET_CODE (x) == IF_THEN_ELSE
+ && GET_CODE (XEXP (x, 2)) == LABEL_REF)
+ x = XEXP (x, 1);
+
+ /* Search backwards and locate the expression stored in X. */
+ for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+ old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+ ;
+
+ /* If X is an expression using a relative address then strip
+ off the addition / subtraction of PC, PIC_OFFSET_TABLE_REGNUM,
+ or the jump table label. */
+ if (GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC
+ && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS))
+ {
+ for (i = 0; i < 2; i++)
+ {
+ old_insn = insn;
+ y = XEXP (x, i);
+
+ if (y == pc_rtx || y == pic_offset_table_rtx)
+ break;
+
+ for (old_y = NULL_RTX; GET_CODE (y) == REG && y != old_y;
+ old_y = y, y = find_last_value (y, &old_insn, NULL_RTX, 0))
+ ;
+
+ if ((GET_CODE (y) == LABEL_REF && XEXP (y, 0) == label))
+ break;
+ }
+
+ if (i >= 2)
+ return NULL_RTX;
+
+ x = XEXP (x, 1 - i);
+
+ for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+ old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+ ;
+ }
+
+ /* Strip off any sign or zero extension. */
+ if (GET_CODE (x) == SIGN_EXTEND || GET_CODE (x) == ZERO_EXTEND)
+ {
+ x = XEXP (x, 0);
+
+ for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+ old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+ ;
+ }
+
+ /* If X isn't a MEM then this isn't a tablejump we understand. */
+ if (GET_CODE (x) != MEM)
+ return NULL_RTX;
+
+ /* Strip off the MEM. */
+ x = XEXP (x, 0);
+
+ for (old_x = NULL_RTX; GET_CODE (x) == REG && x != old_x;
+ old_x = x, x = find_last_value (x, &insn, NULL_RTX, 0))
+ ;
+
+ /* If X isn't a PLUS than this isn't a tablejump we understand. */
+ if (GET_CODE (x) != PLUS)
+ return NULL_RTX;
+
+ /* At this point we should have an expression representing the jump table
+ plus an offset. Examine each operand in order to determine which one
+ represents the jump table. Knowing that tells us that the other operand
+ must represent the offset. */
+ for (i = 0; i < 2; i++)
+ {
+ old_insn = insn;
+ y = XEXP (x, i);
+
+ for (old_y = NULL_RTX; GET_CODE (y) == REG && y != old_y;
+ old_y = y, y = find_last_value (y, &old_insn, NULL_RTX, 0))
+ ;
+
+ if ((GET_CODE (y) == CONST || GET_CODE (y) == LABEL_REF)
+ && reg_mentioned_p (label, y))
+ break;
+ }
+
+ if (i >= 2)
+ return NULL_RTX;
+
+ x = XEXP (x, 1 - i);
+
+ /* Strip off the addition / subtraction of PIC_OFFSET_TABLE_REGNUM. */
+ if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS)
+ for (i = 0; i < 2; i++)
+ if (XEXP (x, i) == pic_offset_table_rtx)
+ {
+ x = XEXP (x, 1 - i);
+ break;
+ }
+
+ if (earliest)
+ *earliest = insn;
+
+ /* Return the RTL expression representing the offset. */
+ return x;
+ }
+
/* Return the number of places FIND appears within X. If COUNT_DEST is
zero, we do not count occurrences inside the destination of a SET. */
-------------------------------------------------------------------------
| Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com |
| John Wehle | Fax: 1-215-540-5495 | |
-------------------------------------------------------------------------