This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Rewrite main mips16_ip parsing loop


Like the previous patch, but for MIPS16.  Posted as a -b diff
because of reindentation.

Tested on various targets and applied.

Richard


gas/
	* config/tc-mips.c (mips32_to_16_reg_map): Delete.
	(match_entry_exit_operand): New function.
	(match_save_restore_list_operand): Likewise.
	(match_operand): Use them.
	(check_absolute_expr): Delete.
	(mips16_ip): Rewrite main parsing loop to use mips_operands.

Index: gas/config/tc-mips.c
===================================================================
*** gas/config/tc-mips.c	2013-07-14 14:48:46.215110230 +0100
--- gas/config/tc-mips.c	2013-07-14 14:50:31.443086793 +0100
*************** struct mips_hi_fixup
*** 755,772 ****
  
  static fragS *prev_reloc_op_frag;
  
- /* Map normal MIPS register numbers to mips16 register numbers.  */
- 
- #define X ILLEGAL_REG
- static const int mips32_to_16_reg_map[] =
- {
-   X, X, 2, 3, 4, 5, 6, 7,
-   X, X, X, X, X, X, X, X,
-   0, 1, X, X, X, X, X, X,
-   X, X, X, X, X, X, X, X
- };
- #undef X
- 
  /* Map mips16 register numbers to normal MIPS register numbers.  */
  
  static const unsigned int mips16_to_32_reg_map[] =
--- 755,760 ----
*************** match_lwm_swm_list_operand (struct mips_
*** 4280,4285 ****
--- 4268,4503 ----
    return s;
  }
  
+ /* OP_ENTRY_EXIT_LIST matcher.  */
+ 
+ static char *
+ match_entry_exit_operand (struct mips_arg_info *arg,
+ 			  const struct mips_operand *operand, char *s)
+ {
+   unsigned int mask;
+   bfd_boolean is_exit;
+ 
+   /* The format is the same for both ENTRY and EXIT, but the constraints
+      are different.  */
+   is_exit = strcmp (arg->insn->insn_mo->name, "exit") == 0;
+   mask = (is_exit ? 7 << 3 : 0);
+   for (;;)
+     {
+       unsigned int regno1, regno2;
+       bfd_boolean is_freg;
+ 
+       if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &regno1))
+ 	is_freg = FALSE;
+       else if (reg_lookup (&s, RTYPE_FPU, &regno1))
+ 	is_freg = TRUE;
+       else
+ 	return 0;
+ 
+       SKIP_SPACE_TABS (s);
+       if (*s == '-')
+ 	{
+ 	  ++s;
+ 	  SKIP_SPACE_TABS (s);
+ 	  if (!reg_lookup (&s, (is_freg ? RTYPE_FPU
+ 				: RTYPE_GP | RTYPE_NUM), &regno2))
+ 	    return 0;
+ 	  SKIP_SPACE_TABS (s);
+ 	}
+       else
+ 	regno2 = regno1;
+ 
+       if (is_exit && is_freg && regno1 == 0 && regno2 < 2)
+ 	{
+ 	  mask &= ~(7 << 3);
+ 	  mask |= (5 + regno2) << 3;
+ 	}
+       else if (!is_exit && regno1 == 4 && regno2 >= 4 && regno2 <= 7)
+ 	mask |= (regno2 - 3) << 3;
+       else if (regno1 == 16 && regno2 >= 16 && regno2 <= 17)
+ 	mask |= (regno2 - 15) << 1;
+       else if (regno1 == RA && regno2 == RA)
+ 	mask |= 1;
+       else
+ 	return 0;
+ 
+       if (!*s)
+ 	break;
+       if (*s != ',')
+ 	return 0;
+       arg->argnum += 1;
+       ++s;
+       SKIP_SPACE_TABS (s);
+     }
+   insn_insert_operand (arg->insn, operand, mask);
+   return s;
+ }
+ 
+ /* OP_SAVE_RESTORE_LIST matcher.  */
+ 
+ static char *
+ match_save_restore_list_operand (struct mips_arg_info *arg, char *s)
+ {
+   unsigned int opcode, args, statics, sregs;
+   unsigned int num_frame_sizes, num_args, num_statics, num_sregs;
+   expressionS value;
+   offsetT frame_size;
+   const char *error;
+ 
+   error = 0;
+   opcode = arg->insn->insn_opcode;
+   frame_size = 0;
+   num_frame_sizes = 0;
+   args = 0;
+   statics = 0;
+   sregs = 0;
+   for (;;)
+     {
+       unsigned int regno1, regno2;
+ 
+       my_getExpression (&value, s);
+       if (value.X_op == O_constant)
+ 	{
+ 	  /* Handle the frame size.  */
+ 	  num_frame_sizes += 1;
+ 	  frame_size = value.X_add_number;
+ 	  s = expr_end;
+ 	  SKIP_SPACE_TABS (s);
+ 	}
+       else
+ 	{
+ 	  if (!reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &regno1))
+ 	    return 0;
+ 
+ 	  SKIP_SPACE_TABS (s);
+ 	  if (*s == '-')
+ 	    {
+ 	      ++s;
+ 	      SKIP_SPACE_TABS (s);
+ 	      if (!reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &regno2)
+ 		  || regno2 < regno1)
+ 		return 0;
+ 	      SKIP_SPACE_TABS (s);
+ 	    }
+ 	  else
+ 	    regno2 = regno1;
+ 
+ 	  while (regno1 <= regno2)
+ 	    {
+ 	      if (regno1 >= 4 && regno1 <= 7)
+ 		{
+ 		  if (num_frame_sizes == 0)
+ 		    /* args $a0-$a3 */
+ 		    args |= 1 << (regno1 - 4);
+ 		  else
+ 		    /* statics $a0-$a3 */
+ 		    statics |= 1 << (regno1 - 4);
+ 		}
+ 	      else if (regno1 >= 16 && regno1 <= 23)
+ 		/* $s0-$s7 */
+ 		sregs |= 1 << (regno1 - 16);
+ 	      else if (regno1 == 30)
+ 		/* $s8 */
+ 		sregs |= 1 << 8;
+ 	      else if (regno1 == 31)
+ 		/* Add $ra to insn.  */
+ 		opcode |= 0x40;
+ 	      else
+ 		return 0;
+ 	      regno1 += 1;
+ 	      if (regno1 == 24)
+ 		regno1 = 30;
+ 	    }
+ 	}
+       if (!*s)
+ 	break;
+       if (*s != ',')
+ 	return 0;
+       arg->argnum += 1;
+       ++s;
+       SKIP_SPACE_TABS (s);
+     }
+ 
+   /* Encode args/statics combination.  */
+   if (args & statics)
+     return 0;
+   else if (args == 0xf)
+     /* All $a0-$a3 are args.  */
+     opcode |= MIPS16_ALL_ARGS << 16;
+   else if (statics == 0xf)
+     /* All $a0-$a3 are statics.  */
+     opcode |= MIPS16_ALL_STATICS << 16;
+   else
+     {
+       /* Count arg registers.  */
+       num_args = 0;
+       while (args & 0x1)
+ 	{
+ 	  args >>= 1;
+ 	  num_args += 1;
+ 	}
+       if (args != 0)
+ 	return 0;
+ 
+       /* Count static registers.  */
+       num_statics = 0;
+       while (statics & 0x8)
+ 	{
+ 	  statics = (statics << 1) & 0xf;
+ 	  num_statics += 1;
+ 	}
+       if (statics != 0)
+ 	return 0;
+ 
+       /* Encode args/statics.  */
+       opcode |= ((num_args << 2) | num_statics) << 16;
+     }
+ 
+   /* Encode $s0/$s1.  */
+   if (sregs & (1 << 0))		/* $s0 */
+     opcode |= 0x20;
+   if (sregs & (1 << 1))		/* $s1 */
+     opcode |= 0x10;
+   sregs >>= 2;
+ 
+   /* Encode $s2-$s8. */
+   num_sregs = 0;
+   while (sregs & 1)
+     {
+       sregs >>= 1;
+       num_sregs += 1;
+     }
+   if (sregs != 0)
+     return 0;
+   opcode |= num_sregs << 24;
+ 
+   /* Encode frame size.  */
+   if (num_frame_sizes == 0)
+     error = _("Missing frame size");
+   else if (num_frame_sizes > 1)
+     error = _("Frame size specified twice");
+   else if ((frame_size & 7) != 0 || frame_size < 0 || frame_size > 0xff * 8)
+     error = _("Invalid frame size");
+   else if (frame_size != 128 || (opcode >> 16) != 0)
+     {
+       frame_size /= 8;
+       opcode |= (((frame_size & 0xf0) << 16)
+ 		 | (frame_size & 0x0f));
+     }
+ 
+   if (error)
+     {
+       if (arg->soft_match)
+ 	return 0;
+       as_bad (error);
+     }
+ 
+   /* Finally build the instruction.  */
+   if ((opcode >> 16) != 0 || frame_size == 0)
+     opcode |= MIPS16_EXTEND;
+   arg->insn->insn_opcode = opcode;
+   return s;
+ }
+ 
  /* OP_MDMX_IMM_REG matcher.  */
  
  static char *
*************** match_operand (struct mips_arg_info *arg
*** 4454,4461 ****
        return match_lwm_swm_list_operand (arg, operand, s);
  
      case OP_ENTRY_EXIT_LIST:
      case OP_SAVE_RESTORE_LIST:
!       abort ();
  
      case OP_MDMX_IMM_REG:
        return match_mdmx_imm_reg_operand (arg, operand, s);
--- 4672,4681 ----
        return match_lwm_swm_list_operand (arg, operand, s);
  
      case OP_ENTRY_EXIT_LIST:
+       return match_entry_exit_operand (arg, operand, s);
+ 
      case OP_SAVE_RESTORE_LIST:
!       return match_save_restore_list_operand (arg, s);
  
      case OP_MDMX_IMM_REG:
        return match_mdmx_imm_reg_operand (arg, operand, s);
*************** set_at (int reg, int unsignedp)
*** 6573,6593 ****
      }
  }
  
- /* Warn if an expression is not a constant.  */
- 
- static void
- check_absolute_expr (struct mips_cl_insn *ip, expressionS *ex)
- {
-   if (ex->X_op == O_big)
-     as_bad (_("unsupported large constant"));
-   else if (ex->X_op != O_constant)
-     as_bad (_("Instruction %s requires absolute expression"),
- 	    ip->insn_mo->name);
- 
-   if (HAVE_32BIT_GPRS)
-     normalize_constant_expr (ex);
- }
- 
  /* Count the leading zeroes by performing a binary chop. This is a
     bulky bit of source, but performance is a LOT better for the
     majority of values than a simple loop to count the bits:
--- 6793,6798 ----
*************** mips16_ip (char *str, struct mips_cl_ins
*** 12064,12073 ****
    const char *args;
    struct mips_opcode *insn;
    char *argsstart;
-   unsigned int regno;
-   unsigned int lastregno = 0;
-   char *s_reset;
    size_t i;
  
    insn_error = NULL;
  
--- 12269,12278 ----
    const char *args;
    struct mips_opcode *insn;
    char *argsstart;
    size_t i;
+   const struct mips_operand *operand;
+   const struct mips_operand *ext_operand;
+   struct mips_arg_info arg;
  
    insn_error = NULL;
  
*************** mips16_ip (char *str, struct mips_cl_ins
*** 12118,12132 ****
    for (;;)
      {
        bfd_boolean ok;
        char relax_char;
  
        gas_assert (strcmp (insn->name, str) == 0);
  
        ok = is_opcode_valid_16 (insn);
        if (! ok)
  	{
! 	  if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
! 	      && strcmp (insn->name, insn[1].name) == 0)
  	    {
  	      ++insn;
  	      continue;
--- 12323,12339 ----
    for (;;)
      {
        bfd_boolean ok;
+       bfd_boolean more_alts;
        char relax_char;
  
        gas_assert (strcmp (insn->name, str) == 0);
  
        ok = is_opcode_valid_16 (insn);
+       more_alts = (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes]
+ 		   && strcmp (insn[0].name, insn[1].name) == 0);
        if (! ok)
  	{
! 	  if (more_alts)
  	    {
  	      ++insn;
  	      continue;
*************** mips16_ip (char *str, struct mips_cl_ins
*** 12154,12179 ****
        offset_reloc[1] = BFD_RELOC_UNUSED;
        offset_reloc[2] = BFD_RELOC_UNUSED;
        relax_char = 0;
        for (args = insn->args; 1; ++args)
  	{
  	  int c;
  
! 	  if (*s == ' ')
! 	    ++s;
! 
! 	  /* In this switch statement we call break if we did not find
!              a match, continue if we did find a match, or return if we
!              are done.  */
! 
! 	  c = *args;
! 	  switch (c)
! 	    {
! 	    case '\0':
! 	      if (*s == '\0')
  		{
  		  offsetT value;
  
! 		  /* Stuff the immediate value in now, if we can.  */
  		  if (insn->pinfo == INSN_MACRO)
  		    {
  		      gas_assert (relax_char == 0);
--- 12361,12401 ----
        offset_reloc[1] = BFD_RELOC_UNUSED;
        offset_reloc[2] = BFD_RELOC_UNUSED;
        relax_char = 0;
+ 
+       memset (&arg, 0, sizeof (arg));
+       arg.insn = ip;
+       arg.argnum = 1;
+       arg.last_regno = ILLEGAL_REG;
+       arg.dest_regno = ILLEGAL_REG;
+       arg.soft_match = more_alts;
+       relax_char = 0;
        for (args = insn->args; 1; ++args)
  	{
  	  int c;
  
! 	  SKIP_SPACE_TABS (s);
! 	  if (*s == 0)
  	    {
  	      offsetT value;
  
! 	      /* Handle unary instructions in which only one operand is given.
! 		 The source is then the same as the destination.  */
! 	      if (arg.opnum == 1 && *args == ',')
! 		switch (args[1])
! 		  {
! 		  case 'v':
! 		  case 'w':
! 		    arg.argnum = 1;
! 		    s = argsstart;
! 		    continue;
! 		  }
! 
! 	      /* Fail the match if there were too few operands.  */
! 	      if (*args)
! 		break;
! 
! 	      /* Successful match.  Stuff the immediate value in now, if
! 		 we can.  */
  	      if (insn->pinfo == INSN_MACRO)
  		{
  		  gas_assert (relax_char == 0);
*************** mips16_ip (char *str, struct mips_cl_ins
*** 12200,12445 ****
  		  else if (relax_char)
  		    *offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
  
  		  return;
  		}
- 	      break;
- 
- 	    case ',':
- 	      if (*s++ == c)
- 		continue;
- 	      s--;
- 	      switch (*++args)
- 		{
- 		case 'v':
- 		  MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
- 		  continue;
- 		case 'w':
- 		  MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
- 		  continue;
- 		}
- 	      break;
  
! 	    case '(':
! 	    case ')':
! 	      if (*s++ == c)
! 		continue;
  	      break;
  
! 	    case 'v':
! 	    case 'w':
! 	      if (s[0] != '$')
! 		{
! 		  if (c == 'v')
! 		    MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
! 		  else
! 		    MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
! 		  ++args;
! 		  continue;
! 		}
! 	      /* Fall through.  */
! 	    case 'x':
! 	    case 'y':
! 	    case 'z':
! 	    case 'Z':
! 	    case '0':
! 	    case 'S':
! 	    case 'R':
! 	    case 'X':
! 	    case 'Y':
!   	      s_reset = s;
! 	      if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, &regno))
! 		{
! 		  if (c == 'v' || c == 'w')
  		    {
! 		      if (c == 'v')
! 			MIPS16_INSERT_OPERAND (RX, *ip, lastregno);
! 		      else
! 			MIPS16_INSERT_OPERAND (RY, *ip, lastregno);
! 		      ++args;
! 		      continue;
! 		    }
  		  break;
! 		}
! 
! 	      if (*s == ' ')
  		++s;
! 	      if (args[1] != *s)
! 		{
! 		  if (c == 'v' || c == 'w')
! 		    {
! 		      regno = mips16_to_32_reg_map[lastregno];
! 		      s = s_reset;
! 		      ++args;
! 		    }
! 		}
! 
! 	      switch (c)
! 		{
! 		case 'x':
! 		case 'y':
! 		case 'z':
! 		case 'v':
! 		case 'w':
! 		case 'Z':
! 		  regno = mips32_to_16_reg_map[regno];
! 		  break;
! 
! 		case '0':
! 		  if (regno != 0)
! 		    regno = ILLEGAL_REG;
! 		  break;
! 
! 		case 'S':
! 		  if (regno != SP)
! 		    regno = ILLEGAL_REG;
! 		  break;
! 
! 		case 'R':
! 		  if (regno != RA)
! 		    regno = ILLEGAL_REG;
! 		  break;
! 
! 		case 'X':
! 		case 'Y':
! 		  if (regno == AT && mips_opts.at)
! 		    {
! 		      if (mips_opts.at == ATREG)
! 			as_warn (_("used $at without \".set noat\""));
! 		      else
! 			as_warn (_("used $%u with \".set at=$%u\""),
! 				 regno, mips_opts.at);
! 		    }
! 		  break;
! 
! 		default:
! 		  abort ();
  		}
  
! 	      if (regno == ILLEGAL_REG)
! 		break;
! 
  	      switch (c)
  		{
- 		case 'x':
  		case 'v':
- 		  MIPS16_INSERT_OPERAND (RX, *ip, regno);
- 		  break;
- 		case 'y':
  		case 'w':
! 		  MIPS16_INSERT_OPERAND (RY, *ip, regno);
! 		  break;
! 		case 'z':
! 		  MIPS16_INSERT_OPERAND (RZ, *ip, regno);
! 		  break;
! 		case 'Z':
! 		  MIPS16_INSERT_OPERAND (MOVE32Z, *ip, regno);
! 		case '0':
! 		case 'S':
! 		case 'R':
! 		  break;
! 		case 'X':
! 		  MIPS16_INSERT_OPERAND (REGR32, *ip, regno);
! 		  break;
! 		case 'Y':
! 		  regno = ((regno & 7) << 2) | ((regno & 0x18) >> 3);
! 		  MIPS16_INSERT_OPERAND (REG32R, *ip, regno);
! 		  break;
! 		default:
! 		  abort ();
! 		}
! 
! 	      lastregno = regno;
! 	      continue;
! 
! 	    case 'P':
! 	      if (strncmp (s, "$pc", 3) == 0)
! 		{
! 		  s += 3;
! 		  continue;
! 		}
! 	      break;
! 
! 	    case '5':
! 	    case 'H':
! 	    case 'W':
! 	    case 'D':
! 	    case 'j':
! 	    case 'V':
! 	    case 'C':
! 	    case 'U':
! 	    case 'k':
! 	    case 'K':
! 	      i = my_getSmallExpression (&offset_expr, offset_reloc, s);
! 	      if (i > 0)
! 		{
! 		  relax_char = c;
! 		  s = expr_end;
! 		  continue;
! 		}
! 	      *offset_reloc = BFD_RELOC_UNUSED;
! 	      /* Fall through.  */
! 	    case '<':
! 	    case '>':
! 	    case '[':
! 	    case ']':
! 	    case '4':
! 	    case '8':
! 	      my_getExpression (&offset_expr, s);
! 	      if (offset_expr.X_op == O_register)
! 		{
! 		  /* What we thought was an expression turned out to
!                      be a register.  */
! 
! 		  if (s[0] == '(' && args[1] == '(')
! 		    {
! 		      /* It looks like the expression was omitted
! 			 before a register indirection, which means
! 			 that the expression is implicitly zero.  We
! 			 still set up offset_expr, so that we handle
! 			 explicit extensions correctly.  */
! 		      offset_expr.X_op = O_constant;
! 		      offset_expr.X_add_number = 0;
! 		      relax_char = c;
! 		      continue;
! 		    }
! 
  		  break;
- 		}
- 
- 	      /* We need to relax this instruction.  */
- 	      relax_char = c;
- 	      s = expr_end;
- 	      continue;
  
  	    case 'p':
  	    case 'q':
  	    case 'A':
  	    case 'B':
  	    case 'E':
- 	      /* We use offset_reloc rather than imm_reloc for the PC
-                  relative operands.  This lets macros with both
-                  immediate and address operands work correctly.  */
- 	      my_getExpression (&offset_expr, s);
- 
- 	      if (offset_expr.X_op == O_register)
- 		break;
- 
- 	      /* We need to relax this instruction.  */
  	      relax_char = c;
! 	      s = expr_end;
! 	      continue;
! 
! 	    case '6':		/* break code */
! 	      my_getExpression (&imm_expr, s);
! 	      check_absolute_expr (ip, &imm_expr);
! 	      if ((unsigned long) imm_expr.X_add_number > 63)
! 		as_warn (_("Invalid value for `%s' (%lu)"),
! 			 ip->insn_mo->name,
! 			 (unsigned long) imm_expr.X_add_number);
! 	      MIPS16_INSERT_OPERAND (IMM6, *ip, imm_expr.X_add_number);
! 	      imm_expr.X_op = O_absent;
! 	      s = expr_end;
! 	      continue;
  
  	    case 'I':
  	      my_getExpression (&imm_expr, s);
--- 12422,12463 ----
  	      else if (relax_char)
  		*offset_reloc = (int) BFD_RELOC_UNUSED + relax_char;
  
+ 	      check_completed_insn (&arg);
  	      return;
  	    }
  
! 	  /* Fail the match if the line has too many operands.   */
! 	  if (*args == 0)
  	    break;
  
! 	  /* Handle characters that need to match exactly.  */
! 	  if (*args == '(' || *args == ')' || *args == ',')
  	    {
! 	      if (*s != *args)
  		break;
! 	      if (*s == ',')
! 		arg.argnum += 1;
  	      ++s;
! 	      continue;
  	    }
  
! 	  arg.opnum += 1;
! 	  arg.optional_reg = FALSE;
! 	  c = *args;
  	  switch (c)
  	    {
  	    case 'v':
  	    case 'w':
! 	      arg.optional_reg = (args[1] == ',');
  	      break;
  
  	    case 'p':
  	    case 'q':
  	    case 'A':
  	    case 'B':
  	    case 'E':
  	      relax_char = c;
! 	      break;
  
  	    case 'I':
  	      my_getExpression (&imm_expr, s);
*************** mips16_ip (char *str, struct mips_cl_ins
*** 12451,12718 ****
  	      s = expr_end;
  	      continue;
  
! 	    case 'a':		/* 26 bit address */
  	    case 'i':
- 	      my_getExpression (&offset_expr, s);
- 	      s = expr_end;
  	      *offset_reloc = BFD_RELOC_MIPS16_JMP;
  	      ip->insn_opcode <<= 16;
- 	      continue;
- 
- 	    case 'l':		/* register list for entry macro */
- 	    case 'L':		/* register list for exit macro */
- 	      {
- 		int mask;
- 
- 		if (c == 'l')
- 		  mask = 0;
- 		else
- 		  mask = 7 << 3;
- 		while (*s != '\0')
- 		  {
- 		    unsigned int freg, reg1, reg2;
- 
- 		    while (*s == ' ' || *s == ',')
- 		      ++s;
- 		    if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
- 		      freg = 0;
- 		    else if (reg_lookup (&s, RTYPE_FPU, &reg1))
- 		      freg = 1;
- 		    else
- 		      {
- 			as_bad (_("can't parse register list"));
- 			break;
- 		      }
- 		    if (*s == ' ')
- 		      ++s;
- 		    if (*s != '-')
- 		      reg2 = reg1;
- 		    else
- 		      {
- 			++s;
- 			if (!reg_lookup (&s, freg ? RTYPE_FPU 
- 					 : (RTYPE_GP | RTYPE_NUM), &reg2))
- 			  {
- 			    as_bad (_("invalid register list"));
- 			    break;
- 			  }
- 		      }
- 		    if (freg && reg1 == 0 && reg2 == 0 && c == 'L')
- 		      {
- 			mask &= ~ (7 << 3);
- 			mask |= 5 << 3;
- 		      }
- 		    else if (freg && reg1 == 0 && reg2 == 1 && c == 'L')
- 		      {
- 			mask &= ~ (7 << 3);
- 			mask |= 6 << 3;
- 		      }
- 		    else if (reg1 == 4 && reg2 >= 4 && reg2 <= 7 && c != 'L')
- 		      mask |= (reg2 - 3) << 3;
- 		    else if (reg1 == 16 && reg2 >= 16 && reg2 <= 17)
- 		      mask |= (reg2 - 15) << 1;
- 		    else if (reg1 == RA && reg2 == RA)
- 		      mask |= 1;
- 		    else
- 		      {
- 			as_bad (_("invalid register list"));
  			break;
  		      }
- 		  }
- 		/* The mask is filled in in the opcode table for the
-                    benefit of the disassembler.  We remove it before
-                    applying the actual mask.  */
- 		ip->insn_opcode &= ~ ((7 << 3) << MIPS16OP_SH_IMM6);
- 		ip->insn_opcode |= mask << MIPS16OP_SH_IMM6;
- 	      }
- 	    continue;
  
! 	    case 'm':		/* Register list for save insn.  */
! 	    case 'M':		/* Register list for restore insn.  */
! 	      {
! 		int opcode = ip->insn_opcode;
! 		int framesz = 0, seen_framesz = 0;
! 		int nargs = 0, statics = 0, sregs = 0;
  
! 		while (*s != '\0')
  		  {
! 		    unsigned int reg1, reg2;
! 
! 		    SKIP_SPACE_TABS (s);
! 		    while (*s == ',')
! 		      ++s;
! 		    SKIP_SPACE_TABS (s);
  
! 		    my_getExpression (&imm_expr, s);
! 		    if (imm_expr.X_op == O_constant)
  		      {
! 			/* Handle the frame size.  */
! 			if (seen_framesz)
  			  {
! 			    as_bad (_("more than one frame size in list"));
! 			    break;
! 			  }
! 			seen_framesz = 1;
! 			framesz = imm_expr.X_add_number;
! 			imm_expr.X_op = O_absent;
! 			s = expr_end;
  			continue;
  		      }
! 
! 		    if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg1))
! 		      {
! 			as_bad (_("can't parse register list"));
  			break;
  		      }
! 
! 		    while (*s == ' ')
! 		      ++s;
! 
! 		    if (*s != '-')
! 		      reg2 = reg1;
! 		    else
! 		      {
! 			++s;
! 			if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, &reg2)
! 			    || reg2 < reg1)
! 			  {
! 			    as_bad (_("can't parse register list"));
  			    break;
  			  }
  		      }
  
! 		    while (reg1 <= reg2)
! 		      {
! 			if (reg1 >= 4 && reg1 <= 7)
! 			  {
! 			    if (!seen_framesz)
! 				/* args $a0-$a3 */
! 				nargs |= 1 << (reg1 - 4);
! 			    else
! 				/* statics $a0-$a3 */
! 				statics |= 1 << (reg1 - 4);
! 			  }
! 			else if ((reg1 >= 16 && reg1 <= 23) || reg1 == 30)
! 			  {
! 			    /* $s0-$s8 */
! 			    sregs |= 1 << ((reg1 == 30) ? 8 : (reg1 - 16));
! 			  }
! 			else if (reg1 == 31)
  			  {
! 			    /* Add $ra to insn.  */
! 			    opcode |= 0x40;
  			  }
! 			else
! 			  {
! 			    as_bad (_("unexpected register in list"));
  			    break;
- 			  }
- 			if (++reg1 == 24)
- 			  reg1 = 30;
- 		      }
- 		  }
- 
- 		/* Encode args/statics combination.  */
- 		if (nargs & statics)
- 		  as_bad (_("arg/static registers overlap"));
- 		else if (nargs == 0xf)
- 		  /* All $a0-$a3 are args.  */
- 		  opcode |= MIPS16_ALL_ARGS << 16;
- 		else if (statics == 0xf)
- 		  /* All $a0-$a3 are statics.  */
- 		  opcode |= MIPS16_ALL_STATICS << 16;
- 		else 
- 		  {
- 		    int narg = 0, nstat = 0;
- 
- 		    /* Count arg registers.  */
- 		    while (nargs & 0x1)
- 		      {
- 			nargs >>= 1;
- 			narg++;
- 		      }
- 		    if (nargs != 0)
- 		      as_bad (_("invalid arg register list"));
- 
- 		    /* Count static registers.  */
- 		    while (statics & 0x8)
- 		      {
- 			statics = (statics << 1) & 0xf;
- 			nstat++;
- 		      }
- 		    if (statics != 0) 
- 		      as_bad (_("invalid static register list"));
- 
- 		    /* Encode args/statics.  */
- 		    opcode |= ((narg << 2) | nstat) << 16;
- 		  }
- 
- 		/* Encode $s0/$s1.  */
- 		if (sregs & (1 << 0))		/* $s0 */
- 		  opcode |= 0x20;
- 		if (sregs & (1 << 1))		/* $s1 */
- 		  opcode |= 0x10;
- 		sregs >>= 2;
- 
- 		if (sregs != 0)
- 		  {
- 		    /* Count regs $s2-$s8.  */
- 		    int nsreg = 0;
- 		    while (sregs & 1)
- 		      {
- 			sregs >>= 1;
- 			nsreg++;
- 		      }
- 		    if (sregs != 0)
- 		      as_bad (_("invalid static register list"));
- 		    /* Encode $s2-$s8. */
- 		    opcode |= nsreg << 24;
- 		  }
- 
- 		/* Encode frame size.  */
- 		if (!seen_framesz)
- 		  as_bad (_("missing frame size"));
- 		else if ((framesz & 7) != 0 || framesz < 0
- 			 || framesz > 0xff * 8)
- 		  as_bad (_("invalid frame size"));
- 		else if (framesz != 128 || (opcode >> 16) != 0)
- 		  {
- 		    framesz /= 8;
- 		    opcode |= (((framesz & 0xf0) << 16)
- 			     | (framesz & 0x0f));
- 		  }
- 
- 		/* Finally build the instruction.  */
- 		if ((opcode >> 16) != 0 || framesz == 0)
- 		  opcode |= MIPS16_EXTEND;
- 		ip->insn_opcode = opcode;
- 	      }
  	    continue;
- 
- 	    case 'e':		/* extend code */
- 	      my_getExpression (&imm_expr, s);
- 	      check_absolute_expr (ip, &imm_expr);
- 	      if ((unsigned long) imm_expr.X_add_number > 0x7ff)
- 		{
- 		  as_warn (_("Invalid value for `%s' (%lu)"),
- 			   ip->insn_mo->name,
- 			   (unsigned long) imm_expr.X_add_number);
- 		  imm_expr.X_add_number &= 0x7ff;
- 		}
- 	      ip->insn_opcode |= imm_expr.X_add_number;
- 	      imm_expr.X_op = O_absent;
- 	      s = expr_end;
- 	      continue;
- 
- 	    default:
- 	      abort ();
- 	    }
- 	  break;
  	}
  
        /* Args don't match.  */
!       if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes] &&
! 	  strcmp (insn->name, insn[1].name) == 0)
  	{
  	  ++insn;
  	  s = argsstart;
--- 12469,12541 ----
  	      s = expr_end;
  	      continue;
  
! 	    case 'a':
  	    case 'i':
  	      *offset_reloc = BFD_RELOC_MIPS16_JMP;
  	      ip->insn_opcode <<= 16;
  	      break;
  	    }
  
! 	  operand = decode_mips16_operand (c, FALSE);
! 	  if (!operand)
! 	    abort ();
  
! 	  /* '6' is a special case.  It is used for BREAK and SDBBP,
! 	     whose operands are only meaningful to the software that decodes
! 	     them.  This means that there is no architectural reason why
! 	     they cannot be prefixed by EXTEND, but in practice,
! 	     exception handlers will only look at the instruction
! 	     itself.  We therefore allow '6' to be extended when
! 	     disassembling but not when assembling.  */
! 	  if (operand->type != OP_PCREL && c != '6')
  	    {
! 	      ext_operand = decode_mips16_operand (c, TRUE);
! 	      if (operand != ext_operand)
! 		{
! 		  /* Parse the expression, allowing relocation operators.  */
! 		  i = my_getSmallExpression (&offset_expr, offset_reloc, s);
! 		  s = expr_end;
  
! 		  if (offset_expr.X_op == O_register)
  		    {
! 		      /* Handle elided offsets, which are equivalent to 0.  */
! 		      if (*s == '(')
  			{
! 			  offset_expr.X_op = O_constant;
! 			  offset_expr.X_add_number = 0;
! 			  relax_char = c;
  			  continue;
  			}
! 		      /* Fail the match.  */
  		      break;
  		    }
! 		  /* '8' is used for SLTI(U) and has traditionally not
! 		     been allowed to take relocation operators.  */
! 		  if (i > 0 && (ext_operand->size != 16 || c == '8'))
  		    break;
+ 		  relax_char = c;
+ 		  continue;
  		}
  	    }
  
! 	  s = match_operand (&arg, operand, s);
! 	  if (!s && arg.optional_reg)
  	    {
! 	      /* Assume that the register has been elided and is the
! 		 same as the first operand.  */
! 	      arg.optional_reg = FALSE;
! 	      arg.argnum = 1;
! 	      s = argsstart;
! 	      SKIP_SPACE_TABS (s);
! 	      s = match_operand (&arg, operand, s);
  	    }
! 	  if (!s)
  	    break;
  	  continue;
  	}
  
        /* Args don't match.  */
!       if (more_alts)
  	{
  	  ++insn;
  	  s = argsstart;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]