aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJohn Wehle <john@feith.com>2001-12-07 16:10:03 +0000
committerJohn Wehle <wehle@gcc.gnu.org>2001-12-07 16:10:03 +0000
commitd644189f51968195dc2fe1b9c4e851f8538475f3 (patch)
tree91871aa733ca0ae38e63395948c525a3d872a6d7 /gcc
parent5af0b89c0d06133ec4fda00a308232f585361850 (diff)
downloadgcc-d644189f51968195dc2fe1b9c4e851f8538475f3.zip
gcc-d644189f51968195dc2fe1b9c4e851f8538475f3.tar.gz
gcc-d644189f51968195dc2fe1b9c4e851f8538475f3.tar.bz2
rtl.h (get_jump_table_offset): Declare.
* rtl.h (get_jump_table_offset): Declare. * rtlanal.c (get_jump_table_offset): Implement. From-SVN: r47756
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c141
3 files changed, 147 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f4ca6e7c..8c11b63 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+Fri Dec 7 11:07:35 EST 2001 John Wehle (john@feith.com)
+
+ * rtl.h (get_jump_table_offset): Declare.
+ * rtlanal.c (get_jump_table_offset): Implement.
+
Fri Dec 7 07:06:17 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* final.c (bb_head, bb_tail, bb_file_label_num, bb_func_label_num):
diff --git a/gcc/rtl.h b/gcc/rtl.h
index b76376a..0fe43aa 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1427,6 +1427,7 @@ extern int rtx_varies_p PARAMS ((rtx, int));
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));
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 07c4676..f105950 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -339,6 +339,147 @@ get_related_value (x)
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. */