improve open-coding of complex divide, use new method in g77

craig@jcb-sc.com craig@jcb-sc.com
Tue May 18 01:06:00 GMT 1999


Committed.  [Jeff, if you've made the release branch before reading
this, please make sure this entire patch made it into that branch,
okay?  I'm 2.5 hours away from leaving for Raleigh, and probably won't
get time to verify that myself.]

        tq vm, (burley)


egcs/gcc/f/ChangeLog:
Tue May 18 03:52:04 1999  Craig Burley  <craig@jcb-sc.com>

	Support use of back end's improved open-coding of complex divide:
	* com.c (ffecom_tree_divide_): Use RDIV_EXPR for complex divide,
	instead of run-time call to [cz]_div, if `-Os' option specified.
	(lang_init_options): Tell back end we want support for wide range
	of inputs to complex divide.

	* Bump version.

*** g77-e/gcc/f/com.c.~1~	Thu May 13 17:06:48 1999
--- g77-e/gcc/f/com.c	Sun May 16 01:03:36 1999
*************** ffecom_tree_divide_ (tree tree_type, tre
*** 9379,9382 ****
--- 9379,9386 ----
  
      case COMPLEX_TYPE:
+       if (! optimize_size)
+ 	return ffecom_2 (RDIV_EXPR, tree_type,
+ 			 left,
+ 			 right);
        {
  	ffecomGfrt ix;
*************** lang_init_options ()
*** 15020,15023 ****
--- 15024,15028 ----
    flag_argument_noalias = 2;
    flag_errno_math = 0;
+   flag_complex_divide_method = 1;
  }
  
*** g77-e/gcc/f/version.c.~1~	Thu May 13 17:13:22 1999
--- g77-e/gcc/f/version.c	Sun May 16 01:03:39 1999
***************
*** 1 ****
! const char *ffe_version_string = "0.5.24-19990513";
--- 1 ----
! const char *ffe_version_string = "0.5.24-19990515";

egcs/gcc/ChangeLog:
Tue May 18 03:53:37 1999  Craig Burley  <craig@jcb-sc.com>

	Improve open-coding of complex divide:
	* flags.h: Declare new front-end-malleable flag.
	* toplev.c: Define new flag.
	* optabs.c (expand_cmplxdiv_straight): New function to do original
	open-coding.
	(expand_cmplxdiv_wide): New function to do new open-coding,
	from Toon Moene, with changes (call to emit_barrier, dropping
	of spurious `ok = 1;', plus the obvious `break;' -> `return 0;').
	(expand_binop): A bit of spacing fixing, while at it.
	Use new functions instead of inlining the open-coding code.

*** g77-e/gcc/flags.h.~1~	Mon May 10 23:25:29 1999
--- g77-e/gcc/flags.h	Sat May 15 21:34:21 1999
*************** extern int flag_fast_math;
*** 297,300 ****
--- 297,306 ----
  extern int flag_errno_math;
  
+ /* 0 means straightforward implementation of complex divide acceptable.
+    1 means wide ranges of inputs must work for complex divide.
+    2 means C9X-like requirements for complex divide (not yet implemented).  */
+ 
+ extern int flag_complex_divide_method;
+ 
  /* Nonzero means to run loop optimizations twice.  */
  
*** g77-e/gcc/optabs.c.~1~	Tue Apr 27 13:08:36 1999
--- g77-e/gcc/optabs.c	Sun May 16 01:09:07 1999
*************** static int add_equal_note	PROTO((rtx, rt
*** 247,250 ****
--- 247,258 ----
  static rtx widen_operand	PROTO((rtx, enum machine_mode,
  				       enum machine_mode, int, int));
+ static int expand_cmplxdiv_straight PROTO((rtx, rtx, rtx, rtx,
+ 					   rtx, rtx, enum machine_mode,
+ 					   int, enum optab_methods,
+ 					   enum mode_class, optab));
+ static int expand_cmplxdiv_wide PROTO((rtx, rtx, rtx, rtx,
+ 				       rtx, rtx, enum machine_mode,
+ 				       int, enum optab_methods,
+ 				       enum mode_class, optab));
  static enum insn_code can_fix_p	PROTO((enum machine_mode, enum machine_mode,
  				       int, int *));
*************** widen_operand (op, mode, oldmode, unsign
*** 349,352 ****
--- 357,719 ----
  }
  
+ /* Generate code to perform a straightforward complex divide.  */
+ 
+ static int
+ expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
+ 			  rtx realr, rtx imagr, enum machine_mode submode,
+ 			  int unsignedp, enum optab_methods methods,
+ 			  enum mode_class class, optab binoptab)
+ {
+   rtx divisor;
+   rtx real_t, imag_t;
+   rtx temp1, temp2;
+   rtx res;
+ 	      
+   /* Don't fetch these from memory more than once.  */
+   real0 = force_reg (submode, real0);
+   real1 = force_reg (submode, real1);
+ 
+   if (imag0 != 0)
+     imag0 = force_reg (submode, imag0);
+ 
+   imag1 = force_reg (submode, imag1);
+ 
+   /* Divisor: c*c + d*d.  */
+   temp1 = expand_binop (submode, smul_optab, real1, real1,
+ 			NULL_RTX, unsignedp, methods);
+ 
+   temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+ 			NULL_RTX, unsignedp, methods);
+ 
+   if (temp1 == 0 || temp2 == 0)
+     return 0;
+ 
+   divisor = expand_binop (submode, add_optab, temp1, temp2,
+ 			  NULL_RTX, unsignedp, methods);
+   if (divisor == 0)
+     return 0;
+ 
+   if (imag0 == 0)
+     {
+       /* Mathematically, ((a)(c-id))/divisor.  */
+       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
+ 
+       /* Calculate the dividend.  */
+       real_t = expand_binop (submode, smul_optab, real0, real1,
+ 			     NULL_RTX, unsignedp, methods);
+ 		  
+       imag_t = expand_binop (submode, smul_optab, real0, imag1,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+ 
+       imag_t = expand_unop (submode, neg_optab, imag_t,
+ 			    NULL_RTX, unsignedp);
+     }
+   else
+     {
+       /* Mathematically, ((a+ib)(c-id))/divider.  */
+       /* Calculate the dividend.  */
+       temp1 = expand_binop (submode, smul_optab, real0, real1,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0 || temp2 == 0)
+ 	return 0;
+ 
+       real_t = expand_binop (submode, add_optab, temp1, temp2,
+ 			     NULL_RTX, unsignedp, methods);
+ 		  
+       temp1 = expand_binop (submode, smul_optab, imag0, real1,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       temp2 = expand_binop (submode, smul_optab, real0, imag1,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0 || temp2 == 0)
+ 	return 0;
+ 
+       imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+     }
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, real_t, divisor,
+ 			realr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 real_t, divisor, realr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != realr)
+     emit_move_insn (realr, res);
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, imag_t, divisor,
+ 			imagr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 imag_t, divisor, imagr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != imagr)
+     emit_move_insn (imagr, res);
+ 
+   return 1;
+ }
+ 
+ /* Generate code to perform a wide-input-range-acceptable complex divide.  */
+ 
+ static int
+ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
+ 		      rtx realr, rtx imagr, enum machine_mode submode,
+ 		      int unsignedp, enum optab_methods methods,
+ 		      enum mode_class class, optab binoptab)
+ {
+   rtx ratio, divisor;
+   rtx real_t, imag_t;
+   rtx temp1, temp2, lab1, lab2;
+   enum machine_mode mode;
+   int align;
+   rtx res;
+ 	      
+   /* Don't fetch these from memory more than once.  */
+   real0 = force_reg (submode, real0);
+   real1 = force_reg (submode, real1);
+ 
+   if (imag0 != 0)
+     imag0 = force_reg (submode, imag0);
+ 
+   imag1 = force_reg (submode, imag1);
+ 
+   temp1 = expand_unop (submode, abs_optab, real1, NULL_RTX,
+ 		       unsignedp);
+ 
+   temp2 = expand_unop (submode, abs_optab, imag1, NULL_RTX,
+ 		       unsignedp);
+ 
+   if (temp1 == 0 || temp2 == 0)
+     return 0;
+ 
+   mode = GET_MODE (temp1);
+   align = GET_MODE_ALIGNMENT (mode);
+   lab1 = gen_label_rtx ();
+   emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
+ 			   mode, unsignedp, align, lab1);
+ 
+   /* |c| >= |d|; use ratio d/c to scale dividend and divisor.  */
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     ratio = expand_binop (submode, binoptab, imag1, real1,
+ 			  NULL_RTX, unsignedp, methods);
+   else
+     ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			   imag1, real1, NULL_RTX, unsignedp);
+ 
+   if (ratio == 0)
+     return 0;
+ 
+   /* Calculate divisor.  */
+ 
+   temp1 = expand_binop (submode, smul_optab, imag1, ratio,
+ 			NULL_RTX, unsignedp, methods);
+ 
+   if (temp1 == 0)
+     return 0;
+ 
+   divisor = expand_binop (submode, add_optab, temp1, real1,
+ 			  NULL_RTX, unsignedp, methods);
+ 
+   if (divisor == 0)
+     return 0;
+ 
+   /* Calculate dividend.  */
+ 
+   if (imag0 == 0)
+     {
+       real_t = real0;
+ 
+       /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
+ 
+       imag_t = expand_binop (submode, smul_optab, real0, ratio,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       if (imag_t == 0)
+ 	return 0;
+ 
+       imag_t = expand_unop (submode, neg_optab, imag_t,
+ 			    NULL_RTX, unsignedp);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+     }
+   else
+     {
+       /* Compute (a+ib)/(c+id) as
+ 	 (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
+ 
+       temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0)
+ 	return 0;
+ 
+       real_t = expand_binop (submode, add_optab, temp1, real0,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       temp1 = expand_binop (submode, smul_optab, real0, ratio,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0)
+ 	return 0;
+ 
+       imag_t = expand_binop (submode, sub_optab, imag0, temp1,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+     }
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, real_t, divisor,
+ 			realr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 real_t, divisor, realr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != realr)
+     emit_move_insn (realr, res);
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, imag_t, divisor,
+ 			imagr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 imag_t, divisor, imagr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != imagr)
+     emit_move_insn (imagr, res);
+ 
+   lab2 = gen_label_rtx ();
+   emit_jump_insn (gen_jump (lab2));
+   emit_barrier ();
+ 
+   emit_label (lab1);
+ 
+   /* |d| > |c|; use ratio c/d to scale dividend and divisor.  */
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     ratio = expand_binop (submode, binoptab, real1, imag1,
+ 			  NULL_RTX, unsignedp, methods);
+   else
+     ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			   real1, imag1, NULL_RTX, unsignedp);
+ 
+   if (ratio == 0)
+     return 0;
+ 
+   /* Calculate divisor.  */
+ 
+   temp1 = expand_binop (submode, smul_optab, real1, ratio,
+ 			NULL_RTX, unsignedp, methods);
+ 
+   if (temp1 == 0)
+     return 0;
+ 
+   divisor = expand_binop (submode, add_optab, temp1, imag1,
+ 			  NULL_RTX, unsignedp, methods);
+ 
+   if (divisor == 0)
+     return 0;
+ 
+   /* Calculate dividend.  */
+ 
+   if (imag0 == 0)
+     {
+       /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
+ 
+       real_t = expand_binop (submode, smul_optab, real0, ratio,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       imag_t = expand_unop (submode, neg_optab, real0,
+ 			    NULL_RTX, unsignedp);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+     }
+   else
+     {
+       /* Compute (a+ib)/(c+id) as
+ 	 (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
+ 
+       temp1 = expand_binop (submode, smul_optab, real0, ratio,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0)
+ 	return 0;
+ 
+       real_t = expand_binop (submode, add_optab, temp1, imag0,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+ 			    NULL_RTX, unsignedp, methods);
+ 
+       if (temp1 == 0)
+ 	return 0;
+ 
+       imag_t = expand_binop (submode, sub_optab, temp1, real0,
+ 			     NULL_RTX, unsignedp, methods);
+ 
+       if (real_t == 0 || imag_t == 0)
+ 	return 0;
+     }
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, real_t, divisor,
+ 			realr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 real_t, divisor, realr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != realr)
+     emit_move_insn (realr, res);
+ 
+   if (class == MODE_COMPLEX_FLOAT)
+     res = expand_binop (submode, binoptab, imag_t, divisor,
+ 			imagr, unsignedp, methods);
+   else
+     res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ 			 imag_t, divisor, imagr, unsignedp);
+ 
+   if (res == 0)
+     return 0;
+ 
+   if (res != imagr)
+     emit_move_insn (imagr, res);
+ 
+   emit_label (lab2);
+ 
+   return 1;
+ }
+ 
  /* Generate code to perform an operation specified by BINOPTAB
     on operands OP0 and OP1, with result having machine-mode MODE.
*************** expand_binop (mode, binoptab, op0, op1, 
*** 1220,1229 ****
        start_sequence ();
  
!       realr = gen_realpart  (submode, target);
        imagr = gen_imagpart (submode, target);
  
        if (GET_MODE (op0) == mode)
  	{
! 	  real0 = gen_realpart  (submode, op0);
  	  imag0 = gen_imagpart (submode, op0);
  	}
--- 1587,1596 ----
        start_sequence ();
  
!       realr = gen_realpart (submode, target);
        imagr = gen_imagpart (submode, target);
  
        if (GET_MODE (op0) == mode)
  	{
! 	  real0 = gen_realpart (submode, op0);
  	  imag0 = gen_imagpart (submode, op0);
  	}
*************** expand_binop (mode, binoptab, op0, op1, 
*** 1233,1237 ****
        if (GET_MODE (op1) == mode)
  	{
! 	  real1 = gen_realpart  (submode, op1);
  	  imag1 = gen_imagpart (submode, op1);
  	}
--- 1600,1604 ----
        if (GET_MODE (op1) == mode)
  	{
! 	  real1 = gen_realpart (submode, op1);
  	  imag1 = gen_imagpart (submode, op1);
  	}
*************** expand_binop (mode, binoptab, op0, op1, 
*** 1391,1499 ****
  	  else
  	    {
! 	      /* Divisor is of complex type:
! 		 X/(a+ib) */
! 	      rtx divisor;
! 	      rtx real_t, imag_t;
! 	      rtx temp1, temp2;
! 	      
! 	      /* Don't fetch these from memory more than once.  */
! 	      real0 = force_reg (submode, real0);
! 	      real1 = force_reg (submode, real1);
! 
! 	      if (imag0 != 0)
! 		imag0 = force_reg (submode, imag0);
! 
! 	      imag1 = force_reg (submode, imag1);
! 
! 	      /* Divisor: c*c + d*d */
! 	      temp1 = expand_binop (submode, smul_optab, real1, real1,
! 				    NULL_RTX, unsignedp, methods);
! 
! 	      temp2 = expand_binop (submode, smul_optab, imag1, imag1,
! 				    NULL_RTX, unsignedp, methods);
! 
! 	      if (temp1 == 0 || temp2 == 0)
! 		break;
! 
! 	      divisor = expand_binop (submode, add_optab, temp1, temp2,
! 				      NULL_RTX, unsignedp, methods);
! 	      if (divisor == 0)
! 		break;
! 
! 	      if (imag0 == 0)
  		{
! 		  /* ((a)(c-id))/divisor */
! 		  /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */
! 
! 		  /* Calculate the dividend */
! 		  real_t = expand_binop (submode, smul_optab, real0, real1,
! 					 NULL_RTX, unsignedp, methods);
! 		  
! 		  imag_t = expand_binop (submode, smul_optab, real0, imag1,
! 					 NULL_RTX, unsignedp, methods);
! 
! 		  if (real_t == 0 || imag_t == 0)
! 		    break;
! 
! 		  imag_t = expand_unop (submode, neg_optab, imag_t,
! 					NULL_RTX, unsignedp);
! 		}
! 	      else
! 		{
! 		  /* ((a+ib)(c-id))/divider */
! 		  /* Calculate the dividend */
! 		  temp1 = expand_binop (submode, smul_optab, real0, real1,
! 					NULL_RTX, unsignedp, methods);
! 
! 		  temp2 = expand_binop (submode, smul_optab, imag0, imag1,
! 					NULL_RTX, unsignedp, methods);
! 
! 		  if (temp1 == 0 || temp2 == 0)
! 		    break;
! 
! 		  real_t = expand_binop (submode, add_optab, temp1, temp2,
! 					 NULL_RTX, unsignedp, methods);
! 		  
! 		  temp1 = expand_binop (submode, smul_optab, imag0, real1,
! 					NULL_RTX, unsignedp, methods);
! 
! 		  temp2 = expand_binop (submode, smul_optab, real0, imag1,
! 					NULL_RTX, unsignedp, methods);
! 
! 		  if (temp1 == 0 || temp2 == 0)
! 		    break;
  
! 		  imag_t = expand_binop (submode, sub_optab, temp1, temp2,
! 					 NULL_RTX, unsignedp, methods);
  
! 		  if (real_t == 0 || imag_t == 0)
! 		    break;
  		}
- 
- 	      if (class == MODE_COMPLEX_FLOAT)
- 		res = expand_binop (submode, binoptab, real_t, divisor,
- 				    realr, unsignedp, methods);
- 	      else
- 		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
- 				     real_t, divisor, realr, unsignedp);
- 
- 	      if (res == 0)
- 		break;
- 	      else if (res != realr)
- 		emit_move_insn (realr, res);
- 
- 	      if (class == MODE_COMPLEX_FLOAT)
- 		res = expand_binop (submode, binoptab, imag_t, divisor,
- 				    imagr, unsignedp, methods);
- 	      else
- 		res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
- 				     imag_t, divisor, imagr, unsignedp);
- 
- 	      if (res == 0)
- 		break;
- 	      else if (res != imagr)
- 		emit_move_insn (imagr, res);
- 
- 	      ok = 1;
  	    }
  	  break;
--- 1758,1780 ----
  	  else
  	    {
! 	      switch (flag_complex_divide_method)
  		{
! 		case 0:
! 		  ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
! 						 realr, imagr, submode,
! 						 unsignedp, methods,
! 						 class, binoptab);
! 		  break;
  
! 		case 1:
! 		  ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
! 					     realr, imagr, submode,
! 					     unsignedp, methods,
! 					     class, binoptab);
! 		  break;
  
! 		default:
! 		  abort ();
  		}
  	    }
  	  break;
*** g77-e/gcc/toplev.c.~1~	Mon May 10 23:20:15 1999
--- g77-e/gcc/toplev.c	Sat May 15 21:33:56 1999
*************** int flag_fast_math = 0;
*** 564,567 ****
--- 564,573 ----
  int flag_errno_math = 1;
  
+ /* 0 means straightforward implementation of complex divide acceptable.
+    1 means wide ranges of inputs must work for complex divide.
+    2 means C9X-like requirements for complex divide (not yet implemented).  */
+ 
+ int flag_complex_divide_method = 0;
+ 
  /* Nonzero means all references through pointers are volatile.  */
  


More information about the Gcc-patches mailing list