ef316ef6e1ccb904c7800e5fd28b897e72cf037c
[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         $cpp .= " -D$arch $srcdir/mini-ops.h|";
41         #print "Running: $cpp\n";
42         open (OPS, $cpp) || die "Cannot execute cpp: $!";
43         while (<OPS>) {
44                 next unless /MINI_OP3?\s*\(\s*(\S+?)\s*,\s*"(.*?)"/;
45                 my ($sym, $name) = ($1, $2);
46                 push @opcodes, [$sym, $name];
47                 $table{$name} = {num => $i, name => $name};
48                 $i++;
49         }
50         close (OPS);
51 }
52
53 sub load_file {
54         my ($name) = @_;
55         my $line = 0;
56         my $comment = "";
57
58         open (DESC, $name) || die "Cannot open $name: $!";
59         while (<DESC>) {
60                 $line++;
61                 next if /^\s*$/;
62                 if (/^\s*(#.*)?$/) {
63                         $comment .= "$1\n";
64                         next;
65                 }
66                 my @values = split (/\s+/);
67                 next unless ($values [0] =~ /(\S+?):/);
68                 my $name = $1;
69                 my $desc = $table {$name};
70                 shift @values;
71                 die "Invalid opcode $name at line $line\n" unless defined $desc;
72                 die "Duplicated opcode $name at line $line\n" if $desc->{"desc"};
73                 $desc->{"desc"} = $_;
74                 $desc->{"comment"} = $comment;
75                 $desc->{"spec"} = {};
76                 $comment = "";
77                 #print "values for $name: " . join (' ', @values) . " num: " . int(@values), "\n";
78                 for my $val (@values) {
79                         if ($val =~ /(\S+):(.*)/) {
80                                 $desc->{"spec"}->{$1} = $2;
81                         }
82                 }
83         }
84         close (DESC);
85 }
86
87 sub build_spec {
88         my ($spec) = shift;
89         my %spec = %{$spec};
90         my @vals = ();
91         foreach (@spec_names) {
92                 my $val = $spec->{$_};
93                 if (defined $val) {
94                         push @vals, $val;
95                 } else {
96                         push @vals, undef;
97                 }
98         }
99         #print "vals: " . join (' ', @vals) . "\n";
100         my $res = "";
101         for (my $i = 0; $i < @vals; ++$i) {
102                 if (defined $vals [$i]) {
103                         if ($i == INST_LEN) {
104                                 $res .= sprintf ("\\x%x\" \"", +$vals [$i]);
105                         } else {
106                                 if ($vals [$i] =~ /^[a-zA-Z0-9]$/) {
107                                         $res .= $vals [$i];
108                                 } else {
109                                         $res .= sprintf ("\\x%x\" \"", $vals [$i]);
110                                 }
111                         }
112                 } else {
113                         $res .= "\\x0\" \"";
114                 }
115         }
116         return $res;
117 }
118
119 sub build_table {
120         my ($fname, $name) = @_;
121         my $i;
122         my $idx;
123         my $idx_array = "const guint16 ${name}_idx [] = {\n";
124
125         open (OUT, ">$fname") || die "Cannot open file $fname: $!";
126         print OUT "/* File automatically generated by genmdesc, don't change */\n\n";
127         print OUT "const char $name [] = {\n";
128         print OUT "\t\"" . ("\\x0" x INST_MAX) . "\"\t/* null entry */\n";
129         $idx = 1;
130
131         for ($i = 0; $i < @opcodes; ++$i) {
132                 my $name = $opcodes [$i]->[1];
133                 my $desc = $table {$name};
134                 my $spec = $desc->{"spec"};
135                 if (defined $spec) {
136                         print OUT "\t\"";
137                         print OUT build_spec ($spec);
138                         print OUT "\"\t/* $name */\n";
139                         my $pos = $idx * INST_MAX;
140                         $idx_array .= "\t$pos,\t/* $name */\n";
141                         ++$idx;
142                 } else {
143                         $idx_array .= "\t0,\t/* $name */\n";
144                 }
145         }
146         print OUT "};\n\n";
147         print OUT "$idx_array};\n\n";
148         close (OUT);
149 }
150
151 sub usage {
152         die "genmdesc.pl arch srcdir output name desc [desc2 ...]\n";
153 }
154
155 my $arch = shift || usage ();
156 my $srcdir = shift || usage ();
157 my $output = shift || usage ();
158 my $name = shift || usage ();
159 usage () unless @ARGV;
160 my @files = @ARGV;
161
162 load_opcodes ($srcdir, $arch);
163 foreach my $file (@files) {
164         load_file ($file);
165 }
166 build_table ($output, $name);
167