This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fix alpha gcc.dg/20040123-1.c


The problem here is that we turn

	&x == 0x40000
into
	&x - 0x40000 == 0

because it looks quicker to implement in the hardware.
This gets folded to

	(const (plus (symbol_ref "x") (const_int -0x40000)))

which, since x is not weak, is automatically considered non-null.

The best solution I could think of is to disable this alpha-specific
transform if op0 is a pointer.  I tried just looking for symbol_ref,
but there's code that fires at -O2 that forces all symbols into
registers.  But that's ok, since adding the alignment bits to the
register data is a good idea anyway.

The splitters that I delete don't ever seem to be a win to me, most
of the time.  In particular,

	(ne (lt reg reg) 0) -> (lt (minus reg reg) 0)

is a lose on ev5, where compare and logical type instructions have a 
special bypass to cmove and branch type instruction.  On other cpu
revisions the transform is neutral.  Similarly,

	(a > 0xffff)	 	-> 	t = a & ~0xffff; t != 0
	ldah	t, 1			zap	a, 0xfc, t
	cmplt	a, t, r			bne	t, dest
	bne	r, dest

is a lose on ev4/ev5 because of shifter latency/overcommitment.

Bootstrapped and tested on alphaev67-linux on mainline.


r~


        * explow.c (force_reg): Call mark_reg_pointer as appropriate.
        * config/alpha/alpha.c (alpha_emit_conditional_branch): Don't
        use (op0-op1) == 0 if op0 is a pointer.
        * config/alpha/alpha.md (cmpdi): Use some_operand.
        (three comparison combine splits): Remove.

Index: gcc/explow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/explow.c,v
retrieving revision 1.118
diff -c -p -d -r1.118 explow.c
*** gcc/explow.c	13 Dec 2003 04:11:20 -0000	1.118
--- gcc/explow.c	26 Feb 2004 01:40:31 -0000
*************** force_reg (enum machine_mode mode, rtx x
*** 721,726 ****
--- 721,760 ----
        && ! rtx_equal_p (x, SET_SRC (set)))
      set_unique_reg_note (insn, REG_EQUAL, x);
  
+   /* Let optimizers know that TEMP is a pointer, and if so, the
+      known alignment of that pointer.  */
+   {
+     unsigned align = 0;
+     if (GET_CODE (x) == SYMBOL_REF)
+       {
+         align = BITS_PER_UNIT;
+ 	if (SYMBOL_REF_DECL (x) && DECL_P (SYMBOL_REF_DECL (x)))
+ 	  align = DECL_ALIGN (SYMBOL_REF_DECL (x));
+       }
+     else if (GET_CODE (x) == LABEL_REF)
+       align = BITS_PER_UNIT;
+     else if (GET_CODE (x) == CONST
+ 	     && GET_CODE (XEXP (x, 0)) == PLUS
+ 	     && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ 	     && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+       {
+ 	rtx s = XEXP (XEXP (x, 0), 0);
+ 	rtx c = XEXP (XEXP (x, 0), 1);
+ 	unsigned sa, ca;
+ 
+ 	sa = BITS_PER_UNIT;
+ 	if (SYMBOL_REF_DECL (s) && DECL_P (SYMBOL_REF_DECL (s)))
+ 	  sa = DECL_ALIGN (SYMBOL_REF_DECL (s));
+ 
+ 	ca = exact_log2 (INTVAL (c) & -INTVAL (c)) * BITS_PER_UNIT;
+ 
+ 	align = MIN (sa, ca);
+       }
+ 
+     if (align)
+       mark_reg_pointer (temp, align);
+   }
+ 
    return temp;
  }
  
Index: gcc/config/alpha/alpha.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v
retrieving revision 1.352
diff -c -p -d -r1.352 alpha.c
*** gcc/config/alpha/alpha.c	8 Feb 2004 23:08:37 -0000	1.352
--- gcc/config/alpha/alpha.c	26 Feb 2004 01:40:32 -0000
*************** alpha_emit_conditional_branch (enum rtx_
*** 3179,3185 ****
  	  /* If the constants doesn't fit into an immediate, but can
   	     be generated by lda/ldah, we adjust the argument and
   	     compare against zero, so we can use beq/bne directly.  */
! 	  else if (GET_CODE (op1) == CONST_INT && (code == EQ || code == NE))
  	    {
  	      HOST_WIDE_INT v = INTVAL (op1), n = -v;
  
--- 3179,3191 ----
  	  /* If the constants doesn't fit into an immediate, but can
   	     be generated by lda/ldah, we adjust the argument and
   	     compare against zero, so we can use beq/bne directly.  */
! 	  /* ??? Don't do this when comparing against symbols, otherwise
! 	     we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will
! 	     be declared false out of hand (at least for non-weak).  */
! 	  else if (GET_CODE (op1) == CONST_INT
! 		   && (code == EQ || code == NE)
! 		   && !(symbolic_operand (op0, VOIDmode)
! 			|| (GET_CODE (op0) == REG && REG_POINTER (op0))))
  	    {
  	      HOST_WIDE_INT v = INTVAL (op1), n = -v;
  
Index: gcc/config/alpha/alpha.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.md,v
retrieving revision 1.219
diff -c -p -d -r1.219 alpha.md
*** gcc/config/alpha/alpha.md	20 Feb 2004 22:12:56 -0000	1.219
--- gcc/config/alpha/alpha.md	26 Feb 2004 01:40:32 -0000
***************
*** 3827,3834 ****
  })
  
  (define_expand "cmpdi"
!   [(set (cc0) (compare (match_operand:DI 0 "general_operand" "")
! 		       (match_operand:DI 1 "general_operand" "")))]
    ""
  {
    alpha_compare.op0 = operands[0];
--- 3827,3834 ----
  })
  
  (define_expand "cmpdi"
!   [(set (cc0) (compare (match_operand:DI 0 "some_operand" "")
! 		       (match_operand:DI 1 "some_operand" "")))]
    ""
  {
    alpha_compare.op0 = operands[0];
***************
*** 4158,4257 ****
    operands[7] = gen_rtx_SIGN_EXTEND (DImode, tem);
    operands[8] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
  				operands[6], const0_rtx);
- })
- 
- (define_split
-   [(set (pc)
- 	(if_then_else
- 	 (match_operator 1 "comparison_operator"
- 			 [(match_operand:DI 2 "reg_or_0_operand" "")
- 			  (match_operand:DI 3 "reg_or_cint_operand" "")])
- 	 (label_ref (match_operand 0 "" ""))
- 	 (pc)))
-    (clobber (match_operand:DI 4 "register_operand" ""))]
-   "operands[3] != const0_rtx"
-   [(set (match_dup 4) (match_dup 5))
-    (set (pc) (if_then_else (match_dup 6) (label_ref (match_dup 0)) (pc)))]
- {
-   enum rtx_code code = GET_CODE (operands[1]);
-   int unsignedp = (code == GEU || code == LEU || code == GTU || code == LTU);
- 
-   if (code == NE || code == EQ
-       || (extended_count (operands[2], DImode, unsignedp) >= 1
- 	  && extended_count (operands[3], DImode, unsignedp) >= 1))
-     {
-       if (GET_CODE (operands[3]) == CONST_INT)
- 	operands[5] = gen_rtx_PLUS (DImode, operands[2],
- 				    GEN_INT (- INTVAL (operands[3])));
-       else
- 	operands[5] = gen_rtx_MINUS (DImode, operands[2], operands[3]);
- 
-       operands[6] = gen_rtx_fmt_ee (code, VOIDmode, operands[4], const0_rtx);
-     }
- 
-   else if (code == EQ || code == LE || code == LT
- 	   || code == LEU || code == LTU)
-     {
-       operands[5] = gen_rtx_fmt_ee (code, DImode, operands[2], operands[3]);
-       operands[6] = gen_rtx_NE (VOIDmode, operands[4], const0_rtx);
-     }
-   else
-     {
-       operands[5] = gen_rtx_fmt_ee (reverse_condition (code), DImode,
- 				    operands[2], operands[3]);
-       operands[6] = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx);
-     }
- })
- 
- (define_split
-   [(set (pc)
- 	(if_then_else
- 	 (match_operator 1 "comparison_operator"
- 			 [(match_operand:SI 2 "reg_or_0_operand" "")
- 			  (match_operand:SI 3 "const_int_operand" "")])
- 	 (label_ref (match_operand 0 "" ""))
- 	 (pc)))
-    (clobber (match_operand:DI 4 "register_operand" ""))]
-   "operands[3] != const0_rtx
-    && (GET_CODE (operands[1]) == EQ || GET_CODE (operands[1]) == NE)"
-   [(set (match_dup 4) (match_dup 5))
-    (set (pc) (if_then_else (match_dup 6) (label_ref (match_dup 0)) (pc)))]
- {
-   rtx tem;
- 
-   if (GET_CODE (operands[3]) == CONST_INT)
-     tem = gen_rtx_PLUS (SImode, operands[2],
- 			GEN_INT (- INTVAL (operands[3])));
-   else
-     tem = gen_rtx_MINUS (SImode, operands[2], operands[3]);
- 
-   operands[5] = gen_rtx_SIGN_EXTEND (DImode, tem);
-   operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
- 				operands[4], const0_rtx);
- })
- 
- ;; We can convert such things as "a > 0xffff" to "t = a & ~ 0xffff; t != 0".
- ;; This eliminates one, and sometimes two, insns when the AND can be done
- ;; with a ZAP.
- (define_split
-   [(set (match_operand:DI 0 "register_operand" "")
- 	(match_operator:DI 1 "comparison_operator"
- 			[(match_operand:DI 2 "register_operand" "")
- 			 (match_operand:DI 3 "const_int_operand" "")]))
-    (clobber (match_operand:DI 4 "register_operand" ""))]
-   "exact_log2 (INTVAL (operands[3]) + 1) >= 0
-    && (GET_CODE (operands[1]) == GTU
-        || GET_CODE (operands[1]) == LEU
-        || ((GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == LE)
- 	   && extended_count (operands[2], DImode, 1) > 0))"
-   [(set (match_dup 4) (and:DI (match_dup 2) (match_dup 5)))
-    (set (match_dup 0) (match_dup 6))]
- {
-   operands[5] = GEN_INT (~ INTVAL (operands[3]));
-   operands[6] = gen_rtx_fmt_ee (((GET_CODE (operands[1]) == GTU
- 				  || GET_CODE (operands[1]) == GT)
- 				 ? NE : EQ),
- 				DImode, operands[4], const0_rtx);
  })
  
  ;; Prefer to use cmp and arithmetic when possible instead of a cmove.
--- 4158,4163 ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]