From patchwork Mon Mar 5 17:58:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 144732 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 D20ECB6F9D for ; Tue, 6 Mar 2012 05:00:37 +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=1331575238; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Subject:From:To:Content-Type:Date:Message-ID:Mime-Version: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=6IG29b/qEUFFGn5KXsnM whuQPCA=; b=cIYVedz0eIqcaZjZ0GoCgBrdZhO7NX4P/HiCrY0DOmhxnu3Kb3U3 blijOyf/q5AbeSFXWIDsp+xKHRAqhI5rCxLQek/bXKVVfB38IIKaON/6gjvxIodS 8UQP4V6759E7Q+uMmb/eaXFE8rP/OKyPptyRINSnJNfCwAUz/6e3KJs= 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:Subject:From:To:Content-Type:Date:Message-ID:Mime-Version:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=fHlkH4/YL+oFF/4T5LwYong2WBXtq+OppTf5dUjXXimLhUTXCMHbCBu6A5f6j5 giXvHwqDnD/iCoB3bwQvP1YmLN6Yv+i0qpbT+uF/7CwVQ8LI0wmc6nRstas8eAtM tdEhHZTzeI+mphV7hyKwMG1qJXqE1rJ8M2kXs7Bfv8Vz0=; Received: (qmail 21249 invoked by alias); 5 Mar 2012 17:59:57 -0000 Received: (qmail 21058 invoked by uid 22791); 5 Mar 2012 17:59:52 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, TW_EG, TW_VR, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout09.t-online.de (HELO mailout09.t-online.de) (194.25.134.84) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 05 Mar 2012 17:59:28 +0000 Received: from fwd02.aul.t-online.de (fwd02.aul.t-online.de ) by mailout09.t-online.de with smtp id 1S4cBy-0008M5-2c; Mon, 05 Mar 2012 18:59:26 +0100 Received: from [192.168.0.104] (JO5ZNZZFrhIfoSyJpURpcpUMWOoW3uPKCV3lVu2UWYPFFiw5d2OOqznZGLvYiQngRt@[87.157.54.217]) by fwd02.t-online.de with esmtp id 1S4cBv-0RbDLk0; Mon, 5 Mar 2012 18:59:23 +0100 Subject: [SH] PR 51244 - Improve conditional branches From: Oleg Endo To: gcc-patches Date: Mon, 05 Mar 2012 18:58:50 +0100 Message-ID: <1330970330.2929.261.camel@yam-132-YW-E178-FTW> 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, The attached patch is the same as the last one proposed in the PR. Tested against rev 184877 with make -k check RUNTESTFLAGS="--target_board=sh-sim \{-m2/-ml,-m2/-mb,-m2a-single/-mb, -m4-single/-ml,-m4-single/-mb, -m4a-single/-ml,-m4a-single/-mb}" and no new failures. OK? Cheers, Oleg ChangeLog: PR target/51244 * config/sh/sh.c (sh_expand_t_scc): Remove SH2A special case and use unified expansion logic. * config/sh/sh.md (xorsi3_movrt): Rename to movrt. Move closer to the existing movt insn. (negc): Rename insn to *negc. Add new expander. (movnegt): Use xor pattern for T bit negation. Reserve helper constant for negc pattern. (*movnegt): New insn and splitter. testsuite/ChangeLog: PR target/51244 * gcc.target/sh/pr51244-1.c: New. * gcc.target/sh/pr51244-2.c: New. * gcc.target/sh/pr51244-3.c: New. Index: gcc/testsuite/gcc.target/sh/pr51244-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr51244-1.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr51244-1.c (revision 0) @@ -0,0 +1,32 @@ +/* Check that inverted conditional branch logic does not generate + unnecessary explicit T bit extractions, inversions and + test instructions. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1 -mbranch-cost=2" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-not "tst|negc|extu" } } */ + +int +testfunc_00 (int a, int b, int c, int d) +{ + return (a != b || a != d) ? b : c; +} + +int +testfunc_01 (int a, char* p, int b, int c) +{ + return (a == b && a == c) ? b : c; +} + +int +testfunc_02 (int a, char* p, int b, int c) +{ + return (a == b && a == c) ? b : c; +} + +int +testfunc_03 (int a, char* p, int b, int c) +{ + return (a != b && a != c) ? b : c; +} + Index: gcc/testsuite/gcc.target/sh/pr51244-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr51244-2.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr51244-2.c (revision 0) @@ -0,0 +1,18 @@ +/* Check that when taking the complement of the T bit using the negc + instruction pattern, the constant -1 is loaded only once. + On SH2A this test is skipped because the movrt instruction is used + to get the complement of the T bit. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1 -mbranch-cost=2" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*" "-m2a*" } { "" } } */ +/* { dg-final { scan-assembler-times "mov\t#-1" 1 } } */ + +void +testfunc_00 (int* a, int* b, int c, int d) +{ + b[0] = a[0] != c; + b[1] = a[1] != d; + b[2] = a[2] != c; + b[3] = a[3] != d; +} + Index: gcc/testsuite/gcc.target/sh/pr51244-3.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr51244-3.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr51244-3.c (revision 0) @@ -0,0 +1,16 @@ +/* Check that when taking the complement of the T bit on SH2A, + the movrt instruction is being generated. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1 -mbranch-cost=2" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "*" } { "-m2a*" } } */ +/* { dg-final { scan-assembler-times "movrt" 4 } } */ + +void +testfunc_00 (int* a, int* b, int c, int d) +{ + b[0] = a[0] != c; + b[1] = a[1] != d; + b[2] = a[2] != c; + b[3] = a[3] != d; +} + Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 184877) +++ gcc/config/sh/sh.c (working copy) @@ -11883,15 +11883,8 @@ val = INTVAL (op1); if ((code == EQ && val == 1) || (code == NE && val == 0)) emit_insn (gen_movt (result)); - else if (TARGET_SH2A && ((code == EQ && val == 0) - || (code == NE && val == 1))) - emit_insn (gen_xorsi3_movrt (result)); else if ((code == EQ && val == 0) || (code == NE && val == 1)) - { - emit_clobber (result); - emit_insn (gen_subc (result, result, result)); - emit_insn (gen_addsi3 (result, result, const1_rtx)); - } + emit_insn (gen_movnegt (result)); else if (code == EQ || code == NE) emit_insn (gen_move_insn (result, GEN_INT (code == NE))); else Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 184877) +++ gcc/config/sh/sh.md (working copy) @@ -3354,15 +3354,6 @@ xori %1, %2, %0" [(set_attr "type" "arith_media")]) -;; Store the complements of the T bit in a register. -(define_insn "xorsi3_movrt" - [(set (match_operand:SI 0 "arith_reg_dest" "=r") - (xor:SI (reg:SI T_REG) - (const_int 1)))] - "TARGET_SH2A" - "movrt\\t%0" - [(set_attr "type" "arith")]) - (define_insn "xordi3" [(set (match_operand:DI 0 "arith_reg_dest" "=r,r") (xor:DI (match_operand:DI 1 "arith_reg_operand" "%r,r") @@ -4387,7 +4378,17 @@ ;; Unary arithmetic ;; ------------------------------------------------------------------------- -(define_insn "negc" +(define_expand "negc" + [(parallel [(set (match_operand:SI 0 "arith_reg_dest" "") + (neg:SI (plus:SI (reg:SI T_REG) + (match_operand:SI 1 "arith_reg_operand" "")))) + (set (reg:SI T_REG) + (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1)) + (const_int 0)))])] + "" + "") + +(define_insn "*negc" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (neg:SI (plus:SI (reg:SI T_REG) (match_operand:SI 1 "arith_reg_operand" "r")))) @@ -9528,6 +9529,13 @@ "movt %0" [(set_attr "type" "arith")]) +(define_insn "movrt" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (xor:SI (reg:SI T_REG) (const_int 1)))] + "TARGET_SH2A" + "movrt %0" + [(set_attr "type" "arith")]) + (define_expand "cstore4_media" [(set (match_operand:SI 0 "register_operand" "=r") (match_operator:SI 1 "sh_float_comparison_operator" @@ -9654,40 +9662,55 @@ DONE; ") -;; sne moves the complement of the T reg to DEST like this: -;; cmp/eq ... -;; mov #-1,temp -;; negc temp,dest -;; This is better than xoring compare result with 1 because it does -;; not require r0 and further, the -1 may be CSE-ed or lifted out of a -;; loop. +;; Move the complement of the T reg to a reg. +;; On SH2A the movrt insn can be used. +;; On anything else than SH2A this has to be done with multiple instructions. +;; One obvious way would be: +;; cmp/eq ... +;; movt r0 +;; xor #1,r0 +;; +;; However, this puts pressure on r0 in most cases and thus the following is +;; more appealing: +;; cmp/eq ... +;; mov #-1,temp +;; negc temp,dest +;; +;; If the constant -1 can be CSE-ed or lifted out of a loop it effectively +;; becomes a one instruction operation. Moreover, care must be taken that +;; the insn can still be combined with inverted compare and branch code +;; around it. +;; The expander will reserve the constant -1, the insn makes the whole thing +;; combinable, the splitter finally emits the insn if it was not combined +;; away. +;; Notice that when using the negc variant the T bit also gets inverted. (define_expand "movnegt" [(set (match_dup 1) (const_int -1)) - (parallel [(set (match_operand:SI 0 "" "") - (neg:SI (plus:SI (reg:SI T_REG) - (match_dup 1)))) - (set (reg:SI T_REG) - (ne:SI (ior:SI (reg:SI T_REG) (match_dup 1)) - (const_int 0)))])] + (parallel [(set (match_operand:SI 0 "arith_reg_dest" "") + (xor:SI (reg:SI T_REG) (const_int 1))) + (use (match_dup 1))])] "" - " { operands[1] = gen_reg_rtx (SImode); -}") +}) -;; Recognize mov #-1/negc/neg sequence, and change it to movt/add #-1. -;; This prevents a regression that occurred when we switched from xor to -;; mov/neg for sne. - -(define_split - [(set (match_operand:SI 0 "arith_reg_dest" "") - (plus:SI (reg:SI T_REG) - (const_int -1)))] +(define_insn_and_split "*movnegt" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (xor:SI (reg:SI T_REG) (const_int 1))) + (use (match_operand:SI 1 "arith_reg_operand" "r"))] "TARGET_SH1" - [(set (match_dup 0) (eq:SI (reg:SI T_REG) (const_int 1))) - (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1)))] - "") + "#" + "&& 1" + [(const_int 0)] +{ + if (TARGET_SH2A) + emit_insn (gen_movrt (operands[0])); + else + emit_insn (gen_negc (operands[0], operands[1])); + DONE; +} + [(set_attr "type" "arith")]) (define_expand "cstoresf4" [(set (match_operand:SI 0 "register_operand" "=r")