[PATCH, RFC] Handling non-trivial comparisons with cond-exec

Richard Earnshaw rearnsha@arm.com
Tue Oct 14 11:15:00 GMT 2003


Richard,

The ARM/Thumb back-end is in effect two back-ends rolled into one.  For 
ARM code we use a condition code register and define 
HAVE_conditional_execution.  For Thumb code we hide the condition code 
register and use cbranch patterns to control code flow.  I'm trying to add 
optimizations to the Thumb compiler to allow the condition-code setting 
effects of data processing operations to be used instead of an explicit 
compare with zero.  So, for example instead of

	sub	r0, r0, #1
	cmp	r0, #0
	bge	<dest>

we can emit

	sub	r0, r0, #1
	bpl	<dest>

This involves recognizing RTL of the form

	(parallel [
		(set (pc) (if_then_else 
				(ge (plus (reg) (const_int -1))
					(const_int 0))
				(label)
				(pc)))
		(set (reg) (plus (reg) (const_int -1)))])

Unfortunately, this is breaking one of the invariants that the 
HAVE_conditional_execution code makes: that a comparison is always a 
register (actually, the invariant should be that it's always a comparison 
of a register against zero, but the second test isn't enforced).

So adding a pattern for the above causes an abort in 
init_propagate_block_info.

It seems to me that what I need to achieve is for the 
conditional_execution code to behave like a no-op if the branch is not 
trivial (since unless it is we can't track the condition accurately).  
This patch effectively achieves that by only trying to apply the cond-exec 
tracking if a block ends with a simple comparison (where simple is defined 
as a comparison of a reg (or subreg of a reg) and zero.

Does this sound OK, or have I missed anything?

R.

<date>  Richard Earnshaw  <rearnsha@arm.com>

	* jump.c (any_simple_condjump_p): New function.
	* rtl.h: Declare it.
	* flow.c (init_propagate_block_info): Only do conditional-execution
	processing if the condjump is simple.


-------------- next part --------------
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.562
diff -p -r1.562 flow.c
*** flow.c	12 Sep 2003 15:07:50 -0000	1.562
--- flow.c	14 Oct 2003 10:58:12 -0000
*************** init_propagate_block_info (basic_block b
*** 1861,1871 ****
  				       free_reg_cond_life_info);
    pbi->reg_cond_reg = BITMAP_XMALLOC ();
  
!   /* If this block ends in a conditional branch, for each register live
!      from one side of the branch and not the other, record the register
!      as conditionally dead.  */
    if (GET_CODE (bb->end) == JUMP_INSN
!       && any_condjump_p (bb->end))
      {
        regset_head diff_head;
        regset diff = INITIALIZE_REG_SET (diff_head);
--- 1861,1872 ----
  				       free_reg_cond_life_info);
    pbi->reg_cond_reg = BITMAP_XMALLOC ();
  
!   /* If this block ends in a conditional branch, for each register
!      live from one side of the branch and not the other, record the
!      register as conditionally dead.  Only do this if the condition is
!      simple enough.  */
    if (GET_CODE (bb->end) == JUMP_INSN
!       && any_simple_condjump_p (bb->end))
      {
        regset_head diff_head;
        regset diff = INITIALIZE_REG_SET (diff_head);
Index: jump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/jump.c,v
retrieving revision 1.236
diff -p -r1.236 jump.c
*** jump.c	22 Jul 2003 23:15:28 -0000	1.236
--- jump.c	14 Oct 2003 10:58:12 -0000
*************** any_condjump_p (rtx insn)
*** 1172,1177 ****
--- 1172,1217 ----
  	  || (a == PC && (b == LABEL_REF || b == RETURN)));
  }
  
+ /* Return true when insn is a conditional jump that has a simple
+    condition.  A simple condition is a comparison of a register (maybe
+    via a subreg) and zero.
+ 
+    The behaviour is similar to any_condjump_p except for the additional
+    restriction.  */
+ 
+ int
+ any_simple_condjump_p (rtx insn)
+ {
+   rtx x = pc_set (insn);
+   rtx cond, reg;
+   enum rtx_code a, b;
+ 
+   if (!x)
+     return 0;
+   if (GET_CODE (SET_SRC (x)) != IF_THEN_ELSE)
+     return 0;
+ 
+   cond = XEXP (SET_SRC (x), 0);
+ 
+   if (GET_RTX_CLASS (GET_CODE (cond)) != '<')
+     return 0;
+ 
+   reg = XEXP (cond, 0);
+ 
+   if (GET_CODE (reg) == SUBREG)
+     reg = SUBREG_REG (reg);
+ 
+   if (GET_CODE (reg) != REG
+       || XEXP (cond, 1) != const0_rtx)
+     return 0;
+ 
+   a = GET_CODE (XEXP (SET_SRC (x), 1));
+   b = GET_CODE (XEXP (SET_SRC (x), 2));
+ 
+   return ((b == PC && (a == LABEL_REF || a == RETURN))
+ 	  || (a == PC && (b == LABEL_REF || b == RETURN)));
+ }
+ 
  /* Return the label of a conditional jump.  */
  
  rtx
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.435
diff -p -r1.435 rtl.h
*** rtl.h	12 Sep 2003 15:07:50 -0000	1.435
--- rtl.h	14 Oct 2003 10:58:12 -0000
*************** extern void cse_end_of_basic_block (rtx,
*** 1974,1979 ****
--- 1974,1980 ----
  extern int comparison_dominates_p (enum rtx_code, enum rtx_code);
  extern int condjump_p (rtx);
  extern int any_condjump_p (rtx);
+ extern int any_simple_condjump_p (rtx);
  extern int any_uncondjump_p (rtx);
  extern int safe_to_remove_jump_p (rtx);
  extern rtx pc_set (rtx);


More information about the Gcc-patches mailing list