Update spec file to 4.5 profile
[mono-project.git] / mono / mini / genmdesc.pl
blob8c13a6171dd947081cc78d7eb28b58ab8a8618b3
1 #!/usr/bin/perl -w
3 # perl replacement of genmdesc.c for use when cross-compiling
5 use strict;
6 no locale;
8 # must keep in sync with mini.h
9 my @spec_names = qw(dest src1 src2 src3 len clob nacl);
10 sub INST_DEST () {return 0;}
11 sub INST_SRC1 () {return 1;}
12 sub INST_SRC2 () {return 2;}
13 sub INST_SRC3 () {return 3;}
14 sub INST_LEN () {return 4;}
15 sub INST_CLOB () {return 5;}
16 # making INST_NACL the same as INST_MAX is not a mistake,
17 # INST_NACL writes over INST_LEN, it's not its own field
18 sub INST_NACL () {return 6;}
19 sub INST_MAX () {return 6;}
21 # this must include all the #defines used in mini-ops.h
22 my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __ppc64__ __arm__
23 __sparc__ sparc __s390__ s390 __ia64__ __alpha__ __mips__);
24 my %table =();
25 my %template_table =();
26 my @opcodes = ();
28 my $nacl = 0;
30 sub parse_file
32 my ($define, $file) = @_;
33 my @enabled = (1);
34 my $i = 0;
35 open (OPS, $file) || die "Cannot open $file: $!";
36 while (<OPS>) {
37 if (/^\s*#\s*if\s+(.*)/) {
38 my $defines = $1;
39 die "fix the genmdesc.pl cpp parser to handle all operators" if /(&&)|([!<>=])/;
40 unshift @enabled, scalar ($defines =~ /defined\s*\(\s*$define\s*\)/);
41 next;
43 if (/^\s*#\s*ifdef\s+(\S+)/) {
44 my $defines = $1;
45 unshift @enabled, $defines eq $define;
46 next;
48 if (/^\s*#\s*endif/) {
49 shift @enabled;
50 next;
52 next unless $enabled [0];
53 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
54 my ($sym, $name) = ($1, $2);
55 push @opcodes, [$sym, $name];
56 $table{$name} = {num => $i, name => $name};
57 $i++;
59 close (OPS);
62 sub load_opcodes
64 my ($srcdir, $arch) = @_;
65 my $opcodes_def = "$srcdir/../cil/opcode.def";
66 my $i = 0;
67 my $arch_found = 0;
69 my $cpp = $ENV{"CPP"};
70 $cpp = "cpp" unless defined $cpp;
71 $cpp .= " -undef ";
72 foreach (@defines) {
73 $cpp .= " -U$_";
74 $arch_found = 1 if $arch eq $_;
76 die "$arch arch is not supported.\n" unless $arch_found;
78 my $arch_define = $arch;
79 if ($arch =~ "__i386__") {
80 $arch_define = "TARGET_X86";
82 if ($arch =~ "__x86_64__") {
83 $arch_define = "TARGET_AMD64";
85 if ($arch =~ "__arm__") {
86 $arch_define = "TARGET_ARM";
89 parse_file ($arch_define, "$srcdir/mini-ops.h");
90 return;
91 $cpp .= " -D$arch_define $srcdir/mini-ops.h|";
92 #print "Running: $cpp\n";
93 open (OPS, $cpp) || die "Cannot execute cpp: $!";
94 while (<OPS>) {
95 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
96 my ($sym, $name) = ($1, $2);
97 push @opcodes, [$sym, $name];
98 $table{$name} = {num => $i, name => $name};
99 $i++;
101 close (OPS);
104 sub load_file {
105 my ($name) = @_;
106 my $line = 0;
107 my $comment = "";
109 open (DESC, $name) || die "Cannot open $name: $!";
110 while (<DESC>) {
111 my $is_template = 0;
112 $line++;
113 next if /^\s*$/;
114 if (/^\s*(#.*)?$/) {
115 $comment .= "$1\n";
116 next;
118 my @values = split (/\s+/);
119 next unless ($values [0] =~ /(\S+?):/);
120 my $name = $1;
121 my $desc;
122 if ($name eq "template") {
123 $is_template = 1;
124 $desc = {};
125 } else {
126 $desc = $table {$name};
127 die "Invalid opcode $name at line $line\n" unless defined $desc;
128 die "Duplicated opcode $name at line $line\n" if $desc->{"desc"};
130 shift @values;
131 $desc->{"desc"} = $_;
132 $desc->{"comment"} = $comment;
133 $desc->{"spec"} = {};
134 $comment = "";
135 #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n";
136 for my $val (@values) {
137 if ($val =~ /(\S+):(.*)/) {
138 if ($1 eq "name") {
139 die "name tag only valid in templates at line $line\n" unless $is_template;
140 die "Duplicated name tag in template $desc->{'name'} at line $line\n" if defined $desc->{'name'};
141 die "Duplicated template $2 at line $line\n" if defined $template_table {$2};
142 $desc->{'name'} = $2;
143 $template_table {$2} = $desc;
144 } elsif ($1 eq "template") {
145 my $tdesc = $template_table {$2};
146 die "Invalid template name $2 at line $line\n" unless defined $tdesc;
147 $desc->{"spec"} = {%{$tdesc->{"spec"}}};
148 } else {
149 $desc->{"spec"}->{$1} = $2;
153 die "Template without name at line $1" if ($is_template && !defined ($desc->{'name'}));
155 close (DESC);
158 sub build_spec {
159 my ($spec) = shift;
160 my %spec = %{$spec};
161 my @vals = ();
162 foreach (@spec_names) {
163 my $val = $spec->{$_};
164 if (defined $val) {
165 push @vals, $val;
166 } else {
167 push @vals, undef;
170 #print "vals: " . join (' ', @vals) . "\n";
171 my $res = "";
172 my $n = 0;
173 for (my $i = 0; $i < @vals; ++$i) {
174 next if $i == INST_NACL;
175 if (defined $vals [$i]) {
176 if ($i == INST_LEN) {
177 $n = $vals [$i];
178 if ((defined $vals [INST_NACL]) and $nacl == 1){
179 $n = $vals [INST_NACL];
181 $res .= sprintf ("\\x%x\" \"", + $n);
182 } else {
183 if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
184 $res .= $vals [$i];
185 } else {
186 $res .= sprintf ("\\x%x\" \"", $vals [$i]);
189 } else {
190 $res .= "\\x0\" \"";
193 return $res;
196 sub build_table {
197 my ($fname, $name) = @_;
198 my $i;
199 my $idx;
200 my $idx_array = "const guint16 ${name}_idx [] = {\n";
202 open (OUT, ">$fname") || die "Cannot open file $fname: $!";
203 print OUT "/* File automatically generated by genmdesc, don't change */\n\n";
204 print OUT "const char $name [] = {\n";
205 print OUT "\t\"" . ("\\x0" x INST_MAX) . "\"\t/* null entry */\n";
206 $idx = 1;
208 for ($i = 0; $i < @opcodes; ++$i) {
209 my $name = $opcodes [$i]->[1];
210 my $desc = $table {$name};
211 my $spec = $desc->{"spec"};
212 if (defined $spec) {
213 print OUT "\t\"";
214 print OUT build_spec ($spec);
215 print OUT "\"\t/* $name */\n";
216 my $pos = $idx * INST_MAX;
217 $idx_array .= "\t$pos,\t/* $name */\n";
218 ++$idx;
219 } else {
220 $idx_array .= "\t0,\t/* $name */\n";
223 print OUT "};\n\n";
224 print OUT "$idx_array};\n\n";
225 close (OUT);
228 sub usage {
229 die "genmdesc.pl arch srcdir [--nacl] output name desc [desc2 ...]\n";
232 my $arch = shift || usage ();
233 my $srcdir = shift || usage ();
234 my $output = shift || usage ();
235 if ($output eq "--nacl")
237 $nacl = 1;
238 $output = shift || usage();
240 my $name = shift || usage ();
241 usage () unless @ARGV;
242 my @files = @ARGV;
244 load_opcodes ($srcdir, $arch);
245 foreach my $file (@files) {
246 load_file ($file);
248 build_table ($output, $name);