;; This is all complicated by the fact that since this is a jump insn
;; we must handle our own output reloads.
+;; branch on index
+
+; This splitter will be matched by combine and has to add the 2 moves
+; necessary to load the compare and the increment values into a
+; register pair as needed by brxle.
+
+(define_insn_and_split "*brx_stage1_<GPR:mode>"
+ [(set (pc)
+ (if_then_else
+ (match_operator 6 "s390_brx_operator"
+ [(plus:GPR (match_operand:GPR 1 "register_operand" "")
+ (match_operand:GPR 2 "general_operand" ""))
+ (match_operand:GPR 3 "register_operand" "")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:GPR 4 "nonimmediate_operand" "")
+ (plus:GPR (match_dup 1) (match_dup 2)))
+ (clobber (match_scratch:GPR 5 ""))]
+ "TARGET_CPU_ZARCH"
+ "#"
+ "!reload_completed && !reload_in_progress"
+ [(set (match_dup 7) (match_dup 2)) ; the increment
+ (set (match_dup 8) (match_dup 3)) ; the comparison value
+ (parallel [(set (pc)
+ (if_then_else
+ (match_op_dup 6
+ [(plus:GPR (match_dup 1) (match_dup 7))
+ (match_dup 8)])
+ (label_ref (match_dup 0))
+ (pc)))
+ (set (match_dup 4)
+ (plus:GPR (match_dup 1) (match_dup 7)))
+ (clobber (match_dup 5))
+ (clobber (reg:CC CC_REGNUM))])]
+ {
+ rtx dreg = gen_reg_rtx (word_mode == DImode ? TImode : DImode);
+ operands[7] = gen_lowpart (<GPR:MODE>mode,
+ gen_highpart (word_mode, dreg));
+ operands[8] = gen_lowpart (<GPR:MODE>mode,
+ gen_lowpart (word_mode, dreg));
+ })
+
+; brxlg, brxhg
+
+(define_insn_and_split "*brxg_64bit"
+ [(set (pc)
+ (if_then_else
+ (match_operator 5 "s390_brx_operator"
+ [(plus:DI (match_operand:DI 1 "register_operand" "d,d,d")
+ (subreg:DI (match_operand:TI 2 "register_operand" "d,d,d") 0))
+ (subreg:DI (match_dup 2) 8)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:DI 3 "nonimmediate_operand" "=1,?X,?X")
+ (plus:DI (match_dup 1)
+ (subreg:DI (match_dup 2) 0)))
+ (clobber (match_scratch:DI 4 "=X,&1,&?d"))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT"
+{
+ if (which_alternative != 0)
+ return "#";
+ else if (get_attr_length (insn) == 6)
+ return "brx%E5g\t%1,%2,%l0";
+ else
+ return "agr\t%1,%2\;cgr\t%1,%M2\;jg%C5\t%l0";
+}
+ "&& reload_completed
+ && (!REG_P (operands[3])
+ || !rtx_equal_p (operands[1], operands[3]))"
+ [(set (match_dup 4) (match_dup 1))
+ (parallel [(set (match_dup 4) (plus:DI (match_dup 4) (subreg:DI (match_dup 2) 0)))
+ (clobber (reg:CC CC_REGNUM))])
+ (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:DI (match_dup 2) 8)))
+ (set (match_dup 3) (match_dup 4))
+ (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)])
+ (label_ref (match_dup 0))
+ (pc)))]
+ ""
+ [(set_attr "op_type" "RIE")
+ (set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
+ (const_int 6) (const_int 16)))])
+
+; brxle, brxh
+
+(define_insn_and_split "*brx_64bit"
+ [(set (pc)
+ (if_then_else
+ (match_operator 5 "s390_brx_operator"
+ [(plus:SI (match_operand:SI 1 "register_operand" "d,d,d")
+ (subreg:SI (match_operand:TI 2 "register_operand" "d,d,d") 4))
+ (subreg:SI (match_dup 2) 12)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 3 "nonimmediate_operand" "=1,?X,?X")
+ (plus:SI (match_dup 1)
+ (subreg:SI (match_dup 2) 4)))
+ (clobber (match_scratch:SI 4 "=X,&1,&?d"))
+ (clobber (reg:CC CC_REGNUM))]
+ "TARGET_64BIT"
+{
+ if (which_alternative != 0)
+ return "#";
+ else if (get_attr_length (insn) == 6)
+ return "brx%C5\t%1,%2,%l0";
+ else
+ return "ar\t%1,%2\;cr\t%1,%M2\;jg%C5\t%l0";
+}
+ "&& reload_completed
+ && (!REG_P (operands[3])
+ || !rtx_equal_p (operands[1], operands[3]))"
+ [(set (match_dup 4) (match_dup 1))
+ (parallel [(set (match_dup 4) (plus:SI (match_dup 4) (subreg:SI (match_dup 2) 4)))
+ (clobber (reg:CC CC_REGNUM))])
+ (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:SI (match_dup 2) 12)))
+ (set (match_dup 3) (match_dup 4))
+ (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)])
+ (label_ref (match_dup 0))
+ (pc)))]
+ ""
+ [(set_attr "op_type" "RSI")
+ (set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
+ (const_int 6) (const_int 14)))])
+
+; brxle, brxh
+
+(define_insn_and_split "*brx_31bit"
+ [(set (pc)
+ (if_then_else
+ (match_operator 5 "s390_brx_operator"
+ [(plus:SI (match_operand:SI 1 "register_operand" "d,d,d")
+ (subreg:SI (match_operand:DI 2 "register_operand" "d,d,d") 0))
+ (subreg:SI (match_dup 2) 4)])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))
+ (set (match_operand:SI 3 "nonimmediate_operand" "=1,?X,?X")
+ (plus:SI (match_dup 1)
+ (subreg:SI (match_dup 2) 0)))
+ (clobber (match_scratch:SI 4 "=X,&1,&?d"))
+ (clobber (reg:CC CC_REGNUM))]
+ "!TARGET_64BIT && TARGET_CPU_ZARCH"
+{
+ if (which_alternative != 0)
+ return "#";
+ else if (get_attr_length (insn) == 6)
+ return "brx%C5\t%1,%2,%l0";
+ else
+ return "ar\t%1,%2\;cr\t%1,%M2\;jg%C5\t%l0";
+}
+ "&& reload_completed
+ && (!REG_P (operands[3])
+ || !rtx_equal_p (operands[1], operands[3]))"
+ [(set (match_dup 4) (match_dup 1))
+ (parallel [(set (match_dup 4) (plus:SI (match_dup 4) (subreg:SI (match_dup 2) 0)))
+ (clobber (reg:CC CC_REGNUM))])
+ (set (reg:CCS CC_REGNUM) (compare:CCS (match_dup 4) (subreg:SI (match_dup 2) 4)))
+ (set (match_dup 3) (match_dup 4))
+ (set (pc) (if_then_else (match_op_dup 5 [(reg:CCS CC_REGNUM) (const_int 0)])
+ (label_ref (match_dup 0))
+ (pc)))]
+ ""
+ [(set_attr "op_type" "RSI")
+ (set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 60000))
+ (const_int 6) (const_int 14)))])
+
+
+;; branch on count
+
(define_expand "doloop_end"
[(use (match_operand 0 "" "")) ; loop pseudo
(use (match_operand 1 "" "")) ; iterations; zero if unknown