OSDN Git Service

* alias.c (get_alias_set): Try to replace PLACEHOLDER_EXPR.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index ed7f33f..52f9cc0 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -163,9 +163,6 @@ static rtx store_field              PARAMS ((rtx, HOST_WIDE_INT,
                                         unsigned int, HOST_WIDE_INT, int));
 static enum memory_use_mode
   get_memory_usage_from_modifier PARAMS ((enum expand_modifier));
-static tree save_noncopied_parts PARAMS ((tree, tree));
-static tree init_noncopied_parts PARAMS ((tree, tree));
-static int fixed_type_p                PARAMS ((tree));
 static rtx var_rtx             PARAMS ((tree));
 static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
 static rtx expand_increment    PARAMS ((tree, int, int));
@@ -177,6 +174,7 @@ static rtx do_store_flag    PARAMS ((tree, rtx, enum machine_mode, int));
 #ifdef PUSH_ROUNDING
 static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
 #endif
+static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx));
 
 /* Record for each mode whether we can move a register directly to or
    from an object of that mode in memory.  If we can't, we won't try
@@ -3101,18 +3099,11 @@ push_block (size, extra, below)
     }
 
 #ifndef STACK_GROWS_DOWNWARD
-#ifdef ARGS_GROW_DOWNWARD
-  if (!ACCUMULATE_OUTGOING_ARGS)
-#else
   if (0)
-#endif
 #else
   if (1)
 #endif
     {
-      /* Return the lowest stack address when STACK or ARGS grow downward and
-        we are not aaccumulating outgoing arguments (the c4x port uses such
-        conventions).  */
       temp = virtual_outgoing_args_rtx;
       if (extra != 0 && below)
        temp = plus_constant (temp, extra);
@@ -3272,8 +3263,9 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
      Default is below for small data on big-endian machines; else above.  */
   enum direction where_pad = FUNCTION_ARG_PADDING (mode, type);
 
-  /* Invert direction if stack is post-update.  */
-  if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC)
+  /* Invert direction if stack is post-decrement. 
+     FIXME: why?  */
+  if (STACK_PUSH_CODE == POST_DEC)
     if (where_pad != none)
       where_pad = (where_pad == downward ? upward : downward);
 
@@ -4718,7 +4710,9 @@ store_constructor (exp, target, align, cleared, size)
       int need_to_clear;
       tree domain = TYPE_DOMAIN (type);
       tree elttype = TREE_TYPE (type);
-      int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+      int const_bounds_p = (TYPE_MIN_VALUE (domain)
+                           && TYPE_MAX_VALUE (domain)
+                           && host_integerp (TYPE_MIN_VALUE (domain), 0)
                            && host_integerp (TYPE_MAX_VALUE (domain), 0));
       HOST_WIDE_INT minelt = 0;
       HOST_WIDE_INT maxelt = 0;
@@ -5664,68 +5658,6 @@ force_operand (value, target)
   return value;
 }
 \f
-/* Subroutine of expand_expr:
-   save the non-copied parts (LIST) of an expr (LHS), and return a list
-   which can restore these values to their previous values,
-   should something modify their storage.  */
-
-static tree
-save_noncopied_parts (lhs, list)
-     tree lhs;
-     tree list;
-{
-  tree tail;
-  tree parts = 0;
-
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      parts = chainon (parts, save_noncopied_parts (lhs, TREE_VALUE (tail)));
-    else
-      {
-       tree part = TREE_VALUE (tail);
-       tree part_type = TREE_TYPE (part);
-       tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
-       rtx target
-         = assign_temp (build_qualified_type (part_type,
-                                              (TYPE_QUALS (part_type)
-                                               | TYPE_QUAL_CONST)),
-                        0, 1, 1);
-
-       parts = tree_cons (to_be_saved,
-                          build (RTL_EXPR, part_type, NULL_TREE,
-                                 (tree) validize_mem (target)),
-                          parts);
-       store_expr (TREE_PURPOSE (parts),
-                   RTL_EXPR_RTL (TREE_VALUE (parts)), 0);
-      }
-  return parts;
-}
-
-/* Subroutine of expand_expr:
-   record the non-copied parts (LIST) of an expr (LHS), and return a list
-   which specifies the initial values of these parts.  */
-
-static tree
-init_noncopied_parts (lhs, list)
-     tree lhs;
-     tree list;
-{
-  tree tail;
-  tree parts = 0;
-
-  for (tail = list; tail; tail = TREE_CHAIN (tail))
-    if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
-      parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
-    else if (TREE_PURPOSE (tail))
-      {
-       tree part = TREE_VALUE (tail);
-       tree part_type = TREE_TYPE (part);
-       tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
-       parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
-      }
-  return parts;
-}
-
 /* Subroutine of expand_expr: return nonzero iff there is no way that
    EXP can reference X, which is being modified.  TOP_P is nonzero if this
    call is going to be used to determine whether we need a temporary
@@ -5950,22 +5882,6 @@ safe_from_p (x, exp, top_p)
   return 1;
 }
 
-/* Subroutine of expand_expr: return nonzero iff EXP is an
-   expression whose type is statically determinable.  */
-
-static int
-fixed_type_p (exp)
-     tree exp;
-{
-  if (TREE_CODE (exp) == PARM_DECL
-      || TREE_CODE (exp) == VAR_DECL
-      || TREE_CODE (exp) == CALL_EXPR || TREE_CODE (exp) == TARGET_EXPR
-      || TREE_CODE (exp) == COMPONENT_REF
-      || TREE_CODE (exp) == ARRAY_REF)
-    return 1;
-  return 0;
-}
-
 /* Subroutine of expand_expr: return rtx if EXP is a
    variable or parameter; else return 0.  */
 
@@ -6039,6 +5955,69 @@ check_max_integer_computation_mode (exp)
 }
 #endif
 \f
+/* Return an object on the placeholder list that matches EXP, a
+   PLACEHOLDER_EXPR.  An object "matches" if it is of the type of the
+   PLACEHOLDER_EXPR or a pointer type to it.  For further information,
+   see tree.def.  If no such object is found, abort.  If PLIST is nonzero,
+   it is a location into which a pointer into the placeholder list at
+   which the object is found is placed.  */
+
+tree
+find_placeholder (exp, plist)
+     tree exp;
+     tree *plist;
+{
+  tree type = TREE_TYPE (exp);
+  tree placeholder_expr;
+
+  for (placeholder_expr = placeholder_list; placeholder_expr != 0;
+       placeholder_expr = TREE_CHAIN (placeholder_expr))
+    {
+      tree need_type = TYPE_MAIN_VARIANT (type);
+      tree elt;
+
+      /* Find the outermost reference that is of the type we want.  If none,
+        see if any object has a type that is a pointer to the type we
+        want.  */
+      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+          elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+                  || TREE_CODE (elt) == COND_EXPR)
+                 ? TREE_OPERAND (elt, 1)
+                 : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                    || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+                 ? TREE_OPERAND (elt, 0) : 0))
+       if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+         {
+           if (plist)
+             *plist = placeholder_expr;
+           return elt;
+         }
+
+      for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+          elt
+          = ((TREE_CODE (elt) == COMPOUND_EXPR
+              || TREE_CODE (elt) == COND_EXPR)
+             ? TREE_OPERAND (elt, 1)
+             : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+                || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+             ? TREE_OPERAND (elt, 0) : 0))
+       if (POINTER_TYPE_P (TREE_TYPE (elt))
+           && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+               == need_type))
+         {
+           if (plist)
+             *plist = placeholder_expr;
+           return build1 (INDIRECT_REF, need_type, elt);
+         }
+    }
+
+  abort ();
+}
+\f
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
    In the case of a void EXP, const0_rtx is returned.
@@ -6566,66 +6545,14 @@ expand_expr (exp, target, tmode, modifier)
 
     case PLACEHOLDER_EXPR:
       {
+       tree old_list = placeholder_list;
        tree placeholder_expr;
 
-       /* If there is an object on the head of the placeholder list,
-          see if some object in it of type TYPE or a pointer to it.  For
-          further information, see tree.def.  */
-       for (placeholder_expr = placeholder_list;
-            placeholder_expr != 0;
-            placeholder_expr = TREE_CHAIN (placeholder_expr))
-         {
-           tree need_type = TYPE_MAIN_VARIANT (type);
-           tree object = 0;
-           tree old_list = placeholder_list;
-           tree elt;
-
-           /* Find the outermost reference that is of the type we want.
-              If none, see if any object has a type that is a pointer to
-              the type we want.  */
-           for (elt = TREE_PURPOSE (placeholder_expr);
-                elt != 0 && object == 0;
-                elt
-                = ((TREE_CODE (elt) == COMPOUND_EXPR
-                    || TREE_CODE (elt) == COND_EXPR)
-                   ? TREE_OPERAND (elt, 1)
-                   : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                   ? TREE_OPERAND (elt, 0) : 0))
-             if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
-               object = elt;
-
-           for (elt = TREE_PURPOSE (placeholder_expr);
-                elt != 0 && object == 0;
-                elt
-                = ((TREE_CODE (elt) == COMPOUND_EXPR
-                    || TREE_CODE (elt) == COND_EXPR)
-                   ? TREE_OPERAND (elt, 1)
-                   : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
-                      || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
-                   ? TREE_OPERAND (elt, 0) : 0))
-             if (POINTER_TYPE_P (TREE_TYPE (elt))
-                 && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
-                     == need_type))
-               object = build1 (INDIRECT_REF, need_type, elt);
-
-           if (object != 0)
-             {
-               /* Expand this object skipping the list entries before
-                  it was found in case it is also a PLACEHOLDER_EXPR.
-                  In that case, we want to translate it using subsequent
-                  entries.  */
-               placeholder_list = TREE_CHAIN (placeholder_expr);
-               temp = expand_expr (object, original_target, tmode,
-                                   ro_modifier);
-               placeholder_list = old_list;
-               return temp;
-             }
-         }
+       exp = find_placeholder (exp, &placeholder_expr);
+       placeholder_list = TREE_CHAIN (placeholder_expr);
+       temp = expand_expr (exp, original_target, tmode, ro_modifier);
+       placeholder_list = old_list;
+       return temp;
       }
 
       /* We can't find the object or there was a missing WITH_RECORD_EXPR.  */
@@ -7007,6 +6934,7 @@ expand_expr (exp, target, tmode, modifier)
        tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
                                        &mode1, &unsignedp, &volatilep,
                                        &alignment);
+       rtx orig_op0;
 
        /* If we got back the original object, something is wrong.  Perhaps
           we are evaluating an expression too early.  In any event, don't
@@ -7018,15 +6946,16 @@ expand_expr (exp, target, tmode, modifier)
           computation, since it will need a temporary and TARGET is known
           to have to do.  This occurs in unchecked conversion in Ada.  */
 
-       op0 = expand_expr (tem,
-                          (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
-                           && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
-                               != INTEGER_CST)
-                           ? target : NULL_RTX),
-                          VOIDmode,
-                          (modifier == EXPAND_INITIALIZER
-                           || modifier == EXPAND_CONST_ADDRESS)
-                          ? modifier : EXPAND_NORMAL);
+       orig_op0 = op0
+         = expand_expr (tem,
+                        (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                         && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+                             != INTEGER_CST)
+                         ? target : NULL_RTX),
+                        VOIDmode,
+                        (modifier == EXPAND_INITIALIZER
+                         || modifier == EXPAND_CONST_ADDRESS)
+                        ? modifier : EXPAND_NORMAL);
 
        /* If this is a constant, put it into a register if it is a
           legitimate constant and OFFSET is 0 and memory if it isn't.  */
@@ -7115,7 +7044,9 @@ expand_expr (exp, target, tmode, modifier)
        /* Don't forget about volatility even if this is a bitfield.  */
        if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
          {
-           op0 = copy_rtx (op0);
+           if (op0 == orig_op0)
+             op0 = copy_rtx (op0);
+
            MEM_VOLATILE_P (op0) = 1;
          }
 
@@ -7257,6 +7188,9 @@ expand_expr (exp, target, tmode, modifier)
        else
          op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
 
+       if (op0 == orig_op0)
+         op0 = copy_rtx (op0);
+
        set_mem_attributes (op0, exp, 0);
        if (GET_CODE (XEXP (op0, 0)) == REG)
          mark_reg_pointer (XEXP (op0, 0), alignment);
@@ -8510,37 +8444,23 @@ expand_expr (exp, target, tmode, modifier)
       {
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
-       tree noncopied_parts = 0;
-       tree lhs_type = TREE_TYPE (lhs);
 
        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
-       if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
-         noncopied_parts
-           = init_noncopied_parts (stabilize_reference (lhs),
-                                   TYPE_NONCOPIED_PARTS (lhs_type));
-
-       while (noncopied_parts != 0)
-         {
-           expand_assignment (TREE_VALUE (noncopied_parts),
-                              TREE_PURPOSE (noncopied_parts), 0, 0);
-           noncopied_parts = TREE_CHAIN (noncopied_parts);
-         }
        return temp;
       }
 
     case MODIFY_EXPR:
       {
        /* If lhs is complex, expand calls in rhs before computing it.
-          That's so we don't compute a pointer and save it over a call.
-          If lhs is simple, compute it first so we can give it as a
-          target if the rhs is just a call.  This avoids an extra temp and copy
-          and that prevents a partial-subsumption which makes bad code.
-          Actually we could treat component_ref's of vars like vars.  */
+          That's so we don't compute a pointer and save it over a
+          call.  If lhs is simple, compute it first so we can give it
+          as a target if the rhs is just a call.  This avoids an
+          extra temp and copy and that prevents a partial-subsumption
+          which makes bad code.  Actually we could treat
+          component_ref's of vars like vars.  */
 
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
-       tree noncopied_parts = 0;
-       tree lhs_type = TREE_TYPE (lhs);
 
        temp = 0;
 
@@ -8576,19 +8496,8 @@ expand_expr (exp, target, tmode, modifier)
            return const0_rtx;
          }
 
-       if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
-           && ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
-         noncopied_parts
-           = save_noncopied_parts (stabilize_reference (lhs),
-                                   TYPE_NONCOPIED_PARTS (lhs_type));
-
        temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
-       while (noncopied_parts != 0)
-         {
-           expand_assignment (TREE_PURPOSE (noncopied_parts),
-                              TREE_VALUE (noncopied_parts), 0, 0);
-           noncopied_parts = TREE_CHAIN (noncopied_parts);
-         }
+       
        return temp;
       }
 
@@ -8866,6 +8775,11 @@ expand_expr (exp, target, tmode, modifier)
     case EXC_PTR_EXPR:
       return get_exception_pointer (cfun);
 
+    case FDESC_EXPR:
+      /* Function descriptors are not valid except for as
+        initialization constants, and should not be expanded.  */
+      abort ();
+
     default:
       return (*lang_expand_expr) (exp, original_target, tmode, modifier);
     }
@@ -10717,11 +10631,112 @@ do_store_flag (exp, target, mode, only_cheap)
   return target;
 }
 \f
-/* Generate a tablejump instruction (used for switch statements).  */
 
-#ifdef HAVE_tablejump
+/* Stubs in case we haven't got a casesi insn.  */
+#ifndef HAVE_casesi
+# define HAVE_casesi 0
+# define gen_casesi(a, b, c, d, e) (0)
+# define CODE_FOR_casesi CODE_FOR_nothing
+#endif
+
+/* If the machine does not have a case insn that compares the bounds,
+   this means extra overhead for dispatch tables, which raises the
+   threshold for using them.  */
+#ifndef CASE_VALUES_THRESHOLD
+#define CASE_VALUES_THRESHOLD (HAVE_casesi ? 4 : 5)
+#endif /* CASE_VALUES_THRESHOLD */
+
+unsigned int
+case_values_threshold ()
+{
+  return CASE_VALUES_THRESHOLD;
+}
+
+/* Attempt to generate a casesi instruction.  Returns 1 if successful,
+   0 otherwise (i.e. if there is no casesi instruction).  */
+int
+try_casesi (index_type, index_expr, minval, range,
+           table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label ATTRIBUTE_UNUSED;
+     rtx default_label;
+{
+  enum machine_mode index_mode = SImode;
+  int index_bits = GET_MODE_BITSIZE (index_mode);
+  rtx op1, op2, index;
+  enum machine_mode op_mode;
+
+  if (! HAVE_casesi)
+    return 0;
+
+  /* Convert the index to SImode.  */
+  if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
+    {
+      enum machine_mode omode = TYPE_MODE (index_type);
+      rtx rangertx = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+      /* We must handle the endpoints in the original mode.  */
+      index_expr = build (MINUS_EXPR, index_type,
+                         index_expr, minval);
+      minval = integer_zero_node;
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+      emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+                              omode, 1, 0, default_label);
+      /* Now we can safely truncate.  */
+      index = convert_to_mode (index_mode, index, 0);
+    }
+  else
+    {
+      if (TYPE_MODE (index_type) != index_mode)
+       {
+         index_expr = convert (type_for_size (index_bits, 0),
+                               index_expr);
+         index_type = TREE_TYPE (index_expr);
+       }
+
+      index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+    }
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[0].mode;
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[0].predicate)
+      (index, op_mode))
+    index = copy_to_mode_reg (op_mode, index);
+
+  op1 = expand_expr (minval, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[1].mode;
+  op1 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (minval)),
+                      op1, TREE_UNSIGNED (TREE_TYPE (minval)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[1].predicate)
+      (op1, op_mode))
+    op1 = copy_to_mode_reg (op_mode, op1);
+
+  op2 = expand_expr (range, NULL_RTX, VOIDmode, 0);
+
+  op_mode = insn_data[(int) CODE_FOR_casesi].operand[2].mode;
+  op2 = convert_modes (op_mode, TYPE_MODE (TREE_TYPE (range)),
+                      op2, TREE_UNSIGNED (TREE_TYPE (range)));
+  if (! (*insn_data[(int) CODE_FOR_casesi].operand[2].predicate)
+      (op2, op_mode))
+    op2 = copy_to_mode_reg (op_mode, op2);
+
+  emit_jump_insn (gen_casesi (index, op1, op2,
+                             table_label, default_label));
+  return 1;
+}
+
+/* Attempt to generate a tablejump instruction; same concept.  */
+#ifndef HAVE_tablejump
+#define HAVE_tablejump 0
+#define gen_tablejump(x, y) (0)
+#endif
+
+/* Subroutine of the next function.
 
-/* INDEX is the value being switched on, with the lowest value
+   INDEX is the value being switched on, with the lowest value
    in the table already subtracted.
    MODE is its expected mode (needed if INDEX is constant).
    RANGE is the length of the jump table.
@@ -10730,7 +10745,7 @@ do_store_flag (exp, target, mode, only_cheap)
    DEFAULT_LABEL is a CODE_LABEL rtx to jump to if the
    index value is out of range.  */
 
-void
+static void
 do_tablejump (index, mode, range, table_label, default_label)
      rtx index, range, table_label, default_label;
      enum machine_mode mode;
@@ -10792,4 +10807,31 @@ do_tablejump (index, mode, range, table_label, default_label)
     emit_barrier ();
 }
 
-#endif /* HAVE_tablejump  */
+int
+try_tablejump (index_type, index_expr, minval, range,
+              table_label, default_label)
+     tree index_type, index_expr, minval, range;
+     rtx table_label, default_label;
+{
+  rtx index;
+
+  if (! HAVE_tablejump)
+    return 0;
+
+  index_expr = fold (build (MINUS_EXPR, index_type,
+                           convert (index_type, index_expr),
+                           convert (index_type, minval)));
+  index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
+  emit_queue ();
+  index = protect_from_queue (index, 0);
+  do_pending_stack_adjust ();
+
+  do_tablejump (index, TYPE_MODE (index_type),
+               convert_modes (TYPE_MODE (index_type),
+                              TYPE_MODE (TREE_TYPE (range)),
+                              expand_expr (range, NULL_RTX,
+                                           VOIDmode, 0),
+                              TREE_UNSIGNED (TREE_TYPE (range))),
+               table_label, default_label);
+  return 1;
+}