[PATCH] CSE bug-fix and REG_EQUAL notes for NEG and ABS.

Roger Sayle roger@eyesopen.com
Thu Oct 9 17:22:00 GMT 2003


The following patch contains two related changes, the annotation
of the sequence of bit-operations used to implement floating point
negation and addition (by twiddling the sign bit), and a minor bug
fix to CSE that didn't correctly initialize substitution costs, so
some simplifications to constants failed to be preferred.  These
two changes are posted together as its more difficult to see/test
the effects of either patch without the other.

Functionally, this patch allows GCC to optimize the following code
when compiled on i686-pc-linux-gnu with "-O2 -msoft-float".  [Note
that I use -msoft-float as a model system for targets without FPUs
such as SH and H8300].

double foo()
{
  double x = 1.0;
  return -x;
}

Currently, GCC emits a code sequence to perform the negation at
run-time by generating a sequence of instructions that flips the
sign bit using xor.  The "optabs.c" changes below annotate this
sequence with a REG_EQUAL note, so the optimizers can see that
the net effect is to negate a floating point value.

Checking compiler output showed that this change is sufficient
to optimize the function below using "-O2 -msoft-float".

double bar(double x)
{
  double y = -x;
  return -y;
}

But mysteriously, it doesn't optimize foo to the equivalent "return -1.0".
Investigating further it turns out to be a bug in CSE deep in the depths
of cse_insn.  During the CSE pass, replacement costs are encoded by a
pair of integer values a_cost and a_regcost.  With a single exception
these variables are updated in pairs, and tested together in the cse.c's
"preferrable" routine.

The single exception is when we iterate attempting to place a constant
in the constant pool.  In this case, we set src_folded_cost but leave
src_folded_regcost with its previous value.  When compiling "foo" above,
src_folded_regcost previously held MAX_COST, which meant "preferrable"
would never make the substitution.  The fix is to introduce a new global
variable constant_pool_entries_regcost that holds the correct "register
cost" component associated with constant_pool_entries_cost.  This provides
a suitable value for the missing initialization, which fixes the test
case above.


The following patch has been tested on i686-pc-linux-gnu with a complete
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures.  This still doesn't
fix gcc.c-torture/execute/20020720-1.c on SH, but we creep ever closer.

Ok for mainline?


2003-10-08  Roger Sayle  <roger@eyesopen.com>

	* cse.c (constant_pool_entries_regcost): New global variable to
	hold the register cost component of constant_pool_entries_cost.
	(fold_rtx): Calculate constant_pool_entries_regcost at the same
	time as constant_pool_entries_cost.
	(cse_insn): Set both src_folded_cost and src_folded_regcost from
	constant_pool_entries_cost and constant_pool_entries_regcost.
	(cse_main): Initialize constant_pool_entries_regcost to zero.

	* optabs.c (expand_unop): Attach a REG_EQUAL note describing
	the semantics of the sequence of bit operations used to negate
	a floating-point value.
	(expand_abs_nojump): Likewise attach a REG_EQUAL note describing
	the semantics of the bit operations used to abs a floating point
	value.


Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.272
diff -c -3 -p -r1.272 cse.c
*** cse.c	6 Oct 2003 09:17:55 -0000	1.272
--- cse.c	8 Oct 2003 22:48:35 -0000
*************** static struct table_elt *last_jump_equiv
*** 569,574 ****
--- 569,575 ----
     the insn.  */

  static int constant_pool_entries_cost;
+ static int constant_pool_entries_regcost;

  /* This data describes a block that will be processed by cse_basic_block.  */

*************** fold_rtx (rtx x, rtx insn)
*** 3529,3535 ****
  	    rtx new;

  	    if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
! 	      constant_pool_entries_cost = COST (constant);

  	    /* If we are loading the full constant, we have an equivalence.  */
  	    if (offset == 0 && mode == const_mode)
--- 3530,3539 ----
  	    rtx new;

  	    if (CONSTANT_P (constant) && GET_CODE (constant) != CONST_INT)
! 	      {
! 		constant_pool_entries_cost = COST (constant);
! 		constant_pool_entries_regcost = approx_reg_cost (constant);
! 	      }

  	    /* If we are loading the full constant, we have an equivalence.  */
  	    if (offset == 0 && mode == const_mode)
*************** cse_insn (rtx insn, rtx libcall_insn)
*** 5507,5512 ****
--- 5511,5517 ----
  	      src_folded_force_flag = 1;
  	      src_folded = trial;
  	      src_folded_cost = constant_pool_entries_cost;
+ 	      src_folded_regcost = constant_pool_entries_regcost;
  	    }
  	}

*************** cse_main (rtx f, int nregs, int after_lo
*** 6939,6944 ****
--- 6944,6950 ----
    cse_jumps_altered = 0;
    recorded_label_ref = 0;
    constant_pool_entries_cost = 0;
+   constant_pool_entries_regcost = 0;
    val.path_size = 0;

    init_recog ();
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.194
diff -c -3 -p -r1.194 optabs.c
*** optabs.c	6 Oct 2003 23:09:28 -0000	1.194
--- optabs.c	8 Oct 2003 22:48:36 -0000
*************** expand_unop (enum machine_mode mode, opt
*** 2614,2620 ****
  			       immed_double_const (lo, hi, imode),
  			       NULL_RTX, 1, OPTAB_LIB_WIDEN);
  	  if (temp != 0)
! 	    return gen_lowpart (mode, temp);
  	  delete_insns_since (last);
          }
      }
--- 2614,2629 ----
  			       immed_double_const (lo, hi, imode),
  			       NULL_RTX, 1, OPTAB_LIB_WIDEN);
  	  if (temp != 0)
! 	    {
! 	      rtx insn;
! 	      if (target == 0)
! 		target = gen_reg_rtx (mode);
! 	      insn = emit_move_insn (target, gen_lowpart (mode, temp));
! 	      set_unique_reg_note (insn, REG_EQUAL,
! 				   gen_rtx_fmt_e (NEG, mode,
! 						  copy_rtx (op0)));
! 	      return target;
! 	    }
  	  delete_insns_since (last);
          }
      }
*************** expand_abs_nojump (enum machine_mode mod
*** 2789,2795 ****
  			       immed_double_const (~lo, ~hi, imode),
  			       NULL_RTX, 1, OPTAB_LIB_WIDEN);
  	  if (temp != 0)
! 	    return gen_lowpart (mode, temp);
  	  delete_insns_since (last);
  	}
      }
--- 2798,2813 ----
  			       immed_double_const (~lo, ~hi, imode),
  			       NULL_RTX, 1, OPTAB_LIB_WIDEN);
  	  if (temp != 0)
! 	    {
! 	      rtx insn;
! 	      if (target == 0)
! 		target = gen_reg_rtx (mode);
! 	      insn = emit_move_insn (target, gen_lowpart (mode, temp));
! 	      set_unique_reg_note (insn, REG_EQUAL,
! 				   gen_rtx_fmt_e (ABS, mode,
! 						  copy_rtx (op0)));
! 	      return target;
! 	    }
  	  delete_insns_since (last);
  	}
      }


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list