[PATCH] Optimize constant condition codes in combine.c

Roger Sayle roger@eyesopen.com
Wed Sep 4 20:05:00 GMT 2002


This tweak to the simplication routines in combine.c covers the
case that a set of a condition code may be determined to be a
constant at compile time.

Currently, simplify_set doesn't consider the fact that combining
instructions may result in a comparison becoming always true or
always false, and directly calls "simplify_comparison".  The
comment above simplify_comparison contains the following:

   It is possible that we might detect that a comparison is either always
   true or always false.  However, we do not perform general constant
   folding in combine, so this knowledge isn't useful.  Such tautologies
   should have been detected earlier.  Hence we ignore all such cases.

Unfortunately, these cases often aren't detected earlier as it may
require the interactions of three or four instructions to determine
the outcome of a comparison.  To provide some data there are 855 cases
in a GCC bootstrap on i686-pc-cygwin where a comparison is determined
always true or false only in combine.c.

A solution is to call simplify_relational_operation to determine
whether the outcome of a comparison is known immediately prior
to simplify_comparison in simplify_set.  In the patch below, if
simplify_relation_operation indicates that the comparison is
constant, it converts the condition code setter into the no-op
move, (set (pc) (pc)), and replaces the single use of the
condition code register (already indicated by other_insn) with the
constant value, and if the user is a conditional branch or simple
set, also attempt to simplify this condition code using instruction.

This change required one extra tweak.  The code in combine.c
handles the case where "i3" may be converted into an unconditional
jump, in which case a barrier needs to inserted after i3 if one
doesn't already exist.  With the change above undobuf.other_insn
may also be transformed into an unconditional jump, so it too needs
to be checked for a barrier if the combination succeeds.


The result of this optimization is that it fixes the failure of
gcc.c-torture/execute/20020720-1.c on both powerpc and mmix (and
possibly other platforms, but alas not MIPS).  By extension, the
division of a complex number by a real now requires no conditional
branches on powerpc.


This patch has been extensively tested.  It has survived "make
bootstrap" and "make -k check", all languages except Ada and
treelang, on i686-pc-linux-gnu, powerpc-ibm-aix5.1.0.0 and
hppa2.0w-hp-hpux11.00 with no new regressions.  It has been bootstraped
on i686-pc-cygwin.  It has also been used to build a cross-compiler from
i686-pc-linux-gnu to mips-elf, and causes no new regressions on
mips-sim.  Its also been used to build cc1 cross-compiler from
i686-pc-linux-gnu to powerpc-eabi.  And many thanks to Hans-Peter
Nilsson for tesing it causes no regressions on mmix-knuth-mmixware
and for confirming that this fixes 20020720-1.c on MMIX.


Ok for the gcc-3_4-basic-improvements-branch?



2002-09-04  Roger Sayle  <roger@eyesopen.com>

	* combine.c (try_combine): Handle the case that undobuf.other_insn
	has been turned into a return or unconditional jump, by inserting
	a BARRIER after it, if necessary.
	(simplify_set):  Test if a condition code setter has a constant
	comparison at compile time, if so convert this insn to a no-op move
	and update/simplify the condition code user (undobuf.other_insn).


Index: combine.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/combine.c,v
retrieving revision 1.310
diff -c -3 -p -r1.310 combine.c
*** combine.c	19 Aug 2002 18:18:11 -0000	1.310
--- combine.c	1 Sep 2002 16:35:47 -0000
*************** try_combine (i3, i2, i1, new_direct_jump
*** 2831,2836 ****
--- 2831,2848 ----
  	    || GET_CODE (temp) != BARRIER)
  	  emit_barrier_after (i3);
        }
+
+     if (undobuf.other_insn != NULL_RTX
+ 	&& (GET_CODE (PATTERN (undobuf.other_insn)) == RETURN
+ 	    || any_uncondjump_p (undobuf.other_insn)))
+       {
+ 	*new_direct_jump_p = 1;
+
+ 	if ((temp = next_nonnote_insn (undobuf.other_insn)) == NULL_RTX
+ 	    || GET_CODE (temp) != BARRIER)
+ 	  emit_barrier_after (undobuf.other_insn);
+       }
+
      /* An NOOP jump does not need barrier, but it does need cleaning up
         of CFG.  */
      if (GET_CODE (newpat) == SET
*************** simplify_set (x)
*** 5014,5027 ****
      {
        enum rtx_code old_code = GET_CODE (*cc_use);
        enum rtx_code new_code;
!       rtx op0, op1;
        int other_changed = 0;
        enum machine_mode compare_mode = GET_MODE (dest);

        if (GET_CODE (src) == COMPARE)
  	op0 = XEXP (src, 0), op1 = XEXP (src, 1);
        else
  	op0 = src, op1 = const0_rtx;

        /* Simplify our comparison, if possible.  */
        new_code = simplify_comparison (old_code, &op0, &op1);
--- 5026,5068 ----
      {
        enum rtx_code old_code = GET_CODE (*cc_use);
        enum rtx_code new_code;
!       rtx op0, op1, tmp;
        int other_changed = 0;
        enum machine_mode compare_mode = GET_MODE (dest);
+       enum machine_mode tmp_mode;

        if (GET_CODE (src) == COMPARE)
  	op0 = XEXP (src, 0), op1 = XEXP (src, 1);
        else
  	op0 = src, op1 = const0_rtx;
+
+       /* Check whether the comparison is known at compile time.  */
+       if (GET_MODE (op0) != VOIDmode)
+ 	tmp_mode = GET_MODE (op0);
+       else if (GET_MODE (op1) != VOIDmode)
+ 	tmp_mode = GET_MODE (op1);
+       else
+ 	tmp_mode = compare_mode;
+       tmp = simplify_relational_operation (old_code, tmp_mode, op0, op1);
+       if (tmp != NULL_RTX)
+ 	{
+ 	  rtx pat = PATTERN (other_insn);
+ 	  undobuf.other_insn = other_insn;
+ 	  SUBST (*cc_use, tmp);
+
+ 	  /* Attempt to simplify CC user.  */
+ 	  if (GET_CODE (pat) == SET)
+ 	    {
+ 	      rtx new = simplify_rtx (SET_SRC (pat));
+ 	      if (new != NULL_RTX)
+ 		SUBST (SET_SRC (pat), new);
+ 	    }
+
+ 	  /* Convert X into a no-op move.  */
+ 	  SUBST (SET_DEST (x), pc_rtx);
+ 	  SUBST (SET_SRC (x), pc_rtx);
+ 	  return x;
+ 	}

        /* Simplify our comparison, if possible.  */
        new_code = simplify_comparison (old_code, &op0, &op1);

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