;; min/max patterns
-(define_mode_iterator MAXMIN_IMODE
- [(SI "TARGET_SSE4_1") (DI "TARGET_AVX512VL")])
(define_code_attr maxmin_rel
[(smax "GE") (smin "LE") (umax "GEU") (umin "LEU")])
(define_expand "<code><mode>3"
[(parallel
- [(set (match_operand:MAXMIN_IMODE 0 "register_operand")
- (maxmin:MAXMIN_IMODE
- (match_operand:MAXMIN_IMODE 1 "register_operand")
- (match_operand:MAXMIN_IMODE 2 "nonimmediate_operand")))
+ [(set (match_operand:SWI248 0 "register_operand")
+ (maxmin:SWI248
+ (match_operand:SWI248 1 "register_operand")
+ (match_operand:SWI248 2 "general_operand")))
(clobber (reg:CC FLAGS_REG))])]
- "TARGET_STV")
+ "TARGET_CMOVE")
(define_insn_and_split "*<code><mode>3_1"
- [(set (match_operand:MAXMIN_IMODE 0 "register_operand")
- (maxmin:MAXMIN_IMODE
- (match_operand:MAXMIN_IMODE 1 "register_operand")
- (match_operand:MAXMIN_IMODE 2 "nonimmediate_operand")))
+ [(set (match_operand:SWI248 0 "register_operand")
+ (maxmin:SWI248
+ (match_operand:SWI248 1 "register_operand")
+ (match_operand:SWI248 2 "general_operand")))
(clobber (reg:CC FLAGS_REG))]
- "(TARGET_64BIT || <MODE>mode != DImode) && TARGET_STV
+ "TARGET_CMOVE
&& ix86_pre_reload_split ()"
"#"
"&& 1"
[(set (match_dup 0)
- (if_then_else:MAXMIN_IMODE (match_dup 3)
+ (if_then_else:SWI248 (match_dup 3)
(match_dup 1)
(match_dup 2)))]
{
machine_mode mode = <MODE>mode;
+ rtx cmp_op = operands[2];
- if (!register_operand (operands[2], mode))
- operands[2] = force_reg (mode, operands[2]);
+ if (!register_operand (cmp_op, mode))
+ operands[2] = force_reg (mode, cmp_op);
enum rtx_code code = <maxmin_rel>;
- machine_mode cmpmode = SELECT_CC_MODE (code, operands[1], operands[2]);
+
+ if (cmp_op == const1_rtx)
+ {
+ /* Convert smax (x, 1) into (x > 0 ? x : 1).
+ Convert umax (x, 1) into (x != 0 ? x : 1).
+ Convert ?min (x, 1) into (x <= 0 ? x : 1). */
+ cmp_op = const0_rtx;
+ if (code == GE)
+ code = GT;
+ else if (code == GEU)
+ code = NE;
+ }
+ /* Convert smin (x, -1) into (x < 0 ? x : -1). */
+ else if (cmp_op == constm1_rtx && code == LE)
+ {
+ cmp_op = const0_rtx;
+ code = LT;
+ }
+ /* Convert smax (x, -1) into (x >= 0 ? x : -1). */
+ else if (cmp_op == constm1_rtx && code == GE)
+ cmp_op = const0_rtx;
+ else if (cmp_op != const0_rtx)
+ cmp_op = operands[2];
+
+ machine_mode cmpmode = SELECT_CC_MODE (code, operands[1], cmp_op);
rtx flags = gen_rtx_REG (cmpmode, FLAGS_REG);
- rtx tmp = gen_rtx_COMPARE (cmpmode, operands[1], operands[2]);
+ rtx tmp = gen_rtx_COMPARE (cmpmode, operands[1], cmp_op);
emit_insn (gen_rtx_SET (flags, tmp));
operands[3] = gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
(define_insn_and_split "*<code>di3_doubleword"
[(set (match_operand:DI 0 "register_operand")
(maxmin:DI (match_operand:DI 1 "register_operand")
- (match_operand:DI 2 "nonimmediate_operand")))
+ (match_operand:DI 2 "general_operand")))
(clobber (reg:CC FLAGS_REG))]
- "!TARGET_64BIT && TARGET_STV && TARGET_AVX512VL
+ "!TARGET_64BIT && TARGET_CMOVE
&& ix86_pre_reload_split ()"
"#"
"&& 1"
gcc_unreachable ();
}
})
+
+;; Avoid clearing a register between a flags setting comparison and its use,
+;; i.e. prefer "xorl %eax,%eax; test/cmp" over "test/cmp; movl $0, %eax".
+(define_peephole2
+ [(set (reg FLAGS_REG) (match_operand 0))
+ (set (match_operand:SWI 1 "register_operand") (const_int 0))]
+ "peep2_regno_dead_p (0, FLAGS_REG)
+ && !reg_overlap_mentioned_p (operands[1], operands[0])"
+ [(set (match_dup 2) (match_dup 0))]
+{
+ operands[2] = gen_rtx_REG (GET_MODE (operands[0]), FLAGS_REG);
+ ix86_expand_clear (operands[1]);
+})
\f
;; Misc patterns (?)