Home | History | Annotate | Line # | Download | only in opcodes
cgen-asm.in revision 1.1
      1 /* Assembler interface for targets using CGEN. -*- C -*-
      2    CGEN: Cpu tools GENerator
      3 
      4    THIS FILE IS MACHINE GENERATED WITH CGEN.
      5    - the resultant file is machine generated, cgen-asm.in isn't
      6 
      7    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2007, 2008, 2010
      8    Free Software Foundation, Inc.
      9 
     10    This file is part of libopcodes.
     11 
     12    This library is free software; you can redistribute it and/or modify
     13    it under the terms of the GNU General Public License as published by
     14    the Free Software Foundation; either version 3, or (at your option)
     15    any later version.
     16 
     17    It is distributed in the hope that it will be useful, but WITHOUT
     18    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     19    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     20    License for more details.
     21 
     22    You should have received a copy of the GNU General Public License
     23    along with this program; if not, write to the Free Software Foundation, Inc.,
     24    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
     25 
     26 
     27 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
     28    Keep that in mind.  */
     29 
     30 #include "sysdep.h"
     31 #include <stdio.h>
     32 #include "ansidecl.h"
     33 #include "bfd.h"
     34 #include "symcat.h"
     35 #include "@prefix (at) -desc.h"
     36 #include "@prefix (at) -opc.h"
     37 #include "opintl.h"
     38 #include "xregex.h"
     39 #include "libiberty.h"
     40 #include "safe-ctype.h"
     41 
     42 #undef  min
     43 #define min(a,b) ((a) < (b) ? (a) : (b))
     44 #undef  max
     45 #define max(a,b) ((a) > (b) ? (a) : (b))
     46 
     47 static const char * parse_insn_normal
     48   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
     49 
     50 /* -- assembler routines inserted here.  */
     52 
     53 
     55 /* Regex construction routine.
     56 
     57    This translates an opcode syntax string into a regex string,
     58    by replacing any non-character syntax element (such as an
     59    opcode) with the pattern '.*'
     60 
     61    It then compiles the regex and stores it in the opcode, for
     62    later use by @arch@_cgen_assemble_insn
     63 
     64    Returns NULL for success, an error message for failure.  */
     65 
     66 char *
     67 @arch@_cgen_build_insn_regex (CGEN_INSN *insn)
     68 {
     69   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
     70   const char *mnem = CGEN_INSN_MNEMONIC (insn);
     71   char rxbuf[CGEN_MAX_RX_ELEMENTS];
     72   char *rx = rxbuf;
     73   const CGEN_SYNTAX_CHAR_TYPE *syn;
     74   int reg_err;
     75 
     76   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
     77 
     78   /* Mnemonics come first in the syntax string.  */
     79   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
     80     return _("missing mnemonic in syntax string");
     81   ++syn;
     82 
     83   /* Generate a case sensitive regular expression that emulates case
     84      insensitive matching in the "C" locale.  We cannot generate a case
     85      insensitive regular expression because in Turkish locales, 'i' and 'I'
     86      are not equal modulo case conversion.  */
     87 
     88   /* Copy the literal mnemonic out of the insn.  */
     89   for (; *mnem; mnem++)
     90     {
     91       char c = *mnem;
     92 
     93       if (ISALPHA (c))
     94 	{
     95 	  *rx++ = '[';
     96 	  *rx++ = TOLOWER (c);
     97 	  *rx++ = TOUPPER (c);
     98 	  *rx++ = ']';
     99 	}
    100       else
    101 	*rx++ = c;
    102     }
    103 
    104   /* Copy any remaining literals from the syntax string into the rx.  */
    105   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
    106     {
    107       if (CGEN_SYNTAX_CHAR_P (* syn))
    108 	{
    109 	  char c = CGEN_SYNTAX_CHAR (* syn);
    110 
    111 	  switch (c)
    112 	    {
    113 	      /* Escape any regex metacharacters in the syntax.  */
    114 	    case '.': case '[': case '\\':
    115 	    case '*': case '^': case '$':
    116 
    117 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
    118 	    case '?': case '{': case '}':
    119 	    case '(': case ')': case '*':
    120 	    case '|': case '+': case ']':
    121 #endif
    122 	      *rx++ = '\\';
    123 	      *rx++ = c;
    124 	      break;
    125 
    126 	    default:
    127 	      if (ISALPHA (c))
    128 		{
    129 		  *rx++ = '[';
    130 		  *rx++ = TOLOWER (c);
    131 		  *rx++ = TOUPPER (c);
    132 		  *rx++ = ']';
    133 		}
    134 	      else
    135 		*rx++ = c;
    136 	      break;
    137 	    }
    138 	}
    139       else
    140 	{
    141 	  /* Replace non-syntax fields with globs.  */
    142 	  *rx++ = '.';
    143 	  *rx++ = '*';
    144 	}
    145     }
    146 
    147   /* Trailing whitespace ok.  */
    148   * rx++ = '[';
    149   * rx++ = ' ';
    150   * rx++ = '\t';
    151   * rx++ = ']';
    152   * rx++ = '*';
    153 
    154   /* But anchor it after that.  */
    155   * rx++ = '$';
    156   * rx = '\0';
    157 
    158   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
    159   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
    160 
    161   if (reg_err == 0)
    162     return NULL;
    163   else
    164     {
    165       static char msg[80];
    166 
    167       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
    168       regfree ((regex_t *) CGEN_INSN_RX (insn));
    169       free (CGEN_INSN_RX (insn));
    170       (CGEN_INSN_RX (insn)) = NULL;
    171       return msg;
    172     }
    173 }
    174 
    175 
    176 /* Default insn parser.
    178 
    179    The syntax string is scanned and operands are parsed and stored in FIELDS.
    180    Relocs are queued as we go via other callbacks.
    181 
    182    ??? Note that this is currently an all-or-nothing parser.  If we fail to
    183    parse the instruction, we return 0 and the caller will start over from
    184    the beginning.  Backtracking will be necessary in parsing subexpressions,
    185    but that can be handled there.  Not handling backtracking here may get
    186    expensive in the case of the m68k.  Deal with later.
    187 
    188    Returns NULL for success, an error message for failure.  */
    189 
    190 static const char *
    191 parse_insn_normal (CGEN_CPU_DESC cd,
    192 		   const CGEN_INSN *insn,
    193 		   const char **strp,
    194 		   CGEN_FIELDS *fields)
    195 {
    196   /* ??? Runtime added insns not handled yet.  */
    197   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
    198   const char *str = *strp;
    199   const char *errmsg;
    200   const char *p;
    201   const CGEN_SYNTAX_CHAR_TYPE * syn;
    202 #ifdef CGEN_MNEMONIC_OPERANDS
    203   /* FIXME: wip */
    204   int past_opcode_p;
    205 #endif
    206 
    207   /* For now we assume the mnemonic is first (there are no leading operands).
    208      We can parse it without needing to set up operand parsing.
    209      GAS's input scrubber will ensure mnemonics are lowercase, but we may
    210      not be called from GAS.  */
    211   p = CGEN_INSN_MNEMONIC (insn);
    212   while (*p && TOLOWER (*p) == TOLOWER (*str))
    213     ++p, ++str;
    214 
    215   if (* p)
    216     return _("unrecognized instruction");
    217 
    218 #ifndef CGEN_MNEMONIC_OPERANDS
    219   if (* str && ! ISSPACE (* str))
    220     return _("unrecognized instruction");
    221 #endif
    222 
    223   CGEN_INIT_PARSE (cd);
    224   cgen_init_parse_operand (cd);
    225 #ifdef CGEN_MNEMONIC_OPERANDS
    226   past_opcode_p = 0;
    227 #endif
    228 
    229   /* We don't check for (*str != '\0') here because we want to parse
    230      any trailing fake arguments in the syntax string.  */
    231   syn = CGEN_SYNTAX_STRING (syntax);
    232 
    233   /* Mnemonics come first for now, ensure valid string.  */
    234   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
    235     abort ();
    236 
    237   ++syn;
    238 
    239   while (* syn != 0)
    240     {
    241       /* Non operand chars must match exactly.  */
    242       if (CGEN_SYNTAX_CHAR_P (* syn))
    243 	{
    244 	  /* FIXME: While we allow for non-GAS callers above, we assume the
    245 	     first char after the mnemonic part is a space.  */
    246 	  /* FIXME: We also take inappropriate advantage of the fact that
    247 	     GAS's input scrubber will remove extraneous blanks.  */
    248 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
    249 	    {
    250 #ifdef CGEN_MNEMONIC_OPERANDS
    251 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
    252 		past_opcode_p = 1;
    253 #endif
    254 	      ++ syn;
    255 	      ++ str;
    256 	    }
    257 	  else if (*str)
    258 	    {
    259 	      /* Syntax char didn't match.  Can't be this insn.  */
    260 	      static char msg [80];
    261 
    262 	      /* xgettext:c-format */
    263 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
    264 		       CGEN_SYNTAX_CHAR(*syn), *str);
    265 	      return msg;
    266 	    }
    267 	  else
    268 	    {
    269 	      /* Ran out of input.  */
    270 	      static char msg [80];
    271 
    272 	      /* xgettext:c-format */
    273 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
    274 		       CGEN_SYNTAX_CHAR(*syn));
    275 	      return msg;
    276 	    }
    277 	  continue;
    278 	}
    279 
    280 #ifdef CGEN_MNEMONIC_OPERANDS
    281       (void) past_opcode_p;
    282 #endif
    283       /* We have an operand of some sort.  */
    284       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn), &str, fields);
    285       if (errmsg)
    286 	return errmsg;
    287 
    288       /* Done with this operand, continue with next one.  */
    289       ++ syn;
    290     }
    291 
    292   /* If we're at the end of the syntax string, we're done.  */
    293   if (* syn == 0)
    294     {
    295       /* FIXME: For the moment we assume a valid `str' can only contain
    296 	 blanks now.  IE: We needn't try again with a longer version of
    297 	 the insn and it is assumed that longer versions of insns appear
    298 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
    299       while (ISSPACE (* str))
    300 	++ str;
    301 
    302       if (* str != '\0')
    303 	return _("junk at end of line"); /* FIXME: would like to include `str' */
    304 
    305       return NULL;
    306     }
    307 
    308   /* We couldn't parse it.  */
    309   return _("unrecognized instruction");
    310 }
    311 
    312 /* Main entry point.
    314    This routine is called for each instruction to be assembled.
    315    STR points to the insn to be assembled.
    316    We assume all necessary tables have been initialized.
    317    The assembled instruction, less any fixups, is stored in BUF.
    318    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
    319    still needs to be converted to target byte order, otherwise BUF is an array
    320    of bytes in target byte order.
    321    The result is a pointer to the insn's entry in the opcode table,
    322    or NULL if an error occured (an error message will have already been
    323    printed).
    324 
    325    Note that when processing (non-alias) macro-insns,
    326    this function recurses.
    327 
    328    ??? It's possible to make this cpu-independent.
    329    One would have to deal with a few minor things.
    330    At this point in time doing so would be more of a curiosity than useful
    331    [for example this file isn't _that_ big], but keeping the possibility in
    332    mind helps keep the design clean.  */
    333 
    334 const CGEN_INSN *
    335 @arch@_cgen_assemble_insn (CGEN_CPU_DESC cd,
    336 			   const char *str,
    337 			   CGEN_FIELDS *fields,
    338 			   CGEN_INSN_BYTES_PTR buf,
    339 			   char **errmsg)
    340 {
    341   const char *start;
    342   CGEN_INSN_LIST *ilist;
    343   const char *parse_errmsg = NULL;
    344   const char *insert_errmsg = NULL;
    345   int recognized_mnemonic = 0;
    346 
    347   /* Skip leading white space.  */
    348   while (ISSPACE (* str))
    349     ++ str;
    350 
    351   /* The instructions are stored in hashed lists.
    352      Get the first in the list.  */
    353   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
    354 
    355   /* Keep looking until we find a match.  */
    356   start = str;
    357   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
    358     {
    359       const CGEN_INSN *insn = ilist->insn;
    360       recognized_mnemonic = 1;
    361 
    362 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
    363       /* Not usually needed as unsupported opcodes
    364 	 shouldn't be in the hash lists.  */
    365       /* Is this insn supported by the selected cpu?  */
    366       if (! @arch@_cgen_insn_supported (cd, insn))
    367 	continue;
    368 #endif
    369       /* If the RELAXED attribute is set, this is an insn that shouldn't be
    370 	 chosen immediately.  Instead, it is used during assembler/linker
    371 	 relaxation if possible.  */
    372       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
    373 	continue;
    374 
    375       str = start;
    376 
    377       /* Skip this insn if str doesn't look right lexically.  */
    378       if (CGEN_INSN_RX (insn) != NULL &&
    379 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
    380 	continue;
    381 
    382       /* Allow parse/insert handlers to obtain length of insn.  */
    383       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
    384 
    385       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
    386       if (parse_errmsg != NULL)
    387 	continue;
    388 
    389       /* ??? 0 is passed for `pc'.  */
    390       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
    391 						 (bfd_vma) 0);
    392       if (insert_errmsg != NULL)
    393         continue;
    394 
    395       /* It is up to the caller to actually output the insn and any
    396          queued relocs.  */
    397       return insn;
    398     }
    399 
    400   {
    401     static char errbuf[150];
    402     const char *tmp_errmsg;
    403 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
    404 #define be_verbose 1
    405 #else
    406 #define be_verbose 0
    407 #endif
    408 
    409     if (be_verbose)
    410       {
    411 	/* If requesting verbose error messages, use insert_errmsg.
    412 	   Failing that, use parse_errmsg.  */
    413 	tmp_errmsg = (insert_errmsg ? insert_errmsg :
    414 		      parse_errmsg ? parse_errmsg :
    415 		      recognized_mnemonic ?
    416 		      _("unrecognized form of instruction") :
    417 		      _("unrecognized instruction"));
    418 
    419 	if (strlen (start) > 50)
    420 	  /* xgettext:c-format */
    421 	  sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
    422 	else
    423 	  /* xgettext:c-format */
    424 	  sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
    425       }
    426     else
    427       {
    428 	if (strlen (start) > 50)
    429 	  /* xgettext:c-format */
    430 	  sprintf (errbuf, _("bad instruction `%.50s...'"), start);
    431 	else
    432 	  /* xgettext:c-format */
    433 	  sprintf (errbuf, _("bad instruction `%.50s'"), start);
    434       }
    435 
    436     *errmsg = errbuf;
    437     return NULL;
    438   }
    439 }
    440