From patchwork Wed Jun 16 18:37:04 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 55920 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 35BF0B7D1F for ; Thu, 17 Jun 2010 04:37:40 +1000 (EST) Received: (qmail 18760 invoked by alias); 16 Jun 2010 18:37:38 -0000 Received: (qmail 18735 invoked by uid 22791); 16 Jun 2010 18:37:33 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM X-Spam-Check-By: sourceware.org Received: from mail-ww0-f47.google.com (HELO mail-ww0-f47.google.com) (74.125.82.47) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 16 Jun 2010 18:37:18 +0000 Received: by wwb34 with SMTP id 34so17149wwb.20 for ; Wed, 16 Jun 2010 11:37:15 -0700 (PDT) Received: by 10.227.138.18 with SMTP id y18mr8964914wbt.198.1276713435311; Wed, 16 Jun 2010 11:37:15 -0700 (PDT) Received: from localhost ([82.133.89.107]) by mx.google.com with ESMTPS id y31sm56919598wby.22.2010.06.16.11.37.11 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 16 Jun 2010 11:37:13 -0700 (PDT) From: Richard Sandiford To: Catherine Moore Mail-Followup-To: Catherine Moore , gcc-patches , "Fu\, Chao-Ying" , "Maciej W. Rozycki" , CodeSourcery MIPS list , rdsandiford@googlemail.com Cc: gcc-patches , "Fu\, Chao-Ying" , "Maciej W. Rozycki" , CodeSourcery MIPS list Subject: Re: [patch] microMIPS ASE instruction set support [Part 1] References: <4C17F9FC.5010909@codesourcery.com> Date: Wed, 16 Jun 2010 19:37:04 +0100 In-Reply-To: <4C17F9FC.5010909@codesourcery.com> (Catherine Moore's message of "Tue, 15 Jun 2010 18:09:00 -0400") Message-ID: <87r5k6kenj.fsf@firetop.home> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 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 Catherine Moore writes: > This patch adds support for the microMIPS ASE instructions. microMIPS > reencodes the MIPS32 instruction set. Some new instructions are added > as well. Calls between microMIPS and MIPS32 are handled in a similar > way to MIPS16/MIPS32 calls. microMIPS and MIPS16 code may not be > intermixed. I assume you mean here that you can't simultaneously enable MIPS16 and microMIPS mode. However, there's a pending clarification on the binutils side about what exactly the restrictions are on having MIPS16 functions and microMIPS functions in the same object file. AIUI, there are also restrictions such as: microMIPS code can't call MIPS16 code, and vice versa (no suitable jump insn). Only the first of these restrictions is actually enforced in the patch. I don't like the way that you need to say: __attribute__((nomips16)) __attribute__((nomicromips)) to mean "no code compression" (which is what nomips16 was originally added for), but I suppose you're going to tell me that this is already in the wild and can't change now. Seems to me that "nomicromips" isn't very useful in a world with MIPS16, microMIPS and traditional encodings, and that it would have been better to make "nomips16" a compatibility alias for a new "traditional mips" attribute. (Suggestions for a name are welcome.) I suppose we could still do that, and make nomicromips an alias for it too. You deal with insn lengths by adding this code to mips_print_operand_punctuation: + case '!': + /* When reorder or noreorder with final_squence 0, the delay slot will + be a nop, so we just use the compact version for microMIPS. */ + if (mips_noreorder.nesting_level == 0 || final_sequence == 0) + putc ('s', file); + else + { + /* Try to find out if the delay slot instruction is 16-bit. */ + + struct recog_data old_recog_data = recog_data; + rtx insn = XVECEXP (final_sequence, 0, 1); + enum attr_mode mode = get_attr_mode (insn); + enum attr_micromips_type micromips_type + = get_attr_micromips_type (insn); + + recog_memoized (insn); + cleanup_subreg_operands (insn); + + if (0 + + /* move16 rd, rs. */ + || (GET_CODE (PATTERN (insn)) == SET + && (REG_P (XEXP (PATTERN (insn), 1)) + || GET_CODE (XEXP (PATTERN (insn), 1)) == CONST_DOUBLE) + && REG_P (recog_data.operand[0]) + && GP_REG_P (REGNO (recog_data.operand[0])) + && ((REG_P (recog_data.operand[1]) + && GP_REG_P (REGNO (recog_data.operand[1]))) + || (recog_data.operand[1] == CONST0_RTX(SFmode)))) + + /* move16 rd, $0. */ + || (GET_CODE (PATTERN (insn)) == SET + && GET_CODE (XEXP (PATTERN (insn), 1)) == CONST_INT + && REG_P (recog_data.operand[0]) + && GP_REG_P (REGNO (recog_data.operand[0])) + && CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) == 0) + + /* li16 rd, imm. */ + || (GET_CODE (PATTERN (insn)) == SET + && GET_CODE (XEXP (PATTERN (insn), 1)) == CONST_INT + && mode == MODE_SI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) >= -1 + && INTVAL (recog_data.operand[1]) <= 126) + + /* lw16 rt, offset(base). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 1)) + && ((mode == MODE_SI + && GET_MODE (recog_data.operand[1]) == SImode) + || (mode == MODE_SF + && GET_MODE (recog_data.operand[1]) == SFmode)) + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && MEM_P (recog_data.operand[1]) + && ((REG_P (XEXP (recog_data.operand[1], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[1], 0)))) + || (GET_CODE (XEXP (recog_data.operand[1], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[1], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[1], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[1], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) & 3) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) <= 60))) + + /* lwsp rt, offset($29). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 1)) + && ((mode == MODE_SI + && GET_MODE (recog_data.operand[1]) == SImode) + || (mode == MODE_SF + && GET_MODE (recog_data.operand[1]) == SFmode)) + && REG_P (recog_data.operand[0]) + && GP_REG_P (REGNO (recog_data.operand[0])) + && MEM_P (recog_data.operand[1]) + && ((REG_P (XEXP (recog_data.operand[1], 0)) + && (REGNO (XEXP (recog_data.operand[1], 0))) == 29) + || (GET_CODE (XEXP (recog_data.operand[1], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[1], 0), 0)) + && REGNO (XEXP (XEXP (recog_data.operand[1], 0), 0)) == 29 + && CONST_INT_P (XEXP (XEXP (recog_data.operand[1], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) & 3) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) <= 124))) + + /* lhu16 rt, offset(base). */ + || (micromips_type == MICROMIPS_TYPE_ZERO_EXTEND + && mode == MODE_SI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && MEM_P (recog_data.operand[1]) + && GET_MODE (recog_data.operand[1]) == HImode + && ((REG_P (XEXP (recog_data.operand[1], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[1], 0)))) + || (GET_CODE (XEXP (recog_data.operand[1], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[1], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[1], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[1], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) & 1) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) <= 30))) + + /* lbu16 rt, offset(base). */ + || (micromips_type == MICROMIPS_TYPE_ZERO_EXTEND + && mode == MODE_SI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && MEM_P (recog_data.operand[1]) + && GET_MODE (recog_data.operand[1]) == QImode + && ((REG_P (XEXP (recog_data.operand[1], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[1], 0)))) + || (GET_CODE (XEXP (recog_data.operand[1], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[1], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[1], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[1], 0), 1)) + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) >= -1 + && INTVAL (XEXP (XEXP (recog_data.operand[1], 0), 1)) <= 14))) + + /* sw16 rt, offset(base). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 0)) + && ((mode == MODE_SI + && GET_MODE (recog_data.operand[0]) == SImode) + || (mode == MODE_SF + && GET_MODE (recog_data.operand[0]) == SFmode)) + && ((CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) == 0) + || (REG_P (recog_data.operand[1]) + && M16STORE_REG_P (REGNO (recog_data.operand[1])))) + && MEM_P (recog_data.operand[0]) + && ((REG_P (XEXP (recog_data.operand[0], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[0], 0)))) + || (GET_CODE (XEXP (recog_data.operand[0], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[0], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[0], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[0], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) & 3) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) <= 60))) + + /* swsp rt, offset($29). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 0)) + && ((mode == MODE_SI + && GET_MODE (recog_data.operand[0]) == SImode) + || (mode == MODE_SF + && GET_MODE (recog_data.operand[0]) == SFmode)) + && ((CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) == 0) + || (REG_P (recog_data.operand[1]) + && GP_REG_P (REGNO (recog_data.operand[1])))) + && MEM_P (recog_data.operand[0]) + && ((REG_P (XEXP (recog_data.operand[0], 0)) + && (REGNO (XEXP (recog_data.operand[0], 0))) == 29) + || (GET_CODE (XEXP (recog_data.operand[0], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[0], 0), 0)) + && (REGNO (XEXP (XEXP (recog_data.operand[0], 0), 0)) == 29) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[0], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) & 3) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) <= 124))) + + /* sh16 rt, offset(base). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 0)) + && mode == MODE_HI + && ((CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) == 0) + || (REG_P (recog_data.operand[1]) + && M16STORE_REG_P (REGNO (recog_data.operand[1])))) + && MEM_P (recog_data.operand[0]) + && GET_MODE (recog_data.operand[0]) == HImode + && ((REG_P (XEXP (recog_data.operand[0], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[0], 0)))) + || (GET_CODE (XEXP (recog_data.operand[0], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[0], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[0], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[0], 0), 1)) + && (INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) & 1) == 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) <= 30))) + + /* sb16 rt, offset(base). */ + || (GET_CODE (PATTERN (insn)) == SET + && MEM_P (XEXP (PATTERN (insn), 0)) + && mode == MODE_QI + && ((CONST_INT_P (recog_data.operand[1]) + && INTVAL (recog_data.operand[1]) == 0) + || (REG_P (recog_data.operand[1]) + && M16STORE_REG_P (REGNO (recog_data.operand[1])))) + && MEM_P (recog_data.operand[0]) + && GET_MODE (recog_data.operand[0]) == QImode + && ((REG_P (XEXP (recog_data.operand[0], 0)) + && M16_REG_P (REGNO (XEXP (recog_data.operand[0], 0)))) + || (GET_CODE (XEXP (recog_data.operand[0], 0)) == PLUS + && REG_P (XEXP (XEXP (recog_data.operand[0], 0), 0)) + && M16_REG_P (REGNO (XEXP (XEXP (recog_data.operand[0], 0), 0))) + && CONST_INT_P (XEXP (XEXP (recog_data.operand[0], 0), 1)) + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) >= 0 + && INTVAL (XEXP (XEXP (recog_data.operand[0], 0), 1)) <= 15))) + + /* addu16 rd, rs, rt. */ + || (micromips_type == MICROMIPS_TYPE_ADD + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && REG_P (recog_data.operand[2]) + && M16_REG_P (REGNO (recog_data.operand[2]))) + + /* addius5 rd, imm. */ + || (micromips_type == MICROMIPS_TYPE_ADD + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && REG_P (recog_data.operand[1]) + && GP_REG_P (REGNO (recog_data.operand[0])) + && (REGNO (recog_data.operand[0]) + == REGNO (recog_data.operand[1])) + && CONST_INT_P (recog_data.operand[2]) + && INTVAL (recog_data.operand[2]) >= -8 + && INTVAL (recog_data.operand[2]) <= 7) + + /* addiusp $29, $29, imm. */ + || (micromips_type == MICROMIPS_TYPE_ADD + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && REGNO (recog_data.operand[0]) == 29 + && REG_P (recog_data.operand[1]) + && REGNO (recog_data.operand[1]) == 29 + && CONST_INT_P (recog_data.operand[2]) + && ((INTVAL (recog_data.operand[2]) >= 2 + && INTVAL (recog_data.operand[2]) <= 257) + || (INTVAL (recog_data.operand[2]) >= -258 + && INTVAL (recog_data.operand[2]) <= -3))) + + /* addiur1sp rd, $29, imm. */ + || (micromips_type == MICROMIPS_TYPE_ADD + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && REGNO (recog_data.operand[1]) == 29 + && CONST_INT_P (recog_data.operand[2]) + && (INTVAL (recog_data.operand[2]) & 3) == 0 + && INTVAL (recog_data.operand[2]) >= 0 + && INTVAL (recog_data.operand[2]) <= 252) + + /* addiur2 rd, rs, imm. */ + || (micromips_type == MICROMIPS_TYPE_ADD + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && CONST_INT_P (recog_data.operand[2]) + && (INTVAL (recog_data.operand[2]) == 1 + || INTVAL (recog_data.operand[2]) == 4 + || INTVAL (recog_data.operand[2]) == 8 + || INTVAL (recog_data.operand[2]) == 12 + || INTVAL (recog_data.operand[2]) == 16 + || INTVAL (recog_data.operand[2]) == 20 + || INTVAL (recog_data.operand[2]) == 24 + || INTVAL (recog_data.operand[2]) == -1)) + + /* subu16 rd, rs, rt. */ + || (micromips_type == MICROMIPS_TYPE_SUB + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && REG_P (recog_data.operand[2]) + && M16_REG_P (REGNO (recog_data.operand[2]))) + + /* sll16/srl16 rd, rt, sa. */ + || (micromips_type == MICROMIPS_TYPE_SHIFT + && mode != MODE_DI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && CONST_INT_P (recog_data.operand[2]) + && INTVAL (recog_data.operand[2]) >= 1 + && INTVAL (recog_data.operand[2]) <= 8) + + /* andi16 rd, rs, imm. */ + || (micromips_type == MICROMIPS_TYPE_LOGICAL_AND + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && CONST_INT_P (recog_data.operand[2]) + && (INTVAL (recog_data.operand[2]) == 128 + || INTVAL (recog_data.operand[2]) == 1 + || INTVAL (recog_data.operand[2]) == 2 + || INTVAL (recog_data.operand[2]) == 3 + || INTVAL (recog_data.operand[2]) == 4 + || INTVAL (recog_data.operand[2]) == 7 + || INTVAL (recog_data.operand[2]) == 8 + || INTVAL (recog_data.operand[2]) == 15 + || INTVAL (recog_data.operand[2]) == 16 + || INTVAL (recog_data.operand[2]) == 31 + || INTVAL (recog_data.operand[2]) == 32 + || INTVAL (recog_data.operand[2]) == 63 + || INTVAL (recog_data.operand[2]) == 64 + || INTVAL (recog_data.operand[2]) == 255 + || INTVAL (recog_data.operand[2]) == 32768 + || INTVAL (recog_data.operand[2]) == 65535)) + + /* andi16 rd, rs, imm. */ + || (micromips_type == MICROMIPS_TYPE_ZERO_EXTEND + && mode == MODE_SI + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1]))) + + /* and16/xor16/or16 rd, rs, rt. */ + || ((micromips_type == MICROMIPS_TYPE_LOGICAL_AND + || micromips_type == MICROMIPS_TYPE_LOGICAL_XOR + || micromips_type == MICROMIPS_TYPE_LOGICAL_OR) + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1])) + && REG_P (recog_data.operand[2]) + && M16_REG_P (REGNO (recog_data.operand[2])) + && (REGNO (recog_data.operand[0]) + == REGNO (recog_data.operand[1]) + || REGNO (recog_data.operand[0]) + == REGNO (recog_data.operand[2]))) + + /* mfhi rd. */ + || (micromips_type == MICROMIPS_TYPE_MFHI + && REG_P (recog_data.operand[0]) + && GP_REG_P (REGNO (recog_data.operand[0]))) + + /* mflo rd. */ + || (GET_CODE (PATTERN (insn)) == SET + && REG_P (XEXP (PATTERN (insn), 0)) + && REG_P (XEXP (PATTERN (insn), 1)) + && REG_P (recog_data.operand[0]) + && GP_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && REGNO (recog_data.operand[1]) == LO_REGNUM) + + /* not rt, rs. */ + || (micromips_type == MICROMIPS_TYPE_LOGICAL_NOT + && REG_P (recog_data.operand[0]) + && M16_REG_P (REGNO (recog_data.operand[0])) + && REG_P (recog_data.operand[1]) + && M16_REG_P (REGNO (recog_data.operand[1]))) + + || 0) + + putc ('s', file); + + recog_data = old_recog_data; + } + break; Don't do that! You should try to make the length attribute correct instead. (We even try to make the length accurate for MIPS16, although in some cases the lengths are conservative.) Try to avoid the micromips attribute and use more generic ones if you can. It's better to extend the existing attributes like move_type where possible, and introduce new ones otherwise. E.g.: @@ -979,6 +988,7 @@ (define_insn "*add3" addu\t%0,%1,%2 addiu\t%0,%1,%2" [(set_attr "type" "arith") + (set_attr "micromips_type" "add") (set_attr "mode" "")]) (define_insn "*add3_mips16" either split "arith" into "add,sub" or add a new attribute (alu_type?) that automatically implies (set_attr "type" "arith") for "add" and "sub". I realise the first one requires a fair few changes to existing code (and would consequently be better as a separate lead-up patch), but that's how these things get done: keep types together while there is no use in splitting them, then split then when we find a need. Same with the "logical" ops. BTW: @@ -2639,6 +2651,8 @@ (define_insn "*ior3" or\t%0,%1,%2 ori\t%0,%1,%x2" [(set_attr "type" "logical") + (set_attr "micromips_type" "logical_and") + (set_attr "micromips_type" "logical_or") (set_attr "mode" "")]) (define_insn "*ior3_mips16" first line is misplaced. @@ -4552,6 +4568,7 @@ (define_insn "mfhi_ "" { return ISA_HAS_MACCHI ? "macchi\t%0,%.,%." : "mfhi\t%0"; } [(set_attr "move_type" "mfhilo") + (set_attr "micromips_type" "mfhi") (set_attr "mode" "")]) ;; Set the high part of a HI/LO value, given that the low part has Split move_type mfhilo into "mfhi" and "mflo". etc. As with GAS, I'd prefer a single macro: #define TARGET_CODE_COMPRESSION (TARGET_MIPS16 || TARGET_MICROMIPS) +(define_insn "*micromips_ashl3" + [(set (match_operand:GPR 0 "register_operand" "=d") + (ashift:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_MICROMIPS" +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) + & (GET_MODE_BITSIZE (mode) - 1)); + + return "sll\t%0,%1,%2"; +} + [(set_attr "type" "shift") + (set_attr "micromips_type" "shift") + (set_attr "mode" "")]) + +(define_insn "*micromips_ashr3" + [(set (match_operand:GPR 0 "register_operand" "=d") + (ashiftrt:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_MICROMIPS" +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) + & (GET_MODE_BITSIZE (mode) - 1)); + + return "sra\t%0,%1,%2"; +} + [(set_attr "type" "shift") + (set_attr "mode" "")]) + +(define_insn "*micromips_lshr3" + [(set (match_operand:GPR 0 "register_operand" "=d") + (lshiftrt:GPR (match_operand:GPR 1 "register_operand" "d") + (match_operand:SI 2 "arith_operand" "dI")))] + "TARGET_MICROMIPS" +{ + if (GET_CODE (operands[2]) == CONST_INT) + operands[2] = GEN_INT (INTVAL (operands[2]) + & (GET_MODE_BITSIZE (mode) - 1)); + + return "srl\t%0,%1,%2"; +} + [(set_attr "type" "shift") + (set_attr "micromips_type" "shift") + (set_attr "mode" "")]) How are these different from the !TARGET_MICROMIPS insns? @@ -5534,7 +5652,12 @@ (define_expand "indirect_jump" (define_insn "indirect_jump" [(set (pc) (match_operand:P 0 "register_operand" "d"))] "" - "%*j\t%0%/" +{ + if (TARGET_MICROMIPS) + return "%*jr%:\t%0"; + else + return "%*j\t%0%/"; +} [(set_attr "type" "jump") (set_attr "mode" "none")]) JR is always valid for jumps to registers. Let's not conditionalise this. As above, this depends on the outcome of the binutils question. It only makes sense if the linker enforces a "no mixing MIPS16 and microMIPS in the same link" rule. @@ -2251,10 +2320,14 @@ mips16_unextended_reference_p (enum mach if MIGHT_SPLIT_P, otherwise assume that a single load or store is enough. + If CHECK_MICROMIPS_12BIT_P, we check if the address is within a 12-bit + offset for microMIPS. + For MIPS16 code, count extended instructions as two instructions. */ int -mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p) +mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p, + bool check_micromips_12bit_p) { struct mips_address_info addr; int factor; @@ -2272,6 +2345,12 @@ mips_address_insns (rtx x, enum machine_ switch (addr.type) { case ADDRESS_REG: + if (TARGET_MICROMIPS && check_micromips_12bit_p + && (!CONST_INT_P (addr.offset) + || INTVAL (addr.offset) < -2048 + || INTVAL (addr.offset) > 2047)) + return 0; + if (TARGET_MIPS16 && !mips16_unextended_reference_p (mode, addr.reg, UINTVAL (addr.offset))) @@ -2279,12 +2358,21 @@ mips_address_insns (rtx x, enum machine_ return factor; case ADDRESS_LO_SUM: + if (TARGET_MICROMIPS && check_micromips_12bit_p) + return 0; + return TARGET_MIPS16 ? factor * 2 : factor; case ADDRESS_CONST_INT: + if (TARGET_MICROMIPS && check_micromips_12bit_p) + return 0; + return factor; case ADDRESS_SYMBOLIC: + if (TARGET_MICROMIPS && check_micromips_12bit_p) + return 0; + return factor * mips_symbol_insns (addr.symbol_type, mode); } return 0; The check_micromips_12bit_p stuff should be a separate function, not added here. +; For movep +(define_peephole2 + [(set (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "reg_or_0_operand" "")) + (set (match_operand:SI 2 "register_operand" "") + (match_operand:SI 3 "reg_or_0_operand" ""))] + "TARGET_MICROMIPS + && micromips_movep_target_p (operands[0], operands[2]) + && (operands[1] == CONST0_RTX (SImode) + || REGNO (operands[1]) == 0 + || REGNO (operands[1]) == 2 + || REGNO (operands[1]) == 3 + || (REGNO (operands[1]) >= 16 && REGNO (operands[1]) <= 20)) + && (operands[3] == CONST0_RTX (SImode) + || REGNO (operands[3]) == 0 + || REGNO (operands[3]) == 2 + || REGNO (operands[3]) == 3 + || (REGNO (operands[3]) >= 16 && REGNO (operands[3]) <= 20))" + [(parallel [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) (match_dup 3))])] +) The operands[1] and operands[3] checks should be done in the predicate. +(define_insn "*movepsisi" + [(parallel [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "reg_or_0_operand")) + (set (match_operand:SI 2 "register_operand") + (match_operand:SI 3 "reg_or_0_operand"))])] + "TARGET_MICROMIPS + && micromips_movep_target_p (operands[0], operands[2]) + && (operands[1] == CONST0_RTX (SImode) + || REGNO (operands[1]) == 0 + || REGNO (operands[1]) == 2 + || REGNO (operands[1]) == 3 + || (REGNO (operands[1]) >= 16 && REGNO (operands[1]) <= 20)) + && (operands[3] == CONST0_RTX (SImode) + || REGNO (operands[3]) == 0 + || REGNO (operands[3]) == 2 + || REGNO (operands[3]) == 3 + || (REGNO (operands[3]) >= 16 && REGNO (operands[3]) <= 20))" +{ + if (REGNO (operands[0]) < REGNO (operands[2])) + return "movep\t%0,%2,%z1,%z3"; + else + return "movep\t%2,%0,%z3,%z1"; +} + [(set_attr "type" "move") + (set_attr "can_delay" "no") + (set_attr "mode" "SI")]) + +(define_insn "*movepsisf" + [(parallel [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "reg_or_0_operand")) + (set (match_operand:SF 2 "register_operand") + (match_operand:SF 3 "const_0_operand"))])] + "TARGET_MICROMIPS + && micromips_movep_target_p (operands[0], operands[2]) + && (operands[1] == CONST0_RTX (SImode) + || REGNO (operands[1]) == 0 + || REGNO (operands[1]) == 2 + || REGNO (operands[1]) == 3 + || (REGNO (operands[1]) >= 16 && REGNO (operands[1]) <= 20)) + && operands[3] == CONST0_RTX (SFmode)" +{ + if (REGNO (operands[0]) < REGNO (operands[2])) + return "movep\t%0,%2,%z1,%z3"; + else + return "movep\t%2,%0,%z3,%z1"; +} + [(set_attr "type" "move") + (set_attr "can_delay" "no") + (set_attr "mode" "SF")]) + +(define_insn "*movepsfsi" + [(parallel [(set (match_operand:SF 0 "register_operand") + (match_operand:SF 1 "const_0_operand")) + (set (match_operand:SI 2 "register_operand") + (match_operand:SI 3 "reg_or_0_operand"))])] + "TARGET_MICROMIPS + && micromips_movep_target_p (operands[0], operands[2]) + && operands[1] == CONST0_RTX (SFmode) + && (operands[3] == CONST0_RTX (SImode) + || REGNO (operands[3]) == 0 + || REGNO (operands[3]) == 2 + || REGNO (operands[3]) == 3 + || (REGNO (operands[3]) >= 16 && REGNO (operands[3]) <= 20))" +{ + if (REGNO (operands[0]) < REGNO (operands[2])) + return "movep\t%0,%2,%z1,%z3"; + else + return "movep\t%2,%0,%z3,%z1"; +} + [(set_attr "type" "move") + (set_attr "can_delay" "no") + (set_attr "mode" "SF")]) + +(define_insn "*movepsfsf" + [(parallel [(set (match_operand:SF 0 "register_operand") + (match_operand:SF 1 "const_0_operand")) + (set (match_operand:SF 2 "register_operand") + (match_operand:SF 3 "const_0_operand"))])] + "TARGET_MICROMIPS + && micromips_movep_target_p (operands[0], operands[2]) + && operands[1] == CONST0_RTX (SFmode) + && operands[3] == CONST0_RTX (SFmode)" +{ + if (REGNO (operands[0]) < REGNO (operands[2])) + return "movep\t%0,%2,%z1,%z3"; + else + return "movep\t%2,%0,%z3,%z1"; +} + [(set_attr "type" "move") + (set_attr "can_delay" "no") + (set_attr "mode" "SF")]) Use (two) mode iterators to combine these patterns. You can use a mode attribute for the predicate. @@ -1313,6 +1325,41 @@ mips_use_mips16_mode_p (tree decl) return mips_base_mips16; } +/* Similar predicates for "micromips"/"nomicromips" function attributes. */ + +static bool +mips_micromips_decl_p (const_tree decl) +{ + return lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL; +} + +static bool +mips_nomicromips_decl_p (const_tree decl) +{ + return lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL; +} + +/* Return true if function DECL is a microMIPS function. Return the ambient + setting if DECL is null. */ + +static bool +mips_use_micromips_mode_p (tree decl) +{ + if (decl) + { + /* Nested functions must use the same frame pointer as their + parent and must therefore use the same ISA mode. */ + tree parent = decl_function_context (decl); + if (parent) + decl = parent; + if (mips_micromips_decl_p (decl)) + return true; + if (mips_nomicromips_decl_p (decl)) + return false; + } + return mips_base_micromips; +} Instead replace the mips16_* functions with ones that return a tristate value (normal, MIPS16 or microMIPS). @@ -2559,16 +2572,41 @@ typedef struct mips_args { afterwards if necessary. Finally, we can only generate direct calls for -mabicalls by temporarily switching to non-PIC mode. */ #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO) \ + (TARGET_MICROMIPS \ + ? (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \ + ? (TARGET_JALS ? "%*" INSN "%!\t%" #TARGET_OPNO "%/" \ + : "%*" INSN "\t%" #TARGET_OPNO "%/") \ + : (REG_P (OPERANDS[TARGET_OPNO]) \ + && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)) \ + ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \ + "1:\t" INSN "r\t%" #TARGET_OPNO "%/") \ + : REG_P (OPERANDS[TARGET_OPNO]) \ + ? (TARGET_JALS ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/" \ + : "%*" INSN "r\t%" #TARGET_OPNO "%/") \ + : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")) \ + : (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \ + ? "%*" INSN "\t%" #TARGET_OPNO "%/" \ + : (REG_P (OPERANDS[TARGET_OPNO]) \ + && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)) \ + ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \ + "1:\t" INSN "r\t%" #TARGET_OPNO "%/") \ + : REG_P (OPERANDS[TARGET_OPNO]) \ + ? "%*" INSN "r\t%" #TARGET_OPNO "%/" \ + : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))) + +/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate + "jrc" when nop is in the delay slot of "jr". */ +#define MICROMIPS_J(OPERANDS, OPNO) \ (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \ - ? "%*" INSN "\t%" #TARGET_OPNO "%/" \ - : (REG_P (OPERANDS[TARGET_OPNO]) \ - && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)) \ - ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \ - "1:\t" INSN "r\t%" #TARGET_OPNO "%/") \ - : REG_P (OPERANDS[TARGET_OPNO]) \ - ? "%*" INSN "r\t%" #TARGET_OPNO "%/" \ - : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")) - + ? "%*j\t%" #OPNO "%/" \ + : REG_P (OPERANDS[OPNO]) \ + ? "%*jr%:\t%" #OPNO \ + : TARGET_ABICALLS && flag_pic \ + ? (".option\tpic0\n\t" \ + "%*j\t%" #OPNO "%/\n\t" \ + ".option\tpic2") \ + : "%*j\t%" #OPNO "%/") + /* Control the assembler format that we output. */ /* Output to assembler file text saying following lines Too much cut-&-paste. + if (!REG_P (reg) || !MEM_P (mem)) + gcc_unreachable (); Things like this should be: gcc_assert (REG_P (reg) && MEM_P (mem)); instead. Try to combine the save-restore code in mips.c with the mips16 version. Watch for long lines and formatting; noticed quite a few transgressions ;-) As with binutils, please submit the MCU and m14k support as (two) separate patches. Please also submit the passes.c change separately. Richard Index: config/mips/mips16.S =================================================================== --- config/mips/mips16.S (revision 160766) +++ config/mips/mips16.S (working copy) @@ -21,6 +21,10 @@ a copy of the GCC Runtime Library Except see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#ifdef __mips_micromips + /* DO NOTHING */ +#else + /* This file contains mips16 floating point support functions. These functions are called by mips16 code to handle floating point when -msoft-float is not used. They accept the arguments and return @@ -707,3 +712,4 @@ CALL_STUB_RET (__mips16_call_stub_dc_10, #endif #endif /* !__mips_single_float */ #endif +#endif /* __mips_micromips */