+/* Maximum number of case bit tests. */
+#define MAX_CASE_BIT_TESTS 3
+
+/* By default, enable case bit tests on targets with ashlsi3. */
+#ifndef CASE_USE_BIT_TESTS
+#define CASE_USE_BIT_TESTS (ashl_optab->handlers[word_mode].insn_code \
+ != CODE_FOR_nothing)
+#endif
+
+
+/* A case_bit_test represents a set of case nodes that may be
+ selected from using a bit-wise comparison. HI and LO hold
+ the integer to be tested against, LABEL contains the label
+ to jump to upon success and BITS counts the number of case
+ nodes handled by this test, typically the number of bits
+ set in HI:LO. */
+
+struct case_bit_test
+{
+ HOST_WIDE_INT hi;
+ HOST_WIDE_INT lo;
+ rtx label;
+ int bits;
+};
+
+/* Determine whether "1 << x" is relatively cheap in word_mode. */
+
+static bool lshift_cheap_p ()
+{
+ static bool init = false;
+ static bool cheap = true;
+
+ if (!init)
+ {
+ rtx reg = gen_rtx_REG (word_mode, 10000);
+ int cost = rtx_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg), SET);
+ cheap = cost < COSTS_N_INSNS (3);
+ init = true;
+ }
+
+ return cheap;
+}
+
+/* Comparison function for qsort to order bit tests by decreasing
+ number of case nodes, i.e. the node with the most cases gets
+ tested first. */
+
+static int case_bit_test_cmp (p1, p2)
+ const void *p1;
+ const void *p2;
+{
+ const struct case_bit_test *d1 = p1;
+ const struct case_bit_test *d2 = p2;
+
+ return d2->bits - d1->bits;
+}
+
+/* Expand a switch statement by a short sequence of bit-wise
+ comparisons. "switch(x)" is effectively converted into
+ "if ((1 << (x-MINVAL)) & CST)" where CST and MINVAL are
+ integer constants.
+
+ INDEX_EXPR is the value being switched on, which is of
+ type INDEX_TYPE. MINVAL is the lowest case value of in
+ the case nodes, of INDEX_TYPE type, and RANGE is highest
+ value minus MINVAL, also of type INDEX_TYPE. NODES is
+ the set of case nodes, and DEFAULT_LABEL is the label to
+ branch to should none of the cases match.
+
+ There *MUST* be MAX_CASE_BIT_TESTS or less unique case
+ node targets. */
+
+static void
+emit_case_bit_tests (index_type, index_expr, minval, range,
+ nodes, default_label)
+ tree index_type, index_expr, minval, range;
+ case_node_ptr nodes;
+ rtx default_label;
+{
+ struct case_bit_test test[MAX_CASE_BIT_TESTS];
+ enum machine_mode mode;
+ rtx expr, index, label;
+ unsigned int i,j,lo,hi;
+ struct case_node *n;
+ unsigned int count;
+
+ count = 0;
+ for (n = nodes; n; n = n->right)
+ {
+ label = label_rtx (n->code_label);
+ for (i = 0; i < count; i++)
+ if (same_case_target_p (label, test[i].label))
+ break;
+
+ if (i == count)
+ {
+ if (count >= MAX_CASE_BIT_TESTS)
+ abort ();
+ test[i].hi = 0;
+ test[i].lo = 0;
+ test[i].label = label;
+ test[i].bits = 1;
+ count++;
+ }
+ else
+ test[i].bits++;
+
+ lo = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+ n->low, minval)), 1);
+ hi = tree_low_cst (fold (build (MINUS_EXPR, index_type,
+ n->high, minval)), 1);
+ for (j = lo; j <= hi; j++)
+ if (j >= HOST_BITS_PER_WIDE_INT)
+ test[i].hi |= (HOST_WIDE_INT) 1 << (j - HOST_BITS_PER_INT);
+ else
+ test[i].lo |= (HOST_WIDE_INT) 1 << j;
+ }
+
+ qsort (test, count, sizeof(*test), case_bit_test_cmp);
+
+ 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 ();
+
+ mode = TYPE_MODE (index_type);
+ expr = expand_expr (range, NULL_RTX, VOIDmode, 0);
+ emit_cmp_and_jump_insns (index, expr, GTU, NULL_RTX, mode, 1,
+ default_label);
+
+ index = convert_to_mode (word_mode, index, 0);
+ index = expand_binop (word_mode, ashl_optab, const1_rtx,
+ index, NULL_RTX, 1, OPTAB_WIDEN);
+
+ for (i = 0; i < count; i++)
+ {
+ expr = immed_double_const (test[i].lo, test[i].hi, word_mode);
+ expr = expand_binop (word_mode, and_optab, index, expr,
+ NULL_RTX, 1, OPTAB_WIDEN);
+ emit_cmp_and_jump_insns (expr, const0_rtx, NE, NULL_RTX,
+ word_mode, 1, test[i].label);
+ }
+
+ emit_jump (default_label);
+}