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]

S/390: Implement CANONICALIZE_COMPARISON


Hello,

this implements CANONICALIZE_COMPARISON for s390, which allows me to get
rid of a significant number of redundant patterns for the TEST UNDER MASK
instruction.  It also generates better code in many cases, and may even
fix the odd latent bug w.r.t. volatile mem accesses ...

Bootstrapped/regtested on s390-ibm-linux and s390x-ibm-linux.
Applied to mainline.

ChangeLog:

	* config/s390/s390-protos.h (s390_canonicalize_comparison): Declare.
	* config/s390/s390.c (s390_canonicalize_comparison): New function.
	* config/s390/s390.h (CANONICALIZE_COMPARISON): Define.
	* config/s390/s390.md ("*tmdi_ext", "*tmsi_ext", "*tmqisi_ext",
	"*tmqidi_ext", "*tmdi_mem", "*tmsi_mem", "*tmhi_mem"): Remove.
	("*tmqi_mem"): Remove SUBREG from pattern.
	("*anddi3_cconly"): Prevent accidentally matching TM pattern.
	("*andsi3_cconly"): Likewise.
	

Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.53
diff -c -p -r1.53 s390-protos.h
*** gcc/config/s390/s390-protos.h	19 Jul 2004 13:59:48 -0000	1.53
--- gcc/config/s390/s390-protos.h	10 Aug 2004 19:08:34 -0000
*************** extern int tls_symbolic_operand (rtx);
*** 50,55 ****
--- 50,56 ----
  extern int s390_match_ccmode (rtx, enum machine_mode);
  extern enum machine_mode s390_tm_ccmode (rtx, rtx, int);
  extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
+ extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
  extern int s390_alc_comparison (rtx op, enum machine_mode mode);
  extern int s390_slb_comparison (rtx op, enum machine_mode mode);
  extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.164
diff -c -p -r1.164 s390.c
*** gcc/config/s390/s390.c	20 Jul 2004 07:27:15 -0000	1.164
--- gcc/config/s390/s390.c	10 Aug 2004 19:08:34 -0000
*************** s390_select_ccmode (enum rtx_code code, 
*** 474,479 ****
--- 474,560 ----
      }
  }
  
+ /* Replace the comparison OP0 CODE OP1 by a semantically equivalent one
+    that we can implement more efficiently.  */
+ 
+ void
+ s390_canonicalize_comparison (enum rtx_code *code, rtx *op0, rtx *op1)
+ {
+   /* Convert ZERO_EXTRACT back to AND to enable TM patterns.  */
+   if ((*code == EQ || *code == NE)
+       && *op1 == const0_rtx
+       && GET_CODE (*op0) == ZERO_EXTRACT
+       && GET_CODE (XEXP (*op0, 1)) == CONST_INT
+       && GET_CODE (XEXP (*op0, 2)) == CONST_INT
+       && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
+     {
+       rtx inner = XEXP (*op0, 0);
+       HOST_WIDE_INT modesize = GET_MODE_BITSIZE (GET_MODE (inner));
+       HOST_WIDE_INT len = INTVAL (XEXP (*op0, 1));
+       HOST_WIDE_INT pos = INTVAL (XEXP (*op0, 2));
+ 
+       if (len > 0 && len < modesize
+ 	  && pos >= 0 && pos + len <= modesize
+ 	  && modesize <= HOST_BITS_PER_WIDE_INT)
+ 	{
+ 	  unsigned HOST_WIDE_INT block;
+ 	  block = ((unsigned HOST_WIDE_INT) 1 << len) - 1;
+ 	  block <<= modesize - pos - len;
+ 
+ 	  *op0 = gen_rtx_AND (GET_MODE (inner), inner,
+ 			      gen_int_mode (block, GET_MODE (inner)));
+ 	}
+     }
+ 
+   /* Narrow AND of memory against immediate to enable TM.  */
+   if ((*code == EQ || *code == NE)
+       && *op1 == const0_rtx
+       && GET_CODE (*op0) == AND
+       && GET_CODE (XEXP (*op0, 1)) == CONST_INT
+       && SCALAR_INT_MODE_P (GET_MODE (XEXP (*op0, 0))))
+     {
+       rtx inner = XEXP (*op0, 0);
+       rtx mask = XEXP (*op0, 1);
+ 
+       /* Ignore paradoxical SUBREGs if all extra bits are masked out.  */
+       if (GET_CODE (inner) == SUBREG
+ 	  && SCALAR_INT_MODE_P (GET_MODE (SUBREG_REG (inner)))
+ 	  && (GET_MODE_SIZE (GET_MODE (inner))
+ 	      >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
+ 	  && ((INTVAL (mask)
+                & GET_MODE_MASK (GET_MODE (inner))
+                & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (inner))))
+ 	      == 0))
+ 	inner = SUBREG_REG (inner);
+ 
+       /* Do not change volatile MEMs.  */
+       if (MEM_P (inner) && !MEM_VOLATILE_P (inner))
+ 	{
+ 	  int part = s390_single_part (XEXP (*op0, 1),
+ 				       GET_MODE (inner), QImode, 0);
+ 	  if (part >= 0)
+ 	    {
+ 	      mask = gen_int_mode (s390_extract_part (mask, QImode, 0), QImode);
+ 	      inner = adjust_address_nv (inner, QImode, part);
+ 	      *op0 = gen_rtx_AND (QImode, inner, mask);
+ 	    }
+ 	}
+     }
+ 
+   /* Narrow comparisons against 0xffff to HImode if possible.  */
+ 
+   if ((*code == EQ || *code == NE)
+       && GET_CODE (*op1) == CONST_INT
+       && INTVAL (*op1) == 0xffff
+       && SCALAR_INT_MODE_P (GET_MODE (*op0))
+       && (nonzero_bits (*op0, GET_MODE (*op0)) 
+ 	  & ~(unsigned HOST_WIDE_INT) 0xffff) == 0)
+     {
+       *op0 = gen_lowpart (HImode, *op0);
+       *op1 = constm1_rtx;
+     }
+ }
+ 
  /* Emit a compare instruction suitable to implement the comparison
     OP0 CODE OP1.  Return the correct condition RTL to be placed in
     the IF_THEN_ELSE of the conditional branch testing the result.  */
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.113
diff -c -p -r1.113 s390.h
*** gcc/config/s390/s390.h	19 Jul 2004 13:59:49 -0000	1.113
--- gcc/config/s390/s390.h	10 Aug 2004 19:08:35 -0000
*************** CUMULATIVE_ARGS;
*** 813,818 ****
--- 813,822 ----
     return the mode to be used for the comparison.  */
  #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
  
+ /* Canonicalize a comparison from one we don't have to one we do have.  */
+ #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
+   s390_canonicalize_comparison (&(CODE), &(OP0), &(OP1))
+ 
  /* Define the information needed to generate branch and scc insns.  This is
     stored from the compare operation.  Note that we can't use "rtx" here
     since it hasn't been defined!  */
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.119
diff -c -p -r1.119 s390.md
*** gcc/config/s390/s390.md	19 Jul 2004 13:59:49 -0000	1.119
--- gcc/config/s390/s390.md	10 Aug 2004 19:08:35 -0000
***************
*** 286,444 ****
  })
  
  
- ; Test-under-Mask (zero_extract) instructions
- 
- (define_insn "*tmdi_ext"
-   [(set (reg 33)
-         (compare (zero_extract:DI (match_operand:DI 0 "register_operand" "d")
- 	                          (match_operand:DI 1 "const_int_operand" "n")
-                                   (match_operand:DI 2 "const_int_operand" "n"))
-                  (const_int 0)))]
-   "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
-    && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
-    && INTVAL (operands[1]) + INTVAL (operands[2]) <= 64
-    && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
-       == INTVAL (operands[2]) >> 4"
- {
-   int part = INTVAL (operands[2]) >> 4;
-   int block = (1 << INTVAL (operands[1])) - 1;
-   int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
- 
-   operands[2] = GEN_INT (block << shift);
- 
-   switch (part)
-     {
-       case 0: return "tmhh\t%0,%x2";
-       case 1: return "tmhl\t%0,%x2";
-       case 2: return "tmlh\t%0,%x2";
-       case 3: return "tmll\t%0,%x2";
-       default: abort ();
-     }
- }
-   [(set_attr "op_type" "RI")])
- 
- (define_insn "*tmsi_ext"
-   [(set (reg 33)
-         (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
- 	                          (match_operand:SI 1 "const_int_operand" "n")
-                                   (match_operand:SI 2 "const_int_operand" "n"))
-                  (const_int 0)))]
-   "s390_match_ccmode(insn, CCTmode)
-    && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
-    && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
-    && (INTVAL (operands[1]) + INTVAL (operands[2]) - 1) >> 4
-       == INTVAL (operands[2]) >> 4"
- {
-   int part = INTVAL (operands[2]) >> 4;
-   int block = (1 << INTVAL (operands[1])) - 1;
-   int shift = 16 - INTVAL (operands[1]) - (INTVAL (operands[2]) & 15);
- 
-   operands[2] = GEN_INT (block << shift);
- 
-   switch (part)
-     {
-       case 0: return "tmh\t%0,%x2";
-       case 1: return "tml\t%0,%x2";
-       default: abort ();
-     }
- }
-   [(set_attr "op_type" "RI")])
- 
- (define_insn "*tmqisi_ext"
-   [(set (reg 33)
-         (compare (zero_extract:SI (match_operand:QI 0 "memory_operand" "Q,S")
- 	                          (match_operand:SI 1 "const_int_operand" "n,n")
-                                   (match_operand:SI 2 "const_int_operand" "n,n"))
-                  (const_int 0)))]
-   "!TARGET_64BIT && s390_match_ccmode(insn, CCTmode)
-    && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
-    && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
- {
-   int block = (1 << INTVAL (operands[1])) - 1;
-   int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
- 
-   operands[2] = GEN_INT (block << shift);
-   return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2";
- }
-   [(set_attr "op_type" "SI,SIY")])
- 
- (define_insn "*tmqidi_ext"
-   [(set (reg 33)
-         (compare (zero_extract:DI (match_operand:QI 0 "memory_operand" "Q,S")
- 	                          (match_operand:SI 1 "const_int_operand" "n,n")
-                                   (match_operand:SI 2 "const_int_operand" "n,n"))
-                  (const_int 0)))]
-   "TARGET_64BIT && s390_match_ccmode(insn, CCTmode)
-    && INTVAL (operands[1]) >= 1 && INTVAL (operands[2]) >= 0
-    && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8"
- {
-   int block = (1 << INTVAL (operands[1])) - 1;
-   int shift = 8 - INTVAL (operands[1]) - INTVAL (operands[2]);
- 
-   operands[2] = GEN_INT (block << shift);
-   return which_alternative == 0 ? "tm\t%0,%b2" : "tmy\t%0,%b2";
- }
-   [(set_attr "op_type" "SI,SIY")])
- 
- 
  ; Test-under-Mask instructions
  
- (define_insn "*tmdi_mem"
-   [(set (reg 33)
-         (compare (and:DI (match_operand:DI 0 "memory_operand" "Q,S")
-                          (match_operand:DI 1 "immediate_operand" "n,n"))
-                  (match_operand:DI 2 "immediate_operand" "n,n")))]
-   "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
-    && s390_single_part (operands[1], DImode, QImode, 0) >= 0"
- {
-   int part = s390_single_part (operands[1], DImode, QImode, 0);
-   operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
- 
-   operands[0] = gen_rtx_MEM (QImode,
- 			     plus_constant (XEXP (operands[0], 0), part));
-   return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
- }
-   [(set_attr "op_type" "SI,SIY")])
- 
- (define_insn "*tmsi_mem"
-   [(set (reg 33)
-         (compare (and:SI (match_operand:SI 0 "memory_operand" "Q,S")
-                          (match_operand:SI 1 "immediate_operand" "n,n"))
-                  (match_operand:SI 2 "immediate_operand" "n,n")))]
-   "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
-    && s390_single_part (operands[1], SImode, QImode, 0) >= 0"
- {
-   int part = s390_single_part (operands[1], SImode, QImode, 0);
-   operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
- 
-   operands[0] = gen_rtx_MEM (QImode,
- 			     plus_constant (XEXP (operands[0], 0), part));
-   return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
- }
-   [(set_attr "op_type" "SI")])
- 
- (define_insn "*tmhi_mem"
-   [(set (reg 33)
-         (compare (and:SI (subreg:SI (match_operand:HI 0 "memory_operand" "Q,S") 0)
-                          (match_operand:SI 1 "immediate_operand" "n,n"))
-                  (match_operand:SI 2 "immediate_operand" "n,n")))]
-   "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))
-    && s390_single_part (operands[1], HImode, QImode, 0) >= 0"
- {
-   int part = s390_single_part (operands[1], HImode, QImode, 0);
-   operands[1] = GEN_INT (s390_extract_part (operands[1], QImode, 0));
- 
-   operands[0] = gen_rtx_MEM (QImode,
- 			     plus_constant (XEXP (operands[0], 0), part));
-   return which_alternative == 0 ? "tm\t%0,%b1" : "tmy\t%0,%b1";
- }
-   [(set_attr "op_type" "SI")])
- 
  (define_insn "*tmqi_mem"
    [(set (reg 33)
!         (compare (and:SI (subreg:SI (match_operand:QI 0 "memory_operand" "Q,S") 0)
!                          (match_operand:SI 1 "immediate_operand" "n,n"))
!                  (match_operand:SI 2 "immediate_operand" "n,n")))]
    "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))"
    "@
     tm\t%0,%b1
--- 286,298 ----
  })
  
  
  ; Test-under-Mask instructions
  
  (define_insn "*tmqi_mem"
    [(set (reg 33)
!         (compare (and:QI (match_operand:QI 0 "memory_operand" "Q,S")
!                          (match_operand:QI 1 "immediate_operand" "n,n"))
!                  (match_operand:QI 2 "immediate_operand" "n,n")))]
    "s390_match_ccmode (insn, s390_tm_ccmode (operands[1], operands[2], 0))"
    "@
     tm\t%0,%b1
***************
*** 5196,5202 ****
                           (match_operand:DI 2 "general_operand" "d,m"))
                   (const_int 0)))
     (clobber (match_scratch:DI 0 "=d,d"))]
!   "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT"
    "@
     ngr\t%0,%2
     ng\t%0,%2"
--- 5050,5058 ----
                           (match_operand:DI 2 "general_operand" "d,m"))
                   (const_int 0)))
     (clobber (match_scratch:DI 0 "=d,d"))]
!   "s390_match_ccmode(insn, CCTmode) && TARGET_64BIT
!    /* Do not steal TM patterns.  */
!    && s390_single_part (operands[2], DImode, HImode, 0) < 0"
    "@
     ngr\t%0,%2
     ng\t%0,%2"
***************
*** 5262,5268 ****
                           (match_operand:SI 2 "general_operand" "d,R,T"))
                   (const_int 0)))
     (clobber (match_scratch:SI 0 "=d,d,d"))]
!   "s390_match_ccmode(insn, CCTmode)"
    "@
     nr\t%0,%2
     n\t%0,%2
--- 5118,5126 ----
                           (match_operand:SI 2 "general_operand" "d,R,T"))
                   (const_int 0)))
     (clobber (match_scratch:SI 0 "=d,d,d"))]
!   "s390_match_ccmode(insn, CCTmode)
!    /* Do not steal TM patterns.  */
!    && s390_single_part (operands[2], SImode, HImode, 0) < 0"
    "@
     nr\t%0,%2
     n\t%0,%2
-- 
  Dr. Ulrich Weigand
  weigand@informatik.uni-erlangen.de


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