From patchwork Mon Sep 28 14:03:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 523351 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 720E7140157 for ; Tue, 29 Sep 2015 00:03:38 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=oy6Yv5Co; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:subject:from:to:date:content-type:mime-version; q= dns; s=default; b=Tf0LG5fFwpauupNee7//Z3xghZSXkOb6yxjeAbyfjd6992 cO4CLARYeV7PBgqYB3C232k7UiA0qvtHx81d1MjeeI48Ssq66qvH7qAzdlt8gUTz EVGtM4Txm08S3nJq/2ZLoFT0gXz8cxhZs8LZ9TA2f01XpHw3656fz+jvMNf0g= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:subject:from:to:date:content-type:mime-version; s= default; bh=pRTtMnPHOcxOsWfqrvxjvphyvcQ=; b=oy6Yv5Cou6Iw71Yelzor eaZdO3VmKIxwDQPbtJdBz2EKZUTD9VUdYUdBFAHk845RCIoWipWG0G+scjvPjzVT S5fMXsikFmJRPY03+xWWEirRAcxgvr6rCayW/esHlh9elYpI+1VpNBOscXdmDP60 Y+1aSACWEI++bR07SjldRNQ= Received: (qmail 24974 invoked by alias); 28 Sep 2015 14:03:31 -0000 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 Received: (qmail 24964 invoked by uid 89); 28 Sep 2015 14:03:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.2 required=5.0 tests=AWL, BAYES_00, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mailout11.t-online.de Received: from mailout11.t-online.de (HELO mailout11.t-online.de) (194.25.134.85) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 28 Sep 2015 14:03:28 +0000 Received: from fwd14.aul.t-online.de (fwd14.aul.t-online.de [172.20.26.242]) by mailout11.t-online.de (Postfix) with SMTP id 5EFB3197AB7 for ; Mon, 28 Sep 2015 16:03:24 +0200 (CEST) Received: from [192.168.0.16] (rfAd0vZdQh8hPmDgjXVbYUuPllT29xShvCQNjtBgOrwuFzsFFik0W60bv84QXsAQlD@[115.165.93.200]) by fwd14.t-online.de with (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384 encrypted) esmtp id 1ZgZ1T-0KaT1k0; Mon, 28 Sep 2015 16:03:19 +0200 Message-ID: <1443448996.2509.133.camel@t-online.de> Subject: [SH][committed] Improve treg_set_expr matching From: Oleg Endo To: gcc-patches Date: Mon, 28 Sep 2015 23:03:16 +0900 Mime-Version: 1.0 X-IsSubscribed: yes Hi, This patch has been hanging around in my queue for a while. Basically, it uses reverse_condition to get better matching for treg_set_expr. Tested on sh-elf 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. Committed as r228202. Cheers, Oleg gcc/ChangeLog: PR target/54236 * config/sh/predicates.md (t_reg_operand, negt_reg_operand): Allow and handle ne and eq codes. * config/sh/sh.c (sh_rtx_costs): Adjust matching of tst #imm,r0 insn. (sh_recog_treg_set_expr): Early accept negt_reg_operand. Eearly reject CONST_INT_P. Use reverse_condition. (sh_split_treg_set_expr): Likewise. gcc/testsuite/ChangeLog: PR target/54236 * gcc.target/sh/pr54236-1.c (test_09, test_10, test_11): New. * gcc.target/sh/pr59533-1.c (test_23, test_24, test_25, test_26, test_27): New. * gcc.target/sh/pr54236-5.c: New. * gcc.target/sh/pr54236-6.c: New. Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 228175) +++ gcc/config/sh/predicates.md (working copy) @@ -1158,10 +1158,18 @@ ;; A predicate describing the T bit register in any form. (define_predicate "t_reg_operand" - (match_code "reg,subreg,sign_extend,zero_extend") + (match_code "reg,subreg,sign_extend,zero_extend,ne,eq") { switch (GET_CODE (op)) { + case EQ: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const1_rtx; + + case NE: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const0_rtx; + case REG: return REGNO (op) == T_REG; @@ -1183,13 +1191,21 @@ ;; A predicate describing a negated T bit register. (define_predicate "negt_reg_operand" - (match_code "subreg,xor") + (match_code "subreg,xor,ne,eq") { switch (GET_CODE (op)) { + case EQ: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const0_rtx; + + case NE: + return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) + && XEXP (op, 1) == const1_rtx; + case XOR: return t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))) - && satisfies_constraint_M (XEXP (op, 1)); + && XEXP (op, 1) == const1_rtx; case SUBREG: return negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0))); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 228176) +++ gcc/config/sh/sh.c (working copy) @@ -3592,13 +3592,12 @@ case EQ: /* An and with a constant compared against zero is - most likely going to be a TST #imm, R0 instruction. - Notice that this does not catch the zero_extract variants from - the md file. */ + most likely going to be a TST #imm, R0 instruction. */ if (XEXP (x, 1) == const0_rtx - && (GET_CODE (XEXP (x, 0)) == AND - || (SUBREG_P (XEXP (x, 0)) - && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND))) + && ((GET_CODE (XEXP (x, 0)) == AND + || (SUBREG_P (XEXP (x, 0)) + && GET_CODE (SUBREG_REG (XEXP (x, 0))) == AND)) + || GET_CODE (XEXP (x, 0)) == ZERO_EXTRACT)) { *total = 1; return true; @@ -14200,7 +14199,8 @@ return false; /* Early accept known possible operands before doing recog. */ - if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode)) + if (op == const0_rtx || op == const1_rtx || t_reg_operand (op, mode) + || negt_reg_operand (op, mode)) return true; /* Early reject impossible operands before doing recog. @@ -14209,8 +14209,8 @@ such as lower-subreg will bail out. Some insns such as SH4A movua are done with UNSPEC, so must reject those, too, or else it would result in an invalid reg -> treg move. */ - if (register_operand (op, mode) || memory_operand (op, mode) - || sh_unspec_insn_p (op)) + if (CONST_INT_P (op) || register_operand (op, mode) + || memory_operand (op, mode) || sh_unspec_insn_p (op)) return false; if (!can_create_pseudo_p ()) @@ -14230,26 +14230,30 @@ SET_PREV_INSN (i) = NULL; SET_NEXT_INSN (i) = NULL; + /* If the comparison op doesn't have a result mode, set it to SImode. */ + machine_mode prev_op_mode = GET_MODE (op); + if (COMPARISON_P (op) && prev_op_mode == VOIDmode) + PUT_MODE (op, SImode); + int result = recog (PATTERN (i), i, 0); - /* It seems there is no insn like that. Create a simple negated - version and try again. If we hit a negated form, we'll allow that - and append a nott sequence when splitting out the insns. Insns that - do the split can then remove the trailing nott if they know how to - deal with it. */ - if (result < 0 && GET_CODE (op) == EQ) + /* It seems there is no insn like that. Create a negated version and + try again. If we hit a negated form, we'll allow that and append a + nott sequence when splitting out the insns. Insns that do the split + can then remove the trailing nott if they know how to deal with it. */ + if (result < 0 && COMPARISON_P (op)) { - PUT_CODE (op, NE); + machine_mode cmp_mode = GET_MODE (XEXP (op, 0)); + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (XEXP (op, 1)); + + rtx_code prev_code = GET_CODE (op); + PUT_CODE (op, reverse_condition (GET_CODE (op))); result = recog (PATTERN (i), i, 0); - PUT_CODE (op, EQ); + PUT_CODE (op, prev_code); } - if (result < 0 && GET_CODE (op) == NE) - { - PUT_CODE (op, EQ); - result = recog (PATTERN (i), i, 0); - PUT_CODE (op, NE); - } + PUT_MODE (op, prev_op_mode); recog_data = prev_recog_data; return result >= 0; } @@ -14350,37 +14354,43 @@ fprintf (dump_file, "\n"); } + /* If the insn is not found, we will try a negated form and append + a nott. */ + bool append_nott = false; + /* We are going to invoke recog/split_insns in a re-entrant way and thus have to capture its current state and restore it afterwards. */ recog_data_d prev_recog_data = recog_data; - int insn_code = recog (PATTERN (i), i, 0); - - /* If the insn was not found, see if we matched the negated form before - and append a nott. */ - bool append_nott = false; - - if (insn_code < 0 && GET_CODE (x) == EQ) + if (negt_reg_operand (x, GET_MODE (x))) { - PUT_CODE (x, NE); - insn_code = recog (PATTERN (i), i, 0); - if (insn_code >= 0) - append_nott = true; - else - PUT_CODE (x, EQ); + /* This is a normal movt followed by a nott. It will be converted + into a movrt after initial expansion. */ + XEXP (PATTERN (i), 1) = get_t_reg_rtx (); + append_nott = true; } - if (insn_code < 0 && GET_CODE (x) == NE) + else { - PUT_CODE (x, EQ); - insn_code = recog (PATTERN (i), i, 0); - if (insn_code >= 0) - append_nott = true; - else - PUT_CODE (x, NE); + /* If the comparison op doesn't have a mode set, set it to SImode. */ + if (COMPARISON_P (x) && GET_MODE (x) == VOIDmode) + PUT_MODE (x, SImode); + + int insn_code = recog (PATTERN (i), i, 0); + + if (insn_code < 0 && COMPARISON_P (x)) + { + machine_mode cmp_mode = GET_MODE (XEXP (x, 0)); + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (XEXP (x, 1)); + + PUT_CODE (x, reverse_condition (GET_CODE (x))); + insn_code = recog (PATTERN (i), i, 0); + append_nott = true; + } + + gcc_assert (insn_code >= 0); } - gcc_assert (insn_code >= 0); - /* Try to recursively split the insn. Some insns might refuse to split any further while we are in the treg_set_expr splitting phase. They will be emitted as part of the outer insn and then split again. */ Index: gcc/testsuite/gcc.target/sh/pr54236-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-1.c (revision 228175) +++ gcc/testsuite/gcc.target/sh/pr54236-1.c (working copy) @@ -4,8 +4,8 @@ /* { dg-do compile } */ /* { dg-options "-O1" } */ /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ -/* { dg-final { scan-assembler-times "addc" 4 } } */ -/* { dg-final { scan-assembler-times "subc" 3 } } */ +/* { dg-final { scan-assembler-times "addc" 6 } } */ +/* { dg-final { scan-assembler-times "subc" 4 } } */ /* { dg-final { scan-assembler-times "sett" 5 } } */ /* { dg-final { scan-assembler-times "negc" 2 { target { ! sh2a } } } } */ @@ -86,3 +86,25 @@ /* 1x addc, 1x sett */ return (a << 1) + 1; } + +unsigned int +test_09 (unsigned int x) +{ + /* 1x tst, 1x addc */ + return x - (x != 0); +} + +unsigned int +test_10 (unsigned int x) +{ + /* 1x tst, 1x subc */ + return x + (x == 0); +} + +unsigned int +test_11 (unsigned int x) +{ + /* 1x tst, 1x addc */ + return x + (x != 0); +} + Index: gcc/testsuite/gcc.target/sh/pr54236-5.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-5.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54236-5.c (working copy) @@ -0,0 +1,89 @@ +/* Check that addc and subc instructions are generated as expected in + combination with ifcvt. */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-times "subc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "not\t" 0 { target { ! sh2a } } } } */ + +/* { dg-final { scan-assembler-times "subc" 4 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "nott" 0 { target { sh2a } } } } */ + +/* { dg-final { scan-assembler-times "tst\t" 4 } } */ +/* { dg-final { scan-assembler-times "cmp/eq" 1 } } */ +/* { dg-final { scan-assembler-times "cmp/pl" 2 } } */ +/* { dg-final { scan-assembler-times "cmp/gt" 1 } } */ + +/* { dg-final { scan-assembler-not "movt" } } */ +/* { dg-final { scan-assembler-not "negc" } } */ +/* { dg-final { scan-assembler-not "movrt" } } */ + +int +test_00 (int x, int y) +{ + /* 1x tst, 1x subc */ + if (y) + ++x; + return x; +} + +int +test_01 (int x, int y) +{ + /* 1x tst, 1x addc */ + if (y) + --x; + return x; +} + +int +test_02 (int x, int y) +{ + /* 1x tst, 1x addc */ + if (!y) + ++x; + return x; +} + +int +test_03 (int x, int y) +{ + /* 1x tst, 1x subc */ + if (!y) + --x; + return x; +} + +int +test_04 (int x, int y) +{ + /* 1x cmp/eq, 1x addc */ + if (y == x) + ++x; + return x; +} + +int +test_05 (int x, int y) +{ + /* 1x cmp/gt, 1x subc */ + if (y < 4) + ++x; + return x; +} + +int +test_06 (int x) +{ + /* 1x cmp/pl, 1x addc */ + return x > 0 ? x + 1 : x; +} + +int +test_07 (int x) +{ + /* 1x cmp/pl, 1x subc */ + return x > 0 ? x - 1 : x; +} Index: gcc/testsuite/gcc.target/sh/pr54236-6.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54236-6.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54236-6.c (working copy) @@ -0,0 +1,75 @@ +/* In this snippet, there was a missed subc case: + tst #1,r0 + movt r0 + neg r0,r0 + + which should be: + tst #1,r0 + subc r0,r0 +*/ + +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* { dg-final { scan-assembler-times {tst #1,r0} 1 } } */ +/* { dg-final { scan-assembler-times {subc r} 1 } } */ + +/* { dg-final { scan-assembler-not "movt|not|neg\movrt" } } */ + + +struct inode +{ + unsigned int i_gid; +}; + +struct iattr +{ + unsigned int ia_valid; + unsigned int ia_gid; +}; + +struct task_struct +{ + unsigned long flags; + unsigned int cap_effective; +}; + +extern int in_group_p (unsigned int); + +static inline struct task_struct* +get_current (void) +{ + struct task_struct *current; + return current; +} + +static inline int +capable (int cap) +{ + if (((get_current()->cap_effective) & (1 << (cap)))) + { + get_current()->flags |= 0x00000100; + return 1; + } + return 0; +} + +int +inode_change_ok (struct inode *inode, struct iattr *attr) +{ + int retval = -1; + unsigned int ia_valid = attr->ia_valid; + + if (ia_valid & 512) + goto fine; + + if ((ia_valid & 4) + && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) + && !capable(0)) + goto error; + +fine: + retval = 0; +error: + return retval; +} Index: gcc/testsuite/gcc.target/sh/pr59533-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr59533-1.c (revision 228175) +++ gcc/testsuite/gcc.target/sh/pr59533-1.c (working copy) @@ -9,13 +9,13 @@ /* { dg-final { scan-assembler-times "and" 3 } } */ /* { dg-final { scan-assembler-times "extu.b" 5 } } */ -/* { dg-final { scan-assembler-times "cmp/pz" 22 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "addc" 3 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "subc" 12 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "cmp/pz" 27 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 4 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "subc" 16 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "cmp/pz" 20 { target { sh2a } } } } */ -/* { dg-final { scan-assembler-times "addc" 5 { target { sh2a } } } } */ -/* { dg-final { scan-assembler-times "subc" 10 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "cmp/pz" 25 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "addc" 6 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "subc" 14 { target { sh2a } } } } */ /* { dg-final { scan-assembler-times "bld" 2 { target { sh2a } } } } */ int @@ -183,3 +183,38 @@ /* 1x cmp/pz, 1x movt */ return (x >> 31) + 1; } + +int +test_23 (int x) +{ + /* 1x cmp/pz, 1x subc */ + return x < 0 ? x + 1 : x; +} + +unsigned int +test_24 (unsigned int x) +{ + /* 1x cmp/pz, 1x subc */ + return x & 0x80000000 ? x + 1 : x; +} + +unsigned int +test_25 (unsigned int x) +{ + /* 1x cmp/pz, 1x subc */ + return x >> 31 ? x + 1 : x; +} + +int +test_26 (int x) +{ + /* 1x cmp/pz, 1x subc */ + return x >> 31 ? x + 1 : x; +} + +int +test_27 (int x, int y, int z) +{ + /* 1x cmp/pz, 1x addc */ + return 1 - ((x >> 4) < 0) + z; +}