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 Free Software Foundation, Inc.
8 
9 This file is part of the GNU Binutils and GDB, the GNU debugger.
10 
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24 
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
26    Keep that in mind.  */
27 
28 #include "sysdep.h"
29 #include <stdio.h>
30 #include "ansidecl.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "openrisc-desc.h"
34 #include "openrisc-opc.h"
35 #include "opintl.h"
36 #include "xregex.h"
37 #include "libiberty.h"
38 #include "safe-ctype.h"
39 
40 #undef  min
41 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #undef  max
43 #define max(a,b) ((a) > (b) ? (a) : (b))
44 
45 static const char * parse_insn_normal
46   (CGEN_CPU_DESC, const CGEN_INSN *, const char **, CGEN_FIELDS *);
47 
48 /* -- assembler routines inserted here.  */
49 
50 /* -- asm.c */
51 
52 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
53 
54 static const char * parse_hi16
55   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
56 static const char * parse_lo16
57   PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
58 
59 long
openrisc_sign_extend_16bit(value)60 openrisc_sign_extend_16bit (value)
61      long value;
62 {
63   return ((value & 0xffff) ^ 0x8000) - 0x8000;
64 }
65 
66 /* Handle hi().  */
67 
68 static const char *
parse_hi16(cd,strp,opindex,valuep)69 parse_hi16 (cd, strp, opindex, valuep)
70      CGEN_CPU_DESC cd;
71      const char **strp;
72      int opindex;
73      long *valuep;
74 {
75   const char *errmsg;
76   enum cgen_parse_operand_result result_type;
77   unsigned long ret;
78 
79   if (**strp == '#')
80     ++*strp;
81 
82   if (strncasecmp (*strp, "hi(", 3) == 0)
83     {
84       bfd_vma value;
85 
86       *strp += 3;
87       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
88                                      &result_type, &value);
89       if (**strp != ')')
90         return _("missing `)'");
91 
92       ++*strp;
93       if (errmsg == NULL
94           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
95         value >>= 16;
96       ret = value;
97     }
98   else
99     {
100       if (**strp == '-')
101 	{
102 	  long value;
103 
104 	  errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
105 	  ret = value;
106 	}
107       else
108 	{
109 	  unsigned long value;
110 
111 	  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
112 	  ret = value;
113 	}
114     }
115 
116   *valuep = ((ret & 0xffff) ^ 0x8000) - 0x8000;
117   return errmsg;
118 }
119 
120 /* Handle lo().  */
121 
122 static const char *
parse_lo16(cd,strp,opindex,valuep)123 parse_lo16 (cd, strp, opindex, valuep)
124      CGEN_CPU_DESC cd;
125      const char **strp;
126      int opindex;
127      long *valuep;
128 {
129   const char *errmsg;
130   enum cgen_parse_operand_result result_type;
131   unsigned long ret;
132 
133   if (**strp == '#')
134     ++*strp;
135 
136   if (strncasecmp (*strp, "lo(", 3) == 0)
137     {
138       bfd_vma value;
139 
140       *strp += 3;
141       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
142 				   &result_type, &value);
143       if (**strp != ')')
144         return _("missing `)'");
145 
146       ++*strp;
147       ret = value;
148     }
149   else
150     {
151       if (**strp == '-')
152 	{
153 	  long value;
154 
155 	  errmsg = cgen_parse_signed_integer (cd, strp, opindex, &value);
156 	  ret = value;
157 	}
158       else
159 	{
160 	  unsigned long value;
161 
162 	  errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, &value);
163 	  ret = value;
164 	}
165     }
166 
167   *valuep = ((ret & 0xffff) ^ 0x8000) - 0x8000;
168   return errmsg;
169 }
170 
171 /* -- */
172 
173 const char * openrisc_cgen_parse_operand
174   PARAMS ((CGEN_CPU_DESC, int, const char **, CGEN_FIELDS *));
175 
176 /* Main entry point for operand parsing.
177 
178    This function is basically just a big switch statement.  Earlier versions
179    used tables to look up the function to use, but
180    - if the table contains both assembler and disassembler functions then
181      the disassembler contains much of the assembler and vice-versa,
182    - there's a lot of inlining possibilities as things grow,
183    - using a switch statement avoids the function call overhead.
184 
185    This function could be moved into `parse_insn_normal', but keeping it
186    separate makes clear the interface between `parse_insn_normal' and each of
187    the handlers.  */
188 
189 const char *
openrisc_cgen_parse_operand(cd,opindex,strp,fields)190 openrisc_cgen_parse_operand (cd, opindex, strp, fields)
191      CGEN_CPU_DESC cd;
192      int opindex;
193      const char ** strp;
194      CGEN_FIELDS * fields;
195 {
196   const char * errmsg = NULL;
197   /* Used by scalar operands that still need to be parsed.  */
198   long junk ATTRIBUTE_UNUSED;
199 
200   switch (opindex)
201     {
202     case OPENRISC_OPERAND_ABS_26 :
203       {
204         bfd_vma value;
205         errmsg = cgen_parse_address (cd, strp, OPENRISC_OPERAND_ABS_26, 0, NULL,  & value);
206         fields->f_abs26 = value;
207       }
208       break;
209     case OPENRISC_OPERAND_DISP_26 :
210       {
211         bfd_vma value;
212         errmsg = cgen_parse_address (cd, strp, OPENRISC_OPERAND_DISP_26, 0, NULL,  & value);
213         fields->f_disp26 = value;
214       }
215       break;
216     case OPENRISC_OPERAND_HI16 :
217       errmsg = parse_hi16 (cd, strp, OPENRISC_OPERAND_HI16, (long *) (& fields->f_simm16));
218       break;
219     case OPENRISC_OPERAND_LO16 :
220       errmsg = parse_lo16 (cd, strp, OPENRISC_OPERAND_LO16, (long *) (& fields->f_lo16));
221       break;
222     case OPENRISC_OPERAND_OP_F_23 :
223       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_OP_F_23, (unsigned long *) (& fields->f_op4));
224       break;
225     case OPENRISC_OPERAND_OP_F_3 :
226       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_OP_F_3, (unsigned long *) (& fields->f_op5));
227       break;
228     case OPENRISC_OPERAND_RA :
229       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r2);
230       break;
231     case OPENRISC_OPERAND_RB :
232       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r3);
233       break;
234     case OPENRISC_OPERAND_RD :
235       errmsg = cgen_parse_keyword (cd, strp, & openrisc_cgen_opval_h_gr, & fields->f_r1);
236       break;
237     case OPENRISC_OPERAND_SIMM_16 :
238       errmsg = cgen_parse_signed_integer (cd, strp, OPENRISC_OPERAND_SIMM_16, (long *) (& fields->f_simm16));
239       break;
240     case OPENRISC_OPERAND_UI16NC :
241       errmsg = parse_lo16 (cd, strp, OPENRISC_OPERAND_UI16NC, (long *) (& fields->f_i16nc));
242       break;
243     case OPENRISC_OPERAND_UIMM_16 :
244       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_UIMM_16, (unsigned long *) (& fields->f_uimm16));
245       break;
246     case OPENRISC_OPERAND_UIMM_5 :
247       errmsg = cgen_parse_unsigned_integer (cd, strp, OPENRISC_OPERAND_UIMM_5, (unsigned long *) (& fields->f_uimm5));
248       break;
249 
250     default :
251       /* xgettext:c-format */
252       fprintf (stderr, _("Unrecognized field %d while parsing.\n"), opindex);
253       abort ();
254   }
255 
256   return errmsg;
257 }
258 
259 cgen_parse_fn * const openrisc_cgen_parse_handlers[] =
260 {
261   parse_insn_normal,
262 };
263 
264 void
openrisc_cgen_init_asm(cd)265 openrisc_cgen_init_asm (cd)
266      CGEN_CPU_DESC cd;
267 {
268   openrisc_cgen_init_opcode_table (cd);
269   openrisc_cgen_init_ibld_table (cd);
270   cd->parse_handlers = & openrisc_cgen_parse_handlers[0];
271   cd->parse_operand = openrisc_cgen_parse_operand;
272 }
273 
274 
275 
276 /* Regex construction routine.
277 
278    This translates an opcode syntax string into a regex string,
279    by replacing any non-character syntax element (such as an
280    opcode) with the pattern '.*'
281 
282    It then compiles the regex and stores it in the opcode, for
283    later use by openrisc_cgen_assemble_insn
284 
285    Returns NULL for success, an error message for failure.  */
286 
287 char *
openrisc_cgen_build_insn_regex(CGEN_INSN * insn)288 openrisc_cgen_build_insn_regex (CGEN_INSN *insn)
289 {
290   CGEN_OPCODE *opc = (CGEN_OPCODE *) CGEN_INSN_OPCODE (insn);
291   const char *mnem = CGEN_INSN_MNEMONIC (insn);
292   char rxbuf[CGEN_MAX_RX_ELEMENTS];
293   char *rx = rxbuf;
294   const CGEN_SYNTAX_CHAR_TYPE *syn;
295   int reg_err;
296 
297   syn = CGEN_SYNTAX_STRING (CGEN_OPCODE_SYNTAX (opc));
298 
299   /* Mnemonics come first in the syntax string.  */
300   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
301     return _("missing mnemonic in syntax string");
302   ++syn;
303 
304   /* Generate a case sensitive regular expression that emulates case
305      insensitive matching in the "C" locale.  We cannot generate a case
306      insensitive regular expression because in Turkish locales, 'i' and 'I'
307      are not equal modulo case conversion.  */
308 
309   /* Copy the literal mnemonic out of the insn.  */
310   for (; *mnem; mnem++)
311     {
312       char c = *mnem;
313 
314       if (ISALPHA (c))
315 	{
316 	  *rx++ = '[';
317 	  *rx++ = TOLOWER (c);
318 	  *rx++ = TOUPPER (c);
319 	  *rx++ = ']';
320 	}
321       else
322 	*rx++ = c;
323     }
324 
325   /* Copy any remaining literals from the syntax string into the rx.  */
326   for(; * syn != 0 && rx <= rxbuf + (CGEN_MAX_RX_ELEMENTS - 7 - 4); ++syn)
327     {
328       if (CGEN_SYNTAX_CHAR_P (* syn))
329 	{
330 	  char c = CGEN_SYNTAX_CHAR (* syn);
331 
332 	  switch (c)
333 	    {
334 	      /* Escape any regex metacharacters in the syntax.  */
335 	    case '.': case '[': case '\\':
336 	    case '*': case '^': case '$':
337 
338 #ifdef CGEN_ESCAPE_EXTENDED_REGEX
339 	    case '?': case '{': case '}':
340 	    case '(': case ')': case '*':
341 	    case '|': case '+': case ']':
342 #endif
343 	      *rx++ = '\\';
344 	      *rx++ = c;
345 	      break;
346 
347 	    default:
348 	      if (ISALPHA (c))
349 		{
350 		  *rx++ = '[';
351 		  *rx++ = TOLOWER (c);
352 		  *rx++ = TOUPPER (c);
353 		  *rx++ = ']';
354 		}
355 	      else
356 		*rx++ = c;
357 	      break;
358 	    }
359 	}
360       else
361 	{
362 	  /* Replace non-syntax fields with globs.  */
363 	  *rx++ = '.';
364 	  *rx++ = '*';
365 	}
366     }
367 
368   /* Trailing whitespace ok.  */
369   * rx++ = '[';
370   * rx++ = ' ';
371   * rx++ = '\t';
372   * rx++ = ']';
373   * rx++ = '*';
374 
375   /* But anchor it after that.  */
376   * rx++ = '$';
377   * rx = '\0';
378 
379   CGEN_INSN_RX (insn) = xmalloc (sizeof (regex_t));
380   reg_err = regcomp ((regex_t *) CGEN_INSN_RX (insn), rxbuf, REG_NOSUB);
381 
382   if (reg_err == 0)
383     return NULL;
384   else
385     {
386       static char msg[80];
387 
388       regerror (reg_err, (regex_t *) CGEN_INSN_RX (insn), msg, 80);
389       regfree ((regex_t *) CGEN_INSN_RX (insn));
390       free (CGEN_INSN_RX (insn));
391       (CGEN_INSN_RX (insn)) = NULL;
392       return msg;
393     }
394 }
395 
396 
397 /* Default insn parser.
398 
399    The syntax string is scanned and operands are parsed and stored in FIELDS.
400    Relocs are queued as we go via other callbacks.
401 
402    ??? Note that this is currently an all-or-nothing parser.  If we fail to
403    parse the instruction, we return 0 and the caller will start over from
404    the beginning.  Backtracking will be necessary in parsing subexpressions,
405    but that can be handled there.  Not handling backtracking here may get
406    expensive in the case of the m68k.  Deal with later.
407 
408    Returns NULL for success, an error message for failure.  */
409 
410 static const char *
parse_insn_normal(CGEN_CPU_DESC cd,const CGEN_INSN * insn,const char ** strp,CGEN_FIELDS * fields)411 parse_insn_normal (CGEN_CPU_DESC cd,
412 		   const CGEN_INSN *insn,
413 		   const char **strp,
414 		   CGEN_FIELDS *fields)
415 {
416   /* ??? Runtime added insns not handled yet.  */
417   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
418   const char *str = *strp;
419   const char *errmsg;
420   const char *p;
421   const CGEN_SYNTAX_CHAR_TYPE * syn;
422 #ifdef CGEN_MNEMONIC_OPERANDS
423   /* FIXME: wip */
424   int past_opcode_p;
425 #endif
426 
427   /* For now we assume the mnemonic is first (there are no leading operands).
428      We can parse it without needing to set up operand parsing.
429      GAS's input scrubber will ensure mnemonics are lowercase, but we may
430      not be called from GAS.  */
431   p = CGEN_INSN_MNEMONIC (insn);
432   while (*p && TOLOWER (*p) == TOLOWER (*str))
433     ++p, ++str;
434 
435   if (* p)
436     return _("unrecognized instruction");
437 
438 #ifndef CGEN_MNEMONIC_OPERANDS
439   if (* str && ! ISSPACE (* str))
440     return _("unrecognized instruction");
441 #endif
442 
443   CGEN_INIT_PARSE (cd);
444   cgen_init_parse_operand (cd);
445 #ifdef CGEN_MNEMONIC_OPERANDS
446   past_opcode_p = 0;
447 #endif
448 
449   /* We don't check for (*str != '\0') here because we want to parse
450      any trailing fake arguments in the syntax string.  */
451   syn = CGEN_SYNTAX_STRING (syntax);
452 
453   /* Mnemonics come first for now, ensure valid string.  */
454   if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
455     abort ();
456 
457   ++syn;
458 
459   while (* syn != 0)
460     {
461       /* Non operand chars must match exactly.  */
462       if (CGEN_SYNTAX_CHAR_P (* syn))
463 	{
464 	  /* FIXME: While we allow for non-GAS callers above, we assume the
465 	     first char after the mnemonic part is a space.  */
466 	  /* FIXME: We also take inappropriate advantage of the fact that
467 	     GAS's input scrubber will remove extraneous blanks.  */
468 	  if (TOLOWER (*str) == TOLOWER (CGEN_SYNTAX_CHAR (* syn)))
469 	    {
470 #ifdef CGEN_MNEMONIC_OPERANDS
471 	      if (CGEN_SYNTAX_CHAR(* syn) == ' ')
472 		past_opcode_p = 1;
473 #endif
474 	      ++ syn;
475 	      ++ str;
476 	    }
477 	  else if (*str)
478 	    {
479 	      /* Syntax char didn't match.  Can't be this insn.  */
480 	      static char msg [80];
481 
482 	      /* xgettext:c-format */
483 	      sprintf (msg, _("syntax error (expected char `%c', found `%c')"),
484 		       CGEN_SYNTAX_CHAR(*syn), *str);
485 	      return msg;
486 	    }
487 	  else
488 	    {
489 	      /* Ran out of input.  */
490 	      static char msg [80];
491 
492 	      /* xgettext:c-format */
493 	      sprintf (msg, _("syntax error (expected char `%c', found end of instruction)"),
494 		       CGEN_SYNTAX_CHAR(*syn));
495 	      return msg;
496 	    }
497 	  continue;
498 	}
499 
500       /* We have an operand of some sort.  */
501       errmsg = cd->parse_operand (cd, CGEN_SYNTAX_FIELD (*syn),
502 					  &str, fields);
503       if (errmsg)
504 	return errmsg;
505 
506       /* Done with this operand, continue with next one.  */
507       ++ syn;
508     }
509 
510   /* If we're at the end of the syntax string, we're done.  */
511   if (* syn == 0)
512     {
513       /* FIXME: For the moment we assume a valid `str' can only contain
514 	 blanks now.  IE: We needn't try again with a longer version of
515 	 the insn and it is assumed that longer versions of insns appear
516 	 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3).  */
517       while (ISSPACE (* str))
518 	++ str;
519 
520       if (* str != '\0')
521 	return _("junk at end of line"); /* FIXME: would like to include `str' */
522 
523       return NULL;
524     }
525 
526   /* We couldn't parse it.  */
527   return _("unrecognized instruction");
528 }
529 
530 /* Main entry point.
531    This routine is called for each instruction to be assembled.
532    STR points to the insn to be assembled.
533    We assume all necessary tables have been initialized.
534    The assembled instruction, less any fixups, is stored in BUF.
535    Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
536    still needs to be converted to target byte order, otherwise BUF is an array
537    of bytes in target byte order.
538    The result is a pointer to the insn's entry in the opcode table,
539    or NULL if an error occured (an error message will have already been
540    printed).
541 
542    Note that when processing (non-alias) macro-insns,
543    this function recurses.
544 
545    ??? It's possible to make this cpu-independent.
546    One would have to deal with a few minor things.
547    At this point in time doing so would be more of a curiosity than useful
548    [for example this file isn't _that_ big], but keeping the possibility in
549    mind helps keep the design clean.  */
550 
551 const CGEN_INSN *
openrisc_cgen_assemble_insn(CGEN_CPU_DESC cd,const char * str,CGEN_FIELDS * fields,CGEN_INSN_BYTES_PTR buf,char ** errmsg)552 openrisc_cgen_assemble_insn (CGEN_CPU_DESC cd,
553 			   const char *str,
554 			   CGEN_FIELDS *fields,
555 			   CGEN_INSN_BYTES_PTR buf,
556 			   char **errmsg)
557 {
558   const char *start;
559   CGEN_INSN_LIST *ilist;
560   const char *parse_errmsg = NULL;
561   const char *insert_errmsg = NULL;
562   int recognized_mnemonic = 0;
563 
564   /* Skip leading white space.  */
565   while (ISSPACE (* str))
566     ++ str;
567 
568   /* The instructions are stored in hashed lists.
569      Get the first in the list.  */
570   ilist = CGEN_ASM_LOOKUP_INSN (cd, str);
571 
572   /* Keep looking until we find a match.  */
573   start = str;
574   for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
575     {
576       const CGEN_INSN *insn = ilist->insn;
577       recognized_mnemonic = 1;
578 
579 #ifdef CGEN_VALIDATE_INSN_SUPPORTED
580       /* Not usually needed as unsupported opcodes
581 	 shouldn't be in the hash lists.  */
582       /* Is this insn supported by the selected cpu?  */
583       if (! openrisc_cgen_insn_supported (cd, insn))
584 	continue;
585 #endif
586       /* If the RELAXED attribute is set, this is an insn that shouldn't be
587 	 chosen immediately.  Instead, it is used during assembler/linker
588 	 relaxation if possible.  */
589       if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_RELAXED) != 0)
590 	continue;
591 
592       str = start;
593 
594       /* Skip this insn if str doesn't look right lexically.  */
595       if (CGEN_INSN_RX (insn) != NULL &&
596 	  regexec ((regex_t *) CGEN_INSN_RX (insn), str, 0, NULL, 0) == REG_NOMATCH)
597 	continue;
598 
599       /* Allow parse/insert handlers to obtain length of insn.  */
600       CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
601 
602       parse_errmsg = CGEN_PARSE_FN (cd, insn) (cd, insn, & str, fields);
603       if (parse_errmsg != NULL)
604 	continue;
605 
606       /* ??? 0 is passed for `pc'.  */
607       insert_errmsg = CGEN_INSERT_FN (cd, insn) (cd, insn, fields, buf,
608 						 (bfd_vma) 0);
609       if (insert_errmsg != NULL)
610         continue;
611 
612       /* It is up to the caller to actually output the insn and any
613          queued relocs.  */
614       return insn;
615     }
616 
617   {
618     static char errbuf[150];
619 #ifdef CGEN_VERBOSE_ASSEMBLER_ERRORS
620     const char *tmp_errmsg;
621 
622     /* If requesting verbose error messages, use insert_errmsg.
623        Failing that, use parse_errmsg.  */
624     tmp_errmsg = (insert_errmsg ? insert_errmsg :
625 		  parse_errmsg ? parse_errmsg :
626 		  recognized_mnemonic ?
627 		  _("unrecognized form of instruction") :
628 		  _("unrecognized instruction"));
629 
630     if (strlen (start) > 50)
631       /* xgettext:c-format */
632       sprintf (errbuf, "%s `%.50s...'", tmp_errmsg, start);
633     else
634       /* xgettext:c-format */
635       sprintf (errbuf, "%s `%.50s'", tmp_errmsg, start);
636 #else
637     if (strlen (start) > 50)
638       /* xgettext:c-format */
639       sprintf (errbuf, _("bad instruction `%.50s...'"), start);
640     else
641       /* xgettext:c-format */
642       sprintf (errbuf, _("bad instruction `%.50s'"), start);
643 #endif
644 
645     *errmsg = errbuf;
646     return NULL;
647   }
648 }
649 
650 #if 0 /* This calls back to GAS which we can't do without care.  */
651 
652 /* Record each member of OPVALS in the assembler's symbol table.
653    This lets GAS parse registers for us.
654    ??? Interesting idea but not currently used.  */
655 
656 /* Record each member of OPVALS in the assembler's symbol table.
657    FIXME: Not currently used.  */
658 
659 void
660 openrisc_cgen_asm_hash_keywords (CGEN_CPU_DESC cd, CGEN_KEYWORD *opvals)
661 {
662   CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
663   const CGEN_KEYWORD_ENTRY * ke;
664 
665   while ((ke = cgen_keyword_search_next (& search)) != NULL)
666     {
667 #if 0 /* Unnecessary, should be done in the search routine.  */
668       if (! openrisc_cgen_opval_supported (ke))
669 	continue;
670 #endif
671       cgen_asm_record_register (cd, ke->name, ke->value);
672     }
673 }
674 
675 #endif /* 0 */
676