1 /* Copyright 2007, 2008 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" },
98 "CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3|CpuSSSE3|CpuSSE4_1|CpuSSE4_2" },
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"},
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
),
238 BITFIELD (Cpu3dnowA
),
239 BITFIELD (CpuPadLock
),
248 BITFIELD (CpuUnused
),
252 static bitfield opcode_modifiers
[] =
257 BITFIELD (ShortForm
),
259 BITFIELD (JumpDword
),
261 BITFIELD (JumpInterSegment
),
268 BITFIELD (IgnoreSize
),
269 BITFIELD (DefaultSize
),
278 BITFIELD (RegKludge
),
279 BITFIELD (FirstXmm0
),
280 BITFIELD (ByteOkIntel
),
283 BITFIELD (AddrPrefixOp0
),
293 BITFIELD (ATTMnemonic
),
294 BITFIELD (ATTSyntax
),
297 static bitfield operand_types
[] =
313 BITFIELD (BaseIndex
),
319 BITFIELD (InOutPortReg
),
320 BITFIELD (ShiftCount
),
328 BITFIELD (JumpAbsolute
),
338 BITFIELD (Unspecified
),
346 static const char *filename
;
349 compare (const void *x
, const void *y
)
351 const bitfield
*xp
= (const bitfield
*) x
;
352 const bitfield
*yp
= (const bitfield
*) y
;
353 return xp
->position
- yp
->position
;
357 fail (const char *message
, ...)
361 va_start (args
, message
);
362 fprintf (stderr
, _("%s: Error: "), program_name
);
363 vfprintf (stderr
, message
, args
);
369 process_copyright (FILE *fp
)
371 fprintf (fp
, "/* This file is automatically generated by i386-gen. Do not edit! */\n\
372 /* Copyright 2007, 2008 Free Software Foundation, Inc.\n\
374 This file is part of the GNU opcodes library.\n\
376 This library is free software; you can redistribute it and/or modify\n\
377 it under the terms of the GNU General Public License as published by\n\
378 the Free Software Foundation; either version 3, or (at your option)\n\
379 any later version.\n\
381 It is distributed in the hope that it will be useful, but WITHOUT\n\
382 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n\
383 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\n\
384 License for more details.\n\
386 You should have received a copy of the GNU General Public License\n\
387 along with this program; if not, write to the Free Software\n\
388 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,\n\
389 MA 02110-1301, USA. */\n");
392 /* Remove leading white spaces. */
395 remove_leading_whitespaces (char *str
)
397 while (ISSPACE (*str
))
402 /* Remove trailing white spaces. */
405 remove_trailing_whitespaces (char *str
)
407 size_t last
= strlen (str
);
415 if (ISSPACE (str
[last
]))
423 /* Find next field separated by SEP and terminate it. Return a
424 pointer to the one after it. */
427 next_field (char *str
, char sep
, char **next
)
431 p
= remove_leading_whitespaces (str
);
432 for (str
= p
; *str
!= sep
&& *str
!= '\0'; str
++);
435 remove_trailing_whitespaces (p
);
443 set_bitfield (const char *f
, bitfield
*array
, unsigned int size
)
447 if (strcmp (f
, "CpuSledgehammer") == 0)
449 else if (strcmp (f
, "Mmword") == 0)
451 else if (strcmp (f
, "Oword") == 0)
454 for (i
= 0; i
< size
; i
++)
455 if (strcasecmp (array
[i
].name
, f
) == 0)
461 fail (_("%s: %d: Unknown bitfield: %s\n"), filename
, lineno
, f
);
465 output_cpu_flags (FILE *table
, bitfield
*flags
, unsigned int size
,
466 int macro
, const char *comma
, const char *indent
)
470 fprintf (table
, "%s{ { ", indent
);
472 for (i
= 0; i
< size
- 1; i
++)
474 fprintf (table
, "%d, ", flags
[i
].value
);
475 if (((i
+ 1) % 20) == 0)
477 /* We need \\ for macro. */
479 fprintf (table
, " \\\n %s", indent
);
481 fprintf (table
, "\n %s", indent
);
485 fprintf (table
, "%d } }%s\n", flags
[i
].value
, comma
);
489 process_i386_cpu_flag (FILE *table
, char *flag
, int macro
,
490 const char *comma
, const char *indent
)
492 char *str
, *next
, *last
;
493 bitfield flags
[ARRAY_SIZE (cpu_flags
)];
495 /* Copy the default cpu flags. */
496 memcpy (flags
, cpu_flags
, sizeof (cpu_flags
));
498 if (strcasecmp (flag
, "unknown") == 0)
502 /* We turn on everything except for cpu64 in case of
503 CPU_UNKNOWN_FLAGS. */
504 for (i
= 0; i
< ARRAY_SIZE (flags
); i
++)
505 if (flags
[i
].position
!= Cpu64
)
508 else if (strcmp (flag
, "0"))
510 last
= flag
+ strlen (flag
);
511 for (next
= flag
; next
&& next
< last
; )
513 str
= next_field (next
, '|', &next
);
515 set_bitfield (str
, flags
, ARRAY_SIZE (flags
));
519 output_cpu_flags (table
, flags
, ARRAY_SIZE (flags
), macro
,
524 output_opcode_modifier (FILE *table
, bitfield
*modifier
, unsigned int size
)
528 fprintf (table
, " { ");
530 for (i
= 0; i
< size
- 1; i
++)
532 fprintf (table
, "%d, ", modifier
[i
].value
);
533 if (((i
+ 1) % 20) == 0)
534 fprintf (table
, "\n ");
537 fprintf (table
, "%d },\n", modifier
[i
].value
);
541 process_i386_opcode_modifier (FILE *table
, char *mod
)
543 char *str
, *next
, *last
;
544 bitfield modifiers
[ARRAY_SIZE (opcode_modifiers
)];
546 /* Copy the default opcode modifier. */
547 memcpy (modifiers
, opcode_modifiers
, sizeof (modifiers
));
549 if (strcmp (mod
, "0"))
551 last
= mod
+ strlen (mod
);
552 for (next
= mod
; next
&& next
< last
; )
554 str
= next_field (next
, '|', &next
);
556 set_bitfield (str
, modifiers
, ARRAY_SIZE (modifiers
));
559 output_opcode_modifier (table
, modifiers
, ARRAY_SIZE (modifiers
));
563 output_operand_type (FILE *table
, bitfield
*types
, unsigned int size
,
564 int macro
, const char *indent
)
568 fprintf (table
, "{ { ");
570 for (i
= 0; i
< size
- 1; i
++)
572 fprintf (table
, "%d, ", types
[i
].value
);
573 if (((i
+ 1) % 20) == 0)
575 /* We need \\ for macro. */
577 fprintf (table
, "\\\n%s", indent
);
579 fprintf (table
, "\n%s", indent
);
583 fprintf (table
, "%d } }", types
[i
].value
);
587 process_i386_operand_type (FILE *table
, char *op
, int macro
,
590 char *str
, *next
, *last
;
591 bitfield types
[ARRAY_SIZE (operand_types
)];
593 /* Copy the default operand type. */
594 memcpy (types
, operand_types
, sizeof (types
));
596 if (strcmp (op
, "0"))
598 last
= op
+ strlen (op
);
599 for (next
= op
; next
&& next
< last
; )
601 str
= next_field (next
, '|', &next
);
603 set_bitfield (str
, types
, ARRAY_SIZE (types
));
606 output_operand_type (table
, types
, ARRAY_SIZE (types
), macro
,
611 process_i386_opcodes (FILE *table
)
616 char *str
, *p
, *last
;
617 char *name
, *operands
, *base_opcode
, *extension_opcode
;
619 char *cpu_flags
, *opcode_modifier
, *operand_types
[MAX_OPERANDS
];
621 filename
= "i386-opc.tbl";
622 fp
= fopen (filename
, "r");
625 fail (_("can't find i386-opc.tbl for reading, errno = %s\n"),
628 fprintf (table
, "\n/* i386 opcode table. */\n\n");
629 fprintf (table
, "const template i386_optab[] =\n{\n");
633 if (fgets (buf
, sizeof (buf
), fp
) == NULL
)
638 p
= remove_leading_whitespaces (buf
);
641 str
= strstr (p
, "//");
645 /* Remove trailing white spaces. */
646 remove_trailing_whitespaces (p
);
651 fprintf (table
, "%s\n", p
);
659 last
= p
+ strlen (p
);
662 name
= next_field (p
, ',', &str
);
667 /* Find number of operands. */
668 operands
= next_field (str
, ',', &str
);
673 /* Find base_opcode. */
674 base_opcode
= next_field (str
, ',', &str
);
679 /* Find extension_opcode. */
680 extension_opcode
= next_field (str
, ',', &str
);
685 /* Find opcode_length. */
686 opcode_length
= next_field (str
, ',', &str
);
691 /* Find cpu_flags. */
692 cpu_flags
= next_field (str
, ',', &str
);
697 /* Find opcode_modifier. */
698 opcode_modifier
= next_field (str
, ',', &str
);
703 /* Remove the first {. */
704 str
= remove_leading_whitespaces (str
);
707 str
= remove_leading_whitespaces (str
+ 1);
711 /* There are at least "X}". */
715 /* Remove trailing white spaces and }. */
719 if (ISSPACE (str
[i
]) || str
[i
] == '}')
728 /* Find operand_types. */
729 for (i
= 0; i
< ARRAY_SIZE (operand_types
); i
++)
733 operand_types
[i
] = NULL
;
737 operand_types
[i
] = next_field (str
, ',', &str
);
738 if (*operand_types
[i
] == '0')
741 operand_types
[i
] = NULL
;
746 fprintf (table
, " { \"%s\", %s, %s, %s, %s,\n",
747 name
, operands
, base_opcode
, extension_opcode
,
750 process_i386_cpu_flag (table
, cpu_flags
, 0, ",", " ");
752 process_i386_opcode_modifier (table
, opcode_modifier
);
754 fprintf (table
, " { ");
756 for (i
= 0; i
< ARRAY_SIZE (operand_types
); i
++)
758 if (operand_types
[i
] == NULL
759 || *operand_types
[i
] == '0')
762 process_i386_operand_type (table
, "0", 0, "\t ");
767 fprintf (table
, ",\n ");
769 process_i386_operand_type (table
, operand_types
[i
], 0,
772 fprintf (table
, " } },\n");
777 fprintf (table
, " { NULL, 0, 0, 0, 0,\n");
779 process_i386_cpu_flag (table
, "0", 0, ",", " ");
781 process_i386_opcode_modifier (table
, "0");
783 fprintf (table
, " { ");
784 process_i386_operand_type (table
, "0", 0, "\t ");
785 fprintf (table
, " } }\n");
787 fprintf (table
, "};\n");
791 process_i386_registers (FILE *table
)
795 char *str
, *p
, *last
;
796 char *reg_name
, *reg_type
, *reg_flags
, *reg_num
;
798 filename
= "i386-reg.tbl";
799 fp
= fopen (filename
, "r");
801 fail (_("can't find i386-reg.tbl for reading, errno = %s\n"),
804 fprintf (table
, "\n/* i386 register table. */\n\n");
805 fprintf (table
, "const reg_entry i386_regtab[] =\n{\n");
809 if (fgets (buf
, sizeof (buf
), fp
) == NULL
)
814 p
= remove_leading_whitespaces (buf
);
817 str
= strstr (p
, "//");
821 /* Remove trailing white spaces. */
822 remove_trailing_whitespaces (p
);
827 fprintf (table
, "%s\n", p
);
835 last
= p
+ strlen (p
);
838 reg_name
= next_field (p
, ',', &str
);
844 reg_type
= next_field (str
, ',', &str
);
849 /* Find reg_flags. */
850 reg_flags
= next_field (str
, ',', &str
);
856 reg_num
= next_field (str
, ',', &str
);
858 fprintf (table
, " { \"%s\",\n ", reg_name
);
860 process_i386_operand_type (table
, reg_type
, 0, "\t");
862 fprintf (table
, ",\n %s, %s },\n", reg_flags
, reg_num
);
867 fprintf (table
, "};\n");
869 fprintf (table
, "\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
873 process_i386_initializers (void)
876 FILE *fp
= fopen ("i386-init.h", "w");
880 fail (_("can't create i386-init.h, errno = %s\n"),
883 process_copyright (fp
);
885 for (i
= 0; i
< ARRAY_SIZE (cpu_flag_init
); i
++)
887 fprintf (fp
, "\n#define %s \\\n", cpu_flag_init
[i
].name
);
888 init
= xstrdup (cpu_flag_init
[i
].init
);
889 process_i386_cpu_flag (fp
, init
, 1, "", " ");
893 for (i
= 0; i
< ARRAY_SIZE (operand_type_init
); i
++)
895 fprintf (fp
, "\n\n#define %s \\\n ", operand_type_init
[i
].name
);
896 init
= xstrdup (operand_type_init
[i
].init
);
897 process_i386_operand_type (fp
, init
, 1, " ");
905 /* Program options. */
906 #define OPTION_SRCDIR 200
908 struct option long_options
[] =
910 {"srcdir", required_argument
, NULL
, OPTION_SRCDIR
},
911 {"debug", no_argument
, NULL
, 'd'},
912 {"version", no_argument
, NULL
, 'V'},
913 {"help", no_argument
, NULL
, 'h'},
914 {0, no_argument
, NULL
, 0}
920 printf ("%s: version 1.0\n", program_name
);
925 usage (FILE * stream
, int status
)
927 fprintf (stream
, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
933 main (int argc
, char **argv
)
935 extern int chdir (char *);
940 program_name
= *argv
;
941 xmalloc_set_program_name (program_name
);
943 while ((c
= getopt_long (argc
, argv
, "vVdh", long_options
, 0)) != EOF
)
968 if (chdir (srcdir
) != 0)
969 fail (_("unable to change directory to \"%s\", errno = %s\n"),
970 srcdir
, xstrerror (errno
));
972 /* Check the unused bitfield in i386_cpu_flags. */
974 c
= CpuNumOfBits
- CpuMax
- 1;
976 fail (_("%d unused bits in i386_cpu_flags.\n"), c
);
979 /* Check the unused bitfield in i386_operand_type. */
981 c
= OTNumOfBits
- OTMax
- 1;
983 fail (_("%d unused bits in i386_operand_type.\n"), c
);
986 qsort (cpu_flags
, ARRAY_SIZE (cpu_flags
), sizeof (cpu_flags
[0]),
989 qsort (opcode_modifiers
, ARRAY_SIZE (opcode_modifiers
),
990 sizeof (opcode_modifiers
[0]), compare
);
992 qsort (operand_types
, ARRAY_SIZE (operand_types
),
993 sizeof (operand_types
[0]), compare
);
995 table
= fopen ("i386-tbl.h", "w");
997 fail (_("can't create i386-tbl.h, errno = %s\n"),
1000 process_copyright (table
);
1002 process_i386_opcodes (table
);
1003 process_i386_registers (table
);
1004 process_i386_initializers ();