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 (3/69)


This is the first in a long, long series of preparatory patches which
decouple the parsing of assembly language from the generation of
machine code.  This is desirable because the Thumb32 syntax is almost
the same as the ARM syntax, so it's best to share the parser.

Here, I create a single function for parsing immediate operands, which
encapsulates the somewhat complicated calling sequence for
my_get_expression, and does range checks too.

zw

	* tc-arm.c (my_get_expression): Clear ep first.
	(immediate_required_here): New function.
	(require_hashconst): Rename immediate_for_directive.
	(s_arm_unwind_pad, s_arm_unwind_setfp): Update to match.
	(five_bit_unsigned_immediate): Delete.
	(cp_opc_expr, cp_address_required_here, do_cps_mode, mav_parse_offset)
	(bfci_lsb_and_width, do_bfi, do_bfx, do_bkpt, do_mov16, do_nop)
	(do_sat, do_sat16, do_sxtah, do_sxth, do_t_bkpt, do_fpa_ldmstm)
	(check_iwmmxt_insn): Use immediate_required_here.

===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c	(revision 3)
+++ gas/config/tc-arm.c	(revision 4)
@@ -1068,6 +1068,8 @@
   char * save_in;
   segT   seg;
 
+  memset (ep, 0, sizeof (expressionS));
+
   save_in = input_line_pointer;
   input_line_pointer = *str;
   in_my_get_expression = 1;
@@ -1288,59 +1290,69 @@
 
 /* Immediate values.  */
 
+/* Generic immediate-value read function for use in insn parsing.
+   STR points to the beginning of the immediate (the leading #);
+   VAL receives the value; if the value is outside [MIN, MAX]
+   issue an error.  PREFIX_OPT is true if the immediate prefix is
+   optional.  */
+
 static int
-require_hashconst (int * val)
+immediate_required_here (char **str, int *val, int min, int max,
+			 bfd_boolean prefix_opt)
 {
   expressionS exp;
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer == '#')
+  skip_whitespace (*str);
+
+  if (is_immediate_prefix (**str))
+    (*str)++;
+  else if (!prefix_opt)
     {
-      input_line_pointer++;
-      expression (&exp);
+      inst.error = _("immediate expression requires a # prefix");
+      return FAIL;
     }
-  else
-    exp.X_op = O_illegal;
 
+  my_get_expression (&exp, str);
   if (exp.X_op != O_constant)
     {
-      as_bad (_("expected #constant"));
-      ignore_rest_of_line ();
+      inst.error = _("constant expression required");
       return FAIL;
     }
+
+  if (exp.X_add_number < min || exp.X_add_number > max)
+    {
+      inst.error = _("immediate value out of range");
+      return FAIL;
+    }
+  
   *val = exp.X_add_number;
   return SUCCESS;
 }
 
+/* As above, but for use in directives, and does not provide
+   range checking.  */
+
 static int
-five_bit_unsigned_immediate (char **str)
+immediate_for_directive (int *val)
 {
-  expressionS expr;
+  expressionS exp;
+  exp.X_op = O_illegal;
 
-  skip_whitespace (*str);
-  if (!is_immediate_prefix (**str))
+  SKIP_WHITESPACE ();
+  if (is_immediate_prefix (*input_line_pointer))
     {
-      inst.error = _("immediate expression expected");
-      return -1;
+      input_line_pointer++;
+      expression (&exp);
     }
-  (*str)++;
-  if (my_get_expression (&expr, str))
+
+  if (exp.X_op != O_constant)
     {
-      inst.error = _("bad expression");
-      return -1;
+      as_bad (_("expected #constant"));
+      ignore_rest_of_line ();
+      return FAIL;
     }
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return -1;
-    }
-  if (expr.X_add_number < 0 || expr.X_add_number > 32)
-    {
-      inst.error = _("immediate value out of range");
-      return -1;
-    }
-  
-  return expr.X_add_number;
+  *val = exp.X_add_number;
+  return SUCCESS;
 }
 
 /* Check that an immediate is valid.
@@ -2857,27 +2869,12 @@
 static int
 cp_opc_expr (char ** str, int where, int length)
 {
-  expressionS expr;
+  unsigned int val;
 
-  skip_whitespace (* str);
-
-  memset (&expr, '\0', sizeof (expr));
-
-  if (my_get_expression (&expr, str))
+  if (immediate_required_here (str, &val, 0, (1 << length) - 1, TRUE) == FAIL)
     return FAIL;
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("bad or missing expression");
-      return FAIL;
-    }
 
-  if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
-    {
-      inst.error = _("immediate co-processor expression too large");
-      return FAIL;
-    }
-
-  inst.instruction |= expr.X_add_number << where;
+  inst.instruction |= val << where;
   return SUCCESS;
 }
 
@@ -2997,40 +2994,21 @@
 
 	      /* [Rn], {<expr>}  */
 	      p++;
+	      if (immediate_required_here (&p, &option, 0, 255, TRUE) == FAIL)
+		return FAIL;
 
 	      skip_whitespace (p);
 
-	      if (my_get_expression (& inst.reloc.exp, & p))
-		return FAIL;
-
-	      if (inst.reloc.exp.X_op == O_constant)
+	      if (*p != '}')
 		{
-		  option = inst.reloc.exp.X_add_number;
-
-		  if (option > 255 || option < 0)
-		    {
-		      inst.error = _("'option' field too large");
-		      return FAIL;
-		    }
-
-		  skip_whitespace (p);
-
-		  if (*p != '}')
-		    {
-		      inst.error = _("'}' expected at end of 'option' field");
-		      return FAIL;
-		    }
-		  else
-		    {
-		      p++;
-		      inst.instruction |= option;
-		      inst.instruction |= INDEX_UP;
-		    }
+		  inst.error = _("'}' expected at end of 'option' field");
+		  return FAIL;
 		}
 	      else
 		{
-		  inst.error = _("non-constant expressions for 'option' field not supported");
-		  return FAIL;
+		  p++;
+		  inst.instruction |= option;
+		  inst.instruction |= INDEX_UP;
 		}
 	    }
 	  else
@@ -3233,38 +3211,13 @@
 static void
 do_cps_mode (char ** str)
 {
-  expressionS expr;
+  int val;
 
-  skip_whitespace (*str);
-
-  if (! is_immediate_prefix (**str))
-    {
-      inst.error = _("immediate expression expected");
-      return;
-    }
-
-  (*str)++; /* Strip off the immediate signifier.  */
-  if (my_get_expression (&expr, str))
-    {
-      inst.error = _("bad expression");
-      return;
-    }
-
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-
   /* The mode is a 5 bit field.  Valid values are 0-31.  */
-  if (((unsigned) expr.X_add_number) > 31
-      || (inst.reloc.exp.X_add_number) < 0)
-    {
-      inst.error = _("invalid constant");
-      return;
-    }
+  if (immediate_required_here (str, &val, 0, 31, TRUE) == FAIL)
+    return;
 
-  inst.instruction |= expr.X_add_number;
+  inst.instruction |= val;
 }
 
 static void
@@ -3315,45 +3268,23 @@
 static int
 mav_parse_offset (char ** str, int * negative)
 {
-  char * p = *str;
   int offset;
 
   *negative = 0;
 
-  skip_whitespace (p);
+  if (immediate_required_here (str, &offset, -0x3fc, 0x3fc, TRUE) == FAIL)
+    return 0;
 
-  if (*p == '#')
-    ++p;
+  if (offset < 0)
+    *negative = 1;
 
-  if (*p == '-')
-    {
-      *negative = 1;
-      ++p;
-    }
-
-  if (!ISDIGIT (*p))
-    {
-      inst.error = _("offset expected");
-      return 0;
-    }
-
-  for (offset = 0; *p && ISDIGIT (*p); ++p)
-    offset = offset * 10 + *p - '0';
-
-  if (offset > 0x3fc)
-    {
-      inst.error = _("offset out of range");
-      return 0;
-    }
   if (offset & 0x3)
     {
       inst.error = _("offset not a multiple of 4");
       return 0;
     }
 
-  *str = p;
-
-  return *negative ? -offset : offset;
+  return offset;
 }
 
 /* Returns true if the endian-specifier indicates big-endianness.  */
@@ -4895,7 +4826,7 @@
 {
   int offset;
 
-  if (require_hashconst (&offset) == FAIL)
+  if (immediate_for_directive (&offset) == FAIL)
     return;
 
   if (offset & 3)
@@ -4934,10 +4865,10 @@
       return;
     }
 
-  /* Optonal constant.  */
+  /* Optional constant.  */
   if (skip_past_comma (&input_line_pointer) != FAIL)
     {
-      if (require_hashconst (&offset) == FAIL)
+      if (immediate_for_directive (&offset) == FAIL)
 	return;
     }
   else
@@ -5164,7 +5095,7 @@
 {
   int lsb, width;
 
-  if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
+  if (immediate_required_here (&str, &lsb, 0, 31, FALSE) == FAIL)
     return;
 
   if (skip_past_comma (&str) == FAIL)
@@ -5172,18 +5103,13 @@
       inst.error = BAD_ARGS;
       return;
     }
-  if ((width = five_bit_unsigned_immediate (&str)) == -1)
+  if (immediate_required_here (&str, &width, 1, 32, FALSE) == FAIL)
     return;
 
   end_of_line (str);
 
-  if (width == 0 || lsb == 32)
+  if (width + lsb > 32)
     {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-  else if (width + lsb > 32)
-    {
       inst.error = _("bit-field extends past end of register");
       return;
     }
@@ -5238,23 +5164,9 @@
   skip_whitespace (str);
   if (is_immediate_prefix (*str))
     {
-      expressionS expr;
-      str++;
-      if (my_get_expression (&expr, &str))
-	{
-	  inst.error = _("bad expression");
-	  return;
-	}
-      if (expr.X_op != O_constant)
-	{
-	  inst.error = _("constant expression expected");
-	  return;
-	}
-      if (expr.X_add_number != 0)
-	{
-	  inst.error = _("immediate value out of range");
-	  return;
-	}
+      int val;
+      if (immediate_required_here (&str, &val, 0, 0, FALSE) == FAIL)
+	return;
       inst.instruction |= 0x0000000f;  /* Rm = PC -> bfc, not bfi.  */
     }
   else
@@ -5302,7 +5214,7 @@
       return;
     }
 
-  if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
+  if (immediate_required_here (&str, &lsb, 0, 31, FALSE) == FAIL)
     return;
 
   if (skip_past_comma (&str) == FAIL)
@@ -5310,18 +5222,13 @@
       inst.error = BAD_ARGS;
       return;
     }
-  if ((width = five_bit_unsigned_immediate (&str)) == -1)
+  if (immediate_required_here (&str, &width, 1, 32, FALSE) == FAIL)
     return;
 
   end_of_line (str);
 
-  if (width == 0 || lsb == 32)
+  if (width + lsb > 32)
     {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-  else if (width + lsb > 32)
-    {
       inst.error = _("bit-field extends past end of register");
       return;
     }
@@ -5339,35 +5246,15 @@
 static void
 do_bkpt (char * str)
 {
-  expressionS expr;
-  unsigned long number;
+  int number = 0;
 
   skip_whitespace (str);
 
-  /* Allow optional leading '#'.  */
-  if (is_immediate_prefix (* str))
-    str++;
-
-  memset (& expr, '\0', sizeof (expr));
-
-  if (my_get_expression (& expr, & str)
-      || (expr.X_op != O_constant
-	  /* As a convenience we allow 'bkpt' without an operand.  */
-	  && expr.X_op != O_absent))
-    {
-      inst.error = _("bad expression");
+  /* As a convenience we allow 'bkpt' without an operand.  */
+  if (is_immediate_prefix (*str) || ISDIGIT (*str))
+    if (immediate_required_here (&str, &number, 0, 0xffff, TRUE) == FAIL)
       return;
-    }
 
-  number = expr.X_add_number;
-
-  /* Check it fits a 16 bit unsigned.  */
-  if (number != (number & 0xffff))
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-
   /* Top 12 of 16 bits to bits 19:8.  */
   inst.instruction |= (number & 0xfff0) << 4;
 
@@ -6818,7 +6705,7 @@
 do_mov16 (char *str)
 {
   int rd;
-  expressionS expr;
+  int val;
 
   /* Rd.  */
   skip_whitespace (str);
@@ -6835,34 +6722,14 @@
     }
 
   /* Imm16.  */
-  skip_whitespace (str);
-  if (!is_immediate_prefix (*str))
-    {
-      inst.error = _("immediate expression expected");
-      return;
-    }
-  str++;
-  if (my_get_expression (&expr, &str))
-    {
-      inst.error = _("bad expression");
-      return;
-    }
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-  if (expr.X_add_number < 0 || expr.X_add_number > 65535)
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
+  if (immediate_required_here (&str, &val, 0, 65535, FALSE) == FAIL)
+    return;
 
   end_of_line (str);
 
   /* The value is in two pieces: 0:11, 16:19.  */
-  inst.instruction |= (expr.X_add_number & 0x00000fff);
-  inst.instruction |= (expr.X_add_number & 0x0000f000) << 4;
+  inst.instruction |= (val & 0x00000fff);
+  inst.instruction |= (val & 0x0000f000) << 4;
 }
 
 static void
@@ -7088,33 +6955,25 @@
 static void
 do_nop (char * str)
 {
+  int hint;
+
   skip_whitespace (str);
   if (*str == '{')
     {
       str++;
+      if (immediate_required_here (&str, &hint, 0, 255, TRUE) == FAIL)
+	return;
 
-      if (my_get_expression (&inst.reloc.exp, &str))
-	inst.reloc.exp.X_op = O_illegal;
-      else
+      if (*str != '}')
 	{
-	  skip_whitespace (str);
-	  if (*str == '}')
-	    str++;
-	  else
-	    inst.reloc.exp.X_op = O_illegal;
-	}
-
-      if (inst.reloc.exp.X_op != O_constant
-	  || inst.reloc.exp.X_add_number > 255
-	  || inst.reloc.exp.X_add_number < 0)
-	{
-	  inst.error = _("Invalid NOP hint");
+	  inst.error = _("'}' expected at end of hint field");
 	  return;
 	}
+      str++;
 
-      /* Arcitectural NOP hints are CPSR sets with no bits selected.  */
+      /* Architectural NOP hints are CPSR sets with no bits selected.  */
       inst.instruction &= 0xf0000000;
-      inst.instruction |= 0x0320f000 + inst.reloc.exp.X_add_number;
+      inst.instruction |= 0x0320f000 + hint;
     }
 
   end_of_line (str);
@@ -7395,8 +7254,7 @@
 static void
 do_sat (char ** str, int bias)
 {
-  int rd, rm;
-  expressionS expr;
+  int rd, rm, val;
 
   skip_whitespace (*str);
 
@@ -7414,30 +7272,10 @@
     }
 
   /* Parse #<immed>,  field.  */
-  if (is_immediate_prefix (**str))
-    (*str)++;
-  else
-    {
-      inst.error = _("immediate expression expected");
-      return;
-    }
-  if (my_get_expression (&expr, str))
-    {
-      inst.error = _("bad expression");
-      return;
-    }
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-  if (expr.X_add_number + bias < 0
-      || expr.X_add_number + bias > 31)
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-  inst.instruction |= (expr.X_add_number + bias) << 16;
+  if (immediate_required_here (str, &val, 0 - bias, 31 - bias, FALSE) == FAIL)
+    return;
+
+  inst.instruction |= (val + bias) << 16;
   if (skip_past_comma (str) == FAIL)
     {
       inst.error = BAD_ARGS;
@@ -7481,8 +7319,7 @@
 static void
 do_sat16 (char ** str, int bias)
 {
-  int rd, rm;
-  expressionS expr;
+  int rd, rm, val;
 
   skip_whitespace (*str);
 
@@ -7500,30 +7337,10 @@
     }
 
   /* Parse #<immed>, field.  */
-  if (is_immediate_prefix (**str))
-    (*str)++;
-  else
-    {
-      inst.error = _("immediate expression expected");
-      return;
-    }
-  if (my_get_expression (&expr, str))
-    {
-      inst.error = _("bad expression");
-      return;
-    }
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-  if (expr.X_add_number + bias < 0
-      || expr.X_add_number + bias > 15)
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-  inst.instruction |= (expr.X_add_number + bias) << 16;
+  if (immediate_required_here (str, &val, 0 - bias, 15 - bias, FALSE) == FAIL)
+    return;
+
+  inst.instruction |= (val + bias) << 16;
   if (skip_past_comma (str) == FAIL)
     {
       inst.error = BAD_ARGS;
@@ -7572,7 +7389,6 @@
     inst.instruction |= 0x200;
 }
 
-
 static void
 do_smi (char * str)
 {
@@ -7942,8 +7758,7 @@
 static void
 do_sxtah (char * str)
 {
-  int rd, rn, rm;
-  expressionS expr;
+  int rd, rn, rm, rot;
   int rotation_clear_mask = 0xfffff3ff;
   int rotation_eight_mask = 0x00000400;
   int rotation_sixteen_mask = 0x00000800;
@@ -7987,29 +7802,11 @@
     }
 
   /* Get the immediate constant.  */
-  skip_whitespace (str);
-  if (is_immediate_prefix (* str))
-    str++;
-  else
-    {
-      inst.error = _("immediate expression expected");
-      return;
-    }
+  if (immediate_required_here (&str, &rot, 0, 24, FALSE) == FAIL)
+    return;
 
-  if (my_get_expression (&expr, &str))
+  switch (rot)
     {
-      inst.error = _("bad expression");
-      return;
-    }
-
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-
-  switch (expr.X_add_number)
-    {
     case 0:
       /* Rotation field has already been zeroed.  */
       break;
@@ -8043,8 +7840,8 @@
 static void
 do_sxth (char * str)
 {
-  int rd, rm;
-  expressionS expr;
+  int rd, rm, rot;
+
   int rotation_clear_mask = 0xfffff3ff;
   int rotation_eight_mask = 0x00000400;
   int rotation_sixteen_mask = 0x00000800;
@@ -8086,29 +7883,10 @@
     }
 
   /* Get the immediate constant.  */
-  skip_whitespace (str);
-  if (is_immediate_prefix (* str))
-    str++;
-  else
+  if (immediate_required_here (&str, &rot, 0, 24, FALSE) == FAIL)
+    return;
+  switch (rot)
     {
-      inst.error = _("immediate expression expected");
-      return;
-    }
-
-  if (my_get_expression (&expr, &str))
-    {
-      inst.error = _("bad expression");
-      return;
-    }
-
-  if (expr.X_op != O_constant)
-    {
-      inst.error = _("constant expression expected");
-      return;
-    }
-
-  switch (expr.X_add_number)
-    {
     case 0:
       /* Rotation field has already been zeroed.  */
       break;
@@ -8831,34 +8609,15 @@
 static void
 do_t_bkpt (char * str)
 {
-  expressionS expr;
-  unsigned long number;
+  int number = 0;
 
   skip_whitespace (str);
 
-  /* Allow optional leading '#'.  */
-  if (is_immediate_prefix (*str))
-    str ++;
-
-  memset (& expr, '\0', sizeof (expr));
-  if (my_get_expression (& expr, & str)
-      || (expr.X_op != O_constant
-	  /* As a convenience we allow 'bkpt' without an operand.  */
-	  && expr.X_op != O_absent))
-    {
-      inst.error = _("bad expression");
+  /* As a convenience we allow 'bkpt' without an operand.  */
+  if (is_immediate_prefix (*str) || ISDIGIT (*str))
+    if (immediate_required_here (&str, &number, 0, 255, TRUE) == FAIL)
       return;
-    }
 
-  number = expr.X_add_number;
-
-  /* Check it fits an 8 bit unsigned.  */
-  if (number != (number & 0xff))
-    {
-      inst.error = _("immediate value out of range");
-      return;
-    }
-
   inst.instruction |= number;
 
   end_of_line (str);
@@ -9882,36 +9641,17 @@
 
   skip_whitespace (str);
 
-  if (fp_reg_required_here (&str, 12) == FAIL)
+  if (fp_reg_required_here (&str, 12) == FAIL
+      || skip_past_comma (&str) == FAIL)
     {
-      if (! inst.error)
-	inst.error = BAD_ARGS;
+      inst.error = BAD_ARGS;
       return;
     }
 
   /* Get Number of registers to transfer.  */
-  if (skip_past_comma (&str) == FAIL
-      || my_get_expression (&inst.reloc.exp, &str))
-    {
-      if (! inst.error)
-	inst.error = _("constant expression expected");
-      return;
-    }
+  if (immediate_required_here (&str, &num_regs, 1, 4, TRUE) == FAIL)
+    return;
 
-  if (inst.reloc.exp.X_op != O_constant)
-    {
-      inst.error = _("constant value required for number of registers");
-      return;
-    }
-
-  num_regs = inst.reloc.exp.X_add_number;
-
-  if (num_regs < 1 || num_regs > 4)
-    {
-      inst.error = _("number of registers must be in the range [1:4]");
-      return;
-    }
-
   switch (num_regs)
     {
     case 1:
@@ -10025,9 +9765,8 @@
 		   int immediate_size)
 {
   int reg = 0;
+  int number;
   const char *  inst_error;
-  expressionS expr;
-  unsigned long number;
 
   inst_error = inst.error;
   if (!inst.error)
@@ -10175,27 +9914,9 @@
     }
   else
     {
-      skip_whitespace (str);
-
-      /* Allow optional leading '#'.  */
-      if (is_immediate_prefix (* str))
-        str++;
-
-      memset (& expr, '\0', sizeof (expr));
-
-      if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
-        {
-          inst.error = _("bad or missing expression");
-          return FAIL;
-        }
-
-      number = expr.X_add_number;
-
-      if (number != (number & immediate_size))
-        {
-          inst.error = _("immediate value out of range");
-          return FAIL;
-        }
+      if (immediate_required_here (&str, &number, 0,
+				   immediate_size, FALSE) == FAIL)
+	return FAIL;
       end_of_line (str);
       inst.error = inst_error;
       return number;

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