Thu Jan 18 11:50:13 CET 2007 Paolo Molaro <lupus@ximian.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 flags clob cost delay res len);
10 sub INST_DEST  () {return 0;}
11 sub INST_SRC1  () {return 1;}
12 sub INST_SRC2  () {return 2;}
13 sub INST_FLAGS () {return 3;}
14 sub INST_CLOB  () {return 4;}
15 sub INST_COST  () {return 5;}
16 sub INST_DELAY () {return 6;}
17 sub INST_RES   () {return 7;}
18 sub INST_LEN   () {return 8;}
19 sub INST_MAX   () {return 9;}
20
21 # this must include all the #defines used in mini-ops.h
22 my @defines = qw (__i386__ __x86_64__ __ppc__ __powerpc__ __arm__ 
23         __sparc__ sparc __s390__ s390 __ia64__ __alpha__ __mips__);
24 my %table =();
25 my @opcodes = ();
26
27 sub load_opcodes
28 {
29         my ($srcdir, $arch) = @_;
30         my $opcodes_def = "$srcdir/../cil/opcode.def";
31         my $i = 0;
32         my $arch_found = 0;
33
34         open (OPS, "$opcodes_def") || die "Cannot open $opcodes_def: $!";
35         while (<OPS>) {
36                 next unless /OPDEF\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
37                 my ($sym, $name) = ($1, $2);
38                 push @opcodes, [$sym, $name];
39                 $table{$name} = {num => $i, name => $name};
40                 $i++;
41         }
42         close (OPS);
43         my $cpp = "cpp -undef ";
44         foreach (@defines) {
45                 $cpp .= " -U$_";
46                 $arch_found = 1 if $arch eq $_;
47         }
48         die "$arch arch is not supported.\n" unless $arch_found;
49
50         $cpp .= " -D$arch $srcdir/mini-ops.h|";
51         #print "Running: $cpp\n";
52         open (OPS, $cpp) || die "Cannot execute cpp: $!";
53         while (<OPS>) {
54                 next unless /MINI_OP\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
55                 my ($sym, $name) = ($1, $2);
56                 push @opcodes, [$sym, $name];
57                 $table{$name} = {num => $i, name => $name};
58                 $i++;
59         }
60         close (OPS);
61 }
62
63 sub load_file {
64         my ($name) = @_;
65         my $line = 0;
66         my $comment = "";
67
68         open (DESC, $name) || die "Cannot open $name: $!";
69         while (<DESC>) {
70                 $line++;
71                 next if /^\s*$/;
72                 if (/^\s*(#.*)?$/) {
73                         $comment .= "$1\n";
74                         next;
75                 }
76                 my @values = split (/\s+/);
77                 next unless ($values [0] =~ /(\S+?):/);
78                 my $name = $1;
79                 my $desc = $table {$name};
80                 shift @values;
81                 die "Invalid opcode $name at line $line\n" unless defined $desc;
82                 die "Duplicated opcode $name at line $line\n" if $desc->{"desc"};
83                 $desc->{"desc"} = $_;
84                 $desc->{"comment"} = $comment;
85                 $desc->{"spec"} = {};
86                 $comment = "";
87                 #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n";
88                 for my $val (@values) {
89                         if ($val =~ /(\S+):(.*)/) {
90                                 $desc->{"spec"}->{$1} = $2;
91                         }
92                 }
93         }
94         close (DESC);
95 }
96
97 sub build_spec {
98         my ($spec) = shift;
99         my %spec = %{$spec};
100         my @vals = ();
101         foreach (@spec_names) {
102                 my $val = $spec->{$_};
103                 if (defined $val) {
104                         push @vals, $val;
105                 } else {
106                         push @vals, undef;
107                 }
108         }
109         #print "vals: " . join (' ', @vals) . "\n";
110         my $res = "";
111         for (my $i = 0; $i < @vals; ++$i) {
112                 if (defined $vals [$i]) {
113                         if ($i == INST_LEN) {
114                                 $res .= sprintf ("\\x%x\" \"", +$vals [$i]);
115                         } else {
116                                 if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
117                                         $res .= $vals [$i];
118                                 } else {
119                                         $res .= sprintf ("\\x%x\" \"", $vals [$i]);
120                                 }
121                         }
122                 } else {
123                         $res .= "\\x0\" \"";
124                 }
125         }
126         return $res;
127 }
128
129 sub build_table {
130         my ($fname, $name) = @_;
131         my $i;
132
133         open (OUT, ">$fname") || die "Cannot open file $fname: $!";
134         print OUT "/* File automatically generated by genmdesc, don't change */\n\n";
135         print OUT "const char * const $name [OP_LAST] = {\n";
136
137         for ($i = 0; $i < @opcodes; ++$i) {
138                 my $name = $opcodes [$i]->[1];
139                 my $desc = $table {$name};
140                 my $spec = $desc->{"spec"};
141                 if (defined $spec) {
142                         print OUT "\t\"";
143                         print OUT build_spec ($spec);
144                         print OUT "\",\t/* $name */\n";
145                 } else {
146                         print OUT "\tNULL,\t/* $name */\n";
147                 }
148         }
149         print OUT "};\n\n";
150         close (OUT);
151 }
152
153 sub usage {
154         die "genmdesc.pl arch srcdir desc output name\n";
155 }
156
157 my $arch = shift || usage ();
158 my $srcdir = shift || usage ();
159 my $file = shift || usage ();
160 my $output = shift || usage ();
161 my $name = shift || usage ();
162
163 load_opcodes ($srcdir, $arch);
164 load_file ($file);
165 build_table ($output, $name);
166