From patchwork Mon Sep 3 08:12:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 181314 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 3F50A2C0094 for ; Mon, 3 Sep 2012 18:13: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=1347264815; 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=mhxwz5vGhPhVgbK7tWms 1GzSMkM=; b=LFfrUTSmpKI4V9rXw0qAjhNp5uJC72lQDsIE8DjbPvX0L9wI04+D sh9mJcp/Pkx1W9AhvvEyJz+ya0K1MmBvtiN5YXJp8/0kmy0JaRhhFILkpxB5DNjK Qv+Y6l4Pm37UzGedJ0DEnW4SfbV2dDAyfsThr9gt+Y2+A1asXoVJ+GI= 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=xEtsO2lAzCHvvlJC7biROzfp4+ZElGhsnasjsHVQ7GdhpH7X40S+2GPjS7Oj5e pW7hXF5ExJScaba8VMgMvuqP1YSOaeh7bAHk2bPjoVmpWAnnnKk32ZROLiPHAAis Q0gtmY313uYNESrj9PpLHMQWQvodA9iuBDb+NgfK7kYLo=; Received: (qmail 5604 invoked by alias); 3 Sep 2012 08:13:30 -0000 Received: (qmail 5515 invoked by uid 22791); 3 Sep 2012 08:13:27 -0000 X-SWARE-Spam-Status: No, hits=-2.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_NO, RP_MATCHES_RCVD, UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout10.t-online.de (HELO mailout10.t-online.de) (194.25.134.21) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 03 Sep 2012 08:13:12 +0000 Received: from fwd01.aul.t-online.de (fwd01.aul.t-online.de ) by mailout10.t-online.de with smtp id 1T8RmQ-0002KJ-Jb; Mon, 03 Sep 2012 10:13:10 +0200 Received: from [192.168.0.100] (TWnXzTZcYhxGLrs1fodZHahmkkfjg9Ah26aPY1TkOKaJKO+fcqtXK8lQmwyFvVGwAb@[93.218.178.140]) by fwd01.t-online.de with esmtp id 1T8RmC-04pjJA0; Mon, 3 Sep 2012 10:12:56 +0200 Message-ID: <1346659967.2200.68.camel@yam-132-YW-E178-FTW> Subject: [SH] PR 51244 - Add CANONICALIZE_COMPARISON macro From: Oleg Endo To: gcc-patches Date: Mon, 03 Sep 2012 10:12:47 +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 adds implementation of the CANONICALIZE_COMPARISON macro to the SH target. So far, it doesn't seem to have an impact on the generated code, but it might be useful to have it in place in the future. Moreover, it changes the behavior of the cbranchsi4 expander, which was checking for TARGET_CBRANCHDI4, which seems a bit odd to do. TARGET_CBRANCHDI4 is disabled for -Os (another story) and thus would affect the behavior of the cbranchsi4 expander. I've briefly checked CSiBE result-size with this change and there are only changes in a few files in the range of -20...+4. Tested on rev 190865 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/51244 * config/sh/sh.c (prepare_cbranch_operands): Pull out comparison canonicalization code into... * (sh_canonicalize_comparison): This new function. * config/sh/sh-protos.h: Declare it. * config/sh/sh.h: Use it in new macro CANONICALIZE_COMPARISON. * config/sh/sh.md (cbranchsi4): Remove TARGET_CBRANCHDI4 check and always invoke expand_cbranchsi4. Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 190840) +++ gcc/config/sh/sh.md (working copy) @@ -881,10 +881,9 @@ if (TARGET_SHMEDIA) emit_jump_insn (gen_cbranchint4_media (operands[0], operands[1], operands[2], operands[3])); - else if (TARGET_CBRANCHDI4) - expand_cbranchsi4 (operands, LAST_AND_UNUSED_RTX_CODE, -1); else - sh_emit_compare_and_branch (operands, SImode); + expand_cbranchsi4 (operands, LAST_AND_UNUSED_RTX_CODE, -1); + DONE; }) Index: gcc/config/sh/sh-protos.h =================================================================== --- gcc/config/sh/sh-protos.h (revision 190840) +++ gcc/config/sh/sh-protos.h (working copy) @@ -106,6 +106,9 @@ extern rtx sh_gen_truncate (enum machine_mode, rtx, int); extern bool sh_vector_mode_supported_p (enum machine_mode); extern bool sh_cfun_trap_exit_p (void); +extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&, + enum machine_mode mode = VOIDmode); + #endif /* RTX_CODE */ extern const char *output_jump_label_table (void); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 190840) +++ gcc/config/sh/sh.c (working copy) @@ -21,6 +21,12 @@ along with GCC; see the file COPYING3. If not see . */ +/* FIXME: This is a temporary hack, so that we can include + below. will try to include which will reference + malloc & co, which are poisoned by "system.h". The proper solution is + to include in "system.h" instead of . */ +#include + #include "config.h" #include "system.h" #include "coretypes.h" @@ -56,6 +62,7 @@ #include "tm-constrs.h" #include "opts.h" +#include int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch; @@ -1791,65 +1798,124 @@ } } -enum rtx_code -prepare_cbranch_operands (rtx *operands, enum machine_mode mode, - enum rtx_code comparison) +// Implement the CANONICALIZE_COMPARISON macro for the combine pass. +// This function is also re-used to canonicalize comparisons in cbranch +// pattern expanders. +void +sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1, + enum machine_mode mode) { - rtx op1; - rtx scratch = NULL_RTX; + // When invoked from within the combine pass the mode is not specified, + // so try to get it from one of the operands. + if (mode == VOIDmode) + mode = GET_MODE (op0); + if (mode == VOIDmode) + mode = GET_MODE (op1); - if (comparison == LAST_AND_UNUSED_RTX_CODE) - comparison = GET_CODE (operands[0]); - else - scratch = operands[4]; - if (CONST_INT_P (operands[1]) - && !CONST_INT_P (operands[2])) + // We need to have a mode to do something useful here. + if (mode == VOIDmode) + return; + + // Currently, we don't deal with floats here. + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + return; + + // Make sure that the constant operand is the second operand. + if (CONST_INT_P (op0) && !CONST_INT_P (op1)) { - rtx tmp = operands[1]; + std::swap (op0, op1); + cmp = swap_condition (cmp); + } - operands[1] = operands[2]; - operands[2] = tmp; - comparison = swap_condition (comparison); - } - if (CONST_INT_P (operands[2])) + if (CONST_INT_P (op1)) { - HOST_WIDE_INT val = INTVAL (operands[2]); - if ((val == -1 || val == -0x81) - && (comparison == GT || comparison == LE)) + // Try to adjust the constant operand in such a way that available + // comparison insns can be utilized better and the constant can be + // loaded with a 'mov #imm,Rm' insn. This avoids a load from the + // constant pool. + const HOST_WIDE_INT val = INTVAL (op1); + + // x > -1 --> x >= 0 + // x > 0xFFFFFF7F --> x >= 0xFFFFFF80 + // x <= -1 --> x < 0 + // x <= 0xFFFFFF7F --> x < 0xFFFFFF80 + if ((val == -1 || val == -0x81) && (cmp == GT || cmp == LE)) { - comparison = (comparison == GT) ? GE : LT; - operands[2] = gen_int_mode (val + 1, mode); + cmp = cmp == GT ? GE : LT; + op1 = gen_int_mode (val + 1, mode); + } + + // x >= 1 --> x > 0 + // x >= 0x80 --> x > 0x7F + // x < 1 --> x <= 0 + // x < 0x80 --> x <= 0x7F + else if ((val == 1 || val == 0x80) && (cmp == GE || cmp == LT)) + { + cmp = cmp == GE ? GT : LE; + op1 = gen_int_mode (val - 1, mode); } - else if ((val == 1 || val == 0x80) - && (comparison == GE || comparison == LT)) + + // unsigned x >= 1 --> x != 0 + // unsigned x < 1 --> x == 0 + else if (val == 1 && (cmp == GEU || cmp == LTU)) { - comparison = (comparison == GE) ? GT : LE; - operands[2] = gen_int_mode (val - 1, mode); + cmp = cmp == GEU ? NE : EQ; + op1 = CONST0_RTX (mode); } - else if (val == 1 && (comparison == GEU || comparison == LTU)) + + // unsigned x >= 0x80 --> unsigned x > 0x7F + // unsigned x < 0x80 --> unsigned x < 0x7F + else if (val == 0x80 && (cmp == GEU || cmp == LTU)) { - comparison = (comparison == GEU) ? NE : EQ; - operands[2] = CONST0_RTX (mode); + cmp = cmp == GEU ? GTU : LEU; + op1 = gen_int_mode (val - 1, mode); } - else if (val == 0x80 && (comparison == GEU || comparison == LTU)) + + // unsigned x > 0 --> x != 0 + // unsigned x <= 0 --> x == 0 + else if (val == 0 && (cmp == GTU || cmp == LEU)) + cmp = cmp == GTU ? NE : EQ; + + // unsigned x > 0x7FFFFFFF --> signed x < 0 + // unsigned x <= 0x7FFFFFFF --> signed x >= 0 + else if (mode == SImode && (cmp == GTU || cmp == LEU) + && val == 0x7FFFFFFF) { - comparison = (comparison == GEU) ? GTU : LEU; - operands[2] = gen_int_mode (val - 1, mode); + cmp = cmp == GTU ? LT : GE; + op1 = const0_rtx; } - else if (val == 0 && (comparison == GTU || comparison == LEU)) - comparison = (comparison == GTU) ? NE : EQ; - else if (mode == SImode - && ((val == 0x7fffffff - && (comparison == GTU || comparison == LEU)) - || ((unsigned HOST_WIDE_INT) val - == (unsigned HOST_WIDE_INT) 0x7fffffff + 1 - && (comparison == GEU || comparison == LTU)))) + + // unsigned x >= 0x80000000 --> signed x < 0 + // unsigned x < 0x80000000 --> signed x >= 0 + else if (mode == SImode && (cmp == GEU || cmp == LTU) + && (unsigned HOST_WIDE_INT)val + == ((unsigned HOST_WIDE_INT)0x7FFFFFFF + 1)) { - comparison = (comparison == GTU || comparison == GEU) ? LT : GE; - operands[2] = CONST0_RTX (mode); + cmp = cmp == GEU ? LT : GE; + op1 = const0_rtx; } } - op1 = operands[1]; +} + +enum rtx_code +prepare_cbranch_operands (rtx *operands, enum machine_mode mode, + enum rtx_code comparison) +{ + // The scratch reg is only available when this is invoked from within + // the cbranchdi4_i splitter, through expand_cbranchdi4. + rtx scratch = NULL_RTX; + + if (comparison == LAST_AND_UNUSED_RTX_CODE) + comparison = GET_CODE (operands[0]); + else + scratch = operands[4]; + + sh_canonicalize_comparison (comparison, operands[1], operands[2], mode); + + // Notice that this function is also invoked after reload by + // the cbranchdi4_i pattern, through expand_cbranchdi4. + rtx op1 = operands[1]; + if (can_create_pseudo_p ()) operands[1] = force_reg (mode, op1); /* When we are handling DImode comparisons, we want to keep constants so @@ -1883,8 +1949,6 @@ expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability) { rtx (*branch_expander) (rtx, rtx) = gen_branch_true; - rtx jump; - comparison = prepare_cbranch_operands (operands, SImode, comparison); switch (comparison) { @@ -1896,10 +1960,9 @@ emit_insn (gen_rtx_SET (VOIDmode, get_t_reg_rtx (), gen_rtx_fmt_ee (comparison, SImode, operands[1], operands[2]))); - jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ())); + rtx jump = emit_jump_insn (branch_expander (operands[3], get_t_reg_rtx ())); if (probability >= 0) add_reg_note (jump, REG_BR_PROB, GEN_INT (probability)); - } /* ??? How should we distribute probabilities when more than one branch @@ -1956,8 +2019,7 @@ lsw_taken = EQ; if (prob >= 0) { - /* If we had more precision, we'd use rev_prob - (rev_prob >> 32) . - */ + // If we had more precision, we'd use rev_prob - (rev_prob >> 32) . msw_skip_prob = rev_prob; if (REG_BR_PROB_BASE <= 65535) lsw_taken_prob = prob ? REG_BR_PROB_BASE : 0; Index: gcc/config/sh/sh.h =================================================================== --- gcc/config/sh/sh.h (revision 190840) +++ gcc/config/sh/sh.h (working copy) @@ -1946,6 +1946,10 @@ leave this zero for correct SH3 code. */ #define SHIFT_COUNT_TRUNCATED (! TARGET_SH3 && ! TARGET_SH2A) +/* CANONICALIZE_COMPARISON macro for the combine pass. */ +#define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \ + sh_canonicalize_comparison ((CODE), (OP0), (OP1)) + /* All integers have the same format so truncation is easy. */ /* But SHmedia must sign-extend DImode when truncating to SImode. */ #define TRULY_NOOP_TRUNCATION(OUTPREC,INPREC) \