From patchwork Tue Mar 5 20:51:47 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 225173 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 4C09A2C032B for ; Wed, 6 Mar 2013 07:52:15 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1363121536; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Message-ID:Subject:From:To:Date:Content-Type:Mime-Version: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=XEqpDjDPQatCMb9/OiQE 8tAfTIs=; b=WpfoZdlQfw5yX+UCW/gpJpkPD9d0X0vBcv/hSXxxqVBN+SQUEPTS 9e6mxPnezfUirbF/7WUorBs1VRh/PeYPmdlvswm76K8ynqcA+PMmtmGnJpZrfh7o 1+YSohHWcQatZnJ4zDubxi10sLQR3wK9Ehhs5GwLT6BOiWSBegLEicI= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Message-ID:Subject:From:To:Date:Content-Type:Mime-Version:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=IxQtwZS2m6ChPtuzTGlbcDrFK0PS/eRlnUnDRv9r9ZwGUxGdNy8UyBFmoTegXL gbEMORTwmIvBokMOBj21TcgVY3L7iR8hRlz1YTO9ktAyPV72juJ1pWBFm9RlNlek T5ajeT8RVfqGEiUXSQcMA8odw7wHJqAfyQhSD5zwoeCe8=; Received: (qmail 15849 invoked by alias); 5 Mar 2013 20:52:07 -0000 Received: (qmail 15839 invoked by uid 22791); 5 Mar 2013 20:52:06 -0000 X-SWARE-Spam-Status: No, hits=-3.4 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_NO, RP_MATCHES_RCVD, TW_VR, UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout06.t-online.de (HELO mailout06.t-online.de) (194.25.134.19) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 05 Mar 2013 20:51:59 +0000 Received: from fwd09.aul.t-online.de (fwd09.aul.t-online.de ) by mailout06.t-online.de with smtp id 1UCyq4-0000UB-Iq; Tue, 05 Mar 2013 21:51:56 +0100 Received: from [192.168.0.103] (XLM19+ZvZh2bePXHkFxyF5xVDCWqzEqS7+z5lRCGoupY5eclk6Isil15IqV9TU1gqF@[87.155.251.108]) by fwd09.t-online.de with esmtp id 1UCyq0-0QQ4LA0; Tue, 5 Mar 2013 21:51:52 +0100 Message-ID: <1362516707.2219.30.camel@yam-132-YW-E178-FTW> Subject: [SH] PR 55303 - Add basic support for SH2A clip insns From: Oleg Endo To: gcc-patches Date: Tue, 05 Mar 2013 21:51:47 +0100 Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi, This adds basic support for the SH2A clips and clipu instructions. Tested on rev 196406 with make -k check RUNTESTFLAGS="--target_board=sh-sim \{-m2/-ml,-m2/-mb,-m2a/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}" and no new failures. OK for trunk or 4.9? Cheers, Oleg gcc/ChangeLog: 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. testsuite/ChangeLog: PR target/55303 * gcc.target/sh/pr55303-1.c: New. * gcc.target/sh/pr55303-2.c: New. * gcc.target/sh/pr55303-3.c: New. Index: gcc/testsuite/gcc.target/sh/pr55303-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr55303-1.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr55303-1.c (revision 0) @@ -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; +} Index: gcc/testsuite/gcc.target/sh/pr55303-3.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr55303-3.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr55303-3.c (revision 0) @@ -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; +} Index: gcc/testsuite/gcc.target/sh/pr55303-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr55303-2.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr55303-2.c (revision 0) @@ -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; +} Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 196091) +++ gcc/config/sh/sh.c (working copy) @@ -3507,6 +3507,22 @@ 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: Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 196091) +++ gcc/config/sh/sh.md (working copy) @@ -11709,6 +11709,140 @@ (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 "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 "*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 ( == 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 ;; ------------------------------------------------------------------------- Index: gcc/config/sh/iterators.md =================================================================== --- gcc/config/sh/iterators.md (revision 196091) +++ gcc/config/sh/iterators.md (working copy) @@ -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]) Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 196091) +++ gcc/config/sh/predicates.md (working copy) @@ -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")