From patchwork Wed Jun 23 22:01:34 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 56730 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 E40BEB6F10 for ; Thu, 24 Jun 2010 08:01:54 +1000 (EST) Received: (qmail 1867 invoked by alias); 23 Jun 2010 22:01:47 -0000 Received: (qmail 1653 invoked by uid 22791); 23 Jun 2010 22:01:43 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, TW_IV X-Spam-Check-By: sourceware.org Received: from mail-pv0-f175.google.com (HELO mail-pv0-f175.google.com) (74.125.83.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 23 Jun 2010 22:01:37 +0000 Received: by pvg3 with SMTP id 3so695839pvg.20 for ; Wed, 23 Jun 2010 15:01:35 -0700 (PDT) MIME-Version: 1.0 Received: by 10.142.67.22 with SMTP id p22mr7849289wfa.179.1277330495042; Wed, 23 Jun 2010 15:01:35 -0700 (PDT) Received: by 10.142.162.10 with HTTP; Wed, 23 Jun 2010 15:01:34 -0700 (PDT) In-Reply-To: References: <20100621193321.GA13780@intel.com> <1277229955.2613.1.camel@localhost> <1277232299.2613.13.camel@localhost> <4C224592.5090100@gnu.org> <4C224EB7.8090900@gnu.org> <4C225D75.2070106@gnu.org> <4C22624E.1050207@gnu.org> Date: Wed, 23 Jun 2010 15:01:34 -0700 Message-ID: Subject: Re: PATCH: PR target/44588: Very inefficient 8bit mod/div From: "H.J. Lu" To: Paolo Bonzini Cc: Uros Bizjak , gcc-patches@gcc.gnu.org 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 On Wed, Jun 23, 2010 at 2:22 PM, H.J. Lu wrote: > On Wed, Jun 23, 2010 at 12:50 PM, H.J. Lu wrote: >> On Wed, Jun 23, 2010 at 12:36 PM, Paolo Bonzini wrote: >>> On 06/23/2010 09:35 PM, H.J. Lu wrote: >>>> >>>> On Wed, Jun 23, 2010 at 12:16 PM, Paolo Bonzini  wrote: >>>>> >>>>> On 06/23/2010 08:24 PM, H.J. Lu wrote: >>>>>> >>>>>>  [(set (match_operand:HI 0 "register_operand" "=a") >>>>>>         (div:HI >>>>>>           (match_operand:HI 1 "register_operand" "0") >>>>>>           (match_operand:QI 2 "nonimmediate_operand" "qm"))) >>>>>>    (clobber (reg:CC FLAGS_REG))] >>>>> >>>>> Maybe this: >>>>> >>>>> [(set (match_operand:QI 0 "register_operand" "=a") >>>>>   (subreg:QI >>>>>    (div:HI >>>>>     (match_operand:HI 1 "register_operand" "0") >>>>>     (match_operand:QI 2 "nonimmediate_operand" "qm")) 0)) >>>>>  (clobber (reg:CC FLAGS_REG))] >>>>> >>>> >>>> It doesn't make a big difference since only lower 8bit >>>> is set by it. >>> >>> For full divmod you have to shift mod and ior of course.  I understood that >>> you were talking of *divqi3. >>> >> >> I can't do shift/ior on QI output from *divqi3. I have >> >> ;; Divide AX by r/m8, with result stored in >> ;; AL <- Quotient >> ;; AH <- Remainder >> (define_insn "*divqi3" >>  [(set (match_operand:QI 0 "register_operand" "=a") >>        (any_div:QI >>          (match_operand:HI 1 "register_operand" "0") >>          (match_operand:QI 2 "nonimmediate_operand" "qm"))) >>   (clobber (reg:CC FLAGS_REG))] >>  "TARGET_QIMODE_MATH" >>  "div{b}\t%2" >>  [(set_attr "type" "idiv") >>   (set_attr "mode" "QI")]) >> >> and use >> >> ;; Used to extract remainder from AH by 8bit divmod.  Use unspec so >> ;; that we can extract it from AL. >> (define_insn "*movqi_extzh" >>  [(set (match_operand:QI 0 "nonimmediate_operand" "=Qm,?R") >>        (unspec:QI [(match_operand 1 "register_operand" "Q,Q")] >>                   UNSPEC_MOVQI_EXTZH))] >> >> to extract it from AL >> > > Here is a different approach.  It uses UNSPEC for 8bit divmod. > The generated code is the same. > > An updated patch. No need for *movqi_extzv_3 and *movqi_extzv_3_rex64. diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index ab90d73..68c9e47 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -104,6 +104,8 @@ UNSPEC_REP UNSPEC_LD_MPIC ; load_macho_picbase UNSPEC_TRUNC_NOOP + UNSPEC_DIVQI + UNSPEC_UDIVQI ;; For SSE/MMX support: UNSPEC_FIX_NOTRUNC @@ -760,6 +762,10 @@ ;; Used in signed and unsigned divisions. (define_code_iterator any_div [div udiv]) +(define_code_attr extend_code + [(div "SIGN_EXTEND") (udiv "ZERO_EXTEND")]) +(define_code_attr extract_code + [(div "SIGN_EXTRACT") (udiv "ZERO_EXTRACT")]) ;; Instruction prefix for signed and unsigned operations. (define_code_attr sgnprefix [(sign_extend "i") (zero_extend "") @@ -7305,17 +7311,6 @@ ;; Divide instructions -(define_insn "divqi3" - [(set (match_operand:QI 0 "register_operand" "=a") - (any_div:QI - (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_QIMODE_MATH" - "div{b}\t%2" - [(set_attr "type" "idiv") - (set_attr "mode" "QI")]) - ;; The patterns that match these are at the end of this file. (define_expand "divxf3" @@ -7352,6 +7347,83 @@ ;; Divmod instructions. +(define_expand "divmodqi4" + [(parallel [(set (match_operand:QI 0 "register_operand" "") + (any_div:QI + (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonimmediate_operand" ""))) + (set (match_operand:QI 3 "register_operand" "") + (mod:QI (match_dup 1) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_QIMODE_MATH" +{ + rtx div, clobber, set; + rtx operand0, operand1; + + operand0 = gen_reg_rtx (HImode); + operand1 = gen_reg_rtx (HImode); + clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); + + /* Properly extend operands[1] to HImode. */ + set = gen_rtx_SET (VOIDmode, operand1, + gen_rtx_ (HImode, operands[1])); + if ( == SIGN_EXTEND) + emit_insn (set); + else + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber))); + + /* Generate 8bit divide. Result is in AX. */ + div = gen_rtx_UNSPEC (HImode, gen_rtvec (2, operand1, operands[2]), + ( == SIGN_EXTEND + ? UNSPEC_DIVQI : UNSPEC_UDIVQI)); + div = gen_rtx_SET (VOIDmode, operand0, div); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, div, clobber))); + + /* Extract remainder from AH. */ + if ( == SIGN_EXTEND) + operand1 = gen_rtx_ (QImode, operand0, + GEN_INT (8), GEN_INT (8)); + else + { + operand1 = gen_rtx_ (SImode, operand0, + GEN_INT (8), GEN_INT (8)); + operand1 = simplify_gen_subreg (QImode, operand1, SImode, 0); + } + emit_move_insn (operands[3], operand1); + + /* Extract quotient from AL. */ + operand1 = simplify_gen_subreg (QImode, operand0, HImode, 0); + emit_move_insn (operands[0], operand1); + DONE; +}) + +;; Divide AX by r/m8, with result stored in +;; AL <- Quotient +;; AH <- Remainder +(define_insn "*divqi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")] + UNSPEC_DIVQI)) + (clobber (reg:CC FLAGS_REG))] + "TARGET_QIMODE_MATH" + "idiv{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI")]) + +(define_insn "*udivqi3" + [(set (match_operand:HI 0 "register_operand" "=a") + (unspec:HI + [(match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm")] + UNSPEC_UDIVQI)) + (clobber (reg:CC FLAGS_REG))] + "TARGET_QIMODE_MATH" + "div{b}\t%2" + [(set_attr "type" "idiv") + (set_attr "mode" "QI")]) + (define_expand "divmod4" [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") (div:SWIM248 --- /dev/null 2010-06-16 10:11:06.602750711 -0700 +++ gcc/gcc/testsuite/gcc.target/i386/umod-1.c 2010-06-21 12:01:25.705950180 -0700 @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=atom" } */ + +unsigned char +foo (unsigned char x, unsigned char y) +{ + return x % y; +} + +/* { dg-final { scan-assembler-times "divb" 1 } } */ +/* { dg-final { scan-assembler-not "divw" } } */ --- /dev/null 2010-06-16 10:11:06.602750711 -0700 +++ gcc/gcc/testsuite/gcc.target/i386/umod-2.c 2010-06-21 12:01:17.857932744 -0700 @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=atom" } */ + +extern unsigned char z; + +unsigned char +foo (unsigned char x, unsigned char y) +{ + z = x/y; + return x % y; +} + +/* { dg-final { scan-assembler-times "divb" 1 } } */ +/* { dg-final { scan-assembler-not "divw" } } */ --- /dev/null 2010-06-16 10:11:06.602750711 -0700 +++ gcc/gcc/testsuite/gcc.target/i386/umod-3.c 2010-06-21 12:02:36.809962702 -0700 @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=atom" } */ + +extern void abort (void); +extern void exit (int); + +unsigned char cx = 7; + +int +main () +{ + unsigned char cy; + + cy = cx / 6; if (cy != 1) abort (); + cy = cx % 6; if (cy != 1) abort (); + + exit(0); +} + +/* { dg-final { scan-assembler-times "divb" 1 } } */ +/* { dg-final { scan-assembler-not "divw" } } */