aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/sh/iterators.md3
-rw-r--r--gcc/config/sh/predicates.md28
-rw-r--r--gcc/config/sh/sh.c16
-rw-r--r--gcc/config/sh/sh.md134
4 files changed, 181 insertions, 0 deletions
diff --git a/gcc/config/sh/iterators.md b/gcc/config/sh/iterators.md
index be8f9d8a..1af06b0 100644
--- a/gcc/config/sh/iterators.md
+++ b/gcc/config/sh/iterators.md
@@ -41,3 +41,6 @@
;; Lowpart subreg byte position code attributes for big and little endian.
(define_mode_attr lowpart_be [(QI "3") (HI "2")])
(define_mode_attr lowpart_le [(QI "0") (HI "0")])
+
+;; Signed minimum/maximum code iterator.
+(define_code_iterator SMIN_SMAX [smin smax])
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index dcbd75b..25949c6 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -195,6 +195,34 @@
return 0;
})
+;; Returns true if OP is either a register or constant 0 or constant 1.
+(define_predicate "arith_reg_or_0_or_1_operand"
+ (match_code "subreg,reg,const_int,const_vector")
+{
+ return arith_reg_or_0_operand (op, mode) || satisfies_constraint_M (op);
+})
+
+;; Returns true if OP is a suitable constant for the minimum value of a
+;; clips.b or clips.w insn.
+(define_predicate "clips_min_const_int"
+ (and (match_code "const_int")
+ (ior (match_test "INTVAL (op) == -128")
+ (match_test "INTVAL (op) == -32768"))))
+
+;; Returns true if OP is a suitable constant for the maximum value of a
+;; clips.b or clips.w insn.
+(define_predicate "clips_max_const_int"
+ (and (match_code "const_int")
+ (ior (match_test "INTVAL (op) == 127")
+ (match_test "INTVAL (op) == 32767"))))
+
+;; Returns true if OP is a suitable constant for the maximum value of a
+;; clipu.b or clipu.w insn.
+(define_predicate "clipu_max_const_int"
+ (and (match_code "const_int")
+ (ior (match_test "INTVAL (op) == 255")
+ (match_test "INTVAL (op) == 65535"))))
+
;; Returns 1 if OP is a floating point operator with two operands.
(define_predicate "binary_float_operator"
(and (match_code "plus,minus,mult,div")
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index c61952e..5976206 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -3504,6 +3504,22 @@ sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
else
return false;
+ case SMIN:
+ case SMAX:
+ /* This is most likely a clips.b or clips.w insn that is being made up
+ by combine. */
+ if (TARGET_SH2A
+ && (GET_CODE (XEXP (x, 0)) == SMAX || GET_CODE (XEXP (x, 0)) == SMIN)
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1))
+ && REG_P (XEXP (XEXP (x, 0), 0))
+ && CONST_INT_P (XEXP (x, 1)))
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ else
+ return false;
+
case CONST:
case LABEL_REF:
case SYMBOL_REF:
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 8984d98..b4fbd58 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -11711,6 +11711,140 @@ label:
(set_attr "in_delay_slot" "no")])
;; -------------------------------------------------------------------------
+;; Minimum / maximum operations.
+;; -------------------------------------------------------------------------
+
+;; The SH2A clips.b and clips.w insns do a signed min-max function. If smin
+;; and smax standard name patterns are defined, they will be used during
+;; initial expansion and combine will then be able to form the actual min-max
+;; pattern.
+;; The clips.b and clips.w set the SR.CS bit if the value in the register is
+;; clipped, but there is currently no way of making use of this information.
+;; The only way to read or reset the SR.CS bit is by accessing the SR.
+(define_expand "<code>si3"
+ [(parallel [(set (match_operand:SI 0 "arith_reg_dest")
+ (SMIN_SMAX:SI (match_operand:SI 1 "arith_reg_operand")
+ (match_operand 2 "const_int_operand")))
+ (clobber (reg:SI T_REG))])]
+ "TARGET_SH2A"
+{
+ /* Force the comparison value into a register, because greater-than
+ comparisons can work only on registers. Combine will be able to pick up
+ the constant value from the REG_EQUAL note when trying to form a min-max
+ pattern. */
+ operands[2] = force_reg (SImode, operands[2]);
+})
+
+;; Convert
+;; smax (smin (...))
+;; to
+;; smin (smax (...))
+(define_insn_and_split "*clips"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (smax:SI (smin:SI (match_operand:SI 1 "arith_reg_operand")
+ (match_operand 2 "clips_max_const_int"))
+ (match_operand 3 "clips_min_const_int")))]
+ "TARGET_SH2A"
+ "#"
+ "&& 1"
+ [(set (match_dup 0)
+ (smin:SI (smax:SI (match_dup 1) (match_dup 3)) (match_dup 2)))])
+
+(define_insn "*clips"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (smin:SI (smax:SI (match_operand:SI 1 "arith_reg_operand" "0")
+ (match_operand 2 "clips_min_const_int"))
+ (match_operand 3 "clips_max_const_int")))]
+ "TARGET_SH2A"
+{
+ if (INTVAL (operands[3]) == 127)
+ return "clips.b %0";
+ else if (INTVAL (operands[3]) == 32767)
+ return "clips.w %0";
+ else
+ gcc_unreachable ();
+}
+ [(set_attr "type" "arith")])
+
+;; If the expanded smin or smax patterns were not combined, split them into
+;; a compare and branch sequence, because there are no real smin or smax
+;; insns.
+(define_insn_and_split "*<code>si3"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (SMIN_SMAX:SI (match_operand:SI 1 "arith_reg_operand")
+ (match_operand:SI 2 "arith_reg_or_0_or_1_operand")))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH2A && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+{
+ rtx skip_label = gen_label_rtx ();
+ emit_move_insn (operands[0], operands[1]);
+
+ rtx cmp_val = operands[2];
+ if (satisfies_constraint_M (cmp_val))
+ cmp_val = const0_rtx;
+
+ emit_insn (gen_cmpgtsi_t (operands[0], cmp_val));
+ emit_jump_insn (<CODE> == SMIN
+ ? gen_branch_false (skip_label)
+ : gen_branch_true (skip_label));
+
+ emit_label_after (skip_label, emit_move_insn (operands[0], operands[2]));
+ DONE;
+})
+
+;; The SH2A clipu.b and clipu.w insns can be used to implement a min function
+;; with a register and a constant.
+;; The clipu.b and clipu.w set the SR.CS bit if the value in the register is
+;; clipped, but there is currently no way of making use of this information.
+;; The only way to read or reset the SR.CS bit is by accessing the SR.
+(define_expand "uminsi3"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (umin:SI (match_operand:SI 1 "arith_reg_operand")
+ (match_operand 2 "const_int_operand")))]
+ "TARGET_SH2A"
+{
+ if (INTVAL (operands[2]) == 1)
+ {
+ emit_insn (gen_clipu_one (operands[0], operands[1]));
+ DONE;
+ }
+ else if (! clipu_max_const_int (operands[2], VOIDmode))
+ FAIL;
+})
+
+(define_insn "*clipu"
+ [(set (match_operand:SI 0 "arith_reg_dest" "=r")
+ (umin:SI (match_operand:SI 1 "arith_reg_operand" "0")
+ (match_operand 2 "clipu_max_const_int")))]
+ "TARGET_SH2A"
+{
+ if (INTVAL (operands[2]) == 255)
+ return "clipu.b %0";
+ else if (INTVAL (operands[2]) == 65535)
+ return "clipu.w %0";
+ else
+ gcc_unreachable ();
+}
+ [(set_attr "type" "arith")])
+
+(define_insn_and_split "clipu_one"
+ [(set (match_operand:SI 0 "arith_reg_dest")
+ (umin:SI (match_operand:SI 1 "arith_reg_operand") (const_int 1)))
+ (clobber (reg:SI T_REG))]
+ "TARGET_SH2A"
+ "#"
+ "&& can_create_pseudo_p ()"
+ [(const_int 0)]
+{
+ emit_insn (gen_cmpeqsi_t (operands[1], const0_rtx));
+ emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ()));
+ DONE;
+})
+
+;; -------------------------------------------------------------------------
;; Misc
;; -------------------------------------------------------------------------