Patchwork microMIPS ASE instruction set support [Part 1]

login
register
mail settings
Submitter Richard Sandiford
Date June 16, 2010, 6:37 p.m.
Message ID <87r5k6kenj.fsf@firetop.home>
Download mbox | patch
Permalink /patch/55920/
State New
Headers show

Comments

Richard Sandiford - June 16, 2010, 6:37 p.m.
Catherine Moore <clm@codesourcery.com> 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 "*add<mode>3"
     <d>addu\t%0,%1,%2
     <d>addiu\t%0,%1,%2"
   [(set_attr "type" "arith")
+   (set_attr "micromips_type" "add")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_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 "*ior<mode>3"
    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" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"

first line is misplaced.

@@ -4552,6 +4568,7 @@ (define_insn "mfhi<GPR:mode>_<HILO:mode>
   ""
   { return ISA_HAS_MACCHI ? "<GPR:d>macchi\t%0,%.,%." : "mfhi\t%0"; }
   [(set_attr "move_type" "mfhilo")
+   (set_attr "micromips_type" "mfhi")
    (set_attr "mode" "<GPR: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_ashl<mode>3"
+  [(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>mode) - 1));
+
+  return "<d>sll\t%0,%1,%2";
+}
+  [(set_attr "type" "shift")
+   (set_attr "micromips_type" "shift")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*micromips_ashr<mode>3"
+  [(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>mode) - 1));
+
+  return "<d>sra\t%0,%1,%2";
+}
+  [(set_attr "type" "shift")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*micromips_lshr<mode>3"
+  [(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>mode) - 1));
+
+  return "<d>srl\t%0,%1,%2";
+}
+  [(set_attr "type" "shift")
+   (set_attr "micromips_type" "shift")
+   (set_attr "mode" "<MODE>")])

How are these different from the !TARGET_MICROMIPS insns?

@@ -5534,7 +5652,12 @@ (define_expand "indirect_jump"
 (define_insn "indirect_jump<mode>"
   [(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
Catherine Moore - June 24, 2010, 9:56 p.m.
Hi Richard,

Thank you for reviewing this patch.  I've started to work through the 
issues that you've mentioned.  I will be posting updated patches over 
the coming days.

Catherine

Richard Sandiford wrote:
> 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 "*add<mode>3"
>      <d>addu\t%0,%1,%2
>      <d>addiu\t%0,%1,%2"
>    [(set_attr "type" "arith")
> +   (set_attr "micromips_type" "add")
>     (set_attr "mode" "<MODE>")])
>  
>  (define_insn "*add<mode>3_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 "*ior<mode>3"
>     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" "<MODE>")])
>  
>  (define_insn "*ior<mode>3_mips16"
> 
> first line is misplaced.
>

Patch

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
 <http://www.gnu.org/licenses/>.  */
 
+#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 */