Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Apr 1998 11:52:42 +1000 (EST)
From:      Peter Jeremy <Peter.Jeremy@alcatel.com.au>
To:        bug-gcc@prep.ai.mit.edu
Cc:        freebsd-ports@FreeBSD.ORG
Subject:   gcc2.8.1 divide-by-constant optimisation causes call to __cmpdi2
Message-ID:  <199804130152.LAA00492@gsms01.alcatel.com.au>

next in thread | raw e-mail | index | archive | help
gcc version 2.8.1 for i386-unknown-freebsd2.2.5 and sparc-sun-solaris2.5

Sample input file (testcase.i):
---
int test_int_ll(long long val)
{
	return (val / 256);
}
---
Compile in the gcc build directory using:
	./cc1 testcase.i -g
The problem is not affected by the use of -O2.

Compiler was configured on a FreeBSD 2.2.5R system using `./configure'
using the standard gcc 2.8.0 + 2.8.0->2.8.1 patches.

Compiler was configured on a Solaris 2.5.1 system in a subdirectory
of gcc-2.8.1 using
`../configure  --with-gnu-ld --with-gnu-as --build=sparc-sun-solaris2.5'.

The compiler recognizes the use of a power-of-2 constant as the
denominator in the above division and expands it inline to a shift.
This requires special handling for negative numerators and so the
expanded code includes a comparison.  In the case of long long
division, the comparison is not explicitly open-coded (unlike the
relational comparison expansions).

The problem is fixed for FreeBSD using the following patch.  This patch
has not been tested on Solaris 2.x:
--
*** ChangeLog~	Sat Mar 28 08:03:41 1998
--- ChangeLog	Sat Apr 11 09:09:50 1998
***************
*** 1,3 ****
--- 1,14 ----
+ Sat Apr 11 08:56:35 1998  Peter Jeremy  <peter.jeremy@alcatel.com.au>
+ 
+ 	* expr.c (do_jump_by_parts_equality_rtx): Make function public
+ 	so it can be referenced from expmed.c.
+ 
+ 	* expmed.c (do_cmp_and_jump): New function based on multi-word
+ 	comparison handling in expr.c:do_jump().
+ 
+ 	* expmed.c (expand_divmod): convert emit_cmp_insn/emit_jump_insn
+ 	sequences to do_cmp_and_jump so multi-word modes are in-lined.
+ 
  Mon Mar  2 08:06:58 1998  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>

	 * Version 2.8.1 released.
*** expmed.c~	Sun Nov  9 09:11:58 1997
--- expmed.c	Sat Apr 11 09:15:53 1998
*************** static rtx mask_rtx			PROTO((enum machin
*** 41,46 ****
--- 41,48 ----
  static rtx lshift_value			PROTO((enum machine_mode, rtx,
						int, int));
  static rtx extract_split_bit_field	PROTO((rtx, int, int, int, int));
+ static void do_cmp_and_jump		PROTO((rtx, rtx, enum rtx_code,
+ 					       enum machine_mode, rtx));

  #define CEIL(x,y) (((x) + (y) - 1) / (y))

*************** expand_divmod (rem_flag, code, mode, op0
*** 3027,3035 ****
			 rtx t1;

			 t1 = copy_to_mode_reg (compute_mode, op0);
! 			emit_cmp_insn (t1, const0_rtx, GE, 
! 				       NULL_RTX, compute_mode, 0, 0);
! 			emit_jump_insn (gen_bge (label));
			 expand_inc (t1, GEN_INT (abs_d - 1));
			 emit_label (label);
			 quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
--- 3029,3036 ----
			 rtx t1;

			 t1 = copy_to_mode_reg (compute_mode, op0);
! 			do_cmp_and_jump (t1, const0_rtx, GE, compute_mode,
! 					 label);
			 expand_inc (t1, GEN_INT (abs_d - 1));
			 emit_label (label);
			 quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
*************** expand_divmod (rem_flag, code, mode, op0
*** 3255,3267 ****
		Save that for later.  */
	     rtx tem;
	     rtx label = gen_label_rtx ();
! 	    emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
! 			   compute_mode, 0, 0);
! 	    emit_jump_insn (gen_beq (label));
	     tem = expand_binop (compute_mode, xor_optab, op0, op1,
				 NULL_RTX, 0, OPTAB_WIDEN);
! 	    emit_cmp_insn (tem, const0_rtx, GE, NULL_RTX, compute_mode, 0, 0);
! 	    emit_jump_insn (gen_bge (label));
	     expand_dec (quotient, const1_rtx);
	     expand_inc (remainder, op1);
	     emit_label (label);
--- 3256,3265 ----
		Save that for later.  */
	     rtx tem;
	     rtx label = gen_label_rtx ();
! 	    do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label);
	     tem = expand_binop (compute_mode, xor_optab, op0, op1,
				 NULL_RTX, 0, OPTAB_WIDEN);
! 	    do_cmp_and_jump (tem, const0_rtx, GE, compute_mode, label);
	     expand_dec (quotient, const1_rtx);
	     expand_inc (remainder, op1);
	     emit_label (label);
*************** expand_divmod (rem_flag, code, mode, op0
*** 3282,3292 ****
	   label3 = gen_label_rtx ();
	   label4 = gen_label_rtx ();
	   label5 = gen_label_rtx ();
! 	  emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, compute_mode, 0, 0);
	   emit_jump_insn (gen_blt (label2));
! 	  emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX,
! 			 compute_mode, 0, 0);
! 	  emit_jump_insn (gen_blt (label1));
	   tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
			       quotient, 0, OPTAB_LIB_WIDEN);
	   if (tem != quotient)
--- 3280,3288 ----
	   label3 = gen_label_rtx ();
	   label4 = gen_label_rtx ();
	   label5 = gen_label_rtx ();
! 	  do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
	   emit_jump_insn (gen_blt (label2));
! 	  do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, label1);
	   tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
			       quotient, 0, OPTAB_LIB_WIDEN);
	   if (tem != quotient)
*************** expand_divmod (rem_flag, code, mode, op0
*** 3298,3306 ****
	   emit_jump_insn (gen_jump (label4));
	   emit_barrier ();
	   emit_label (label2);
! 	  emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX,
! 			 compute_mode, 0, 0);
! 	  emit_jump_insn (gen_bgt (label3));
	   tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
			       quotient, 0, OPTAB_LIB_WIDEN);
	   if (tem != quotient)
--- 3294,3300 ----
	   emit_jump_insn (gen_jump (label4));
	   emit_barrier ();
	   emit_label (label2);
! 	  do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, label3);
	   tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
			       quotient, 0, OPTAB_LIB_WIDEN);
	   if (tem != quotient)
*************** expand_divmod (rem_flag, code, mode, op0
*** 3340,3348 ****
		   {
		     rtx lab;
		     lab = gen_label_rtx ();
! 		    emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX,
! 				   compute_mode, 0, 0);
! 		    emit_jump_insn (gen_beq (lab));
		     expand_inc (t1, const1_rtx);
		     emit_label (lab);
		     quotient = t1;
--- 3334,3340 ----
		   {
		     rtx lab;
		     lab = gen_label_rtx ();
! 		    do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
		     expand_inc (t1, const1_rtx);
		     emit_label (lab);
		     quotient = t1;
*************** expand_divmod (rem_flag, code, mode, op0
*** 3381,3389 ****
		 /* This could be computed with a branch-less sequence.
		    Save that for later.  */
		 rtx label = gen_label_rtx ();
! 		emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
! 			       compute_mode, 0, 0);
! 		emit_jump_insn (gen_beq (label));
		 expand_inc (quotient, const1_rtx);
		 expand_dec (remainder, op1);
		 emit_label (label);
--- 3373,3380 ----
		 /* This could be computed with a branch-less sequence.
		    Save that for later.  */
		 rtx label = gen_label_rtx ();
! 		do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode,
! 				 label);
		 expand_inc (quotient, const1_rtx);
		 expand_dec (remainder, op1);
		 emit_label (label);
*************** expand_divmod (rem_flag, code, mode, op0
*** 3400,3408 ****
	       adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
	       label1 = gen_label_rtx ();
	       label2 = gen_label_rtx ();
! 	      emit_cmp_insn (adjusted_op0, const0_rtx, NE, NULL_RTX,
! 			     compute_mode, 0, 0);
! 	      emit_jump_insn (gen_bne (label1));
	       emit_move_insn  (quotient, const0_rtx);
	       emit_jump_insn (gen_jump (label2));
	       emit_barrier ();
--- 3391,3398 ----
	       adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
	       label1 = gen_label_rtx ();
	       label2 = gen_label_rtx ();
! 	      do_cmp_and_jump (adjusted_op0, const0_rtx, NE, compute_mode,
! 			       label1);
	       emit_move_insn  (quotient, const0_rtx);
	       emit_jump_insn (gen_jump (label2));
	       emit_barrier ();
*************** expand_divmod (rem_flag, code, mode, op0
*** 3442,3450 ****
		   {
		     rtx lab;
		     lab = gen_label_rtx ();
! 		    emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX,
! 				   compute_mode, 0, 0);
! 		    emit_jump_insn (gen_beq (lab));
		     expand_inc (t1, const1_rtx);
		     emit_label (lab);
		     quotient = t1;
--- 3432,3438 ----
		   {
		     rtx lab;
		     lab = gen_label_rtx ();
! 		    do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
		     expand_inc (t1, const1_rtx);
		     emit_label (lab);
		     quotient = t1;
*************** expand_divmod (rem_flag, code, mode, op0
*** 3483,3496 ****
		    Save that for later.  */
		 rtx tem;
		 rtx label = gen_label_rtx ();
! 		emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
! 			       compute_mode, 0, 0);
! 		emit_jump_insn (gen_beq (label));
		 tem = expand_binop (compute_mode, xor_optab, op0, op1,
				     NULL_RTX, 0, OPTAB_WIDEN);
! 		emit_cmp_insn (tem, const0_rtx, LT, NULL_RTX,
! 			       compute_mode, 0, 0);
! 		emit_jump_insn (gen_blt (label));
		 expand_inc (quotient, const1_rtx);
		 expand_dec (remainder, op1);
		 emit_label (label);
--- 3471,3481 ----
		    Save that for later.  */
		 rtx tem;
		 rtx label = gen_label_rtx ();
! 		do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode,
! 				 label);
		 tem = expand_binop (compute_mode, xor_optab, op0, op1,
				     NULL_RTX, 0, OPTAB_WIDEN);
! 		do_cmp_and_jump (tem, const0_rtx, LT, compute_mode, label);
		 expand_inc (quotient, const1_rtx);
		 expand_dec (remainder, op1);
		 emit_label (label);
*************** expand_divmod (rem_flag, code, mode, op0
*** 3511,3522 ****
	       label3 = gen_label_rtx ();
	       label4 = gen_label_rtx ();
	       label5 = gen_label_rtx ();
! 	      emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX,
! 			     compute_mode, 0, 0);
! 	      emit_jump_insn (gen_blt (label2));
! 	      emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX,
! 			     compute_mode, 0, 0);
! 	      emit_jump_insn (gen_bgt (label1));
	       tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
				   quotient, 0, OPTAB_LIB_WIDEN);
	       if (tem != quotient)
--- 3496,3504 ----
	       label3 = gen_label_rtx ();
	       label4 = gen_label_rtx ();
	       label5 = gen_label_rtx ();
! 	      do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
! 	      do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode,
! 			       label1);
	       tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
				   quotient, 0, OPTAB_LIB_WIDEN);
	       if (tem != quotient)
*************** expand_divmod (rem_flag, code, mode, op0
*** 3528,3536 ****
	       emit_jump_insn (gen_jump (label4));
	       emit_barrier ();
	       emit_label (label2);
! 	      emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX,
! 			     compute_mode, 0, 0);
! 	      emit_jump_insn (gen_blt (label3));
	       tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
				   quotient, 0, OPTAB_LIB_WIDEN);
	       if (tem != quotient)
--- 3510,3517 ----
	       emit_jump_insn (gen_jump (label4));
	       emit_barrier ();
	       emit_label (label2);
! 	      do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode,
! 			       label3);
	       tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
				   quotient, 0, OPTAB_LIB_WIDEN);
	       if (tem != quotient)
*************** expand_divmod (rem_flag, code, mode, op0
*** 3596,3603 ****
	     tem = plus_constant (op1, -1);
	     tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
				 build_int_2 (1, 0), NULL_RTX, 1);
! 	    emit_cmp_insn (remainder, tem, LEU, NULL_RTX, compute_mode, 0, 0);
! 	    emit_jump_insn (gen_bleu (label));
	     expand_inc (quotient, const1_rtx);
	     expand_dec (remainder, op1);
	     emit_label (label);
--- 3577,3583 ----
	     tem = plus_constant (op1, -1);
	     tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
				 build_int_2 (1, 0), NULL_RTX, 1);
! 	    do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
	     expand_inc (quotient, const1_rtx);
	     expand_dec (remainder, op1);
	     emit_label (label);
*************** expand_divmod (rem_flag, code, mode, op0
*** 3622,3629 ****
	     abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0);
	     tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
				 build_int_2 (1, 0), NULL_RTX, 1);
! 	    emit_cmp_insn (tem, abs_op1, LTU, NULL_RTX, compute_mode, 0, 0);
! 	    emit_jump_insn (gen_bltu (label));
	     tem = expand_binop (compute_mode, xor_optab, op0, op1,
				 NULL_RTX, 0, OPTAB_WIDEN);
	     mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
--- 3602,3608 ----
	     abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0);
	     tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
				 build_int_2 (1, 0), NULL_RTX, 1);
! 	    do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
	     tem = expand_binop (compute_mode, xor_optab, op0, op1,
				 NULL_RTX, 0, OPTAB_WIDEN);
	     mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
*************** emit_store_flag_force (target, code, op0
*** 4327,4330 ****
--- 4306,4383 ----
    emit_label (label);

    return target;
+ }
+ 
+ 
+ /* Perform possibly multi-word comparison and conditional jump as follows:
+  * if (ARG1 OP ARG2) goto LABEL
+  * where ARG1 and ARG2 are of mode MODE
+  *
+  * The algorithm is based on the code in expr.c:do_jump().
+  *
+  * Note that this does not perform a general comparison.  Only variants
+  * generated within expmed.c are correctly handled, others abort (but could
+  * be handled if needed).
+  */
+ static void
+ do_cmp_and_jump (arg1, arg2, op, mode, label)
+     rtx	arg1, arg2, label;
+     enum rtx_code op;
+     enum machine_mode mode;
+ {
+   /* If this mode is an integer too wide to compare properly,
+      compare word by word.  Rely on cse to optimize constant cases.  */
+   if (GET_MODE_CLASS (mode) == MODE_INT && !can_compare_p (mode))
+     {
+       rtx label2 = gen_label_rtx ();
+ 
+       switch (op)
+ 	{
+ 	case LTU:
+ 	  do_jump_by_parts_greater_rtx (mode, 1, arg2, arg1, label2, label);
+ 	  break;
+ 
+ 	case LEU:
+ 	  do_jump_by_parts_greater_rtx (mode, 1, arg1, arg2, label, label2);
+ 	  break;
+ 
+ 	case LT:
+ 	  do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label2, label);
+ 	  break;
+ 
+ 	case GT:
+ 	  do_jump_by_parts_greater_rtx (mode, 0, arg1, arg2, label2, label);
+ 	  break;
+ 
+ 	case GE:
+ 	  do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label, label2);
+ 	  break;
+ 
+ 	  /* do_jump_by_parts_equality_rtx() compares with zero.  Luckily
+ 	   * that's the only equality operations we do */
+ 	case EQ:
+ 	  if (arg2 != const0_rtx || mode != GET_MODE(arg1))
+ 	    abort();
+ 	  do_jump_by_parts_equality_rtx (arg1, label2, label);
+ 	  break;
+ 
+ 	case NE:
+ 	  if (arg2 != const0_rtx || mode != GET_MODE(arg1))
+ 	    abort();
+ 	  do_jump_by_parts_equality_rtx (arg1, label, label2);
+ 	  break;
+ 
+ 	default:
+ 	  abort();
+ 	}
+ 
+       emit_label (label2);
+     }
+   else
+     {
+       emit_cmp_insn(arg1, arg2, op, NULL_RTX, mode, 0, 0);
+       if (bcc_gen_fctn[(int) op] == 0)
+ 	abort ();
+       emit_jump_insn ((*bcc_gen_fctn[(int) op]) (label));
+     }
  }
*** expr.c~	Sat Mar 28 08:04:29 1998
--- expr.c	Fri Apr 10 23:41:40 1998
*************** static void preexpand_calls	PROTO((tree)
*** 209,215 ****
  static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
  void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
  static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
! static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
  static void do_jump_for_compare	PROTO((rtx, rtx, rtx));
  static rtx compare		PROTO((tree, enum rtx_code, enum rtx_code));
  static rtx do_store_flag	PROTO((tree, rtx, enum machine_mode, int));
--- 209,215 ----
  static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
  void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
  static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
! void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
  static void do_jump_for_compare	PROTO((rtx, rtx, rtx));
  static rtx compare		PROTO((tree, enum rtx_code, enum rtx_code));
  static rtx do_store_flag	PROTO((tree, rtx, enum machine_mode, int));
*************** do_jump_by_parts_equality (exp, if_false
*** 10747,10753 ****
     We assume that OP0 has an integer mode that is too wide
     for the available compare insns.  */

! static void
  do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
	rtx op0;
	rtx if_false_label, if_true_label;
--- 10747,10753 ----
     We assume that OP0 has an integer mode that is too wide
     for the available compare insns.  */

! void
  do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
	rtx op0;
	rtx if_false_label, if_true_label;
---
Peter Jeremy (VK2PJ)			peter.jeremy@alcatel.com.au
Alcatel Australia Limited
41 Mandible St				Phone: +61 2 9690 5019
ALEXANDRIA  NSW  2015			Fax:   +61 2 9690 5247

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199804130152.LAA00492>