From patchwork Fri Jul 31 11:48:11 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 502503 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 572071402D5 for ; Fri, 31 Jul 2015 21:48:34 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=bS3gWxsd; 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:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=r8G6zKlMa4LnkEKF nMueO9Toy8q11ZKIrL/h2AyQhQk15oOYsim+I3B6znDLwbVSGPjAy4cILzICX2L2 Vp+WtjikDHb7bTTtug1h50+i//yydQaee7fF1/xGzHRCuyMgAF3L2egr8vOX53sr 4zqIOPSLvuwucd1cNJPe/hJcL5w= 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:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=PiO/4kZRSIwGNiTtZuahRp 1CXWU=; b=bS3gWxsd0+1intDeP2EBnzVgTu7Og6qxCAjSSfqexm8yfv0+dqrPUS HQMXSXqh5olTjYBAp208FtsXs9y2Se4I48kUYZhGdmc1aOPx8WOeyycH2x7rEDfd aaMBn/9u9Uwus4n77CUR2/xANSXoGKNCCFYtBqBfMU04njjeeFFEM= Received: (qmail 34106 invoked by alias); 31 Jul 2015 11:48:26 -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 34097 invoked by uid 89); 31 Jul 2015 11:48:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 31 Jul 2015 11:48:15 +0000 Received: from cam-owa2.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-8-0n74VYc-Tei12avqXIzXUA-1; Fri, 31 Jul 2015 12:48:11 +0100 Received: from localhost ([10.1.2.79]) by cam-owa2.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 31 Jul 2015 12:48:10 +0100 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: Use cmpstr and cmpstrn optabs Date: Fri, 31 Jul 2015 12:48:11 +0100 Message-ID: <87k2tglf9g.fsf@e105548-lin.cambridge.arm.com> User-Agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-MC-Unique: 0n74VYc-Tei12avqXIzXUA-1 expand_builtin_strcmp has: if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing) { ... machine_mode insn_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; ... insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, GEN_INT (MIN (arg1_align, arg2_align))); ... } which is mixing the optabs interface and the CODE_FOR_foo/gen_foo interface. It also doesn't check the predicates of the pattern, unlike a normal optab expansion. This patch converts the code to do everything via the optabs interface. This required a change to the sh.md cmpstrn pattern, where the length predicate was "immediate_operand" but where the expander code wanted to handle nonimmediates too. I also removed the now-redundant force_operand of the length in the rx.md pattern (because the predicate is now enforced and already an operand). The check whether "target" has insn_mode is performed by create_output_operand so we no longer need to check it in the builtins.c code too. Bootstrapped & regression-tested on x86_64-linux-gnu. Also tested by building ft32-elf, s390x-linux-gnu, m32c-elf, rx-elf and sh4-elf and checking that (with the appropriate target flags) the optabs are working for various strcmp and strncmp calls. OK to install? Thanks, Richard gcc/ * builtins.c (expand_cmpstr, expand_cmpstrn): New functions. (expand_builtin_strcmp, expand_builtin_strncmp): Use them. Remove references to HAVE_cmpstr{,n}si and CODE_FOR_cmpstr{,n}si. * config/m32c/blkmov.md (cmpstrsi): Fix predicates of operands 1 and 2. Add predicates for operands 0 and 3. * config/rx/rx.md (cmpstrnsi): Remove force_operand for the length operand. * config/sh/sh.md (cmpstrnsi): Change the length predicate from immediate_operand to nonmemory_operand. diff --git a/gcc/builtins.c b/gcc/builtins.c index d7eb65f..f5da72b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -4016,6 +4016,53 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target, return NULL_RTX; } +/* Try to expand cmpstr operation ICODE with the given operands. + Return the result rtx on success, otherwise return null. */ + +static rtx +expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx, + HOST_WIDE_INT align) +{ + machine_mode insn_mode = insn_data[icode].operand[0].mode; + + if (target && (!REG_P (target) || HARD_REGISTER_P (target))) + target = NULL_RTX; + + struct expand_operand ops[4]; + create_output_operand (&ops[0], target, insn_mode); + create_fixed_operand (&ops[1], arg1_rtx); + create_fixed_operand (&ops[2], arg2_rtx); + create_integer_operand (&ops[3], align); + if (maybe_expand_insn (icode, 4, ops)) + return ops[0].value; + return NULL_RTX; +} + +/* Try to expand cmpstrn operation ICODE with the given operands. + ARG3_TYPE is the type of ARG3_RTX. Return the result rtx on success, + otherwise return null. */ + +static rtx +expand_cmpstrn (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx, + tree arg3_type, rtx arg3_rtx, HOST_WIDE_INT align) +{ + machine_mode insn_mode = insn_data[icode].operand[0].mode; + + if (target && (!REG_P (target) || HARD_REGISTER_P (target))) + target = NULL_RTX; + + struct expand_operand ops[5]; + create_output_operand (&ops[0], target, insn_mode); + create_fixed_operand (&ops[1], arg1_rtx); + create_fixed_operand (&ops[2], arg2_rtx); + create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type), + TYPE_UNSIGNED (arg3_type)); + create_integer_operand (&ops[4], align); + if (maybe_expand_insn (icode, 5, ops)) + return ops[0].value; + return NULL_RTX; +} + /* Expand expression EXP, which is a call to the strcmp builtin. Return NULL_RTX if we failed the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient. */ @@ -4026,15 +4073,15 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) return NULL_RTX; -#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi - if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing - || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing) + insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode); + insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode); + if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing) { rtx arg1_rtx, arg2_rtx; - rtx result, insn = NULL_RTX; tree fndecl, fn; tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg2 = CALL_EXPR_ARG (exp, 1); + rtx result = NULL_RTX; unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT; unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT; @@ -4050,33 +4097,17 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) arg1_rtx = get_memory_rtx (arg1, NULL); arg2_rtx = get_memory_rtx (arg2, NULL); -#ifdef HAVE_cmpstrsi /* Try to call cmpstrsi. */ - if (HAVE_cmpstrsi) - { - machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode; - - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - - insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); - } -#endif -#ifdef HAVE_cmpstrnsi + if (cmpstr_icode != CODE_FOR_nothing) + result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx, + MIN (arg1_align, arg2_align)); + /* Try to determine at least one length and call cmpstrnsi. */ - if (!insn && HAVE_cmpstrnsi) + if (!result && cmpstrn_icode != CODE_FOR_nothing) { tree len; rtx arg3_rtx; - machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; tree len1 = c_strlen (arg1, 1); tree len2 = c_strlen (arg2, 1); @@ -4110,30 +4141,19 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) len = len2; /* If both arguments have side effects, we cannot optimize. */ - if (!len || TREE_SIDE_EFFECTS (len)) - goto do_libcall; - - arg3_rtx = expand_normal (len); - - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - - insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); + if (len && !TREE_SIDE_EFFECTS (len)) + { + arg3_rtx = expand_normal (len); + result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx, + arg2_rtx, TREE_TYPE (len), arg3_rtx, + MIN (arg1_align, arg2_align)); + } } -#endif - if (insn) + if (result) { - machine_mode mode; - emit_insn (insn); - /* Return the value in the proper mode for this function. */ - mode = TYPE_MODE (TREE_TYPE (exp)); + machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); if (GET_MODE (result) == mode) return result; if (target == 0) @@ -4144,16 +4164,12 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target) /* Expand the library call ourselves using a stabilized argument list to avoid re-evaluating the function's arguments twice. */ -#ifdef HAVE_cmpstrnsi - do_libcall: -#endif fndecl = get_callee_fndecl (exp); fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2); gcc_assert (TREE_CODE (fn) == CALL_EXPR); CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_call (fn, target, target == const0_rtx); } -#endif return NULL_RTX; } @@ -4174,12 +4190,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, /* If c_strlen can determine an expression for one of the string lengths, and it doesn't have side effects, then emit cmpstrnsi using length MIN(strlen(string)+1, arg3). */ -#ifdef HAVE_cmpstrnsi - if (HAVE_cmpstrnsi) + insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode); + if (cmpstrn_icode != CODE_FOR_nothing) { tree len, len1, len2; rtx arg1_rtx, arg2_rtx, arg3_rtx; - rtx result, insn; + rtx result; tree fndecl, fn; tree arg1 = CALL_EXPR_ARG (exp, 0); tree arg2 = CALL_EXPR_ARG (exp, 1); @@ -4187,8 +4203,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT; unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT; - machine_mode insn_mode - = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode; len1 = c_strlen (arg1, 1); len2 = c_strlen (arg2, 1); @@ -4234,13 +4248,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, if (arg1_align == 0 || arg2_align == 0) return NULL_RTX; - /* Make a place to write the result of the instruction. */ - result = target; - if (! (result != 0 - && REG_P (result) && GET_MODE (result) == insn_mode - && REGNO (result) >= FIRST_PSEUDO_REGISTER)) - result = gen_reg_rtx (insn_mode); - /* Stabilize the arguments in case gen_cmpstrnsi fails. */ arg1 = builtin_save_expr (arg1); arg2 = builtin_save_expr (arg2); @@ -4249,12 +4256,11 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, arg1_rtx = get_memory_rtx (arg1, len); arg2_rtx = get_memory_rtx (arg2, len); arg3_rtx = expand_normal (len); - insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx, - GEN_INT (MIN (arg1_align, arg2_align))); - if (insn) + result = expand_cmpstrn (cmpstrn_icode, target, arg1_rtx, arg2_rtx, + TREE_TYPE (len), arg3_rtx, + MIN (arg1_align, arg2_align)); + if (result) { - emit_insn (insn); - /* Return the value in the proper mode for this function. */ mode = TYPE_MODE (TREE_TYPE (exp)); if (GET_MODE (result) == mode) @@ -4274,7 +4280,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target, CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp); return expand_call (fn, target, target == const0_rtx); } -#endif return NULL_RTX; } diff --git a/gcc/config/m32c/blkmov.md b/gcc/config/m32c/blkmov.md index 88d0406..02ad345 100644 --- a/gcc/config/m32c/blkmov.md +++ b/gcc/config/m32c/blkmov.md @@ -178,10 +178,10 @@ ;; 3 = alignment (define_expand "cmpstrsi" - [(match_operand:HI 0 "" "") - (match_operand 1 "ap_operand" "") - (match_operand 2 "ap_operand" "") - (match_operand 3 "" "") + [(match_operand:HI 0 "register_operand" "") + (match_operand 1 "memory_operand" "") + (match_operand 2 "memory_operand" "") + (match_operand 3 "const_int_operand" "") ] "TARGET_A24" "if (m32c_expand_cmpstr(operands)) DONE; FAIL;" diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 8b12475..6faf771 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -2315,7 +2315,7 @@ emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); - emit_move_insn (len, force_operand (operands[3], NULL_RTX)); + emit_move_insn (len, operands[3]); emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); DONE; diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 61f6637..0885ff3 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -12731,7 +12731,7 @@ label: [(set (match_operand:SI 0 "register_operand") (compare:SI (match_operand:BLK 1 "memory_operand") (match_operand:BLK 2 "memory_operand"))) - (use (match_operand:SI 3 "immediate_operand")) + (use (match_operand:SI 3 "nonmemory_operand")) (use (match_operand:SI 4 "immediate_operand"))] "TARGET_SH1 && optimize" {