From patchwork Sun Sep 25 17:48:10 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Georg-Johann Lay X-Patchwork-Id: 116313 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 153F0B6F67 for ; Mon, 26 Sep 2011 03:52:58 +1000 (EST) Received: (qmail 6431 invoked by alias); 25 Sep 2011 17:52:56 -0000 Received: (qmail 6420 invoked by uid 22791); 25 Sep 2011 17:52:53 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_NONE, TW_OV, TW_VH X-Spam-Check-By: sourceware.org Received: from mo-p00-ob.rzone.de (HELO mo-p00-ob.rzone.de) (81.169.146.160) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 25 Sep 2011 17:52:37 +0000 X-RZG-AUTH: :LXoWVUeid/7A29J/hMvvT2k715jHQaJercGObUOFkj18odoYNahU4Q== X-RZG-CLASS-ID: mo00 Received: from [192.168.0.22] (business-188-111-022-002.static.arcor-ip.net [188.111.22.2]) by post.strato.de (mrclete mo33) (RZmta 26.7) with ESMTPA id c02ba5n8PF8NzV ; Sun, 25 Sep 2011 19:48:12 +0200 (MEST) Message-ID: <4E7F695A.5030906@gjlay.de> Date: Sun, 25 Sep 2011 19:48:10 +0200 From: Georg-Johann Lay User-Agent: Thunderbird 2.0.0.24 (X11/20100302) MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: Anatoly Sokolov , Denis Chertykov , Eric Weddington Subject: [Patch,AVR]: Clean-up loading HI constants. 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 is just a code clean-up that deals with loading 16-bit constants (HImode). o Length adjustment is triggered by insn attribute "adjust_len" o To print the constant output_movhi can use output_reload_inhi o output_reload_inhi can use the same function as output_reload_insisf uses, just a small change is needed when handling (reg:SI/SF 14) o That function can use avr_popcount_each_byte to detect if scratch needed o avr_popcount_each_byte is extended to handle float mode for that Passed without regression. Ok to install? Johann * config/avr/avr-protos.h (output_reload_inhi): Change prototype. * config/avr/avr.md (adjust_len): Add "reload_in16" alternative. (*reload_inhi): Use it. Adapt call to output_reload_inhi to new prototype. (*movhi): Split constraint alternative "r,rL" into "r,r" and "r,L". * config/avr/avr.c: Rename output_reload_insisf_1 to output_reload_in_const. (avr_popcount_each_byte): Handle SFmode, too. (output_reload_in_const): Change so it can handle HI loads, too. Use avr_popcount_each_byte to work out if scratch register must be created on the fly. (output_reload_inhi): Rewrite using output_reload_in_const and... (output_movhi): ...use it to print constants' loads. (adjust_insn_length): New case ADJUST_LEN_RELOAD_IN16. Cleanup code. Index: config/avr/avr.md =================================================================== --- config/avr/avr.md (revision 179124) +++ config/avr/avr.md (working copy) @@ -136,7 +136,7 @@ (define_attr "length" "" ;; Otherwise do special processing depending on the attribute. (define_attr "adjust_len" - "yes,no,reload_in32,out_bitop,out_plus,tsthi,tstsi,compare" + "yes,no,reload_in16,reload_in32,out_bitop,out_plus,tsthi,tstsi,compare" (const_string "yes")) ;; Define mode iterators @@ -387,18 +387,21 @@ (define_insn "*reload_inhi" (match_operand:HI 1 "immediate_operand" "i")) (clobber (match_operand:QI 2 "register_operand" "=&d"))] "reload_completed" - "* return output_reload_inhi (insn, operands, NULL);" + { + return output_reload_inhi (operands, operands[2], NULL); + } [(set_attr "length" "4") + (set_attr "adjust_len" "reload_in16") (set_attr "cc" "none")]) (define_insn "*movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,d,*r,q,r") - (match_operand:HI 1 "general_operand" "rL,m,rL,i,i,r,q"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m,d,*r,q,r") + (match_operand:HI 1 "general_operand" "r,L,m,rL,i,i,r,q"))] "(register_operand (operands[0],HImode) || register_operand (operands[1],HImode) || const0_rtx == operands[1])" "* return output_movhi (insn, operands, NULL);" - [(set_attr "length" "2,6,7,2,6,5,2") - (set_attr "cc" "none,clobber,clobber,none,clobber,none,none")]) + [(set_attr "length" "2,2,6,7,2,6,5,2") + (set_attr "cc" "none,clobber,clobber,clobber,none,clobber,none,none")]) (define_peephole2 ; movw [(set (match_operand:QI 0 "even_register_operand" "") Index: config/avr/avr-protos.h =================================================================== --- config/avr/avr-protos.h (revision 179124) +++ config/avr/avr-protos.h (working copy) @@ -87,7 +87,7 @@ extern bool avr_popcount_each_byte (rtx, extern int extra_constraint_Q (rtx x); extern int adjust_insn_length (rtx insn, int len); -extern const char *output_reload_inhi (rtx insn, rtx *operands, int *len); +extern const char* output_reload_inhi (rtx*, rtx, int*); extern const char *output_reload_insisf (rtx insn, rtx *operands, rtx clobber, int *len); extern void notice_update_cc (rtx body, rtx insn); extern void print_operand (FILE *file, rtx x, int code); Index: config/avr/avr.c =================================================================== --- config/avr/avr.c (revision 179127) +++ config/avr/avr.c (working copy) @@ -319,19 +319,24 @@ avr_popcount (unsigned int val) } -/* Constraint helper function. XVAL is an CONST_INT. Return true if the least - significant N_BYTES bytes of XVAL all have a popcount in POP_MASK and false, - otherwise. POP_MASK represents a subset of integers which contains an - integer N iff bit N of POP_MASK is set. */ +/* Constraint helper function. XVAL is an CONST_INT or a CONST_DOUBLE. + Return true if the least significant N_BYTES bytes of XVAL all have a + popcount in POP_MASK and false, otherwise. POP_MASK represents a subset + of integers which contains an integer N iff bit N of POP_MASK is set. */ bool avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask) { int i; + enum machine_mode mode = GET_MODE (xval); + + if (VOIDmode == mode) + mode = SImode; + for (i = 0; i < n_bytes; i++) { - rtx xval8 = simplify_gen_subreg (QImode, xval, SImode, i); + rtx xval8 = simplify_gen_subreg (QImode, xval, mode, i); unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode); if (0 == (pop_mask & (1 << avr_popcount (val8)))) @@ -2077,84 +2082,9 @@ output_movhi (rtx insn, rtx operands[], } } else if (CONSTANT_P (src)) - { - if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */ - { - *l = 2; - return (AS2 (ldi,%A0,lo8(%1)) CR_TAB - AS2 (ldi,%B0,hi8(%1))); - } - - if (GET_CODE (src) == CONST_INT) - { - if (src == const0_rtx) /* mov r,L */ - { - *l = 2; - return (AS1 (clr,%A0) CR_TAB - AS1 (clr,%B0)); - } - else if (src == const1_rtx) - { - *l = 3; - return (AS1 (clr,%A0) CR_TAB - AS1 (clr,%B0) CR_TAB - AS1 (inc,%A0)); - } - else if (src == constm1_rtx) - { - /* Immediate constants -1 to any register */ - *l = 3; - return (AS1 (clr,%0) CR_TAB - AS1 (dec,%A0) CR_TAB - AS2 (mov,%B0,%A0)); - } - else - { - int bit_nr = exact_log2 (INTVAL (src)); - - if (bit_nr >= 0) - { - *l = 4; - if (!real_l) - output_asm_insn ((AS1 (clr,%A0) CR_TAB - AS1 (clr,%B0) CR_TAB - "set"), operands); - if (!real_l) - avr_output_bld (operands, bit_nr); - - return ""; - } - } - - if ((INTVAL (src) & 0xff) == 0) - { - *l = 5; - return (AS2 (mov,__tmp_reg__,r31) CR_TAB - AS1 (clr,%A0) CR_TAB - AS2 (ldi,r31,hi8(%1)) CR_TAB - AS2 (mov,%B0,r31) CR_TAB - AS2 (mov,r31,__tmp_reg__)); - } - else if ((INTVAL (src) & 0xff00) == 0) - { - *l = 5; - return (AS2 (mov,__tmp_reg__,r31) CR_TAB - AS2 (ldi,r31,lo8(%1)) CR_TAB - AS2 (mov,%A0,r31) CR_TAB - AS1 (clr,%B0) CR_TAB - AS2 (mov,r31,__tmp_reg__)); - } - } - - /* Last resort, equal to loading from memory. */ - *l = 6; - return (AS2 (mov,__tmp_reg__,r31) CR_TAB - AS2 (ldi,r31,lo8(%1)) CR_TAB - AS2 (mov,%A0,r31) CR_TAB - AS2 (ldi,r31,hi8(%1)) CR_TAB - AS2 (mov,%B0,r31) CR_TAB - AS2 (mov,r31,__tmp_reg__)); - } + { + return output_reload_inhi (operands, NULL, real_l); + } else if (GET_CODE (src) == MEM) return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */ } @@ -5125,6 +5055,10 @@ adjust_insn_length (rtx insn, int len) switch (adjust_len) { + case ADJUST_LEN_RELOAD_IN16: + output_reload_inhi (op, op[2], &len); + break; + case ADJUST_LEN_RELOAD_IN32: output_reload_insisf (insn, op, op[2], &len); break; @@ -5185,31 +5119,7 @@ adjust_insn_length (rtx insn, int len) op[1] = SET_SRC (set); op[0] = SET_DEST (set); - if (GET_CODE (patt) == PARALLEL - && general_operand (op[1], VOIDmode) - && general_operand (op[0], VOIDmode)) - { - if (XVECLEN (patt, 0) == 2) - op[2] = XVECEXP (patt, 0, 1); - - switch (GET_MODE (op[0])) - { - case QImode: - len = 2; - break; - case HImode: - output_reload_inhi (insn, op, &len); - break; - case SImode: - case SFmode: - /* Handled by ADJUST_LEN_RELOAD_INSISF above. */ - gcc_unreachable(); - break; - default: - break; - } - } - else if (GET_CODE (op[1]) == ASHIFT + if (GET_CODE (op[1]) == ASHIFT || GET_CODE (op[1]) == ASHIFTRT || GET_CODE (op[1]) == LSHIFTRT) { @@ -7153,45 +7063,6 @@ avr_hard_regno_mode_ok (int regno, enum return !(regno & 1); } -const char * -output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len) -{ - int tmp; - if (!len) - len = &tmp; - - if (GET_CODE (operands[1]) == CONST_INT) - { - int val = INTVAL (operands[1]); - if ((val & 0xff) == 0) - { - *len = 3; - return (AS2 (mov,%A0,__zero_reg__) CR_TAB - AS2 (ldi,%2,hi8(%1)) CR_TAB - AS2 (mov,%B0,%2)); - } - else if ((val & 0xff00) == 0) - { - *len = 3; - return (AS2 (ldi,%2,lo8(%1)) CR_TAB - AS2 (mov,%A0,%2) CR_TAB - AS2 (mov,%B0,__zero_reg__)); - } - else if ((val & 0xff) == ((val & 0xff00) >> 8)) - { - *len = 3; - return (AS2 (ldi,%2,lo8(%1)) CR_TAB - AS2 (mov,%A0,%2) CR_TAB - AS2 (mov,%B0,%2)); - } - } - *len = 4; - return (AS2 (ldi,%2,lo8(%1)) CR_TAB - AS2 (mov,%A0,%2) CR_TAB - AS2 (ldi,%2,hi8(%1)) CR_TAB - AS2 (mov,%B0,%2)); -} - /* A helper for `output_reload_insisf'. */ /* Set 32-bit register OP[0] to compile-time constant OP[1]. @@ -7203,7 +7074,7 @@ output_reload_inhi (rtx insn ATTRIBUTE_U If CLEAR_P is false, nothing is known about OP[0]. */ static void -output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p) +output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) { rtx src = op[1]; rtx dest = op[0]; @@ -7223,7 +7094,8 @@ output_reload_insisf_1 (rtx *op, rtx clo /* (REG:SI 14) is special: It's neither in LD_REGS nor in NO_LD_REGS but has some subregs that are in LD_REGS. Use the MSB (REG:QI 17). */ - if (14 == REGNO (dest)) + if (14 == REGNO (dest) + && 4 == GET_MODE_SIZE (mode)) { clobber_reg = gen_rtx_REG (QImode, 17); } @@ -7233,25 +7105,16 @@ output_reload_insisf_1 (rtx *op, rtx clo a byte that is neither 0, -1 or a power of 2. */ if (NULL_RTX == clobber_reg - && !test_hard_reg_class (LD_REGS, dest)) - { - for (n = 0; n < GET_MODE_SIZE (mode); n++) - { - xval = simplify_gen_subreg (QImode, src, mode, n); - - if (!(const0_rtx == xval - || constm1_rtx == xval - || single_one_operand (xval, QImode))) - { - /* We have no clobber reg but need one. Cook one up. - That's cheaper than loading from constant pool. */ - - cooked_clobber_p = true; - clobber_reg = gen_rtx_REG (QImode, REG_Z + 1); - avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1); - break; - } - } + && !test_hard_reg_class (LD_REGS, dest) + && !avr_popcount_each_byte (src, GET_MODE_SIZE (mode), + (1 << 0) | (1 << 1) | (1 << 8))) + { + /* We have no clobber register but need one. Cook one up. + That's cheaper than loading from constant pool. */ + + cooked_clobber_p = true; + clobber_reg = gen_rtx_REG (QImode, REG_Z + 1); + avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1); } /* Now start filling DEST from LSB to MSB. */ @@ -7396,6 +7259,63 @@ output_reload_insisf_1 (rtx *op, rtx clo } +/* Reload the constant OP[1] into the HI register OP[0]. + CLOBBER_REG is a QI clobber reg needed to move vast majority of consts + into a NO_LD_REGS register. If CLOBBER_REG is NULL_RTX we either don't + need a clobber reg or have to cook one up. + + PLEN == NULL: Output instructions. + PLEN != NULL: Output nothing. Set *PLEN to number of words occupied + by the insns printed. + + Return "". */ + +const char* +output_reload_inhi (rtx *op, rtx clobber_reg, int *plen) +{ + if (CONST_INT_P (op[1])) + { + output_reload_in_const (op, clobber_reg, plen, false); + } + else if (test_hard_reg_class (LD_REGS, op[0])) + { + avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB + "ldi %B0,hi8(%1)", op, plen, -2); + } + else + { + rtx xop[3]; + + xop[0] = op[0]; + xop[1] = op[1]; + xop[2] = clobber_reg; + + if (plen) + *plen = 0; + + if (clobber_reg == NULL_RTX) + { + /* No scratch register provided: cook une up. */ + + xop[2] = gen_rtx_REG (QImode, REG_Z + 1); + avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1); + } + + avr_asm_len ("ldi %2,lo8(%1)" CR_TAB + "mov %A0,%2" CR_TAB + "ldi %2,hi8(%1)" CR_TAB + "mov %B0,%2", xop, plen, 4); + + if (clobber_reg == NULL_RTX) + { + avr_asm_len ("mov %2,__tmp_reg__", xop, plen, 1); + } + } + + return ""; +} + + /* Reload a SI or SF compile time constant OP[1] into the register OP[0]. CLOBBER_REG is a QI clobber reg needed to move vast majority of consts into a NO_LD_REGS register. If CLOBBER_REG is NULL_RTX we either don't @@ -7432,8 +7352,8 @@ output_reload_insisf (rtx insn ATTRIBUTE Instead, we call the print function twice to get the lengths of both methods and use the shortest one. */ - output_reload_insisf_1 (op, clobber_reg, &len_clr, true); - output_reload_insisf_1 (op, clobber_reg, &len_noclr, false); + output_reload_in_const (op, clobber_reg, &len_clr, true); + output_reload_in_const (op, clobber_reg, &len_noclr, false); if (len_noclr - len_clr == 4) { @@ -7443,7 +7363,7 @@ output_reload_insisf (rtx insn ATTRIBUTE "clr %B0" CR_TAB "movw %C0,%A0", &op[0], len, 3); - output_reload_insisf_1 (op, clobber_reg, len, true); + output_reload_in_const (op, clobber_reg, len, true); if (len) *len += 3; @@ -7454,7 +7374,7 @@ output_reload_insisf (rtx insn ATTRIBUTE /* Default: destination not pre-cleared. */ - output_reload_insisf_1 (op, clobber_reg, len, false); + output_reload_in_const (op, clobber_reg, len, false); return ""; }