1 /* Copyright 2007 Free Software Foundation, Inc.
3 This file is part of the GNU opcodes library.
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
10 It is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
13 License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18 MA 02110-1301, USA. */
24 #include "libiberty.h"
25 #include "safe-ctype.h"
30 #define _(String) gettext (String)
32 static const char *program_name
= NULL
;
35 typedef struct initializer
41 static initializer cpu_flag_init
[] =
43 { "CPU_UNKNOWN_FLAGS",
45 { "CPU_GENERIC32_FLAGS",
46 "Cpu186|Cpu286|Cpu386" },
47 { "CPU_GENERIC64_FLAGS",
48 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2" },
56 "Cpu186|Cpu286|Cpu386" },
58 "Cpu186|Cpu286|Cpu386|Cpu486" },
60 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586" },
62 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686" },
64 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX" },
66 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE" },
68 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2" },
70 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuLM" },
72 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3" },
74 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuLM" },
76 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX" },
78 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow" },
80 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA" },
82 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuK8|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuLM" },
83 { "CPU_AMDFAM10_FLAGS",
84 "Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuK8|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a|CpuABM|CpuLM" },
88 "CpuMMX|CpuMMX2|CpuSSE" },
90 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2" },
92 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3" },
94 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3" },
96 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_1_Or_5" },
98 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2|CpuSSE4_1_Or_5" },
101 { "CPU_3DNOWA_FLAGS",
102 "CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA" },
103 { "CPU_PADLOCK_FLAGS",
108 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a" },
112 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSE4a|CpuABM|CpuSSE5|CpuSSE4_1_Or_5"}
115 static initializer operand_type_init
[] =
117 { "OPERAND_TYPE_NONE",
119 { "OPERAND_TYPE_REG8",
121 { "OPERAND_TYPE_REG16",
123 { "OPERAND_TYPE_REG32",
125 { "OPERAND_TYPE_REG64",
127 { "OPERAND_TYPE_IMM1",
129 { "OPERAND_TYPE_IMM8",
131 { "OPERAND_TYPE_IMM8S",
133 { "OPERAND_TYPE_IMM16",
135 { "OPERAND_TYPE_IMM32",
137 { "OPERAND_TYPE_IMM32S",
139 { "OPERAND_TYPE_IMM64",
141 { "OPERAND_TYPE_BASEINDEX",
143 { "OPERAND_TYPE_DISP8",
145 { "OPERAND_TYPE_DISP16",
147 { "OPERAND_TYPE_DISP32",
149 { "OPERAND_TYPE_DISP32S",
151 { "OPERAND_TYPE_DISP64",
153 { "OPERAND_TYPE_INOUTPORTREG",
155 { "OPERAND_TYPE_SHIFTCOUNT",
157 { "OPERAND_TYPE_CONTROL",
159 { "OPERAND_TYPE_TEST",
161 { "OPERAND_TYPE_DEBUG",
163 { "OPERAND_TYPE_FLOATREG",
165 { "OPERAND_TYPE_FLOATACC",
167 { "OPERAND_TYPE_SREG2",
169 { "OPERAND_TYPE_SREG3",
171 { "OPERAND_TYPE_ACC",
173 { "OPERAND_TYPE_JUMPABSOLUTE",
175 { "OPERAND_TYPE_REGMMX",
177 { "OPERAND_TYPE_REGXMM",
179 { "OPERAND_TYPE_ESSEG",
181 { "OPERAND_TYPE_ACC32",
183 { "OPERAND_TYPE_ACC64",
185 { "OPERAND_TYPE_REG16_INOUTPORTREG",
186 "Reg16|InOutPortReg" },
187 { "OPERAND_TYPE_DISP16_32",
189 { "OPERAND_TYPE_ANYDISP",
190 "Disp8|Disp16|Disp32|Disp32S|Disp64" },
191 { "OPERAND_TYPE_IMM16_32",
193 { "OPERAND_TYPE_IMM16_32S",
195 { "OPERAND_TYPE_IMM16_32_32S",
196 "Imm16|Imm32|Imm32S" },
197 { "OPERAND_TYPE_IMM32_32S_DISP32",
198 "Imm32|Imm32S|Disp32" },
199 { "OPERAND_TYPE_IMM64_DISP64",
201 { "OPERAND_TYPE_IMM32_32S_64_DISP32",
202 "Imm32|Imm32S|Imm64|Disp32" },
203 { "OPERAND_TYPE_IMM32_32S_64_DISP32_64",
204 "Imm32|Imm32S|Imm64|Disp32|Disp64" },
207 typedef struct bitfield
214 #define BITFIELD(n) { n, 0, #n }
216 static bitfield cpu_flags
[] =
233 BITFIELD (CpuSSE4_1
),
234 BITFIELD (CpuSSE4_2
),
237 BITFIELD (CpuSSE4_1_Or_5
),
239 BITFIELD (Cpu3dnowA
),
240 BITFIELD (CpuPadLock
),
249 BITFIELD (CpuUnused
),
253 static bitfield opcode_modifiers
[] =
258 BITFIELD (ShortForm
),
260 BITFIELD (JumpDword
),
262 BITFIELD (JumpInterSegment
),
269 BITFIELD (IgnoreSize
),
270 BITFIELD (DefaultSize
),
279 BITFIELD (RegKludge
),
280 BITFIELD (FirstXmm0
),
281 BITFIELD (ByteOkIntel
),
284 BITFIELD (AddrPrefixOp0
),
294 BITFIELD (ATTMnemonic
),
295 BITFIELD (IntelMnemonic
),
298 static bitfield operand_types
[] =
314 BITFIELD (BaseIndex
),
320 BITFIELD (InOutPortReg
),
321 BITFIELD (ShiftCount
),
329 BITFIELD (JumpAbsolute
),
338 compare (const void *x
, const void *y
)
340 const bitfield
*xp
= (const bitfield
*) x
;
341 const bitfield
*yp
= (const bitfield
*) y
;
342 return xp
->position
- yp
->position
;
346 fail (const char *message
, ...)
350 va_start (args
, message
);
351 fprintf (stderr
, _("%s: Error: "), program_name
);
352 vfprintf (stderr
, message
, args
);
358 process_copyright (FILE *fp
)
360 fprintf (fp
, "/* This file is automatically generated by i386-gen. Do not edit! */\n\
361 /* Copyright 2007 Free Software Foundation, Inc.\n\
363 This file is part of the GNU opcodes library.\n\
365 This library is free software; you can redistribute it and/or modify\n\
366 it under the terms of the GNU General Public License as published by\n\
367 the Free Software Foundation; either version 3, or (at your option)\n\
368 any later version.\n\
370 It is distributed in the hope that it will be useful, but WITHOUT\n\
371 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
372 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\
373 License for more details.\n\
375 You should have received a copy of the GNU General Public License\n\
376 along with this program; if not, write to the Free Software\n\
377 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\
378 MA 02110-1301, USA. */\n");
381 /* Remove leading white spaces. */
384 remove_leading_whitespaces (char *str
)
386 while (ISSPACE (*str
))
391 /* Remove trailing white spaces. */
394 remove_trailing_whitespaces (char *str
)
396 size_t last
= strlen (str
);
404 if (ISSPACE (str
[last
]))
412 /* Find next field separated by SEP and terminate it. Return a
413 pointer to the one after it. */
416 next_field (char *str
, char sep
, char **next
)
420 p
= remove_leading_whitespaces (str
);
421 for (str
= p
; *str
!= sep
&& *str
!= '\0'; str
++);
424 remove_trailing_whitespaces (p
);
432 set_bitfield (const char *f
, bitfield
*array
, unsigned int size
)
436 if (strcmp (f
, "CpuSledgehammer") == 0)
439 for (i
= 0; i
< size
; i
++)
440 if (strcasecmp (array
[i
].name
, f
) == 0)
446 printf ("Unknown bitfield: %s\n", f
);
451 output_cpu_flags (FILE *table
, bitfield
*flags
, unsigned int size
,
452 int macro
, const char *comma
, const char *indent
)
456 fprintf (table
, "%s{ { ", indent
);
458 for (i
= 0; i
< size
- 1; i
++)
460 fprintf (table
, "%d, ", flags
[i
].value
);
461 if (((i
+ 1) % 20) == 0)
463 /* We need \\ for macro. */
465 fprintf (table
, " \\\n %s", indent
);
467 fprintf (table
, "\n %s", indent
);
471 fprintf (table
, "%d } }%s\n", flags
[i
].value
, comma
);
475 process_i386_cpu_flag (FILE *table
, char *flag
, int macro
,
476 const char *comma
, const char *indent
)
478 char *str
, *next
, *last
;
479 bitfield flags
[ARRAY_SIZE (cpu_flags
)];
481 /* Copy the default cpu flags. */
482 memcpy (flags
, cpu_flags
, sizeof (cpu_flags
));
484 if (strcasecmp (flag
, "unknown") == 0)
488 /* We turn on everything except for cpu64 in case of
489 CPU_UNKNOWN_FLAGS. */
490 for (i
= 0; i
< ARRAY_SIZE (flags
); i
++)
491 if (flags
[i
].position
!= Cpu64
)
494 else if (strcmp (flag
, "0"))
496 last
= flag
+ strlen (flag
);
497 for (next
= flag
; next
&& next
< last
; )
499 str
= next_field (next
, '|', &next
);
501 set_bitfield (str
, flags
, ARRAY_SIZE (flags
));
505 output_cpu_flags (table
, flags
, ARRAY_SIZE (flags
), macro
,
510 output_opcode_modifier (FILE *table
, bitfield
*modifier
, unsigned int size
)
514 fprintf (table
, " { ");
516 for (i
= 0; i
< size
- 1; i
++)
518 fprintf (table
, "%d, ", modifier
[i
].value
);
519 if (((i
+ 1) % 20) == 0)
520 fprintf (table
, "\n ");
523 fprintf (table
, "%d },\n", modifier
[i
].value
);
527 process_i386_opcode_modifier (FILE *table
, char *mod
)
529 char *str
, *next
, *last
;
530 bitfield modifiers
[ARRAY_SIZE (opcode_modifiers
)];
532 /* Copy the default opcode modifier. */
533 memcpy (modifiers
, opcode_modifiers
, sizeof (modifiers
));
535 if (strcmp (mod
, "0"))
537 last
= mod
+ strlen (mod
);
538 for (next
= mod
; next
&& next
< last
; )
540 str
= next_field (next
, '|', &next
);
542 set_bitfield (str
, modifiers
, ARRAY_SIZE (modifiers
));
545 output_opcode_modifier (table
, modifiers
, ARRAY_SIZE (modifiers
));
549 output_operand_type (FILE *table
, bitfield
*types
, unsigned int size
,
550 int macro
, const char *indent
)
554 fprintf (table
, "{ { ");
556 for (i
= 0; i
< size
- 1; i
++)
558 fprintf (table
, "%d, ", types
[i
].value
);
559 if (((i
+ 1) % 20) == 0)
561 /* We need \\ for macro. */
563 fprintf (table
, "\\\n%s", indent
);
565 fprintf (table
, "\n%s", indent
);
569 fprintf (table
, "%d } }", types
[i
].value
);
573 process_i386_operand_type (FILE *table
, char *op
, int macro
,
576 char *str
, *next
, *last
;
577 bitfield types
[ARRAY_SIZE (operand_types
)];
579 /* Copy the default operand type. */
580 memcpy (types
, operand_types
, sizeof (types
));
582 if (strcmp (op
, "0"))
584 last
= op
+ strlen (op
);
585 for (next
= op
; next
&& next
< last
; )
587 str
= next_field (next
, '|', &next
);
589 set_bitfield (str
, types
, ARRAY_SIZE (types
));
592 output_operand_type (table
, types
, ARRAY_SIZE (types
), macro
,
597 process_i386_opcodes (FILE *table
)
599 FILE *fp
= fopen ("i386-opc.tbl", "r");
602 char *str
, *p
, *last
;
603 char *name
, *operands
, *base_opcode
, *extension_opcode
;
605 char *cpu_flags
, *opcode_modifier
, *operand_types
[MAX_OPERANDS
];
608 fail (_("can't find i386-opc.tbl for reading, errno = %s\n"),
611 fprintf (table
, "\n/* i386 opcode table. */\n\n");
612 fprintf (table
, "const template i386_optab[] =\n{\n");
616 if (fgets (buf
, sizeof (buf
), fp
) == NULL
)
619 p
= remove_leading_whitespaces (buf
);
622 str
= strstr (p
, "//");
626 /* Remove trailing white spaces. */
627 remove_trailing_whitespaces (p
);
632 fprintf (table
, "%s\n", p
);
640 last
= p
+ strlen (p
);
643 name
= next_field (p
, ',', &str
);
648 /* Find number of operands. */
649 operands
= next_field (str
, ',', &str
);
654 /* Find base_opcode. */
655 base_opcode
= next_field (str
, ',', &str
);
660 /* Find extension_opcode. */
661 extension_opcode
= next_field (str
, ',', &str
);
666 /* Find opcode_length. */
667 opcode_length
= next_field (str
, ',', &str
);
672 /* Find cpu_flags. */
673 cpu_flags
= next_field (str
, ',', &str
);
678 /* Find opcode_modifier. */
679 opcode_modifier
= next_field (str
, ',', &str
);
684 /* Remove the first {. */
685 str
= remove_leading_whitespaces (str
);
688 str
= remove_leading_whitespaces (str
+ 1);
692 /* There are at least "X}". */
696 /* Remove trailing white spaces and }. */
700 if (ISSPACE (str
[i
]) || str
[i
] == '}')
709 /* Find operand_types. */
710 for (i
= 0; i
< ARRAY_SIZE (operand_types
); i
++)
714 operand_types
[i
] = NULL
;
718 operand_types
[i
] = next_field (str
, ',', &str
);
719 if (*operand_types
[i
] == '0')
722 operand_types
[i
] = NULL
;
727 fprintf (table
, " { \"%s\", %s, %s, %s, %s,\n",
728 name
, operands
, base_opcode
, extension_opcode
,
731 process_i386_cpu_flag (table
, cpu_flags
, 0, ",", " ");
733 process_i386_opcode_modifier (table
, opcode_modifier
);
735 fprintf (table
, " { ");
737 for (i
= 0; i
< ARRAY_SIZE (operand_types
); i
++)
739 if (operand_types
[i
] == NULL
740 || *operand_types
[i
] == '0')
743 process_i386_operand_type (table
, "0", 0, "\t ");
748 fprintf (table
, ",\n ");
750 process_i386_operand_type (table
, operand_types
[i
], 0,
753 fprintf (table
, " } },\n");
758 fprintf (table
, " { NULL, 0, 0, 0, 0,\n");
760 process_i386_cpu_flag (table
, "0", 0, ",", " ");
762 process_i386_opcode_modifier (table
, "0");
764 fprintf (table
, " { ");
765 process_i386_operand_type (table
, "0", 0, "\t ");
766 fprintf (table
, " } }\n");
768 fprintf (table
, "};\n");
772 process_i386_registers (FILE *table
)
774 FILE *fp
= fopen ("i386-reg.tbl", "r");
776 char *str
, *p
, *last
;
777 char *reg_name
, *reg_type
, *reg_flags
, *reg_num
;
780 fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
783 fprintf (table
, "\n/* i386 register table. */\n\n");
784 fprintf (table
, "const reg_entry i386_regtab[] =\n{\n");
788 if (fgets (buf
, sizeof (buf
), fp
) == NULL
)
791 p
= remove_leading_whitespaces (buf
);
794 str
= strstr (p
, "//");
798 /* Remove trailing white spaces. */
799 remove_trailing_whitespaces (p
);
804 fprintf (table
, "%s\n", p
);
812 last
= p
+ strlen (p
);
815 reg_name
= next_field (p
, ',', &str
);
821 reg_type
= next_field (str
, ',', &str
);
826 /* Find reg_flags. */
827 reg_flags
= next_field (str
, ',', &str
);
833 reg_num
= next_field (str
, ',', &str
);
835 fprintf (table
, " { \"%s\",\n ", reg_name
);
837 process_i386_operand_type (table
, reg_type
, 0, "\t");
839 fprintf (table
, ",\n %s, %s },\n", reg_flags
, reg_num
);
844 fprintf (table
, "};\n");
846 fprintf (table
, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
850 process_i386_initializers (void)
853 FILE *fp
= fopen ("i386-init.h", "w");
857 fail (_("can't create i386-init.h, errno = %s\n"),
860 process_copyright (fp
);
862 for (i
= 0; i
< ARRAY_SIZE (cpu_flag_init
); i
++)
864 fprintf (fp
, "\n#define %s \\\n", cpu_flag_init
[i
].name
);
865 init
= xstrdup (cpu_flag_init
[i
].init
);
866 process_i386_cpu_flag (fp
, init
, 1, "", " ");
870 for (i
= 0; i
< ARRAY_SIZE (operand_type_init
); i
++)
872 fprintf (fp
, "\n\n#define %s \\\n ", operand_type_init
[i
].name
);
873 init
= xstrdup (operand_type_init
[i
].init
);
874 process_i386_operand_type (fp
, init
, 1, " ");
882 /* Program options. */
883 #define OPTION_SRCDIR 200
885 struct option long_options
[] =
887 {"srcdir", required_argument
, NULL
, OPTION_SRCDIR
},
888 {"debug", no_argument
, NULL
, 'd'},
889 {"version", no_argument
, NULL
, 'V'},
890 {"help", no_argument
, NULL
, 'h'},
891 {0, no_argument
, NULL
, 0}
897 printf ("%s: version 1.0\n", program_name
);
902 usage (FILE * stream
, int status
)
904 fprintf (stream
, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
910 main (int argc
, char **argv
)
912 extern int chdir (char *);
917 program_name
= *argv
;
918 xmalloc_set_program_name (program_name
);
920 while ((c
= getopt_long (argc
, argv
, "vVdh", long_options
, 0)) != EOF
)
945 if (chdir (srcdir
) != 0)
946 fail (_("unable to change directory to \"%s\", errno = %s\n"),
947 srcdir
, xstrerror (errno
));
949 /* Check the unused bitfield in i386_cpu_flags. */
951 c
= CpuNumOfBits
- CpuMax
- 1;
953 fail (_("%d unused bits in i386_cpu_flags.\n"), c
);
956 /* Check the unused bitfield in i386_operand_type. */
958 c
= OTNumOfBits
- OTMax
- 1;
960 fail (_("%d unused bits in i386_operand_type.\n"), c
);
963 qsort (cpu_flags
, ARRAY_SIZE (cpu_flags
), sizeof (cpu_flags
[0]),
966 qsort (opcode_modifiers
, ARRAY_SIZE (opcode_modifiers
),
967 sizeof (opcode_modifiers
[0]), compare
);
969 qsort (operand_types
, ARRAY_SIZE (operand_types
),
970 sizeof (operand_types
[0]), compare
);
972 table
= fopen ("i386-tbl.h", "w");
974 fail (_("can't create i386-tbl.h, errno = %s\n"),
977 process_copyright (table
);
979 process_i386_opcodes (table
);
980 process_i386_registers (table
);
981 process_i386_initializers ();