2010-04-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / genmdesc.pl
blob7216f36529c233ac3683a5c6fcbeb5450085eb57
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);
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 sub INST_MAX () {return 6;}
18 # this must include all the #defines used in mini-ops.h
19 my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __ppc64__ __arm__
20 __sparc__ sparc __s390__ s390 __ia64__ __alpha__ __mips__);
21 my %table =();
22 my %template_table =();
23 my @opcodes = ();
25 sub parse_file
27 my ($define, $file) = @_;
28 my @enabled = (1);
29 my $i = 0;
30 open (OPS, $file) || die "Cannot open $file: $!";
31 while (<OPS>) {
32 if (/^\s*#\s*if\s+(.*)/) {
33 my $defines = $1;
34 die "fix the genmdesc.pl cpp parser to handle all operators" if /(&&)|([!<>=])/;
35 unshift @enabled, scalar ($defines =~ /defined\s*\(\s*$define\s*\)/);
36 next;
38 if (/^\s*#\s*ifdef\s+(\S+)/) {
39 my $defines = $1;
40 unshift @enabled, $defines eq $define;
41 next;
43 if (/^\s*#\s*endif/) {
44 shift @enabled;
45 next;
47 next unless $enabled [0];
48 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
49 my ($sym, $name) = ($1, $2);
50 push @opcodes, [$sym, $name];
51 $table{$name} = {num => $i, name => $name};
52 $i++;
54 close (OPS);
57 sub load_opcodes
59 my ($srcdir, $arch) = @_;
60 my $opcodes_def = "$srcdir/../cil/opcode.def";
61 my $i = 0;
62 my $arch_found = 0;
64 my $cpp = $ENV{"CPP"};
65 $cpp = "cpp" unless defined $cpp;
66 $cpp .= " -undef ";
67 foreach (@defines) {
68 $cpp .= " -U$_";
69 $arch_found = 1 if $arch eq $_;
71 die "$arch arch is not supported.\n" unless $arch_found;
73 my $arch_define = $arch;
74 if ($arch =~ "__i386__") {
75 $arch_define = "TARGET_X86";
77 if ($arch =~ " __x86_64__") {
78 $arch_define = "TARGET_AMD64";
80 if ($arch =~ "__arm__") {
81 $arch_define = "TARGET_ARM";
84 parse_file ($arch_define, "$srcdir/mini-ops.h");
85 return;
86 $cpp .= " -D$arch_define $srcdir/mini-ops.h|";
87 #print "Running: $cpp\n";
88 open (OPS, $cpp) || die "Cannot execute cpp: $!";
89 while (<OPS>) {
90 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
91 my ($sym, $name) = ($1, $2);
92 push @opcodes, [$sym, $name];
93 $table{$name} = {num => $i, name => $name};
94 $i++;
96 close (OPS);
99 sub load_file {
100 my ($name) = @_;
101 my $line = 0;
102 my $comment = "";
104 open (DESC, $name) || die "Cannot open $name: $!";
105 while (<DESC>) {
106 my $is_template = 0;
107 $line++;
108 next if /^\s*$/;
109 if (/^\s*(#.*)?$/) {
110 $comment .= "$1\n";
111 next;
113 my @values = split (/\s+/);
114 next unless ($values [0] =~ /(\S+?):/);
115 my $name = $1;
116 my $desc;
117 if ($name eq "template") {
118 $is_template = 1;
119 $desc = {};
120 } else {
121 $desc = $table {$name};
122 die "Invalid opcode $name at line $line\n" unless defined $desc;
123 die "Duplicated opcode $name at line $line\n" if $desc->{"desc"};
125 shift @values;
126 $desc->{"desc"} = $_;
127 $desc->{"comment"} = $comment;
128 $desc->{"spec"} = {};
129 $comment = "";
130 #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n";
131 for my $val (@values) {
132 if ($val =~ /(\S+):(.*)/) {
133 if ($1 eq "name") {
134 die "name tag only valid in templates at line $line\n" unless $is_template;
135 die "Duplicated name tag in template $desc->{'name'} at line $line\n" if defined $desc->{'name'};
136 die "Duplicated template $2 at line $line\n" if defined $template_table {$2};
137 $desc->{'name'} = $2;
138 $template_table {$2} = $desc;
139 } elsif ($1 eq "template") {
140 my $tdesc = $template_table {$2};
141 die "Invalid template name $2 at line $line\n" unless defined $tdesc;
142 $desc->{"spec"} = {%{$tdesc->{"spec"}}};
143 } else {
144 $desc->{"spec"}->{$1} = $2;
148 die "Template without name at line $1" if ($is_template && !defined ($desc->{'name'}));
150 close (DESC);
153 sub build_spec {
154 my ($spec) = shift;
155 my %spec = %{$spec};
156 my @vals = ();
157 foreach (@spec_names) {
158 my $val = $spec->{$_};
159 if (defined $val) {
160 push @vals, $val;
161 } else {
162 push @vals, undef;
165 #print "vals: " . join (' ', @vals) . "\n";
166 my $res = "";
167 for (my $i = 0; $i < @vals; ++$i) {
168 if (defined $vals [$i]) {
169 if ($i == INST_LEN) {
170 $res .= sprintf ("\\x%x\" \"", +$vals [$i]);
171 } else {
172 if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
173 $res .= $vals [$i];
174 } else {
175 $res .= sprintf ("\\x%x\" \"", $vals [$i]);
178 } else {
179 $res .= "\\x0\" \"";
182 return $res;
185 sub build_table {
186 my ($fname, $name) = @_;
187 my $i;
188 my $idx;
189 my $idx_array = "const guint16 ${name}_idx [] = {\n";
191 open (OUT, ">$fname") || die "Cannot open file $fname: $!";
192 print OUT "/* File automatically generated by genmdesc, don't change */\n\n";
193 print OUT "const char $name [] = {\n";
194 print OUT "\t\"" . ("\\x0" x INST_MAX) . "\"\t/* null entry */\n";
195 $idx = 1;
197 for ($i = 0; $i < @opcodes; ++$i) {
198 my $name = $opcodes [$i]->[1];
199 my $desc = $table {$name};
200 my $spec = $desc->{"spec"};
201 if (defined $spec) {
202 print OUT "\t\"";
203 print OUT build_spec ($spec);
204 print OUT "\"\t/* $name */\n";
205 my $pos = $idx * INST_MAX;
206 $idx_array .= "\t$pos,\t/* $name */\n";
207 ++$idx;
208 } else {
209 $idx_array .= "\t0,\t/* $name */\n";
212 print OUT "};\n\n";
213 print OUT "$idx_array};\n\n";
214 close (OUT);
217 sub usage {
218 die "genmdesc.pl arch srcdir output name desc [desc2 ...]\n";
221 my $arch = shift || usage ();
222 my $srcdir = shift || usage ();
223 my $output = shift || usage ();
224 my $name = shift || usage ();
225 usage () unless @ARGV;
226 my @files = @ARGV;
228 load_opcodes ($srcdir, $arch);
229 foreach my $file (@files) {
230 load_file ($file);
232 build_table ($output, $name);