[gnu.gcc.bug] Unsigned index for case statement generates incorrect comparisons

keith@EXPO.LCS.MIT.EDU (Keith Packard) (01/22/89)

Version:
	gcc version 1.32, ftp'd from prep Sat Jan 21, 1989.

Synopsis:
	Unsigned expression indexing case statements can generate incorrect
	comparison branches.

Description:
	The case statement has added comparisons to reduce the
	number of tests.  When the comparisons contain -MAXINT,
	the sense of the test is inverted.

From:
	Keith Packard
	keith@expo.lcs.mit.edu

Repeat by:
	unsigned long	l;
	
	f ()
	{
		switch (l) {
		case 0x80000000:
			return 2;
		case 0x70000000:
			return 0;
		case 0x50000000:
			return 1;
		default:
			return 3;
		}
	}
	
	gcc -O -S test.c
	
	#NO_APP
	gcc_compiled.:
	.text
		.even
	.globl _f
	_f:
		link a6,#0
		movel _l,d0
		cmpl #1879048192,d0
		jeq L4
	/*
 	 * this next comparison should be unsigned as the destination
 	 * fork tests for 0x80000000.  The sun assembler converts
 	 * this to
 		bgts L8
 	 */
		jgt L8
		cmpl #1342177280,d0
		jeq L5
		jra L6
	L8:
		cmpl #-2147483648,d0
		jne L6
		moveq #2,d0
		jra L1
	L4:
		clrl d0
		jra L1
	L5:
		moveq #1,d0
		jra L1
	L6:
		moveq #3,d0
	L1:
		unlk a6
		rts
	.comm _l,4
	
Fix:

	The trouble lies in expand_end_case.  It was assuming that the index
	expression was of signed type.  In the example, this is not so.
	Here is an obvious fix; perhaps a more correct solution exists as
	well?

*** /tmp/,RCSt1a04922	Sun Jan 22 00:43:05 1989
--- stmt.c	Sun Jan 22 00:34:50 1989
***************
*** 2194,2199 ****
--- 2194,2200 ----
    rtx before_case;
    register struct nesting *thiscase = case_stack;
    tree index_expr = thiscase->data.case_stmt.index_expr;
+   int unsigned_case;
  
    do_pending_stack_adjust ();
  
***************
*** 2218,2223 ****
--- 2219,2227 ----
        /* Get upper and lower bounds of case values.
  	 Also convert all the case values to the index expr's data type.  */
  
+       unsigned_case = 0;
+       if (TREE_TYPE (index_expr)->common.unsigned_attr)
+ 	unsigned_case = 1;
        count = 0;
        for (n = thiscase->data.case_stmt.case_list; n; n = n->right)
  	{
***************
*** 2239,2247 ****
  	    }
  	  else
  	    {
! 	      if (INT_CST_LT (n->low, minval))
  		minval = n->low;
! 	      if (INT_CST_LT (maxval, n->high))
  		maxval = n->high;
  	    }
  	  /* A range counts double, since it requires two compares.  */
--- 2243,2255 ----
  	    }
  	  else
  	    {
! 	      if (unsigned_case ?
! 	          INT_CST_LT_UNSIGNED (n->low, minval) :
! 	          INT_CST_LT (n->low, minval))
  		minval = n->low;
! 	      if (unsigned_case ?
! 		  INT_CST_LT_UNSIGNED (maxval, n->high) :
! 	          INT_CST_LT (maxval, n->high))
  		maxval = n->high;
  	    }
  	  /* A range counts double, since it requires two compares.  */
***************
*** 2318,2324 ****
  		 default code is emitted.  */
  	      balance_case_nodes (&thiscase->data.case_stmt.case_list, 0);
  	      emit_case_nodes (index, thiscase->data.case_stmt.case_list,
! 			       default_label);
  	      emit_jump_if_reachable (default_label);
  	    }
  	}
--- 2326,2332 ----
  		 default code is emitted.  */
  	      balance_case_nodes (&thiscase->data.case_stmt.case_list, 0);
  	      emit_case_nodes (index, thiscase->data.case_stmt.case_list,
! 			       default_label, unsigned_case);
  	      emit_jump_if_reachable (default_label);
  	    }
  	}
***************
*** 2656,2666 ****
     code for out of bound conditions on the current node node.  */
  
  static void
! emit_case_nodes (index, node, default_label)
       tree index;
       case_node_ptr node;
       tree default_label;
  {
    if (node->test_label)
      {
        /* If this test node requires a label it follows that
--- 2664,2685 ----
     code for out of bound conditions on the current node node.  */
  
  static void
! emit_case_nodes (index, node, default_label, unsigned_case)
       tree index;
       case_node_ptr node;
       tree default_label;
+      int unsigned_case;
  {
+   rtx	(*bgt)(), (*blt)(), (*bge)(), (*ble)();
+   extern rtx	gen_bgt (), gen_bgtu (),
+ 		gen_blt (), gen_bltu (),
+ 		gen_bge (), gen_bgeu (),
+ 		gen_ble (), gen_bleu ();
+ 
+   bgt = unsigned_case ? gen_bgtu : gen_bgt;
+   blt = unsigned_case ? gen_bltu : gen_blt;
+   bge = unsigned_case ? gen_bgeu : gen_bge;
+   ble = unsigned_case ? gen_bleu : gen_ble;
    if (node->test_label)
      {
        /* If this test node requires a label it follows that
***************
*** 2683,2689 ****
  
  	      if (node_is_bounded (node->right))
  		{
! 		  emit_jump_insn (gen_bgt (label_rtx (node->right->code_label)));
  		  if (node_is_bounded (node->left))
  		    emit_jump (label_rtx (node->left->code_label));
  		  else
--- 2702,2708 ----
  
  	      if (node_is_bounded (node->right))
  		{
! 		  emit_jump_insn ((*bgt) (label_rtx (node->right->code_label)));
  		  if (node_is_bounded (node->left))
  		    emit_jump (label_rtx (node->left->code_label));
  		  else
***************
*** 2692,2703 ****
  	      else
  		{
  		  if (node_is_bounded (node->left))
! 		    emit_jump_insn (gen_blt (label_rtx (node->left->code_label)));
  		  else
  		    {
  		      node->right->test_label =
  			build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! 		      emit_jump_insn (gen_bgt (label_rtx (node->right->test_label)));
  		      emit_case_nodes (index, node->left, default_label);
  		    }
  		  emit_case_nodes (index, node->right, default_label);
--- 2711,2722 ----
  	      else
  		{
  		  if (node_is_bounded (node->left))
! 		    emit_jump_insn ((*blt) (label_rtx (node->left->code_label)));
  		  else
  		    {
  		      node->right->test_label =
  			build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! 		      emit_jump_insn ((*bgt) (label_rtx (node->right->test_label)));
  		      emit_case_nodes (index, node->left, default_label);
  		    }
  		  emit_case_nodes (index, node->right, default_label);
***************
*** 2713,2719 ****
  		 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_jump_insn (gen_blt (default_label));
  	      if (node_is_bounded (node->right))
  		emit_jump (label_rtx (node->right->code_label));
  	      else
--- 2732,2738 ----
  		 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_jump_insn ((*blt) (default_label));
  	      if (node_is_bounded (node->right))
  		emit_jump (label_rtx (node->right->code_label));
  	      else
***************
*** 2741,2747 ****
  		  /* Right hand node is fully bounded so we can
  		     eliminate any testing and branch directly
  		     to the target code.  */
! 		  emit_jump_insn (gen_bgt (label_rtx (node->right->code_label)));
  		}
  	      else
  		{
--- 2760,2766 ----
  		  /* Right hand node is fully bounded so we can
  		     eliminate any testing and branch directly
  		     to the target code.  */
! 		  emit_jump_insn ((*bgt) (label_rtx (node->right->code_label)));
  		}
  	      else
  		{
***************
*** 2749,2758 ****
  		     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 (label_rtx (node->right->test_label)));
  		}
  	      emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! 	      emit_jump_insn (gen_bge (label_rtx (node->code_label)));
  	      if (node_is_bounded (node->left))
  		{
  		  /* Left hand node is fully bounded so we can
--- 2768,2777 ----
  		     a label to put on the cmp code.  */
  		  node->right->test_label =
  		    build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
! 		  emit_jump_insn ((*bgt) (label_rtx (node->right->test_label)));
  		}
  	      emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! 	      emit_jump_insn ((*bge) (label_rtx (node->code_label)));
  	      if (node_is_bounded (node->left))
  		{
  		  /* Left hand node is fully bounded so we can
***************
*** 2772,2781 ****
  	      if (!node_has_low_bound (node))
  		{
  		  emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! 		  emit_jump_insn (gen_blt (default_label));
  		}
  	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, 0);
! 	      emit_jump_insn (gen_ble (label_rtx (node->code_label)));
  	      if (node_is_bounded (node->right))
  		{
  		  /* Right hand node is fully bounded so we can
--- 2791,2800 ----
  	      if (!node_has_low_bound (node))
  		{
  		  emit_cmp_insn (index, expand_expr (node->low, 0, VOIDmode, 0), 0, 0);
! 		  emit_jump_insn ((*blt) (default_label));
  		}
  	      emit_cmp_insn (index, expand_expr (node->high, 0, VOIDmode, 0), 0, 0);
! 	      emit_jump_insn ((*ble) (label_rtx (node->code_label)));
  	      if (node_is_bounded (node->right))
  		{
  		  /* Right hand node is fully bounded so we can