2009-05-05 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / genmdesc.pl
1 #!/usr/bin/perl -w
2
3 # perl replacement of genmdesc.c for use when cross-compiling
4
5 use strict;
6 no locale;
7
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;}
17
18 # this must include all the #defines used in mini-ops.h
19 my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __arm__ 
20         __sparc__ sparc __s390__ s390 __ia64__ __alpha__ __mips__);
21 my %table =();
22 my @opcodes = ();
23
24 sub load_opcodes
25 {
26         my ($srcdir, $arch) = @_;
27         my $opcodes_def = "$srcdir/../cil/opcode.def";
28         my $i = 0;
29         my $arch_found = 0;
30
31         my $cpp = $ENV{"CPP"};
32         $cpp = "cpp" unless defined $cpp;
33         $cpp .= " -undef ";
34         foreach (@defines) {
35                 $cpp .= " -U$_";
36                 $arch_found = 1 if $arch eq $_;
37         }
38         die "$arch arch is not supported.\n" unless $arch_found;
39
40         my $arch_define = $arch;
41         if ($arch =~ "__i386__") {
42                 $arch_define = "TARGET_X86";
43         }
44         if ($arch =~ " __x86_64__") {
45                 $arch_define = "TARGET_AMD64";
46         }
47         if ($arch =~ "__arm__") {
48                 $arch_define = "TARGET_ARM";
49         }
50                 
51         $cpp .= " -D$arch_define $srcdir/mini-ops.h|";
52         #print "Running: $cpp\n";
53         open (OPS, $cpp) || die "Cannot execute cpp: $!";
54         while (<OPS>) {
55                 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
56                 my ($sym, $name) = ($1, $2);
57                 push @opcodes, [$sym, $name];
58                 $table{$name} = {num => $i, name => $name};
59                 $i++;
60         }
61         close (OPS);
62 }
63
64 sub load_file {
65         my ($name) = @_;
66         my $line = 0;
67         my $comment = "";
68
69         open (DESC, $name) || die "Cannot open $name: $!";
70         while (<DESC>) {
71                 $line++;
72                 next if /^\s*$/;
73                 if (/^\s*(#.*)?$/) {
74                         $comment .= "$1\n";
75                         next;
76                 }
77                 my @values = split (/\s+/);
78                 next unless ($values [0] =~ /(\S+?):/);
79                 my $name = $1;
80                 my $desc = $table {$name};
81                 shift @values;
82                 die "Invalid opcode $name at line $line\n" unless defined $desc;
83                 die "Duplicated opcode $name at line $line\n" if $desc->{"desc"};
84                 $desc->{"desc"} = $_;
85                 $desc->{"comment"} = $comment;
86                 $desc->{"spec"} = {};
87                 $comment = "";
88                 #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n";
89                 for my $val (@values) {
90                         if ($val =~ /(\S+):(.*)/) {
91                                 $desc->{"spec"}->{$1} = $2;
92                         }
93                 }
94         }
95         close (DESC);
96 }
97
98 sub build_spec {
99         my ($spec) = shift;
100         my %spec = %{$spec};
101         my @vals = ();
102         foreach (@spec_names) {
103                 my $val = $spec->{$_};
104                 if (defined $val) {
105                         push @vals, $val;
106                 } else {
107                         push @vals, undef;
108                 }
109         }
110         #print "vals: " . join (' ', @vals) . "\n";
111         my $res = "";
112         for (my $i = 0; $i < @vals; ++$i) {
113                 if (defined $vals [$i]) {
114                         if ($i == INST_LEN) {
115                                 $res .= sprintf ("\\x%x\" \"", +$vals [$i]);
116                         } else {
117                                 if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
118                                         $res .= $vals [$i];
119                                 } else {
120                                         $res .= sprintf ("\\x%x\" \"", $vals [$i]);
121                                 }
122                         }
123                 } else {
124                         $res .= "\\x0\" \"";
125                 }
126         }
127         return $res;
128 }
129
130 sub build_table {
131         my ($fname, $name) = @_;
132         my $i;
133         my $idx;
134         my $idx_array = "const guint16 ${name}_idx [] = {\n";
135
136         open (OUT, ">$fname") || die "Cannot open file $fname: $!";
137         print OUT "/* File automatically generated by genmdesc, don't change */\n\n";
138         print OUT "const char $name [] = {\n";
139         print OUT "\t\"" . ("\\x0" x INST_MAX) . "\"\t/* null entry */\n";
140         $idx = 1;
141
142         for ($i = 0; $i < @opcodes; ++$i) {
143                 my $name = $opcodes [$i]->[1];
144                 my $desc = $table {$name};
145                 my $spec = $desc->{"spec"};
146                 if (defined $spec) {
147                         print OUT "\t\"";
148                         print OUT build_spec ($spec);
149                         print OUT "\"\t/* $name */\n";
150                         my $pos = $idx * INST_MAX;
151                         $idx_array .= "\t$pos,\t/* $name */\n";
152                         ++$idx;
153                 } else {
154                         $idx_array .= "\t0,\t/* $name */\n";
155                 }
156         }
157         print OUT "};\n\n";
158         print OUT "$idx_array};\n\n";
159         close (OUT);
160 }
161
162 sub usage {
163         die "genmdesc.pl arch srcdir output name desc [desc2 ...]\n";
164 }
165
166 my $arch = shift || usage ();
167 my $srcdir = shift || usage ();
168 my $output = shift || usage ();
169 my $name = shift || usage ();
170 usage () unless @ARGV;
171 my @files = @ARGV;
172
173 load_opcodes ($srcdir, $arch);
174 foreach my $file (@files) {
175         load_file ($file);
176 }
177 build_table ($output, $name);
178