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]

[patch]: Fix 16457, missed ppc optimization


This fixes 16457, a missed opportunity to use a single rlwinm
insn, instead of two rldicr instructions.

booted & tested on powerpc64-unknown-linux-gnu, ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2004-11-08  Nathan Sidwell  <nathan@codesourcery.com>

	PR target/16457
	* config/rs6000/rs6000.c (mask64_2_operand): Stub to call
	mask64_1or2_operand.
	(mask64_1or_2_operand): Broken out of mask64_2_operand, add flag
	to spot rlwinm opportunities.
	(and64_2_operand): Use mask_1or2_operand.
	* config/rs6000/rs6000.md (anddi3): Use rlwinm when possible.

Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.734
diff -c -3 -p -r1.734 rs6000.c
*** config/rs6000/rs6000.c	2 Nov 2004 09:50:28 -0000	1.734
--- config/rs6000/rs6000.c	8 Nov 2004 14:16:47 -0000
*************** mask64_operand (rtx op, enum machine_mod
*** 2708,2730 ****
    return 0;
  }
  
! /* Like mask64_operand, but allow up to three transitions.  This
!    predicate is used by insn patterns that generate two rldicl or
!    rldicr machine insns.  */
! 
! int
! mask64_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
  {
    if (GET_CODE (op) == CONST_INT)
      {
        HOST_WIDE_INT c, lsb;
! 
        c = INTVAL (op);
  
        /* Disallow all zeros.  */
        if (c == 0)
  	return 0;
  
        /* We don't change the number of transitions by inverting,
  	 so make sure we start with the LS bit zero.  */
        if (c & 1)
--- 2708,2733 ----
    return 0;
  }
  
! static int
! mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED,
! 		       bool allow_one)
  {
    if (GET_CODE (op) == CONST_INT)
      {
        HOST_WIDE_INT c, lsb;
!       bool one_ok;
!       
        c = INTVAL (op);
  
        /* Disallow all zeros.  */
        if (c == 0)
  	return 0;
  
+       /* We can use a single rlwinm insn if no upper bits of C are set
+          AND there are zero, one or two transitions in the _whole_ of
+          C.  */
+       one_ok = !(c & ~(HOST_WIDE_INT)0xffffffff);
+       
        /* We don't change the number of transitions by inverting,
  	 so make sure we start with the LS bit zero.  */
        if (c & 1)
*************** mask64_2_operand (rtx op, enum machine_m
*** 2748,2753 ****
--- 2751,2759 ----
        /* Erase second transition.  */
        c &= -lsb;
  
+       if (one_ok && !(allow_one || c))
+ 	return 0;
+ 
        /* Find the third transition (if any).  */
        lsb = c & -c;
  
*************** mask64_2_operand (rtx op, enum machine_m
*** 2757,2762 ****
--- 2763,2776 ----
    return 0;
  }
  
+ /* Like mask64_operand, but allow up to three transitions.  This
+    predicate is used by insn patterns that generate two rldicl or
+    rldicr machine insns.   */
+ int mask64_2_operand (rtx op, enum machine_mode mode)
+ {
+   return mask64_1or2_operand (op, mode, false);
+ }
+ 
  /* Generates shifts and masks for a pair of rldicl or rldicr insns to
     implement ANDing by the mask IN.  */
  void
*************** int
*** 2846,2854 ****
  and64_2_operand (rtx op, enum machine_mode mode)
  {
    if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
!     return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
  
!   return logical_operand (op, mode) || mask64_2_operand (op, mode);
  }
  
  /* Return 1 if the operand is either a non-special register or a
--- 2860,2868 ----
  and64_2_operand (rtx op, enum machine_mode mode)
  {
    if (fixed_regs[CR0_REGNO])	/* CR0 not available, don't do andi./andis.  */
!     return gpc_reg_operand (op, mode) || mask64_1or2_operand (op, mode, true);
  
!   return logical_operand (op, mode) || mask64_1or2_operand (op, mode, true);
  }
  
  /* Return 1 if the operand is either a non-special register or a
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.327
diff -c -3 -p -r1.327 rs6000.md
*** config/rs6000/rs6000.md	27 Oct 2004 20:18:42 -0000	1.327
--- config/rs6000/rs6000.md	8 Nov 2004 14:16:48 -0000
***************
*** 7170,7188 ****
    "")
  
  (define_insn "anddi3"
!   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r")
! 	(and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r")
! 		(match_operand:DI 2 "and64_2_operand" "?r,S,K,J,t")))
!    (clobber (match_scratch:CC 3 "=X,X,x,x,X"))]
    "TARGET_POWERPC64"
    "@
     and %0,%1,%2
     rldic%B2 %0,%1,0,%S2
     andi. %0,%1,%b2
     andis. %0,%1,%u2
     #"
!   [(set_attr "type" "*,*,compare,compare,*")
!    (set_attr "length" "4,4,4,4,8")])
  
  (define_split
    [(set (match_operand:DI 0 "gpc_reg_operand" "")
--- 7170,7189 ----
    "")
  
  (define_insn "anddi3"
!   [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r")
! 	(and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r")
! 		(match_operand:DI 2 "and64_2_operand" "?r,S,T,K,J,t")))
!    (clobber (match_scratch:CC 3 "=X,X,X,x,x,X"))]
    "TARGET_POWERPC64"
    "@
     and %0,%1,%2
     rldic%B2 %0,%1,0,%S2
+    rlwinm %0,%1,0,%m2,%M2
     andi. %0,%1,%b2
     andis. %0,%1,%u2
     #"
!   [(set_attr "type" "*,*,*,compare,compare,*")
!    (set_attr "length" "4,4,4,4,4,8")])
  
  (define_split
    [(set (match_operand:DI 0 "gpc_reg_operand" "")
***************
*** 7200,7209 ****
  	(and:DI (rotate:DI (match_dup 0)
  			   (match_dup 6))
  		(match_dup 7)))]
-   "
  {
    build_mask64_2_operands (operands[2], &operands[4]);
! }")
  
  (define_insn "*anddi3_internal2"
    [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,?y,?y,??y,??y,?y")
--- 7201,7209 ----
  	(and:DI (rotate:DI (match_dup 0)
  			   (match_dup 6))
  		(match_dup 7)))]
  {
    build_mask64_2_operands (operands[2], &operands[4]);
! })
  
  (define_insn "*anddi3_internal2"
    [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,?y,?y,??y,??y,?y")
/* { dg-do compile { target powerpc64-*-* } } */
/* { dg-options "-m64 -O2" } */

/* { dg-final { scan-assembler "rlwinm \[0-9\]+,\[0-9\]+,0,0,30"  } } */
/* { dg-final { scan-assembler "rlwinm \[0-9\]+,\[0-9\]+,0,29,30"  } } */
/* { dg-final { scan-assembler-not "rldicr" } } */

/* Origin:Pete Steinmetz <steinmtz@us.ibm.com> */

/* PR 16457 - use rlwinm insn.  */

char *foo1 (char *p, unsigned int x)
{
  return p - (x & ~1);
}

char *foo2 (char *p, unsigned int x)
{
  return p - (x & 6);
}

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