OSDN Git Service

* stmt.c (all_cases_count, mark_seen_cases): New functions.
authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 31 Aug 1994 23:42:28 +0000 (23:42 +0000)
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 31 Aug 1994 23:42:28 +0000 (23:42 +0000)
(BITARRAY_TEST, BITARRAY_SET):  New macros.  Used (mainly by
Chill) to check all cases are covered (for enums and ranges).
(check_for_full_enumeration_handling):  Re-write to use the
new functions, now that we have them.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@8009 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/stmt.c

index 1116f0a..59a6777 100644 (file)
@@ -4077,6 +4077,193 @@ bc_pushcase (value, label)
   return 0;
 }
 \f
+/* Returns the number of possible values of TYPE.
+   Returns -1 if the number is unknown or variable.
+   Returns -2 if the number does not fit in a HOST_WIDE_INT.
+   Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values
+   do not increase monotonically (there may be duplicates);
+   to 1 if the values increase monotonically, but not always by 1;
+   otherwise sets it to 0.  */
+
+HOST_WIDE_INT
+all_cases_count (type, spareness)
+     tree type;
+     int *spareness;
+{
+  HOST_WIDE_INT count, count_high = 0;
+  *spareness = 0;
+
+  switch (TREE_CODE (type))
+    {
+      tree t;
+    case BOOLEAN_TYPE:
+      count = 2;
+      break;
+    case CHAR_TYPE:
+      count = 1 << BITS_PER_UNIT;
+      break;
+    default:
+    case INTEGER_TYPE:
+      if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+         || TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST)
+       return -1;
+      else
+       {
+         /* count
+            = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
+            - TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
+            but with overflow checking. */
+         tree mint = TYPE_MIN_VALUE (type);
+         tree maxt = TYPE_MAX_VALUE (type);
+         HOST_WIDE_INT lo, hi;
+         neg_double(TREE_INT_CST_LOW (mint), TREE_INT_CST_HIGH (mint),
+                    &lo, &hi);
+         add_double(TREE_INT_CST_LOW (maxt), TREE_INT_CST_HIGH (maxt),
+                    lo, hi, &lo, &hi);
+         add_double (lo, hi, 1, 0, &lo, &hi);
+         if (hi != 0 || lo < 0)
+           return -2;
+         count = lo;
+       }
+      break;
+    case ENUMERAL_TYPE:
+      count = 0;
+      for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t))
+       {
+         if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+             || TREE_CODE (TREE_VALUE (t)) != INTEGER_CST
+             || TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + count
+             != TREE_INT_CST_LOW (TREE_VALUE (t)))
+           *spareness = 1;
+         count++;
+       }
+      if (*spareness == 1)
+       {
+         tree prev = TREE_VALUE (TYPE_VALUES (type));
+         for (t = TYPE_VALUES (type); t = TREE_CHAIN (t), t != NULL_TREE; )
+           {
+             if (! tree_int_cst_lt (prev, TREE_VALUE (t)))
+               {
+                 *spareness = 2;
+                 break;
+               }
+             prev = TREE_VALUE (t);
+           }
+         
+       }
+    }
+  return count;
+}
+
+
+#define BITARRAY_TEST(ARRAY, INDEX) \
+  ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+                         & (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
+#define BITARRAY_SET(ARRAY, INDEX) \
+  ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
+                         |= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
+
+/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
+   with the case values we have seen, assuming the case expression
+   has the given TYPE.
+   SPARSENESS is as determined by all_cases_count.
+
+   The time needed is propotional to COUNT, unless
+   SPARSENESS is 2, in which case quadratic time is needed.  */
+
+void
+mark_seen_cases (type, cases_seen, count, sparseness)
+     tree type;
+     unsigned char *cases_seen;
+     long count;
+     int sparseness;
+{
+  long i;
+
+  tree next_node_to_try = NULL_TREE;
+  long next_node_offset = 0;
+
+  register struct case_node *n;
+  tree val = make_node (INTEGER_CST);
+  TREE_TYPE (val) = type;
+  for (n = case_stack->data.case_stmt.case_list; n;
+       n = n->right)
+    {
+      TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
+      TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
+      while ( ! tree_int_cst_lt (n->high, val))
+       {
+         /* Calculate (into xlo) the "offset" of the integer (val).
+            The element with lowest value has offset 0, the next smallest
+            element has offset 1, etc.  */
+
+         HOST_WIDE_INT xlo, xhi;
+         tree t;
+         if (sparseness == 2)
+           {
+             /* This less efficient loop is only needed to handle
+                duplicate case values (multiple enum constants
+                with the same value).  */
+             for (t = TYPE_VALUES (type), xlo = 0;  t != NULL_TREE;
+                  t = TREE_CHAIN (t), xlo++)
+               {
+                 if (tree_int_cst_equal (val, TREE_VALUE (t)))
+                   BITARRAY_SET (cases_seen, xlo);
+               }
+           }
+         else
+           {
+             if (sparseness && TYPE_VALUES (type) != NULL_TREE)
+               {
+                 /* The TYPE_VALUES will be in increasing order, so
+                    starting searching where we last ended.  */
+                 t = next_node_to_try;
+                 xlo = next_node_offset;
+                 xhi = 0;
+                 for (;;)
+                   {
+                     if (t == NULL_TREE)
+                       {
+                         t = TYPE_VALUES (type);
+                         xlo = 0;
+                       }
+                     if (tree_int_cst_equal (val, TREE_VALUE (t)))
+                       {
+                         next_node_to_try = TREE_CHAIN (t);
+                         next_node_offset = xlo + 1;
+                         break;
+                       }
+                     xlo++;
+                     t = TREE_CHAIN (t);
+                     if (t == next_node_to_try)
+                       break;
+                   }
+               }
+             else
+               {
+                 t = TYPE_MIN_VALUE (type);
+                 if (t)
+                   neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t),
+                               &xlo, &xhi);
+                 else
+                   xlo = xhi = 0;
+                 add_double (xlo, xhi,
+                             TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+                             &xlo, &xhi);
+               }
+             
+             if (xhi != 0 || xlo < 0 || xlo >= count)
+               fatal ("internal error - mark_cases_seen");
+             else
+               BITARRAY_SET (cases_seen, xlo);
+           }
+         add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+                     1, 0,
+                     &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
+       }
+    }
+}
+
 /* Called when the index of a switch statement is an enumerated type
    and there is no default label.
 
@@ -4097,37 +4284,55 @@ check_for_full_enumeration_handling (type)
   register tree chain;
   int all_values = 1;
 
+  /* True iff the selector type is a numbered set mode. */
+  int sparseness = 0;
+
+  /* The number of possible selector values. */
+  HOST_WIDE_INT size;
+
+  /* For each possible selector value. a one iff it has been matched
+     by a case value alternative. */
+  unsigned char *cases_seen;
+
+  /* The allocated size of cases_seen, in chars. */
+  long bytes_needed;
+  tree t;
+
   if (output_bytecode)
     {
       bc_check_for_full_enumeration_handling (type);
       return;
     }
 
-  /* The time complexity of this loop is currently O(N * M), with
-     N being the number of members in the enumerated type, and
-     M being the number of case expressions in the switch. */
+  if (! warn_switch)
+    return;
+
+  size = all_cases_count (type, &sparseness);
+  bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
 
-  for (chain = TYPE_VALUES (type);
-       chain;
-       chain = TREE_CHAIN (chain))
+  if (size > 0 && size < 600000
+      /* We deliberately use malloc here - not xmalloc. */
+      && (cases_seen = (char*) malloc (bytes_needed)) != NULL)
     {
-      /* Find a match between enumeral and case expression, if possible.
-        Quit looking when we've gone too far (since case expressions
-        are kept sorted in ascending order).  Warn about enumerators not
-        handled in the switch statement case expression list. */
-
-      for (n = case_stack->data.case_stmt.case_list;
-          n && tree_int_cst_lt (n->high, TREE_VALUE (chain));
-          n = n->right)
-       ;
+      long i;
+      tree v = TYPE_VALUES (type);
+      bzero (cases_seen, bytes_needed);
+
+      /* The time complexity of this code is normally O(N), where
+        N being the number of members in the enumerated type.
+        However, if type is a ENUMERAL_TYPE whose values do not
+        increase monotonically, quadratic time may be needed. */
 
-      if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low))
+      mark_seen_cases (type, cases_seen, size, sparseness);
+
+      for (i = 0;  v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v))
        {
-         if (warn_switch)
+         if (BITARRAY_TEST(cases_seen, i) == 0)
            warning ("enumeration value `%s' not handled in switch",
-                    IDENTIFIER_POINTER (TREE_PURPOSE (chain)));
-         all_values = 0;
+                    IDENTIFIER_POINTER (TREE_PURPOSE (v)));
        }
+
+      free (cases_seen);
     }
 
   /* Now we go the other way around; we warn if there are case