Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 197037)
+++ gcc/common.opt	(working copy)
@@ -1426,6 +1426,10 @@
 Common Var(flag_jump_tables) Init(1) Optimization
 Use jump tables for sufficiently large switch statements
 
+fswitch-conditional-heuristics
+Common Var(flag_switch_conditional_heuristics) Init(0) Optimization
+Enable conditional heuristics usage when processing the switch statement
+
 fkeep-inline-functions
 Common Report Var(flag_keep_inline_functions)
 Generate code for functions even if they are fully inlined
Index: gcc/params.def
===================================================================
--- gcc/params.def	(revision 197037)
+++ gcc/params.def	(working copy)
@@ -801,6 +801,24 @@
 	  "a switch conversion to take place",
 	  8, 1, 0)
 
+/* For switches witch has less than PARAM_SWITCH_JUMP_TABLES_BB_OPS_LIMIT operations under
+   each case label jump tables can be avoided because of the conditional heuristic.  */
+
+DEFPARAM (PARAM_SWITCH_JUMP_TABLES_BB_OPS_LIMIT,
+          "switch-no-jump-tables-bb-ops-limit",
+          "The maximal number of statements under case label for disabling the jump tables"
+          "because of the conditional heuristic",
+          8, 1, 0)
+
+/* For switches witch has less than PARAM_SWITCH_JUMP_TABLES_LIMIT branches
+   jump tables can be avoided because of the conditional heuristic.  */
+
+DEFPARAM (PARAM_SWITCH_JUMP_TABLES_LIMIT,
+          "switch-no-jump-tables-limit",
+          "The maximal number of switch branches for disabling the jump tables"
+          "because of the conditional heuristic",
+          8, 1, 0)
+
 /* Size of tiles when doing loop blocking.  */
 
 DEFPARAM (PARAM_LOOP_BLOCK_TILE_SIZE,
Index: gcc/stmt.c
===================================================================
--- gcc/stmt.c	(revision 197037)
+++ gcc/stmt.c	(working copy)
@@ -53,6 +53,7 @@
 #include "pointer-set.h"
 #include "params.h"
 #include "dumpfile.h"
+#include "tree-flow.h"
 
 
 /* Functions and data structures for expanding case statements.  */
@@ -115,6 +116,8 @@
 static int node_has_high_bound (case_node_ptr, tree);
 static int node_is_bounded (case_node_ptr, tree);
 static void emit_case_nodes (rtx, case_node_ptr, rtx, int, tree);
+static bool try_conditional_heuristics (gimple);
+
 
 /* Return the rtx-label that corresponds to a LABEL_DECL,
    creating it if necessary.  */
@@ -1748,7 +1751,7 @@
    COUNT is the number of comparisons needed, not counting the default case.  */
 
 static bool
-expand_switch_as_decision_tree_p (tree range,
+expand_switch_as_decision_tree_p (gimple stmt, tree range,
 				  unsigned int uniq ATTRIBUTE_UNUSED,
 				  unsigned int count)
 {
@@ -1758,7 +1761,8 @@
      over-ruled us, we really have no choice.  */
   if (!HAVE_casesi && !HAVE_tablejump)
     return true;
-  if (!flag_jump_tables)
+  if (!flag_jump_tables
+     || (flag_switch_conditional_heuristics && try_conditional_heuristics (stmt)))
     return true;
 #ifndef ASM_OUTPUT_ADDR_DIFF_ELT
   if (flag_pic)
@@ -2067,6 +2071,199 @@
     }
 }
 
+static bool check_bb_for_conditional_heuristics (basic_block, basic_block, basic_block *);
+
+/* Check whether the switch statement can be expanded with conditional
+   instructions. In that case jump tables should be avoided since some branch
+   instructions can be eliminated in further passes (replaced by conditional
+   execution).
+
+   For example:
+   switch (i)
+   {
+     case 1: sum += 1;
+     case 2: sum += 3;
+     case 3: sum += 5;
+     case 4: sum += 10;
+   }
+
+   Using jump tables the following code will be generated (ARM assembly):
+
+   ldrcc pc, [pc, r0, lsl #2]
+   b .L5
+   .L0:
+        .word L1
+        .word L2
+        .word L3
+        .word L4
+
+   .L1:
+        add r3, #1
+   .L2:
+        add r3, #4
+   .L3:
+        add r3, #5
+   .L4:
+        add r3, #10
+   .L5
+
+   Although this code has a constant complexity it can be improved by
+   the conditional execution to avoid implicit branching:
+
+   cmp r0,1
+   addeq r3, #1
+   cmp r0,2
+   addeq r3, #4
+   cmp r0,3
+   addeq r3, #5
+   cmp r0,4
+   addeq r3, #10
+
+   Although the assembly below requires more assembly instructions to be
+   executed, it doesn't violate the CPU pipeline (since no branching is
+   performed).   */
+
+static bool
+try_conditional_heuristics (gimple stmt)
+{
+  int num_labels;
+  int i;
+  basic_block next_bb = NULL;
+  GIMPLE_CHECK (stmt, GIMPLE_SWITCH);
+
+  num_labels = gimple_switch_num_labels (stmt);
+
+  if (num_labels > PARAM_VALUE (PARAM_SWITCH_JUMP_TABLES_LIMIT))
+    return false;
+
+  for (i = gimple_switch_num_labels (stmt) - 1; i >= 0; --i)
+    {
+      tree elt = gimple_switch_label (stmt, i);
+      tree label = CASE_LABEL (elt);
+      basic_block bb = label_to_block (label);
+      gcc_assert (bb);
+      if (!check_bb_for_conditional_heuristics (bb, gimple_bb (stmt), &next_bb))
+        return false;
+    }
+
+  return true;
+}
+
+static bool
+check_bb_statements_for_conditional_heuristics (basic_block bb)
+{
+  int count = 0;
+  rtx insn;
+  gimple_stmt_iterator gsi;
+
+
+  if (bb->flags & BB_RTL)
+  for (insn = BB_HEAD (bb);
+           insn != NEXT_INSN (BB_END (bb));
+           insn = NEXT_INSN (insn))
+  {
+       if (CALL_P(insn)) return false;
+       if (!DEBUG_INSN_P(insn) || (!NOTE_P(insn))) count++;
+       if (count > 3*PARAM_VALUE (PARAM_SWITCH_JUMP_TABLES_BB_OPS_LIMIT))
+           return false;
+  }
+  else
+  for (gsi = gsi_start_bb (bb);
+       !gsi_end_p (gsi);
+       gsi_next (&gsi))
+    {
+      gimple stmt = gsi_stmt (gsi);
+
+      /* Return statements should be ignored since they terminate the switch
+         statement.  */
+      if ((gimple_code (stmt) != GIMPLE_RETURN) || (gimple_code (stmt) != GIMPLE_DEBUG))
+        count++;
+
+      /* Call statements might trash the last comparison result register
+         (Current program status register) used for conditional execution.  */
+      if (gimple_code (stmt) == GIMPLE_CALL)
+        return false;
+
+      /* Large basic blocks should be generally avoided.  */
+      if (count > PARAM_VALUE (PARAM_SWITCH_JUMP_TABLES_BB_OPS_LIMIT))
+        return false;
+
+    }
+               
+  return true;
+}
+
+/* This function checks whether the given basic block corresponds to the one
+   of the following types:
+   1. Fall through basic block:
+     L1:
+       BB
+     L2:
+
+   2. Exit basic block:
+     L1:
+       BB
+       return
+   3. Break basic block:
+     L1:
+       BB
+       break
+
+   In all cases basic block has exactly one successor. For the first type the
+   following statement is true:
+   PARENT basic block is one of the successor's predictors (i.e. the successor
+   is marked by the case label).
+   For the second case the single successor must have the only successor - the
+   EXIT_BLOCK.
+   All basic blocks, matched the third case mush have the same successor.  */
+
+static bool
+check_bb_for_conditional_heuristics (basic_block bb, basic_block parent,
+                                     basic_block * next_bb)
+{
+  basic_block dest_bb;
+  edge e;
+  edge_iterator ei;
+
+  if (!single_succ_p (bb))
+    return false;
+
+  dest_bb = single_succ (bb);
+
+  FOR_EACH_EDGE (e, ei, dest_bb->preds)
+    {
+      if (e->src == parent)
+        {
+          /* First case matched.  */
+          return check_bb_statements_for_conditional_heuristics (bb);
+        }
+    }
+
+  /* Second case matched.  */
+  if (single_succ_edge (bb)->dest == EXIT_BLOCK_PTR ||
+      (single_succ_p (dest_bb)
+       && single_succ_edge (dest_bb)->dest == EXIT_BLOCK_PTR))
+    return check_bb_statements_for_conditional_heuristics (bb);
+
+  /* Try the third case.  */
+  if (*next_bb == NULL)
+    {
+      /* Mark first met basic block, as a switch successor. If it is not, this
+         check will fail for the next basic block.  */
+      *next_bb = dest_bb;
+      return check_bb_statements_for_conditional_heuristics (bb);
+    }
+  else
+    {
+      /* We have switch successor candidate.  */
+      if (dest_bb == *next_bb)
+        return check_bb_statements_for_conditional_heuristics (bb);
+      else
+        return false;
+    }
+  gcc_unreachable ();
+}
+
 /* Terminate a case (Pascal/Ada) or switch (C) statement
    in which ORIG_INDEX is the expression to be tested.
    If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
@@ -2196,7 +2393,7 @@
      The two options at this point are a dispatch table (casesi or
      tablejump) or a decision tree.  */
 
-  if (expand_switch_as_decision_tree_p (range, uniq, count))
+  if (expand_switch_as_decision_tree_p (stmt, range, uniq, count))
     emit_case_decision_tree (index_expr, index_type,
                              case_list, default_label,
                              default_prob);
