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
This commit is contained in:
parent
459efabf05
commit
2353515daf
|
@ -1,3 +1,14 @@
|
|||
2013-05-06 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
|
||||
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.
|
||||
|
||||
2013-05-05 Steven Bosscher <steven@gcc.gnu.org>
|
||||
John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -11710,6 +11710,140 @@ label:
|
|||
[(set_attr "length" "0")
|
||||
(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
|
||||
;; -------------------------------------------------------------------------
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2013-05-06 Oleg Endo <olegendo@gcc.gnu.org>
|
||||
|
||||
PR target/55303
|
||||
* gcc.target/sh/pr55303-1.c: New.
|
||||
* gcc.target/sh/pr55303-2.c: New.
|
||||
* gcc.target/sh/pr55303-3.c: New.
|
||||
|
||||
2013-05-05 Tobias Burnus <burnus@net-b.de>
|
||||
|
||||
* gfortran.dg/allocate_with_source_3.f90: New.
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* Verify that the SH2A clips and clipu instructions are generated as
|
||||
expected. */
|
||||
/* { dg-do compile { target "sh*-*-*" } } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
|
||||
/* { dg-final { scan-assembler-times "clips.b" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "clips.w" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "clipu.b" 2 } } */
|
||||
/* { dg-final { scan-assembler-times "clipu.w" 2 } } */
|
||||
|
||||
static inline int
|
||||
min (int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static inline int
|
||||
max (int a, int b)
|
||||
{
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
int
|
||||
test_00 (int a)
|
||||
{
|
||||
/* 1x clips.b */
|
||||
return max (-128, min (127, a));
|
||||
}
|
||||
|
||||
int
|
||||
test_01 (int a)
|
||||
{
|
||||
/* 1x clips.b */
|
||||
return min (127, max (-128, a));
|
||||
}
|
||||
|
||||
int
|
||||
test_02 (int a)
|
||||
{
|
||||
/* 1x clips.w */
|
||||
return max (-32768, min (32767, a));
|
||||
}
|
||||
|
||||
int
|
||||
test_03 (int a)
|
||||
{
|
||||
/* 1x clips.w */
|
||||
return min (32767, max (-32768, a));
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_04 (unsigned int a)
|
||||
{
|
||||
/* 1x clipu.b */
|
||||
return a > 255 ? 255 : a;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_05 (unsigned int a)
|
||||
{
|
||||
/* 1x clipu.b */
|
||||
return a >= 255 ? 255 : a;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_06 (unsigned int a)
|
||||
{
|
||||
/* 1x clipu.w */
|
||||
return a > 65535 ? 65535 : a;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
test_07 (unsigned int a)
|
||||
{
|
||||
/* 1x clipu.w */
|
||||
return a >= 65535 ? 65535 : a;
|
||||
}
|
||||
|
||||
void
|
||||
test_08 (unsigned short a, unsigned short b, unsigned int* r)
|
||||
{
|
||||
/* Must not see a clip insn here -- it is not needed. */
|
||||
unsigned short x = a + b;
|
||||
if (x > 65535)
|
||||
x = 65535;
|
||||
*r = x;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/* Verify that for SH2A smax/smin -> cbranch conversion is done properly
|
||||
if the clips insn is not used and the expected comparison insns are
|
||||
generated. */
|
||||
/* { dg-do compile { target "sh*-*-*" } } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
|
||||
/* { dg-final { scan-assembler-times "cmp/pl" 4 } } */
|
||||
|
||||
int
|
||||
test_00 (int a)
|
||||
{
|
||||
/* 1x cmp/pl */
|
||||
return a >= 0 ? a : 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_01 (int a)
|
||||
{
|
||||
/* 1x cmp/pl */
|
||||
return a <= 0 ? a : 0;
|
||||
}
|
||||
|
||||
int
|
||||
test_02 (int a)
|
||||
{
|
||||
/* 1x cmp/pl */
|
||||
return a < 1 ? 1 : a;
|
||||
}
|
||||
|
||||
int
|
||||
test_03 (int a)
|
||||
{
|
||||
/* 1x cmp/pl */
|
||||
return a < 1 ? a : 1;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/* Verify that the special case (umin (reg const_int 1)) results in the
|
||||
expected instruction sequence on SH2A. */
|
||||
/* { dg-do compile { target "sh*-*-*" } } */
|
||||
/* { dg-options "-O2" } */
|
||||
/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */
|
||||
/* { dg-final { scan-assembler-times "tst" 1 } } */
|
||||
/* { dg-final { scan-assembler-times "movrt" 1 } } */
|
||||
|
||||
unsigned int
|
||||
test_00 (unsigned int a)
|
||||
{
|
||||
/* 1x tst
|
||||
1x movrt */
|
||||
return a > 1 ? 1 : a;
|
||||
}
|
Loading…
Reference in New Issue