This is the mail archive of the binutils@sources.redhat.com 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]

Thumb32 assembler (55/69)


Rewrite parse_operands' handling of optional arguments so that the
optional argument doesn't have to be last on the line.  This in turn
allows simplification to several of the Thumb encoder functions, and
the elimination of two parse codes.

zw

	* config/tc-arm.c (OP_oRL_EXi, OP_oRR_EXi): Delete.
	(OP_oRR): New operand parse code.
	(parse_operands): Update to match.  Reimplement optional
	arguments with backtracking, so that the optional argument
	need not be last.  Remove #undefs of macros which are no
	longer defined.
	(do_t_add_sub, do_t_arit3, do_t_shift): Restructure for arg 1
	being the optional argument, and only ever being a register.
	(tinsns): Make the optional argument be the second argument
	for adc, and, asr, bic, eor, lsl, lsr, mul, orr, ror, sbc, sub.
	No need to use oRL_EXi or oRR_EXi anymore.

===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c	(revision 57)
+++ gas/config/tc-arm.c	(revision 58)
@@ -3806,8 +3806,7 @@
   OP_oI255c,	 /*	  curly-brace enclosed, 0 .. 255 */
 
   OP_oRL,	 /* Thumb low register */
-  OP_oRL_EXi,	 /* Thumb low register or expression */
-  OP_oRR_EXi,	 /* ARM register or expression */
+  OP_oRR,	 /* ARM register */
 
   OP_oSHll,	 /* LSL immediate */
   OP_oSHar,	 /* ASR immediate */
@@ -3824,9 +3823,10 @@
 static int
 parse_operands (char *str, const char *pattern)
 {
-  int i;
-  int val;
-  unsigned const char *p = pattern;
+  unsigned const char *upat = pattern;
+  char *backtrack_pos = 0;
+  const char *backtrack_error = 0;
+  int i, val, backtrack_index = 0;
 
 #define po_char_or_fail(chr) do {		\
   if (skip_past_char (&str, chr) == FAIL)	\
@@ -3838,7 +3838,7 @@
   if (val == FAIL)					\
     {							\
       inst.error = _(reg_expected_msgs[regtype]);	\
-      return FAIL;					\
+      goto failure;					\
     }							\
   inst.operands[i].reg = val;				\
   inst.operands[i].isreg = 1;				\
@@ -3855,25 +3855,38 @@
 
 #define po_imm_or_fail(min, max, popt) do {				\
   if (immediate_required_here (&str, &val, min, max, popt) == FAIL)	\
-    return FAIL;							\
+    goto failure;							\
   inst.operands[i].imm = val;						\
 } while (0)
 
+#define po_misc_or_fail(expr) do {		\
+  if (expr)					\
+    goto failure;				\
+} while (0)
+
   skip_whitespace (str);
 
-  /* Check for a no-operand instruction, or an instruction with only
-     optional operands given none, and bypass the loop if so.  */
-  if (*p == OP_stop || (*p >= OP_FIRST_OPTIONAL && *str == 0))
-    goto done;
-
-  for (i = 0; ; i++)
+  for (i = 0; upat[i] != OP_stop; i++)
     {
-      switch (*p)
+      if (upat[i] >= OP_FIRST_OPTIONAL)
 	{
+	  /* Remember where we are in case we need to backtrack.  */
+	  assert (!backtrack_pos);
+	  backtrack_pos = str;
+	  backtrack_error = inst.error;
+	  backtrack_index = i;
+	}
+
+      if (i > 0)
+	po_char_or_fail (',');
+
+      switch (upat[i])
+	{
 	  /* Registers */
 	case OP_RRnpc:
 	case OP_oRL:
 	case OP_RL:
+	case OP_oRR:
 	case OP_RR:    po_reg_or_fail (REG_TYPE_RN);	  break;
 	case OP_RCP:   po_reg_or_fail (REG_TYPE_CP);	  break;
 	case OP_RCN:   po_reg_or_fail (REG_TYPE_CN);	  break;
@@ -3951,25 +3964,25 @@
 
 	  /* Expressions */
 	case OP_EXPi:	EXPi:
-	  if (my_get_expression (&inst.reloc.exp, &str, GE_OPT_PREFIX))
-	    return FAIL;
+	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+					      GE_OPT_PREFIX));
 	  break;
 
 	case OP_EXP:	EXP:
-	  if (my_get_expression (&inst.reloc.exp, &str, GE_NO_PREFIX))
-	    return FAIL;
+	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+					      GE_NO_PREFIX));
 	  break;
 
 	case OP_EXPr:	EXPr:
-	  if (my_get_expression (&inst.reloc.exp, &str, GE_NO_PREFIX))
-	    return FAIL;
+	  po_misc_or_fail (my_get_expression (&inst.reloc.exp, &str,
+					      GE_NO_PREFIX));
 	  if (inst.reloc.exp.X_op == O_symbol)
 	    {
 	      val = parse_reloc (&str);
 	      if (val == -1)
 		{
 		  inst.error = _("unrecognized relocation suffix");
-		  return FAIL;
+		  goto failure;
 		}
 	      else if (val != BFD_RELOC_UNUSED)
 		{
@@ -3982,8 +3995,6 @@
 	  /* Register or expression */
 	case OP_RR_EX:	  po_reg_or_goto (REG_TYPE_RN, EXP);  break;
 	case OP_RR_EXr:	  po_reg_or_goto (REG_TYPE_RN, EXPr); break;
-	case OP_oRL_EXi:
-	case OP_oRR_EXi:
 	case OP_RL_EXi:
 	case OP_RR_EXi:	  po_reg_or_goto (REG_TYPE_RN, EXPi); break;
 
@@ -3991,21 +4002,18 @@
 	case OP_RRnpc_I0: po_reg_or_goto (REG_TYPE_RN, I0);   break;
 	I0:		  po_imm_or_fail (0, 0, FALSE);	      break;
 
-
-	case OP_RF_IF:
+	case OP_RF_IF:    po_reg_or_goto (REG_TYPE_FN, IF);   break;
+	IF:
 	  if (!is_immediate_prefix (*str))
-	    po_reg_or_fail (REG_TYPE_FN);
-	  else
-	    {
-	      str++;
-	      val = fpa_immediate (&str);
-	      if (val == FAIL)
-		return FAIL;
-	      /* FPA immediates are encoded as registers 8-15.
-		 fpa_immediate has already applied the offset.	*/
-	      inst.operands[i].reg = val;
-	      inst.operands[i].isreg = 1;
-	    }
+	    goto bad_args;
+	  str++;
+	  val = fpa_immediate (&str);
+	  if (val == FAIL)
+	    goto failure;
+	  /* FPA immediates are encoded as registers 8-15.
+	     fpa_immediate has already applied the offset.  */
+	  inst.operands[i].reg = val;
+	  inst.operands[i].isreg = 1;
 	  break;
 
 	  /* Two kinds of register */
@@ -4015,7 +4023,7 @@
 	    if (rege->type != REG_TYPE_MMXWR && rege->type != REG_TYPE_MMXWC)
 	      {
 		inst.error = _("iWMMXt data or control register expected");
-		return FAIL;
+		goto failure;
 	      }
 	    inst.operands[i].reg = rege->number;
 	    inst.operands[i].isreg = (rege->type == REG_TYPE_MMXWR);
@@ -4048,38 +4056,33 @@
 
 	  /* Addressing modes */
 	case OP_ADDR:
-	  if (parse_address (&str, i))
-	    return FAIL;
+	  po_misc_or_fail (parse_address (&str, i));
 	  break;
 
 	case OP_SH:
-	  if (parse_shifter_operand (&str, i))
-	    return FAIL;
+	  po_misc_or_fail (parse_shifter_operand (&str, i));
 	  break;
 
 	case OP_oSHll:
-	  if (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE))
-	    return FAIL;
+	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_IMMEDIATE));
 	  break;
 
 	case OP_oSHar:
-	  if (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE))
-	    return FAIL;
+	  po_misc_or_fail (parse_shift (&str, i, SHIFT_ASR_IMMEDIATE));
 	  break;
 
 	case OP_oSHllar:
-	  if (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE))
-	    return FAIL;
+	  po_misc_or_fail (parse_shift (&str, i, SHIFT_LSL_OR_ASR_IMMEDIATE));
 	  break;
 
 	default:
-	  as_fatal ("unhandled operand code %03o", *p);
+	  as_fatal ("unhandled operand code %d", upat[i]);
 	}
 
       /* Various value-based sanity checks and shared operations.  We
 	 do not signal immediate failures for the register constraints;
 	 this allows a syntax error to take precedence.	 */
-      switch (*p)
+      switch (upat[i])
 	{
 	case OP_RRnpc:
 	case OP_RRnpcb:
@@ -4092,7 +4095,6 @@
 	case OP_oRL:
 	case OP_RL:
 	case OP_RLw:
-	case OP_oRL_EXi:
 	case OP_RL_EXi:
 	  if (inst.operands[i].isreg && inst.operands[i].reg > 7)
 	    inst.error = BAD_HIREG;
@@ -4106,7 +4108,7 @@
 	case OP_VRSLST:
 	case OP_VRDLST:
 	  if (val == FAIL)
-	    return FAIL;
+	    goto failure;
 	  inst.operands[i].imm = val;
 	  break;
 
@@ -4116,40 +4118,35 @@
 
       /* If we get here, this operand was successfully parsed.	*/
       inst.operands[i].present = 1;
+      continue;
 
-      if (*++p == OP_stop)
-	break;
+    bad_args:
+      inst.error = BAD_ARGS;
 
-      /* If this is an optional argument, and we have no further
-	 operands, stop.  */
-      if (*p >= OP_FIRST_OPTIONAL && *str == '\0')
-	break;
+    failure:
+      if (!backtrack_pos)
+	return FAIL;
 
-      if (skip_past_comma (&str) == FAIL)
-	goto bad_args;
+      /* Try again, skipping the optional argument at backtrack_pos.  */
+      str = backtrack_pos;
+      inst.error = backtrack_error;
+      inst.operands[backtrack_index].present = 0;
+      i = backtrack_index;
+      backtrack_pos = 0;
     }
 
- done:
   /* Check that we have parsed all the arguments.  */
   if (*str != '\0' && !inst.error)
     inst.error = _("garbage following instruction");
 
   return inst.error ? FAIL : SUCCESS;
+}
 
- bad_args:
-  inst.error = BAD_ARGS;
-  return FAIL;
-
 #undef po_char_or_fail
 #undef po_reg_or_fail
 #undef po_reg_or_goto
 #undef po_imm_or_fail
-}
 
-#undef OP_
-#undef OP__
-#undef OP___
-
 /* Operand validation functions.  */
 
 /* Set inst.error to BAD_OVERLAP and return FAIL if any of the
@@ -5062,38 +5059,20 @@
   int subtract = !!(inst.instruction & 0x8000);
 
   Rd = inst.operands[0].reg;
-  if (inst.operands[2].present)
-    {
-      /* If there were three operands, operand 1 must be a register.  */
-      if (!inst.operands[1].isreg)
-	{
-	  inst.error = BAD_ARGS;
-	  return;
-	}
+  Rs = (inst.operands[1].present
+	? inst.operands[1].reg    /* Rd, Rs, foo */
+	: inst.operands[0].reg);  /* Rd, foo -> Rd, Rd, foo */
 
-      Rs = inst.operands[1].reg;
-      if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
-	{
-	  inst.instruction |= (Rd << 4) | Rs;
-	  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
-	  return;
-	}
-      else /* Rd, Rs, Rn */
-	Rn = inst.operands[2].reg;
-    }
-  else if (!inst.operands[1].isreg)  /* Rd, #imm -> Rd, Rd, #imm */
+  if (!inst.operands[2].isreg) /* Rd, Rs, #imm */
     {
-      inst.instruction |= (Rd << 4) | Rd;
+      inst.instruction |= (Rd << 4) | Rs;
       inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
       return;
     }
-  else	/* Rd, Rs -> Rd, Rd, Rs */
-    {
-      Rs = inst.operands[0].reg;
-      Rn = inst.operands[1].reg;
-    }
 
-  /* We now have Rd and Rs, and Rn set to registers.  */
+  Rn = inst.operands[2].reg;
+
+  /* We now have Rd, Rs, and Rn set to registers.  */
   if (Rd > 7 || Rs > 7 || Rn > 7)
     {
       if (Rs != Rd)
@@ -5151,16 +5130,14 @@
 static void
 do_t_arit3 (void)
 {
-  if (inst.operands[2].present)
+  if (inst.operands[1].present
+      && inst.operands[0].reg != inst.operands[1].reg)
     {
-      if (inst.operands[0].reg != inst.operands[1].reg)
-	{
-	  inst.error = _("dest and source1 must be the same register");
-	  return;
-	}
-      inst.operands[1].reg = inst.operands[2].reg;
+      inst.error = _("dest and source1 must be the same register");
+      return;
     }
-  do_t_arit ();
+  inst.instruction |= inst.operands[0].reg;
+  inst.instruction |= inst.operands[2].reg << 3;
 }
 
 /* ARM V5 Thumb BLX (argument parse)
@@ -5424,38 +5401,21 @@
 static void
 do_t_shift (void)
 {
-  int Rs;
+  unsigned int Rs = (inst.operands[1].present
+		     ? inst.operands[1].reg
+		     : inst.operands[0].reg);
 
-  if (inst.operands[2].present)
+  if (inst.operands[2].isreg)  /* Rd, {Rs,} Rn */
     {
-      /* If there were three operands, operand 1 must be a register.  */
-      if (!inst.operands[1].isreg)
+      if (inst.operands[0].reg != Rs)
 	{
-	  inst.error = BAD_ARGS;
+	  inst.error = _("source1 and dest must be same register");
 	  return;
 	}
-      else if (inst.operands[2].isreg)	/* Rd, Rs, Rn */
-	{
-	  if (inst.operands[0].reg != inst.operands[1].reg)
-	    {
-	      inst.error = _("source1 and dest must be same register");
-	      return;
-	    }
-	  inst.instruction |= inst.operands[0].reg;
-	  inst.instruction |= inst.operands[2].reg << 3;
-	  return;
-	}
-      else /* Rd, Rs, imm */
-	Rs = inst.operands[1].reg;
-    }
-  else if (inst.operands[1].isreg)  /* Rd, Rs -> Rd, Rd, Rs */
-    {
       inst.instruction |= inst.operands[0].reg;
       inst.instruction |= inst.operands[2].reg << 3;
       return;
     }
-  else /* Rd, imm -> Rd, Rd, imm */
-    Rs = inst.operands[0].reg;
 
   /* If we get here, we are doing a shift by an immediate. inst.operands[0].reg
      and Rs are the registers, and inst.reloc is the immediate.	 */
@@ -7621,10 +7581,10 @@
 static const struct asm_opcode tinsns[] =
 {
 #define THUMB_VARIANT ARM_EXT_V4T  /* Thumb v1 (ARMv4T).  */
-  TI(adc,    4140,     3, (RL, RL, oRL),	 t_arit3),
-  TI(add,    0000,     3, (RR, RR_EXi, oRR_EXi), t_add_sub),
-  TI(and,    4000,     3, (RL, RL, oRL),	 t_arit3),
-  TI(asr,    4100,     3, (RL, RL_EXi, oRL_EXi), t_shift),
+  TI(adc,    4140,     3, (RL, oRL, RL),	 t_arit3),
+  TI(add,    0000,     3, (RR, oRR, RR_EXi),	 t_add_sub),
+  TI(and,    4000,     3, (RL, oRL, RL),	 t_arit3),
+  TI(asr,    4100,     3, (RL, oRL, RL_EXi), 	 t_shift),
   TI(b,	     e7fe,     1, (EXP),		 t_branch12),
   TI(beq,    d0fe,     1, (EXP),		 t_branch9),
   TI(bne,    d1fe,     1, (EXP),		 t_branch9),
@@ -7644,12 +7604,12 @@
   TI(bgt,    dcfe,     1, (EXP),		 t_branch9),
   TI(ble,    ddfe,     1, (EXP),		 t_branch9),
   TI(bal,    defe,     1, (EXP),		 t_branch9),
-  TI(bic,    4380,     3, (RL, RL, oRL),	 t_arit3),
+  TI(bic,    4380,     3, (RL, oRL, RL),	 t_arit3),
   TI(bl,     f7fffffe, 1, (EXP),		 t_branch23),
   TI(bx,     4700,     1, (RR),			 t_bx),
   TI(cmn,    42c0,     2, (RL, RL),		 t_arit),
   TI(cmp,    4280,     2, (RR, RR_EXi),		 t_mov_cmp),
-  TI(eor,    4040,     3, (RL, RL, oRL),	 t_arit3),
+  TI(eor,    4040,     3, (RL, oRL, RL),	 t_arit3),
   TI(ldmia,  c800,     2, (RLw, REGLST),	 t_ldmstm),
   TI(ldr,    5800,     2, (RL, ADDR),		 t_ldst),
   TI(ldrb,   5c00,     2, (RL, ADDR),		 t_ldst),
@@ -7658,23 +7618,23 @@
   TI(ldrsh,  5e00,     2, (RL, ADDR),		 t_lds),
   TI(ldsb,   5600,     2, (RL, ADDR),		 t_lds),
   TI(ldsh,   5e00,     2, (RL, ADDR),		 t_lds),
-  TI(lsl,    4080,     3, (RL, RL_EXi, oRL_EXi), t_shift),
-  TI(lsr,    40c0,     3, (RL, RL_EXi, oRL_EXi), t_shift),
+  TI(lsl,    4080,     3, (RL, oRL, RL_EXi),	 t_shift),
+  TI(lsr,    40c0,     3, (RL, oRL, RL_EXi),	 t_shift),
   TI(mov,    4600,     2, (RR, RR_EXi),		 t_mov_cmp),
-  TI(mul,    4340,     3, (RL, RL, oRL),	 t_arit3),
+  TI(mul,    4340,     3, (RL, oRL, RL),	 t_arit3),
   TI(mvn,    43c0,     2, (RL, RL),	 	 t_arit),
   TI(neg,    4240,     2, (RL, RL),		 t_arit),
-  TI(orr,    4300,     3, (RL, RL, oRL),	 t_arit3),
+  TI(orr,    4300,     3, (RL, oRL, RL),	 t_arit3),
   TI(pop,    bc00,     1, (REGLST),		 t_push_pop),
   TI(push,   b400,     1, (REGLST),		 t_push_pop),
-  TI(ror,    41c0,     3, (RL, RL, oRL),	 t_arit3),
-  TI(sbc,    4180,     3, (RL, RL, oRL),	 t_arit3),
+  TI(ror,    41c0,     3, (RL, oRL, RL),	 t_arit3),
+  TI(sbc,    4180,     3, (RL, oRL, RL),	 t_arit3),
   TI(stmia,  c000,     2, (RLw, REGLST),	 t_ldmstm),
   TI(str,    5000,     2, (RL, ADDR),		 t_ldst),
   TI(strb,   5400,     2, (RL, ADDR),		 t_ldst),
   TI(strh,   5200,     2, (RL, ADDR),		 t_ldst),
   TI(swi,    df00,     1, (EXP),		 t_swi),
-  TI(sub,    8000,     3, (RR, RR_EXi, oRR_EXi), t_add_sub),
+  TI(sub,    8000,     3, (RR, oRR, RR_EXi),	 t_add_sub),
   TI(tst,    4200,     2, (RL, RL),		 t_arit),
   /* Pseudo ops:  */
   TI(adr,    000f,     2, (RL, EXP),		 t_adr),


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