#ifndef FIRST_PSEUDO_REGISTER
#define NULL 0
#include "config.h"
#include "rtl.h"
#include "tree.h"
#include "insn-flags.h"
#endif

/* Functions and data structures for expanding case statements.  */

/* Case label structure, used to hold info on labels within case
   statements.  We handle "range" labels; for a single-value label
   as in C, the high and low limits are the same.  */

struct case_node
{
  struct case_node	*left;
  struct case_node	*right;
  struct case_node	*parent;
  tree			low;
  tree			high;
  tree			test_label;
  tree			code_label;
};

typedef struct case_node case_node;
typedef struct case_node *case_node_ptr;

void balance_case_nodes ();
void emit_case_nodes ();
void group_case_nodes ();
void emit_jump_if_reachable ();

/* Generate code to jump to LABEL if OP1 and OP2 are equal.  */

static void
do_jump_if_equal (op1, op2, label, unsignedp)
     rtx op1, op2, label;
     int unsignedp;
{
  if (GET_CODE (op1) == CONST_INT
      && GET_CODE (op2) == CONST_INT)
    {
      if (INTVAL (op1) == INTVAL (op2))
	emit_jump (label);
    }
  else
    {
      emit_cmp_insn (op1, op2, 0, unsignedp, 0);
      emit_jump_insn (gen_beq (label));
    }
}

/* Not all case values are encountered equally.  This function
   uses a heuristic to weight case labels, in cases where that
   looks like a reasonable thing to do.

   Right now, all we try to guess is text, and we establish the
   following weights:

	chars above space:	16
	digits:			16
	default:		12
	space, punct:		8
	tab:			4
	newline:		2
	other "\" chars:	1
	remaining chars:	0

   Under this weighting, ranges are automagically taken care of.  */

#include <ctype.h>
static char *cost_table;
static int use_cost_table;

void
estimate_case_costs (node, default_label)
     case_node_ptr node;
     rtx default_label;
{
  use_cost_table = 0;

  /* If the user is running without default, who are we
     to guess where values are likely to land?  */
  if (default_label == 0)
    return;

  /* Doesn't look like text.  */
  if (TREE_INT_CST_LOW (node->high) - TREE_INT_CST_LOW (node->low) > 128)
    return;
  if (TREE_INT_CST_LOW (node->low) < -1)
    return;
  if (TREE_INT_CST_LOW (node->high) > 127)
    return;

  /* All interesting values with within the range of
     interesting ASCII characters.  */
  if (cost_table == NULL)
    {
      int i;
      cost_table = ((char *)malloc (129)) + 1;
      bzero (cost_table-1, 128);
      for (i = 0; i < 128; i++)
	{
	  if (isalnum (i))
	    cost_table[i] = 16;
	  else if (ispunct (i))
	    cost_table[i] = 8;
	  else if (iscntrl (i))
	    cost_table[i] = -1;
	}
      cost_table[' '] = 8;
      cost_table['\t'] = 4;
      cost_table['\0'] = 4;
      cost_table['\n'] = 2;
      cost_table['\f'] = 1;
      cost_table['\v'] = 1;
      cost_table['\b'] = 1;
    }
  use_cost_table = 1;
}

/* Scan an ordered list of case nodes
   combining those with consecutive values or ranges.

   Eg. three separate entries 1: 2: 3: become one entry 1..3:  */

void
group_case_nodes (head)
     case_node_ptr head;
{
  case_node_ptr node = head;

  while (node)
    {
      rtx lb = next_real_insn (label_rtx (node->code_label));
      case_node_ptr np = node;

      /* Try to group the successors of NODE with NODE.  */
      while (((np = np->right) != 0)
	     /* Do they jump to the same place?  */
	     && next_real_insn (label_rtx (np->code_label)) == lb
	     /* Are their ranges consecutive?  */
	     && tree_int_cst_equal (np->low,
				    combine (PLUS_EXPR, node->high,
					     build_int_2 (1, 0))))
	{
	  node->high = np->high;
	}
      /* NP is the first node after NODE which can't be grouped with it.
	 Delete the nodes in between, and move on to that node.  */
      node->right = np;
      node = np;
    }
}

/* Take an ordered list of case nodes
   and transform them into a near optimal binary tree,
   on the assumtion that any target code selection value is as
   likely as any other.

   The transformation is performed by splitting the ordered
   list into two equal sections plus a pivot.  The parts are
   then attached to the pivot as left and right branches.  Each
   branch is is then transformed recursively.  */

void
balance_case_nodes (head, parent)
     case_node_ptr *head;
     case_node_ptr parent;
{
  register case_node_ptr np;

  np = *head;
  if (np)
    {
      int cost = 0;
      int i = 0;
      int ranges = 0;
      register case_node_ptr *npp;
      case_node_ptr left;

      /* Count the number of entries on branch.
	 Also count the ranges.  */
      while (np)
	{
	  if (!tree_int_cst_equal (np->low, np->high))
	    {
	      ranges++;
	      if (use_cost_table)
		{
		  int hi_cost = cost_table[TREE_INT_CST_LOW (np->high)];
		  if (hi_cost < 0)
		    use_cost_table = 0;
		  else
		    cost += hi_cost;
		}
	    }
	  if (use_cost_table)
	    {
	      int lo_cost = cost_table[TREE_INT_CST_LOW (np->low)];
	      if (lo_cost < 0)
		use_cost_table = 0;
	      else
		cost += lo_cost;
	    }
	  else
	    cost += 1;
	  i++;
	  np = np->right;
	}
      if (i > 2)
	{
	  /* Split this list if it is long enough for that to help.  */
	  npp = head;
	  left = *npp;
	  if (use_cost_table)
	    {
	      /* Find the place in the list that bisects the list's total cost,
		 Here I gets half the total cost.  */
	      int n_moved = 0;
	      i = (cost + 1) / 2;
	      while (1)
		{
		  /* Skip nodes while their cost does not reach that amount.  */
		  if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
		    i -= cost_table[TREE_INT_CST_LOW ((*npp)->high)];
		  i -= cost_table[TREE_INT_CST_LOW ((*npp)->low)];
		  if (i <= 0)
		    break;
		  npp = &(*npp)->right;
		  n_moved += 1;
		}
	      if (n_moved == 0)
		{
		  /* Leave this branch lopsided, but optimize left-hand
		     side and fill in `parent' fields for right-hand side.  */
		  np = *head;
		  np->parent = parent;
		  balance_case_nodes (&np->left, np);
		  for (; np->right; np = np->right)
		    np->right->parent = np;
		  return;
		}
	    }
	  /* If there are just three nodes, split at the middle one.  */
	  else if (i == 3)
	    npp = &(*npp)->right;
	  else
	    {
	      /* Find the place in the list that bisects the list's total cost,
		 where ranges count as 2.
		 Here I gets half the total cost.  */
	      i = (i + ranges + 1) / 2;
	      while (1)
		{
		  /* Skip nodes while their cost does not reach that amount.  */
		  if (!tree_int_cst_equal ((*npp)->low, (*npp)->high))
		    i--;
		  i--;
		  if (i <= 0)
		    break;
		  npp = &(*npp)->right;
		}
	    }
	  *head = np = *npp;
	  *npp = 0;
	  np->parent = parent;
	  np->left = left;

	  /* Optimize each of the two split parts.  */
	  balance_case_nodes (&np->left, np);
	  balance_case_nodes (&np->right, np);
	}
      else
	{
	  /* Else leave this branch as one level,
	     but fill in `parent' fields.  */
	  np = *head;
	  np->parent = parent;
	  for (; np->right; np = np->right)
	    np->right->parent = np;
	}
    }
}

/* Search the parent sections of the case node tree
   to see if a test for the lower bound of NODE would be redundant.

   The instructions to synthesis the case decision tree are
   output in the same order as nodes are processed so it is
   known that if a parent node checks the range of the current
   node minus one that the current node is bounded at its lower
   span.  Thus the test would be redundant.  */

static int
node_has_low_bound (node)
     case_node_ptr node;
{
  tree low_minus_one;
  case_node_ptr pnode;

  if (node->left)
    {
      low_minus_one = combine (MINUS_EXPR, node->low, build_int_2 (1, 0));
      /* Avoid the screw case of overflow where low_minus_one is > low.  */
      if (tree_int_cst_lt (low_minus_one, node->low))
	for (pnode = node->parent; pnode; pnode = pnode->parent)
	  {
	    if (tree_int_cst_equal (low_minus_one, pnode->high))
	      return 1;
	    /* If a parent node has a left branch we know that none
	       of its parents can have a high bound of our target
	       minus one so we abort the search.  */
	    if (node->left)
	      break;
	  }
    }
  return 0;
}

/* Search the parent sections of the case node tree
   to see if a test for the upper bound of NODE would be redundant.

   The instructions to synthesis the case decision tree are
   output in the same order as nodes are processed so it is
   known that if a parent node checks the range of the current
   node plus one that the current node is bounded at its upper
   span.  Thus the test would be redundant.  */

static int
node_has_high_bound (node)
     case_node_ptr node;
{
  tree high_plus_one;
  case_node_ptr pnode;

  if (node->right == 0)
    {
      high_plus_one = combine (PLUS_EXPR, node->high, build_int_2 (1, 0));
      /* Avoid the screw case of overflow where high_plus_one is > high.  */
      if (tree_int_cst_lt (node->high, high_plus_one))
	for (pnode = node->parent; pnode; pnode = pnode->parent)
	  {
	    if (tree_int_cst_equal (high_plus_one, pnode->low))
	      return 1;
	    /* If a parent node has a right branch we know that none
	       of its parents can have a low bound of our target
	       plus one so we abort the search.  */
	    if (node->right)
	      break;
	  }
    }
  return 0;
}

/* Search the parent sections of the
   case node tree to see if both tests for the upper and lower
   bounds of NODE would be redundant.  */

static int
node_is_bounded (node)
     case_node_ptr node;
{
  if (node->left || node->right)
    return 0;
  return node_has_low_bound (node) && node_has_high_bound (node);
}

/*  Emit an unconditional jump to LABEL unless it would be dead code.  */

void
emit_jump_if_reachable (label)
     rtx label;
{
  rtx last_insn;

  if (GET_CODE (get_last_insn ()) != BARRIER)
    emit_jump (label);
}

/* Emit step-by-step code to select a case for the value of INDEX.
   The thus generated decision tree follows the form of the
   case-node binary tree NODE, whose nodes represent test conditions.
   UNSIGNEDP is nonzero if we should do unsigned comparisons.

   Care is taken to prune redundant tests from the decision tree
   by detecting any boundary conditions already checked by
   emitted rtx.  (See node_has_high_bound, node_has_low_bound
   and node_is_bounded, above.)

   Where the test conditions can be shown to be redundant we emit
   an unconditional jump to the target code.  As a further
   optimization, the subordinates of a tree node are examined to
   check for bounded nodes.  In this case conditional and/or
   unconditional jumps as a result of the boundary check for the
   current node are arranged to target the subordinates associated
   code for out of bound conditions on the current node node.  */

void
emit_case_nodes (index, node, default_label, unsignedp)
     rtx index;
     case_node_ptr node;
     rtx default_label;
     int unsignedp;
{
  /* If INDEX has an unsigned type, we must make unsigned branches.  */
  typedef rtx rtx_function ();
  rtx_function *gen_bgt_pat = unsignedp ? gen_bgtu : gen_bgt;
  rtx_function *gen_bge_pat = unsignedp ? gen_bgeu : gen_bge;
  rtx_function *gen_blt_pat = unsignedp ? gen_bltu : gen_blt;
  rtx_function *gen_ble_pat = unsignedp ? gen_bleu : gen_ble;
  int defaulted_left = 0;
  int defaulted_right = 0;

  if (node->test_label)
    {
      /* If this test node requires a label it follows that
	 it must be preceeded by an unconditional branch.
	 If control can pass to this point we can assume that
	 a "br default" is in order.  */
      emit_jump_if_reachable (default_label);
      expand_label (node->test_label);
    }
  if (tree_int_cst_equal (node->low, node->high))
    {
      /* Node is single valued.  */
      do_jump_if_equal (index, expand_expr (node->low, 0, VOIDmode, 0),
			label_rtx (node->code_label), unsignedp);
      if (node->right)
	{
	  if (node->left)
	    {
	      /* This node has children on either side.  */
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);

	      if (node_is_bounded (node->right))
		{
		  emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label)));
		  if (node_is_bounded (node->left))
		    emit_jump (label_rtx (node->left->code_label));
		  else
		    emit_case_nodes (index, node->left,
				     default_label, unsignedp);
		}
	      else
		{
		  if (node_is_bounded (node->left))
		    emit_jump_insn ((*gen_blt_pat) (label_rtx (node->left->code_label)));
		  else
		    {
		      node->right->test_label =
			build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
		      emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->test_label)));
		      emit_case_nodes (index, node->left,
				       default_label, unsignedp);
		    }
		  emit_case_nodes (index, node->right,
				   default_label, unsignedp);
		}
	    }
	  else
	    {
	      /* Here we have a right child but no left
		 so we issue conditional branch to default
		 and process the right child.  */

	      /* Omit the conditional branch to default
		 if we it avoid only one right child;
		 it costs too much space to save so little time.  */
	      if (node->right->right && !node_has_low_bound (node))
		{
		  emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
		  emit_jump_insn ((*gen_blt_pat) (default_label));
		}
	      if (node_is_bounded (node->right))
		emit_jump (label_rtx (node->right->code_label));
	      else
		emit_case_nodes (index, node->right, default_label, unsignedp);
	    }
	}
      else if (node->left)
	{
	  if (use_cost_table
	      && ! defaulted_right
	      && cost_table[TREE_INT_CST_LOW (node->high)] < 12)
	    {
	      /* If our "most probably entry" is less probable
		 than the default label, emit a jump to
		 the default label using condition codes
		 already lying around.  With no right branch,
		 a branch-greater-than will get us to the default
		 label correctly.  */
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_bgt_pat) (default_label));
	      /* No sense doing this too often.  */
	      defaulted_right = 1;
	    }
	  if (node_is_bounded (node->left))
	    emit_jump (label_rtx (node->left->code_label));
	  else
	    emit_case_nodes (index, node->left, default_label, unsignedp);
	}
    }
  else
    {
      /* Node is a range.  */
      if (node->right)
	{
	  if (node->left)
	    {
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
	      if (node_is_bounded (node->right))
		{
		  /* Right hand node is fully bounded so we can
		     eliminate any testing and branch directly
		     to the target code.  */
		  emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->code_label)));
		}
	      else
		{
		  /* Right hand node requires testing so create
		     a label to put on the cmp code.  */
		  node->right->test_label =
		    build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
		  emit_jump_insn ((*gen_bgt_pat) (label_rtx (node->right->test_label)));
		}
	      emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
	      if (node_is_bounded (node->left))
		{
		  /* Left hand node is fully bounded so we can
		     eliminate any testing and branch directly
		     to the target code.  */
		  emit_jump (label_rtx (node->left->code_label));
		}
	      else
		emit_case_nodes (index, node->left, default_label, unsignedp);
	      /* If right node has been given a test label above
		 we must process it now.  */
	      if (node->right->test_label)
		emit_case_nodes (index, node->right, default_label, unsignedp);
	    }
	  else
	    {
	      if (!node_has_low_bound (node))
		{
		  emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0);
		  emit_jump_insn ((*gen_blt_pat) (default_label));
		}
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_ble_pat) (label_rtx (node->code_label)));
	      if (node_is_bounded (node->right))
		{
		  /* Right hand node is fully bounded so we can
		     eliminate any testing and branch directly
		     to the target code.  */
		  emit_jump (label_rtx (node->right->code_label));
		}
	      else
		emit_case_nodes (index, node->right, default_label, unsignedp);
	    }
	}
      else if (node->left)
	{
	  if (!node_has_high_bound (node))
	    {
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_bgt_pat) (default_label));
	    }
	  emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0);
	  emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
	  if (node_is_bounded (node->left))
	    {
	      /* Left hand node is fully bounded so we can
		 eliminate any testing and branch directly
		 to the target code.  */
	      emit_jump (label_rtx (node->left->code_label));
	    }
	  else
	    emit_case_nodes (index, node->left, default_label, unsignedp);
	}
      else
	{
	  /* Node has no children so we check low and
	     high bounds to remove redundant tests. In practice
	     only one of the limits may be bounded or the parent
	     node will have emmited a jump to our target code.  */
	  if (!node_has_high_bound (node))
	    {
	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_bgt_pat) (default_label));
	    }
	  if (!node_has_low_bound (node))
	    {
	      emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, unsignedp, 0);
	      emit_jump_insn ((*gen_bge_pat) (label_rtx (node->code_label)));
	    }
	  /* We allow the default case to drop through since
	     it will picked up by calls to `jump_if_reachable'
	     either on the next test label or at the end of
	     the decision tree emission.  */
	}
    }
}

