* 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.
From-SVN: r83287
+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.
CC_MODE (CCL);
CC_MODE (CCL1);
CC_MODE (CCL2);
+CC_MODE (CCL3);
CC_MODE (CCU);
CC_MODE (CCUR);
CC_MODE (CCS);
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);
case CCLmode:
case CCL1mode:
case CCL2mode:
+ case CCL3mode:
case CCT1mode:
case CCT2mode:
case CCT3mode:
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;
case CCL2mode:
return GET_CODE (op) == LEU;
+ case CCL3mode:
+ return GET_CODE (op) == GEU;
+
case CCUmode:
return GET_CODE (op) == GTU;
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;
case CCL2mode:
return GET_CODE (op) == GTU;
+ case CCL3mode:
+ return GET_CODE (op) == LTU;
+
case CCUmode:
return GET_CODE (op) == LEU;
}
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))
{
#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. */
{"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. */
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")
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")
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")
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")
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).
;
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.