From 3b699fc76495238a47d65c9164f93e321d175248 Mon Sep 17 00:00:00 2001
From: uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 17 Jun 2004 10:32:14 +0000
Subject: [PATCH] 	* config/s390/s390-modes.def (CCL3mode): New machine
 mode. 	* config/s390/s390.c (s390_match_ccmode_set): Support CCL3mode. 
 (s390_alc_comparison, s390_slb_comparison): Likewise. 
 (s390_branch_condition_mask): Likewise. 	* config/s390/s390.md
 ("*subdi3_cc2", "*subdi3_cconly2"): New. 	("*subsi3_cc2",
 "*subsi3_cconly2"): New.

	* config/s390/s390.h (PREDICATE_CODE): Accept SIGN_EXTEND and
	ZERO_EXTEND for s390_alc_comparison and s390_slb_comparison.
	* config/s390/s390.c (s390_alc_comparison, s390_slb_comparison):
	Handle SIGN_EXTEND and ZERO_EXTEND.

	* config/s390/s390-protos.h (s390_expand_addcc): New prototype.
	* config/s390/s390.c (s390_expand_addcc): New function.
	* config/s390/s390.md ("adddicc", "addsicc"): New expanders.
	("*sconddi", "*scondsi", "*sconddi_neg", "*scondsi_neg"): New insns.
	("sltu", "sgtu", "sleu", "sgeu"): New expanders.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@83287 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                  |  20 ++++
 gcc/config/s390/s390-modes.def |   1 +
 gcc/config/s390/s390-protos.h  |   1 +
 gcc/config/s390/s390.c         | 194 +++++++++++++++++++++++++++++++++
 gcc/config/s390/s390.h         |   6 +-
 gcc/config/s390/s390.md        | 164 ++++++++++++++++++++++++++++
 6 files changed, 384 insertions(+), 2 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5c07681ecc61..17ffc884dcba 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2004-06-17  Ulrich Weigand  <uweigand@de.ibm.com>
+
+	* config/s390/s390-modes.def (CCL3mode): New machine mode.
+	* config/s390/s390.c (s390_match_ccmode_set): Support CCL3mode.
+	(s390_alc_comparison, s390_slb_comparison): Likewise.
+	(s390_branch_condition_mask): Likewise.
+	* config/s390/s390.md ("*subdi3_cc2", "*subdi3_cconly2"): New.
+	("*subsi3_cc2", "*subsi3_cconly2"): New.
+
+	* config/s390/s390.h (PREDICATE_CODE): Accept SIGN_EXTEND and
+	ZERO_EXTEND for s390_alc_comparison and s390_slb_comparison.
+	* config/s390/s390.c (s390_alc_comparison, s390_slb_comparison):
+	Handle SIGN_EXTEND and ZERO_EXTEND.
+
+	* config/s390/s390-protos.h (s390_expand_addcc): New prototype.
+	* config/s390/s390.c (s390_expand_addcc): New function.
+	* config/s390/s390.md ("adddicc", "addsicc"): New expanders.
+	("*sconddi", "*scondsi", "*sconddi_neg", "*scondsi_neg"): New insns.
+	("sltu", "sgtu", "sleu", "sgeu"): New expanders.
+
 2004-06-17  Ben Elliston  <bje@au.ibm.com>
 
 	* tree-alias-common.c: Add whitespace.
diff --git a/gcc/config/s390/s390-modes.def b/gcc/config/s390/s390-modes.def
index 08759558871a..d1e7304e4253 100644
--- a/gcc/config/s390/s390-modes.def
+++ b/gcc/config/s390/s390-modes.def
@@ -32,6 +32,7 @@ CC_MODE (CCAN);
 CC_MODE (CCL);
 CC_MODE (CCL1);
 CC_MODE (CCL2);
+CC_MODE (CCL3);
 CC_MODE (CCU);
 CC_MODE (CCUR);
 CC_MODE (CCS);
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 90e4de61ac30..2362cb66d0a6 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -76,6 +76,7 @@ extern void s390_load_address (rtx, rtx);
 extern void s390_expand_movstr (rtx, rtx, rtx);
 extern void s390_expand_clrstr (rtx, rtx);
 extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx);
+extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern rtx s390_return_addr_rtx (int, rtx);
 extern rtx s390_emit_call (rtx, rtx, rtx, rtx);
 
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index ed1eb50f8302..d922e94a4997 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -282,6 +282,7 @@ s390_match_ccmode_set (rtx set, enum machine_mode req_mode)
     case CCLmode:
     case CCL1mode:
     case CCL2mode:
+    case CCL3mode:
     case CCT1mode:
     case CCT2mode:
     case CCT3mode:
@@ -477,6 +478,9 @@ s390_alc_comparison (rtx op, enum machine_mode mode)
   if (mode != VOIDmode && mode != GET_MODE (op))
     return 0;
 
+  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
+    op = XEXP (op, 0);
+
   if (!COMPARISON_P (op))
     return 0;
 
@@ -493,6 +497,9 @@ s390_alc_comparison (rtx op, enum machine_mode mode)
     case CCL2mode:
       return GET_CODE (op) == LEU;
 
+    case CCL3mode:
+      return GET_CODE (op) == GEU;
+
     case CCUmode:
       return GET_CODE (op) == GTU;
 
@@ -519,6 +526,9 @@ s390_slb_comparison (rtx op, enum machine_mode mode)
   if (mode != VOIDmode && mode != GET_MODE (op))
     return 0;
 
+  while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
+    op = XEXP (op, 0);
+
   if (!COMPARISON_P (op))
     return 0;
 
@@ -535,6 +545,9 @@ s390_slb_comparison (rtx op, enum machine_mode mode)
     case CCL2mode:
       return GET_CODE (op) == GTU;
 
+    case CCL3mode:
+      return GET_CODE (op) == LTU;
+
     case CCUmode:
       return GET_CODE (op) == LEU;
 
@@ -640,6 +653,19 @@ s390_branch_condition_mask (rtx code)
         }
       break;
 
+    case CCL3mode:
+      switch (GET_CODE (code))
+	{
+	case EQ:	return CC0 | CC2;
+	case NE:	return CC1 | CC3;
+	case LTU:	return CC1;
+	case GTU:	return CC3;
+	case LEU:	return CC1 | CC2;
+	case GEU:	return CC2 | CC3;
+	default:
+	  abort ();
+	}
+
     case CCUmode:
       switch (GET_CODE (code))
         {
@@ -3194,6 +3220,174 @@ s390_expand_cmpmem (rtx target, rtx op0, rtx op1, rtx len)
 #endif
 }
 
+
+/* Expand conditional increment or decrement using alc/slb instructions.
+   Should generate code setting DST to either SRC or SRC + INCREMENT,
+   depending on the result of the comparison CMP_OP0 CMP_CODE CMP_OP1.
+   Returns true if successful, false otherwise.  */
+
+bool
+s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1,
+		   rtx dst, rtx src, rtx increment)
+{
+  enum machine_mode cmp_mode;
+  enum machine_mode cc_mode;
+  rtx op_res;
+  rtx insn;
+  rtvec p;
+
+  if ((GET_MODE (cmp_op0) == SImode || GET_MODE (cmp_op0) == VOIDmode)
+      && (GET_MODE (cmp_op1) == SImode || GET_MODE (cmp_op1) == VOIDmode))
+    cmp_mode = SImode;
+  else if ((GET_MODE (cmp_op0) == DImode || GET_MODE (cmp_op0) == VOIDmode)
+	   && (GET_MODE (cmp_op1) == DImode || GET_MODE (cmp_op1) == VOIDmode))
+    cmp_mode = DImode;
+  else
+    return false;
+
+  /* Try ADD LOGICAL WITH CARRY.  */
+  if (increment == const1_rtx)
+    {
+      /* Determine CC mode to use.  */
+      if (cmp_code == EQ || cmp_code == NE)
+	{
+	  if (cmp_op1 != const0_rtx)
+	    {
+	      cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
+					     NULL_RTX, 0, OPTAB_WIDEN);
+	      cmp_op1 = const0_rtx;
+	    }
+
+	  cmp_code = cmp_code == EQ ? LEU : GTU;
+	}
+
+      if (cmp_code == LTU || cmp_code == LEU)
+	{
+	  rtx tem = cmp_op0;
+	  cmp_op0 = cmp_op1;
+	  cmp_op1 = tem;
+	  cmp_code = swap_condition (cmp_code);
+	}
+
+      switch (cmp_code)
+	{
+	  case GTU:
+	    cc_mode = CCUmode;
+	    break;
+
+	  case GEU:
+	    cc_mode = CCL3mode;
+	    break;
+
+	  default:
+	    return false;
+	}
+
+      /* Emit comparison instruction pattern. */
+      if (!register_operand (cmp_op0, cmp_mode))
+	cmp_op0 = force_reg (cmp_mode, cmp_op0);
+
+      insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
+			  gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
+      /* We use insn_invalid_p here to add clobbers if required.  */
+      if (insn_invalid_p (emit_insn (insn)))
+	abort ();
+
+      /* Emit ALC instruction pattern.  */
+      op_res = gen_rtx_fmt_ee (cmp_code, GET_MODE (dst),
+			       gen_rtx_REG (cc_mode, CC_REGNUM),
+			       const0_rtx);
+
+      if (src != const0_rtx)
+	{
+	  if (!register_operand (src, GET_MODE (dst)))
+	    src = force_reg (GET_MODE (dst), src);
+
+	  src = gen_rtx_PLUS (GET_MODE (dst), src, const0_rtx);
+	  op_res = gen_rtx_PLUS (GET_MODE (dst), src, op_res);
+	}
+
+      p = rtvec_alloc (2);
+      RTVEC_ELT (p, 0) = 
+        gen_rtx_SET (VOIDmode, dst, op_res);
+      RTVEC_ELT (p, 1) = 
+	gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+
+      return true;
+    }
+
+  /* Try SUBTRACT LOGICAL WITH BORROW.  */
+  if (increment == constm1_rtx)
+    {
+      /* Determine CC mode to use.  */
+      if (cmp_code == EQ || cmp_code == NE)
+	{
+	  if (cmp_op1 != const0_rtx)
+	    {
+	      cmp_op0 = expand_simple_binop (cmp_mode, XOR, cmp_op0, cmp_op1,
+					     NULL_RTX, 0, OPTAB_WIDEN);
+	      cmp_op1 = const0_rtx;
+	    }
+
+	  cmp_code = cmp_code == EQ ? LEU : GTU;
+	}
+
+      if (cmp_code == GTU || cmp_code == GEU)
+	{
+	  rtx tem = cmp_op0;
+	  cmp_op0 = cmp_op1;
+	  cmp_op1 = tem;
+	  cmp_code = swap_condition (cmp_code);
+	}
+
+      switch (cmp_code)
+	{
+	  case LEU:
+	    cc_mode = CCUmode;
+	    break;
+
+	  case LTU:
+	    cc_mode = CCL3mode;
+	    break;
+
+	  default:
+	    return false;
+	}
+
+      /* Emit comparison instruction pattern. */
+      if (!register_operand (cmp_op0, cmp_mode))
+	cmp_op0 = force_reg (cmp_mode, cmp_op0);
+
+      insn = gen_rtx_SET (VOIDmode, gen_rtx_REG (cc_mode, CC_REGNUM),
+			  gen_rtx_COMPARE (cc_mode, cmp_op0, cmp_op1));
+      /* We use insn_invalid_p here to add clobbers if required.  */
+      if (insn_invalid_p (emit_insn (insn)))
+	abort ();
+
+      /* Emit SLB instruction pattern.  */
+      if (!register_operand (src, GET_MODE (dst)))
+	src = force_reg (GET_MODE (dst), src);
+
+      op_res = gen_rtx_MINUS (GET_MODE (dst), 
+			      gen_rtx_MINUS (GET_MODE (dst), src, const0_rtx), 
+			      gen_rtx_fmt_ee (cmp_code, GET_MODE (dst), 
+					      gen_rtx_REG (cc_mode, CC_REGNUM), 
+					      const0_rtx));
+      p = rtvec_alloc (2);
+      RTVEC_ELT (p, 0) = 
+        gen_rtx_SET (VOIDmode, dst, op_res);
+      RTVEC_ELT (p, 1) = 
+	gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM));
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+
+      return true;
+    }
+
+  return false;
+}
+
+
 /* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index a73a68048619..af7551d93183 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -990,8 +990,10 @@ do {									\
   {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, 		\
 			   CONST_INT, CONST_DOUBLE }},			\
   {"s390_plus_operand", { PLUS }},					\
-  {"s390_alc_comparison", { LTU, GTU, LEU, GEU }},			\
-  {"s390_slb_comparison", { LTU, GTU, LEU, GEU }},
+  {"s390_alc_comparison", { ZERO_EXTEND, SIGN_EXTEND, 			\
+			    LTU, GTU, LEU, GEU }},			\
+  {"s390_slb_comparison", { ZERO_EXTEND, SIGN_EXTEND,			\
+			    LTU, GTU, LEU, GEU }},
 
 /* Specify the machine mode that this machine uses for the index in the
    tablejump instruction.  */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 91caa4a14225..8c3708769a6d 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -3976,6 +3976,18 @@
    slg\t%0,%2"
   [(set_attr "op_type"  "RRE,RXY")])
 
+(define_insn "*subdi3_cc2"
+  [(set (reg 33)
+        (compare (match_operand:DI 1 "register_operand" "0,0")
+                 (match_operand:DI 2 "general_operand" "d,m")))
+   (set (match_operand:DI 0 "register_operand" "=d,d")
+        (minus:DI (match_dup 1) (match_dup 2)))]
+  "s390_match_ccmode (insn, CCL3mode) && TARGET_64BIT"
+  "@
+   slgr\t%0,%2
+   slg\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
 (define_insn "*subdi3_cconly"
   [(set (reg 33)
         (compare (minus:DI (match_operand:DI 1 "register_operand" "0,0")
@@ -3988,6 +4000,17 @@
    slg\t%0,%2"
   [(set_attr "op_type"  "RRE,RXY")])
 
+(define_insn "*subdi3_cconly2"
+  [(set (reg 33)
+        (compare (match_operand:DI 1 "register_operand" "0,0")
+                 (match_operand:DI 2 "general_operand" "d,m")))
+   (clobber (match_scratch:DI 0 "=d,d"))]
+  "s390_match_ccmode (insn, CCL3mode) && TARGET_64BIT"
+  "@
+   slgr\t%0,%2
+   slg\t%0,%2"
+  [(set_attr "op_type"  "RRE,RXY")])
+
 (define_insn "*subdi3_64"
   [(set (match_operand:DI 0 "register_operand" "=d,d")
         (minus:DI (match_operand:DI 1 "register_operand" "0,0")
@@ -4111,6 +4134,19 @@
    sly\t%0,%2"
   [(set_attr "op_type"  "RR,RX,RXY")])
 
+(define_insn "*subsi3_cc2"
+  [(set (reg 33)
+        (compare (match_operand:SI 1 "register_operand" "0,0,0")
+                 (match_operand:SI 2 "general_operand" "d,R,T")))
+   (set (match_operand:SI 0 "register_operand" "=d,d,d")
+        (minus:SI (match_dup 1) (match_dup 2)))]
+  "s390_match_ccmode (insn, CCL3mode)"
+  "@
+   slr\t%0,%2
+   sl\t%0,%2
+   sly\t%0,%2"
+  [(set_attr "op_type"  "RR,RX,RXY")])
+
 (define_insn "*subsi3_cconly"
   [(set (reg 33)
         (compare (minus:SI (match_operand:SI 1 "register_operand" "0,0,0")
@@ -4124,6 +4160,18 @@
    sly\t%0,%2"
   [(set_attr "op_type"  "RR,RX,RXY")])
 
+(define_insn "*subsi3_cconly2"
+  [(set (reg 33)
+        (compare (match_operand:SI 1 "register_operand" "0,0,0")
+                 (match_operand:SI 2 "general_operand" "d,R,T")))
+   (clobber (match_scratch:SI 0 "=d,d,d"))]
+  "s390_match_ccmode (insn, CCL3mode)"
+  "@
+   slr\t%0,%2
+   sl\t%0,%2
+   sly\t%0,%2"
+  [(set_attr "op_type"  "RR,RX,RXY")])
+
 (define_insn "*subsi3_sign"
   [(set (match_operand:SI 0 "register_operand" "=d,d")
         (minus:SI (match_operand:SI 1 "register_operand" "0,0")
@@ -4339,6 +4387,17 @@
    slbg\\t%0,%2"
   [(set_attr "op_type"  "RRE,RXY")])
 
+(define_expand "adddicc"
+  [(match_operand:DI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:DI 2 "register_operand" "")
+   (match_operand:DI 3 "const_int_operand" "")]
+  "TARGET_64BIT"
+  "if (!s390_expand_addcc (GET_CODE (operands[1]), 
+			   s390_compare_op0, s390_compare_op1, 
+			   operands[0], operands[2], 
+			   operands[3])) FAIL; DONE;")
+
 ;
 ; addsicc instruction pattern(s).
 ;
@@ -4397,6 +4456,111 @@
    slb\\t%0,%2"
   [(set_attr "op_type"  "RRE,RXY")])
 
+(define_expand "addsicc"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand 1 "comparison_operator" "")
+   (match_operand:SI 2 "register_operand" "")
+   (match_operand:SI 3 "const_int_operand" "")]
+  "TARGET_CPU_ZARCH"
+  "if (!s390_expand_addcc (GET_CODE (operands[1]), 
+			   s390_compare_op0, s390_compare_op1, 
+			   operands[0], operands[2], 
+			   operands[3])) FAIL; DONE;")
+
+;
+; scond instruction pattern(s).
+;
+
+(define_insn_and_split "*sconddi"
+  [(set (match_operand:DI 0 "register_operand" "=&d")
+        (match_operand:DI 1 "s390_alc_comparison" ""))
+   (clobber (reg:CC 33))]
+  "TARGET_64BIT"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (parallel
+    [(set (match_dup 0) (plus:DI (plus:DI (match_dup 0) (match_dup 0))
+                                 (match_dup 1)))
+     (clobber (reg:CC 33))])]
+  ""
+  [(set_attr "op_type"  "NN")])
+
+(define_insn_and_split "*scondsi"
+  [(set (match_operand:SI 0 "register_operand" "=&d")
+        (match_operand:SI 1 "s390_alc_comparison" ""))
+   (clobber (reg:CC 33))]
+  "TARGET_CPU_ZARCH"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (parallel
+    [(set (match_dup 0) (plus:SI (plus:SI (match_dup 0) (match_dup 0))
+                                 (match_dup 1)))
+     (clobber (reg:CC 33))])]
+  ""
+  [(set_attr "op_type"  "NN")])
+
+(define_insn_and_split "*sconddi_neg"
+  [(set (match_operand:DI 0 "register_operand" "=&d")
+        (match_operand:DI 1 "s390_slb_comparison" ""))
+   (clobber (reg:CC 33))]
+  "TARGET_64BIT"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (parallel
+    [(set (match_dup 0) (minus:DI (minus:DI (match_dup 0) (match_dup 0))
+                                  (match_dup 1)))
+     (clobber (reg:CC 33))])
+   (parallel
+    [(set (match_dup 0) (neg:DI (match_dup 0)))
+     (clobber (reg:CC 33))])]
+  ""
+  [(set_attr "op_type"  "NN")])
+
+(define_insn_and_split "*scondsi_neg"
+  [(set (match_operand:SI 0 "register_operand" "=&d")
+        (match_operand:SI 1 "s390_slb_comparison" ""))
+   (clobber (reg:CC 33))]
+  "TARGET_CPU_ZARCH"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (const_int 0))
+   (parallel
+    [(set (match_dup 0) (minus:SI (minus:SI (match_dup 0) (match_dup 0))
+                                  (match_dup 1)))
+     (clobber (reg:CC 33))])
+   (parallel
+    [(set (match_dup 0) (neg:SI (match_dup 0)))
+     (clobber (reg:CC 33))])]
+  ""
+  [(set_attr "op_type"  "NN")])
+
+(define_expand "sltu"
+  [(match_operand:SI 0 "register_operand" "")]
+  "TARGET_CPU_ZARCH"
+  "if (!s390_expand_addcc (LTU, s390_compare_op0, s390_compare_op1,
+			   operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
+
+(define_expand "sgtu"
+  [(match_operand:SI 0 "register_operand" "")]
+  "TARGET_CPU_ZARCH"
+  "if (!s390_expand_addcc (GTU, s390_compare_op0, s390_compare_op1,
+			   operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
+
+(define_expand "sleu"
+  [(match_operand:SI 0 "register_operand" "")]
+  "TARGET_CPU_ZARCH"
+  "if (!s390_expand_addcc (LEU, s390_compare_op0, s390_compare_op1,
+			   operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
+
+(define_expand "sgeu"
+  [(match_operand:SI 0 "register_operand" "")]
+  "TARGET_CPU_ZARCH"
+  "if (!s390_expand_addcc (GEU, s390_compare_op0, s390_compare_op1,
+			   operands[0], const0_rtx, const1_rtx)) FAIL; DONE;")
+
 
 ;;
 ;;- Multiply instructions.
-- 
GitLab