diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2013-05-06 00:16:55 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2013-05-06 00:16:55 +0000 |
commit | 2353515dafac6c7999110c09568b3cd0ba779710 (patch) | |
tree | e9abc6e1a00878a0e359e237b7b39316b2a8f7dc /gcc/config | |
parent | 459efabf0586f8fe5abcebef1837e2386a4326b0 (diff) | |
download | gcc-2353515dafac6c7999110c09568b3cd0ba779710.zip gcc-2353515dafac6c7999110c09568b3cd0ba779710.tar.gz gcc-2353515dafac6c7999110c09568b3cd0ba779710.tar.bz2 |
re PR target/55303 ([SH] Add support for clips / clipu instructions)
PR target/55303
* config/sh/sh.c (sh_rtx_costs): Handle SMIN and SMAX cases.
* config/sh/sh.md (*clips, uminsi3, *clipu, clipu_one): New insns and
related expanders.
* config/sh/iterators.md (SMIN_SMAX): New code iterator.
* config/sh/predicates.md (arith_reg_or_0_or_1_operand,
clips_min_const_int, clips_max_const_int, clipu_max_const_int):
New predicates.
PR target/55303
* gcc.target/sh/pr55303-1.c: New.
* gcc.target/sh/pr55303-2.c: New.
* gcc.target/sh/pr55303-3.c: New.
From-SVN: r198617
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/sh/iterators.md | 3 | ||||
-rw-r--r-- | gcc/config/sh/predicates.md | 28 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 16 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 134 |
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 ;; ------------------------------------------------------------------------- |