S/390: Support addMcc and sCOND patterns

Ulrich Weigand weigand@i1.informatik.uni-erlangen.de
Thu Jun 17 15:28:00 GMT 2004


Hello,

this adds support to use the ADD LOGICAL WITH CARRY and
SUBTRACT LOGICAL WITH BORROW instructions via the addMcc
and sCOND named patterns.

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

ChangeLog:

	* 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.


Index: gcc/config/s390/s390-modes.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-modes.def,v
retrieving revision 1.5
diff -c -p -r1.5 s390-modes.def
*** gcc/config/s390/s390-modes.def	13 Oct 2003 21:16:31 -0000	1.5
--- gcc/config/s390/s390-modes.def	15 Jun 2004 02:37:19 -0000
*************** CC_MODE (CCAN);
*** 32,37 ****
--- 32,38 ----
  CC_MODE (CCL);
  CC_MODE (CCL1);
  CC_MODE (CCL2);
+ CC_MODE (CCL3);
  CC_MODE (CCU);
  CC_MODE (CCUR);
  CC_MODE (CCS);
Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.47
diff -c -p -r1.47 s390-protos.h
*** gcc/config/s390/s390-protos.h	14 Jun 2004 12:11:06 -0000	1.47
--- gcc/config/s390/s390-protos.h	15 Jun 2004 02:37:19 -0000
*************** extern void s390_load_address (rtx, rtx)
*** 76,81 ****
--- 76,82 ----
  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);
  
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.148
diff -c -p -r1.148 s390.c
*** gcc/config/s390/s390.c	14 Jun 2004 12:11:06 -0000	1.148
--- gcc/config/s390/s390.c	15 Jun 2004 02:37:19 -0000
*************** s390_match_ccmode_set (rtx set, enum mac
*** 281,286 ****
--- 281,287 ----
      case CCLmode:
      case CCL1mode:
      case CCL2mode:
+     case CCL3mode:
      case CCT1mode:
      case CCT2mode:
      case CCT3mode:
*************** s390_alc_comparison (rtx op, enum machin
*** 476,481 ****
--- 477,485 ----
    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;
  
*************** s390_alc_comparison (rtx op, enum machin
*** 492,497 ****
--- 496,504 ----
      case CCL2mode:
        return GET_CODE (op) == LEU;
  
+     case CCL3mode:
+       return GET_CODE (op) == GEU;
+ 
      case CCUmode:
        return GET_CODE (op) == GTU;
  
*************** s390_slb_comparison (rtx op, enum machin
*** 518,523 ****
--- 525,533 ----
    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;
  
*************** s390_slb_comparison (rtx op, enum machin
*** 534,539 ****
--- 544,552 ----
      case CCL2mode:
        return GET_CODE (op) == GTU;
  
+     case CCL3mode:
+       return GET_CODE (op) == LTU;
+ 
      case CCUmode:
        return GET_CODE (op) == LEU;
  
*************** s390_branch_condition_mask (rtx code)
*** 639,644 ****
--- 652,670 ----
          }
        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))
          {
*************** s390_expand_cmpmem (rtx target, rtx op0,
*** 3193,3198 ****
--- 3219,3392 ----
  #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.  */
  
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.106
diff -c -p -r1.106 s390.h
*** gcc/config/s390/s390.h	14 Jun 2004 21:36:40 -0000	1.106
--- gcc/config/s390/s390.h	15 Jun 2004 02:37:19 -0000
*************** do {									\
*** 990,997 ****
    {"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 }},
  
  /* Specify the machine mode that this machine uses for the index in the
     tablejump instruction.  */
--- 990,999 ----
    {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, 		\
  			   CONST_INT, CONST_DOUBLE }},			\
    {"s390_plus_operand", { PLUS }},					\
!   {"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.  */
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.110
diff -c -p -r1.110 s390.md
*** gcc/config/s390/s390.md	13 Jun 2004 00:40:37 -0000	1.110
--- gcc/config/s390/s390.md	15 Jun 2004 02:37:20 -0000
***************
*** 3976,3981 ****
--- 3976,3993 ----
     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,3993 ****
--- 4000,4016 ----
     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,4116 ****
--- 4134,4152 ----
     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,4129 ****
--- 4160,4177 ----
     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,4344 ****
--- 4387,4403 ----
     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,4402 ****
--- 4456,4566 ----
     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.
-- 
  Dr. Ulrich Weigand
  weigand@informatik.uni-erlangen.de



More information about the Gcc-patches mailing list