FreeBSD/contrib/binutils/gas/config/tc-arm.c
/* Parse a VFP register list.  If the string is invalid return FAIL.
   Otherwise return the number of registers, and set PBASE to the first
   register.  Parses registers of type ETYPE.
   If REGLIST_NEON_D is used, several syntax enhancements are enabled:
     - Q registers can be used to specify pairs of D registers
     - { } can be omitted from around a singleton register list
         FIXME: This is not implemented, as it would require backtracking in
         some cases, e.g.:
           vtbl.8 d3,d4,d5
         This could be done (the meaning isn't really ambiguous), but doesn't
         fit in well with the current parsing framework.
     - 32 D registers may be used (also true for VFPv3).
   FIXME: Types are ignored in these register lists, which is probably a
   bug.  */
Parse a VFP register list.  If the string is invalid return FAIL.
Otherwise return the number of registers, and set PBASE to the first
register.  Parses registers of type ETYPE.
If REGLIST_NEON_D is used, several syntax enhancements are enabled:
Q registers can be used to specify pairs of D registers
{ } can be omitted from around a singleton register list
FIXME: This is not implemented, as it would require backtracking in
some cases, e.g.:
vtbl.8 d3,d4,d5
This could be done (the meaning isn't really ambiguous), but doesn't
fit in well with the current parsing framework.
32 D registers may be used (also true for VFPv3).
FIXME: Types are ignored in these register lists, which is probably a
bug.
Parse a VFP register list . If the string is invalid return FAIL . Otherwise return the number of registers and set PBASE to the first register . Parses registers of type ETYPE . If REGLIST_NEON_D is used several syntax enhancements are enabled : Q registers can be used to specify pairs of D registers { } can be omitted from around a singleton register list FIXME : This is not implemented as it would require backtracking in some cases e . g . : vtbl . 8 d3 d4 d5 This could be done ( the meaning isn ' t really ambiguous ) but doesn ' t fit in well with the current parsing framework . 32 D registers may be used ( also true for VFPv3 ) . FIXME : Types are ignored in these register lists which is probably a bug .
static int
parse_vfp_reg_list (char **ccp, unsigned int *pbase, enum reg_list_els etype)
{
  char *str = *ccp;
  int base_reg;
  int new_base;
  enum arm_reg_type regtype = 0;
  int max_regs = 0;
  int count = 0;
  int warned = 0;
  unsigned long mask = 0;
  int i;
  if (*str != '{')
    {
      inst.error = _("expecting {");
      return FAIL;
    }
  str++;
  switch (etype)
    {
    case REGLIST_VFP_S:
      regtype = REG_TYPE_VFS;
      max_regs = 32;
      break;
    case REGLIST_VFP_D:
      regtype = REG_TYPE_VFD;
      break;
    case REGLIST_NEON_D:
      regtype = REG_TYPE_NDQ;
      break;
    }
  if (etype != REGLIST_VFP_S)
    {
      if (ARM_CPU_HAS_FEATURE (cpu_variant, fpu_vfp_ext_v3))
        {
          max_regs = 32;
          if (thumb_mode)
            ARM_MERGE_FEATURE_SETS (thumb_arch_used, thumb_arch_used,
                                    fpu_vfp_ext_v3);
          else
            ARM_MERGE_FEATURE_SETS (arm_arch_used, arm_arch_used,
                                    fpu_vfp_ext_v3);
        }
      else
        max_regs = 16;
    }
  base_reg = max_regs;
  do
    {
      int setmask = 1, addregs = 1;
      new_base = arm_typed_reg_parse (&str, regtype, &regtype, NULL);
      if (new_base == FAIL)
	{
	  first_error (_(reg_expected_msgs[regtype]));
	  return FAIL;
	}
      if (new_base >= max_regs)
        {
          first_error (_("register out of range in list"));
          return FAIL;
        }
      if (regtype == REG_TYPE_NQ)
        {
          setmask = 3;
          addregs = 2;
        }
      if (new_base < base_reg)
	base_reg = new_base;
      if (mask & (setmask << new_base))
	{
	  first_error (_("invalid register list"));
	  return FAIL;
	}
      if ((mask >> new_base) != 0 && ! warned)
	{
	  as_tsktsk (_("register list not in ascending order"));
	  warned = 1;
	}
      mask |= setmask << new_base;
      count += addregs;
      if (*str == '-') 
	{
	  int high_range;
	  str++;
	  if ((high_range = arm_typed_reg_parse (&str, regtype, NULL, NULL))
              == FAIL)
	    {
	      inst.error = gettext (reg_expected_msgs[regtype]);
	      return FAIL;
	    }
          if (high_range >= max_regs)
            {
              first_error (_("register out of range in list"));
              return FAIL;
            }
          if (regtype == REG_TYPE_NQ)
            high_range = high_range + 1;
	  if (high_range <= new_base)
	    {
	      inst.error = _("register range not in ascending order");
	      return FAIL;
	    }
	  for (new_base += addregs; new_base <= high_range; new_base += addregs)
	    {
	      if (mask & (setmask << new_base))
		{
		  inst.error = _("invalid register list");
		  return FAIL;
		}
	      mask |= setmask << new_base;
	      count += addregs;
	    }
	}
    }
  while (skip_past_comma (&str) != FAIL);
  str++;
  if (count == 0 || count > max_regs)
    abort ();
  *pbase = base_reg;
  mask >>= base_reg;
  for (i = 0; i < count; i++)
    {
      if ((mask & (1u << i)) == 0)
	{
	  inst.error = _("non-contiguous register range");
	  return FAIL;
	}
    }
  *ccp = str;
  return count;
}
static int parse_vfp_reg_list ( char * * ccp , unsigned int * pbase , enum reg_list_els etype ) { char * str = * ccp ; int base_reg ; int new_base ; enum arm_reg_type regtype = 0 ; int max_regs = 0 ; int count = 0 ; int warned = 0 ; unsigned long mask = 0 ; int i ; if ( * str != ' ' ) { inst . error = _ ( " " ) ; return FAIL ; } str ++ ; switch ( etype ) { case REGLIST_VFP_S : regtype = REG_TYPE_VFS ; max_regs = 32 ; break ; case REGLIST_VFP_D : regtype = REG_TYPE_VFD ; break ; case REGLIST_NEON_D : regtype = REG_TYPE_NDQ ; break ; } if ( etype != REGLIST_VFP_S ) { if ( ARM_CPU_HAS_FEATURE ( cpu_variant , fpu_vfp_ext_v3 ) ) { max_regs = 32 ; if ( thumb_mode ) ARM_MERGE_FEATURE_SETS ( thumb_arch_used , thumb_arch_used , fpu_vfp_ext_v3 ) ; else ARM_MERGE_FEATURE_SETS ( arm_arch_used , arm_arch_used , fpu_vfp_ext_v3 ) ; } else max_regs = 16 ; } base_reg = max_regs ; do { int setmask = 1 , addregs = 1 ; new_base = arm_typed_reg_parse ( & str , regtype , & regtype , NULL ) ; if ( new_base == FAIL ) { first_error ( _ ( reg_expected_msgs [ regtype ] ) ) ; return FAIL ; } if ( new_base >= max_regs ) { first_error ( _ ( " " ) ) ; return FAIL ; } if ( regtype == REG_TYPE_NQ ) { setmask = 3 ; addregs = 2 ; } if ( new_base < base_reg ) base_reg = new_base ; if ( mask & ( setmask << new_base ) ) { first_error ( _ ( " " ) ) ; return FAIL ; } if ( ( mask >> new_base ) != 0 && ! warned ) { as_tsktsk ( _ ( " " ) ) ; warned = 1 ; } mask |= setmask << new_base ; count += addregs ; if ( * str == ' ' ) { int high_range ; str ++ ; if ( ( high_range = arm_typed_reg_parse ( & str , regtype , NULL , NULL ) ) == FAIL ) { inst . error = gettext ( reg_expected_msgs [ regtype ] ) ; return FAIL ; } if ( high_range >= max_regs ) { first_error ( _ ( " " ) ) ; return FAIL ; } if ( regtype == REG_TYPE_NQ ) high_range = high_range + 1 ; if ( high_range <= new_base ) { inst . error = _ ( " " ) ; return FAIL ; } for ( new_base += addregs ; new_base <= high_range ; new_base += addregs ) { if ( mask & ( setmask << new_base ) ) { inst . error = _ ( " " ) ; return FAIL ; } mask |= setmask << new_base ; count += addregs ; } } } while ( skip_past_comma ( & str ) != FAIL ) ; str ++ ; if ( count == 0 || count > max_regs ) abort ( ) ; * pbase = base_reg ; mask >>= base_reg ; for ( i = 0 ; i < count ; i ++ ) { if ( ( mask & ( 1u << i ) ) == 0 ) { inst . error = _ ( " " ) ; return FAIL ; } } * ccp = str ; return count ; }
Parse a VFP register list.
Parse a VFP register list .
/* VFPv3 allows 32 D registers.  */ /* Note: a value of 2 * n is returned for the register Q<n>.  */ /* We have the start of a range expression */ /* Sanity check -- should have raised a parse error above.  */ /* Final test -- the registers must be consecutive.  */