From patchwork Wed Jul 14 02:17:51 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: DJ Delorie X-Patchwork-Id: 58832 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 34C80B6EED for ; Wed, 14 Jul 2010 12:18:03 +1000 (EST) Received: (qmail 16537 invoked by alias); 14 Jul 2010 02:18:01 -0000 Received: (qmail 16527 invoked by uid 22791); 14 Jul 2010 02:18:00 -0000 X-SWARE-Spam-Status: No, hits=-5.9 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 14 Jul 2010 02:17:55 +0000 Received: from int-mx03.intmail.prod.int.phx2.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o6E2Hr3E013128 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 13 Jul 2010 22:17:54 -0400 Received: from greed.delorie.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx03.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o6E2HpqZ022223 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 13 Jul 2010 22:17:53 -0400 Received: from greed.delorie.com (greed.delorie.com [127.0.0.1] (may be forged)) by greed.delorie.com (8.14.3/8.14.3) with ESMTP id o6E2HpMn001035; Tue, 13 Jul 2010 22:17:51 -0400 Received: (from dj@localhost) by greed.delorie.com (8.14.3/8.14.3/Submit) id o6E2Hp4w001032; Tue, 13 Jul 2010 22:17:51 -0400 Date: Tue, 13 Jul 2010 22:17:51 -0400 Message-Id: <201007140217.o6E2Hp4w001032@greed.delorie.com> From: DJ Delorie To: gcc-patches@gcc.gnu.org CC: Paolo Bonzini , Nick Clifton Subject: [patch] Add TST to RX 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 This patch adds support for the TST opcode to the RX target. The first two patterns are the real patterns; the rest are other ways that gcc handles "a & const", they're converted to one of the first two forms. Paolo: if you replace the "return 0;" in the rtlanal.c chunk with an abort(), you can see where the zero_extend comes from. GCC uses that for single-bit tests other than bit 0. Ok to apply? * rtlanal.c (canonicalize_condition): Exit early if we're passed something other than a condition. * config/rx/predicates.md (rx_constshift_operand): New. (rx_onebit_operand): New. * config/rx/rx.md (zs_cond): New. (*tstbranchsi4_): New. (*tstbranchsi4_): New. (*tstbranchsi4b_eq): New. (*tstbranchsi4m_eq): New. (*tstbranchsi4m_ne): New. (*tstbranchsi4a_ne): New. (*tstbranchsi4a_eq): New. Index: rtlanal.c =================================================================== --- rtlanal.c (revision 162148) +++ rtlanal.c (working copy) @@ -4695,12 +4695,17 @@ canonicalize_condition (rtx insn, rtx co rtx tem; rtx op0, op1; int reverse_code = 0; enum machine_mode mode; basic_block bb = BLOCK_FOR_INSN (insn); + /* Single-bit tests sometimes use logic ops to generate the + condition, rather than comparisons. */ + if (! COMPARISON_P (cond)) + return 0; + code = GET_CODE (cond); mode = GET_MODE (cond); op0 = XEXP (cond, 0); op1 = XEXP (cond, 1); if (reverse) Index: config/rx/predicates.md =================================================================== --- config/rx/predicates.md (revision 162148) +++ config/rx/predicates.md (working copy) @@ -42,12 +42,29 @@ if (CONST_INT_P (op)) return IN_RANGE (INTVAL (op), 0, 31); return true; } ) +(define_predicate "rx_constshift_operand" + (match_code "const_int") + { + return IN_RANGE (INTVAL (op), 0, 31); + } +) + +;; Check that the operand is suitable for a TST inversion + +(define_predicate "rx_onebit_operand" + (match_code "const_int") + { + HOST_WIDE_INT ival = INTVAL (op); + return (ival && (ival & (ival-1)) == 0); + } +) + ;; Check that the operand is suitable as the source operand ;; for a logic or arithmeitc instruction. Registers, integers ;; and a restricted subset of memory addresses are allowed. (define_predicate "rx_source_operand" (match_code "const_int,const_double,const,symbol_ref,label_ref,reg,mem") Index: config/rx/rx.md =================================================================== --- config/rx/rx.md (revision 162148) +++ config/rx/rx.md (working copy) @@ -21,12 +21,15 @@ ;; This code iterator allows all branch instructions to ;; be generated from a single define_expand template. (define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu unordered ordered ]) +;; Likewise, but only the ones that use Z or S. +(define_code_iterator zs_cond [eq ne gtu geu ltu leu ]) + ;; This code iterator is used for sign- and zero- extensions. (define_mode_iterator small_int_modes [(HI "") (QI "")]) ;; We do not handle DFmode here because it is either ;; the same as SFmode, or if -m64bit-doubles is active ;; then all operations on doubles have to be handled by @@ -186,12 +189,190 @@ emit_jump_insn (gen_conditional_branch (operands[2], gen_rtx_fmt_ee (, CCmode, gen_rtx_REG (CCmode, CC_REG), const0_rtx))); " ) +;; ----------------------------------------------------------------------------- +;; These two are the canonical TST/branch insns. However, GCC +;; generates a wide variety of tst-like patterns, we catch those +;; below. +(define_insn_and_split "*tstbranchsi4_" + [(set (pc) + (if_then_else (zs_cond:SI (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")) + (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + ] + "" + "#" + "reload_completed" + [(const_int 0)] + " + emit_insn (gen_tstsi (operands[0], operands[1])); + + emit_jump_insn (gen_conditional_branch (operands[2], + gen_rtx_fmt_ee (, CCmode, + gen_rtx_REG (CCmode, CC_REG), const0_rtx))); + " +) + +;; Inverse of above +(define_insn_and_split "*tstbranchsi4_" + [(set (pc) + (if_then_else (zs_cond:SI (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "rx_source_operand" "riQ")) + (const_int 0)) + (pc) + (label_ref (match_operand 2 "" "")))) + ] + "" + "#" + "reload_completed" + [(const_int 0)] + " + emit_insn (gen_tstsi (operands[0], operands[1])); + + emit_jump_insn (gen_conditional_branch (operands[2], + gen_rtx_fmt_ee (reverse_condition (), CCmode, + gen_rtx_REG (CCmode, CC_REG), const0_rtx))); + " +) + +;; Various other ways that GCC codes "var & const" + +(define_insn_and_split "*tstbranchsi4b_eq" + [(set (pc) + (if_then_else (zero_extract:SI (xor:SI (match_operand:SI 0 "register_operand" "r") + (match_operand 1 "immediate_operand" "i")) + (const_int 1) + (match_operand 2 "rx_constshift_operand" "i")) + (label_ref (match_operand 3 "" "")) + (pc))) + ] + "" + "#" + "" + [(set (pc) + (if_then_else (eq:SI (and:SI (match_dup 0) + (match_dup 4)) + (const_int 0)) + (label_ref (match_dup 3)) + (pc))) + ] + "operands[4] = GEN_INT (1 << INTVAL (operands[2]));" +) + +(define_insn_and_split "*tstbranchsi4b_ne" + [(set (pc) + (if_then_else (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand 1 "rx_constshift_operand" "i") + (match_operand 2 "rx_constshift_operand" "i")) + (label_ref (match_operand 3 "" "")) + (pc))) + ] + "" + "#" + "" + [(set (pc) + (if_then_else (ne:SI (and:SI (match_dup 0) + (match_dup 4)) + (const_int 0)) + (label_ref (match_dup 3)) + (pc))) + ] + "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" +) + +(define_insn_and_split "*tstbranchsi4m_eq" + [(set (pc) + (if_then_else (eq:SI (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand 1 "rx_constshift_operand" "i") + (match_operand 2 "rx_constshift_operand" "i")) + (const_int 0)) + (label_ref (match_operand 3 "" "")) + (pc))) + ] + "" + "#" + "" + [(set (pc) + (if_then_else (eq:SI (and:SI (match_dup 0) + (match_dup 4)) + (const_int 0)) + (label_ref (match_dup 3)) + (pc))) + ] + "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" +) + +(define_insn_and_split "*tstbranchsi4m_ne" + [(set (pc) + (if_then_else (ne:SI (zero_extract:SI (match_operand:SI 0 "register_operand" "r") + (match_operand 1 "rx_constshift_operand" "i") + (match_operand 2 "rx_constshift_operand" "i")) + (const_int 0)) + (label_ref (match_operand 3 "" "")) + (pc))) + ] + "" + "#" + "" + [(set (pc) + (if_then_else (ne:SI (and:SI (match_dup 0) + (match_dup 4)) + (const_int 0)) + (label_ref (match_dup 3)) + (pc))) + ] + "operands[4] = GEN_INT (((1 << INTVAL (operands[1]))-1) << INTVAL (operands[2]));" +) + +(define_insn_and_split "*tstbranchsi4a_ne" + [(set (pc) + (if_then_else (and:SI (match_operand:SI 0 "register_operand" "r") + (match_operand 1 "immediate_operand" "i")) + (label_ref (match_operand 2 "" "")) + (pc))) + ] + "" + "#" + "" + [(set (pc) + (if_then_else (ne:SI (and:SI (match_dup 0) + (match_dup 1)) + (const_int 0)) + (label_ref (match_dup 2)) + (pc))) + ] + "" +) + +(define_insn_and_split "*tstbranchsi4a_eq" + [(set (pc) + (if_then_else (and:SI (not:SI (match_operand:SI 0 "register_operand" "r")) + (match_operand 1 "immediate_operand" "i")) + (label_ref (match_operand 2 "" "")) + (pc))) + ] + "rx_onebit_operand (operands[1], VOIDmode)" + "#" + "" + [(set (pc) + (if_then_else (eq:SI (and:SI (match_dup 0) + (match_dup 1)) + (const_int 0)) + (label_ref (match_dup 2)) + (pc))) + ] + "" +) + +;; ----------------------------------------------------------------------------- + (define_expand "cbranchsf4" [(set (pc) (if_then_else (match_operator:SF 0 "comparison_operator" [(match_operand:SF 1 "register_operand") (match_operand:SF 2 "rx_source_operand")]) (label_ref (match_operand 3 ""))