From patchwork Mon Aug 13 20:08:52 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 177058 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 4B6742C0092 for ; Tue, 14 Aug 2012 06:09:34 +1000 (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=1345493374; 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=AHwj5o/oe7j667zKCd00 a9DLDpI=; b=n/wqHP/3Gb6A9RLSB0M7UYBpapQ78GM5BRpZi19xF9xHQH/rNRjo eJqiv/JuG88khx7ItOpX/Tkm4XORzrgqaVM1H7jhiB1kNUluKGi2FmZoQ7+2lI3X D8dRFbVlirXm1F5xDpo0hmWRcFloblYh5+26LiR0ru8BLpM74avr2eU= 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=HgRZnAdpMKo4UtW5Nps6VfNBNkv6gr5mnPlBxjW1AT5oUpFv9s83+7hvhF4huK QB5kypzZX3+KFwtLii5zw5dZDzcEBuSYhgsqvVCDbZ1tfG9vJsS8Jx9rFdNXkV6y 0i5J3IChnEHa0CyUFmnMzwnx9plGHqIhuaUO6p5OicXCo=; Received: (qmail 30549 invoked by alias); 13 Aug 2012 20:09:30 -0000 Received: (qmail 30529 invoked by uid 22791); 13 Aug 2012 20:09:24 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_NO, RCVD_IN_HOSTKARMA_YE, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout08.t-online.de (HELO mailout08.t-online.de) (194.25.134.20) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 13 Aug 2012 20:09:08 +0000 Received: from fwd24.aul.t-online.de (fwd24.aul.t-online.de ) by mailout08.t-online.de with smtp id 1T10wk-0006Dh-0W; Mon, 13 Aug 2012 22:09:06 +0200 Received: from [192.168.0.100] (SapwBgZOohLJC7U-zC3jjRWMaxZonLysVm+ZyRIxXlgR54n3MWZmBHeAuV3kuPOwON@[93.218.180.188]) by fwd24.t-online.de with esmtp id 1T10wi-093muu0; Mon, 13 Aug 2012 22:09:04 +0200 Message-ID: <1344888532.2279.51.camel@yam-132-YW-E178-FTW> Subject: [SH] PR 52933 - Use div0s insn for integer sign comparisons From: Oleg Endo To: gcc-patches Date: Mon, 13 Aug 2012 22:08:52 +0200 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 Hello, This patch adds basic support for utilizing the SH div0s instruction to simplify some integer sign comparisons such as '(a < 0) == (b < 0)'. Tested on rev 190332 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? Cheers, Oleg ChangeLog: PR target/52933 * config/sh/sh.md (cmp_div0s_0, cmp_div0s_1, *cmp_div0s_0, *cmp_div0s_1, *cbranch_div0s, *movsicc_div0s): New insns. * config/sh/sh.c (sh_rtx_costs): Handle div0s patterns. testsuite/ChangeLog: PR target/52933 * gcc.target/sh/pr52933-1.c: New. * gcc.target/sh/pr52933-2.c: New. Index: gcc/testsuite/gcc.target/sh/pr52933-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52933-1.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr52933-1.c (revision 0) @@ -0,0 +1,168 @@ +/* Check that the div0s instruction is used for integer sign comparisons. + Each test case is expected to emit at least one div0s insn. + Problems when combining the div0s comparison result with surrounding + logic usually show up as redundant tst insns. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O2" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */ +/* { dg-final { scan-assembler-times "div0s" 25 } } */ +/* { dg-final { scan-assembler-not "tst" } } */ + +typedef unsigned char bool; + +int other_func_a (int, int); +int other_func_b (int, int); + +bool +test_00 (int a, int b) +{ + return (a ^ b) >= 0; +} + +bool +test_01 (int a, int b) +{ + return (a ^ b) < 0; +} + +int +test_02 (int a, int b, int c, int d) +{ + if ((a ^ b) < 0) + return other_func_a (a, c); + else + return other_func_b (d, b); +} + +int +test_03 (int a, int b, int c, int d) +{ + if ((a ^ b) >= 0) + return other_func_a (a, c); + else + return other_func_b (d, b); +} + +int +test_04 (int a, int b) +{ + return (a ^ b) >= 0 ? -20 : -40; +} + +bool +test_05 (int a, int b) +{ + return (a ^ b) < 0; +} + +int +test_06 (int a, int b) +{ + return (a ^ b) < 0 ? -20 : -40; +} + +bool +test_07 (int a, int b) +{ + return (a < 0) == (b < 0); +} + +int +test_08 (int a, int b) +{ + return (a < 0) == (b < 0) ? -20 : -40; +} + +bool +test_09 (int a, int b) +{ + return (a < 0) != (b < 0); +} + +int +test_10 (int a, int b) +{ + return (a < 0) != (b < 0) ? -20 : -40; +} + +bool +test_11 (int a, int b) +{ + return (a >= 0) ^ (b < 0); +} + +int +test_12 (int a, int b) +{ + return (a >= 0) ^ (b < 0) ? -20 : -40; +} + +bool +test_13 (int a, int b) +{ + return !((a >= 0) ^ (b < 0)); +} + +int +test_14 (int a, int b) +{ + return !((a >= 0) ^ (b < 0)) ? -20 : -40; +} + +bool +test_15 (int a, int b) +{ + return (a & 0x80000000) == (b & 0x80000000); +} + +int +test_16 (int a, int b) +{ + return (a & 0x80000000) == (b & 0x80000000) ? -20 : -40; +} + +bool +test_17 (int a, int b) +{ + return (a & 0x80000000) != (b & 0x80000000); +} + +int +test_18 (int a, int b) +{ + return (a & 0x80000000) != (b & 0x80000000) ? -20 : -40; +} + +int +test_19 (unsigned int a, unsigned int b) +{ + return (a ^ b) >> 31; +} + +int +test_20 (unsigned int a, unsigned int b) +{ + return (a >> 31) ^ (b >> 31); +} + +int +test_21 (int a, int b) +{ + return ((a & 0x80000000) ^ (b & 0x80000000)) >> 31 ? -30 : -10; +} + +int +test_22 (int a, int b, int c, int d) +{ + if ((a < 0) == (b < 0)) + return other_func_a (a, b); + else + return other_func_b (c, d); +} + +bool +test_23 (int a, int b, int c, int d) +{ + /* Should emit 2x div0s. */ + return ((a < 0) == (b < 0)) | ((c < 0) == (d < 0)); +} Index: gcc/testsuite/gcc.target/sh/pr52933-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52933-2.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr52933-2.c (revision 0) @@ -0,0 +1,12 @@ +/* Check that the div0s instruction is used for integer sign comparisons + when -mpretend-cmove is enabled. + Each test case is expected to emit at least one div0s insn. + Problems when combining the div0s comparison result with surrounding + logic usually show up as redundant tst insns. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O2 -mpretend-cmove" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" } { "" } } */ +/* { dg-final { scan-assembler-times "div0s" 25 } } */ +/* { dg-final { scan-assembler-not "tst" } } */ + +#include "pr52933-1.c" Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 190332) +++ gcc/config/sh/sh.md (working copy) @@ -801,6 +801,70 @@ "cmp/pl %0" [(set_attr "type" "mt_group")]) +;; Some integer sign comparison patterns can be realized with the div0s insn. +;; div0s Rm,Rn T = (Rm >> 31) ^ (Rn >> 31) +(define_insn "cmp_div0s_0" + [(set (reg:SI T_REG) + (lshiftrt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "arith_reg_operand" "r")) + (const_int 31)))] + "TARGET_SH1" + "div0s %0,%1" + [(set_attr "type" "arith")]) + +(define_insn "cmp_div0s_1" + [(set (reg:SI T_REG) + (lt:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "arith_reg_operand" "r")) + (const_int 0)))] + "TARGET_SH1" + "div0s %0,%1" + [(set_attr "type" "arith")]) + +(define_insn_and_split "*cmp_div0s_0" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (lshiftrt:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" "")) + (const_int 31))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(set (reg:SI T_REG) + (lshiftrt:SI (xor:SI (match_dup 1) (match_dup 2)) (const_int 31))) + (set (match_dup 0) (reg:SI T_REG))]) + +(define_insn_and_split "*cmp_div0s_1" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (ge:SI (xor:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" "")) + (const_int 0))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(const_int 0)] +;; We have to go through the movnegt expander here which will handle the +;; SH2A vs non-SH2A cases. +{ + emit_insn (gen_cmp_div0s_1 (operands[1], operands[2])); + emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ())); + DONE; +}) + +(define_insn_and_split "*cmp_div0s_1" + [(set (reg:SI T_REG) + (ge:SI (xor:SI (match_operand:SI 0 "arith_reg_operand" "") + (match_operand:SI 1 "arith_reg_operand" "")) + (const_int 0)))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 0) (match_dup 1)) + (const_int 0))) + (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))]) + + ;; ------------------------------------------------------------------------- ;; SImode compare and branch ;; ------------------------------------------------------------------------- @@ -918,6 +982,63 @@ (label_ref (match_dup 2)) (pc)))]) +;; Compare and branch combine patterns for div0s comparisons. +(define_insn_and_split "*cbranch_div0s" + [(set (pc) + (if_then_else (lt (xor:SI (match_operand:SI 0 "arith_reg_operand" "") + (match_operand:SI 1 "arith_reg_operand" "")) + (const_int 0)) + (label_ref (match_operand 2)) + (pc))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(set (reg:SI T_REG) + (lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0))) + (set (pc) + (if_then_else (ne (reg:SI T_REG) (const_int 0)) + (label_ref (match_dup 2)) + (pc)))]) + +(define_insn_and_split "*cbranch_div0s" + [(set (pc) + (if_then_else (ge (xor:SI (match_operand:SI 0 "arith_reg_operand" "") + (match_operand:SI 1 "arith_reg_operand" "")) + (const_int 0)) + (label_ref (match_operand 2)) + (pc))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& 1" + [(set (reg:SI T_REG) + (lt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 0))) + (set (pc) + (if_then_else (eq (reg:SI T_REG) (const_int 0)) + (label_ref (match_dup 2)) + (pc)))]) + +;; Conditional move combine pattern for div0s comparisons. +;; This is used when TARGET_PRETEND_CMOVE is in effect. +(define_insn_and_split "*movsicc_div0s" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (if_then_else:SI (ge (xor:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" "")) + (const_int 0)) + (match_operand:SI 3 "arith_reg_operand" "") + (match_operand:SI 4 "general_movsrc_operand" ""))) + (clobber (reg:SI T_REG))] + "TARGET_PRETEND_CMOVE" + "#" + "&& 1" + [(set (reg:SI T_REG) (lt:SI (xor:SI (match_dup 1) (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (if_then_else (ne (reg:SI T_REG) (const_int 0)) + (match_dup 4) + (match_dup 3)))]) + ;; ------------------------------------------------------------------------- ;; SImode unsigned integer comparisons ;; ------------------------------------------------------------------------- Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 190332) +++ gcc/config/sh/sh.c (working copy) @@ -3186,9 +3186,33 @@ *total = COSTS_N_INSNS (multcosts (x)); return true; + case LT: + case GE: + /* div0s sign comparison. */ + if (GET_CODE (XEXP (x, 0)) == XOR + && REG_P ((XEXP (XEXP (x, 0), 0))) + && REG_P ((XEXP (XEXP (x, 0), 1))) + && satisfies_constraint_Z (XEXP (x, 1))) + { + *total = COSTS_N_INSNS (1); + return true; + } + else + return false; + + case LSHIFTRT: + /* div0s sign comparison. */ + if (GET_CODE (XEXP (x, 0)) == XOR + && REG_P ((XEXP (XEXP (x, 0), 0))) + && REG_P ((XEXP (XEXP (x, 0), 1))) + && CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 31) + { + *total = COSTS_N_INSNS (1); + return true; + } + /* Fall through to shiftcosts. */ case ASHIFT: case ASHIFTRT: - case LSHIFTRT: { int cost = shiftcosts (x); if (cost < 0)