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
- From: John Wehle <john at feith dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 30 Nov 2001 21:12:02 -0500 (EST)
- Subject: Patch to implement get_jump_table_offset for VRP
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:
Fri Nov 30 13:08:02 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 Fri Nov 30 12:59:33 2001
--- gcc/rtlanal.c Fri Nov 30 13:02:42 2001
*************** get_related_value (x)
*** 339,344 ****
--- 339,502 ----
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 x;
+ rtx old_x;
+ int i;
+ int j;
+ rtx current_insn;
+ rtx current_x;
+
+ 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++)
+ if (XEXP (x, i) == pc_rtx
+ || XEXP (x, i) == pic_offset_table_rtx
+ || (GET_CODE (XEXP (x, i)) == LABEL_REF
+ && XEXP (XEXP (x, i), 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. */
+
+ current_insn = insn;
+ current_x = x;
+
+ for (i = 0; i < 2; i++)
+ {
+ x = XEXP (current_x, i);
+ insn = current_insn;
+
+ 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 (GET_CODE (x) == LO_SUM)
+ {
+ for (j = 0; j < 2; j++)
+ if ((GET_CODE (XEXP (x, j)) == CONST
+ || GET_CODE (XEXP (x, j)) == LABEL_REF)
+ && reg_mentioned_p (label, XEXP (x, j)))
+ break;
+
+ if (j >= 2)
+ continue;
+
+ x = XEXP (x, 1 - j);
+
+ 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 (GET_CODE (x) != HIGH)
+ continue;
+
+ x = XEXP (x, 0);
+ }
+
+ if ((GET_CODE (x) == CONST || GET_CODE (x) == LABEL_REF)
+ && reg_mentioned_p (label, x))
+ break;
+ }
+
+ if (i >= 2)
+ return NULL_RTX;
+
+ x = XEXP (current_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 = current_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 | |
-------------------------------------------------------------------------