we don't need no stinking selfs
[libfirm] / ir / be / scripts / generate_regalloc_if.pl
1 #!/usr/bin/perl -w
2
3 #
4 # Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
5 #
6 # This file is part of libFirm.
7 #
8 # This file may be distributed and/or modified under the terms of the
9 # GNU General Public License version 2 as published by the Free Software
10 # Foundation and appearing in the file LICENSE.GPL included in the
11 # packaging of this file.
12 #
13 # Licensees holding valid libFirm Professional Edition licenses may use
14 # this file in accordance with the libFirm Commercial License.
15 # Agreement provided with the Software.
16 #
17 # This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 # WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE.
20 #
21
22 # This script generates C code which creates ands sets up functions and
23 # data structures for the register allocator.
24 # Creation: 2005/11/14
25 # $Id$
26
27 use strict;
28 use Data::Dumper;
29 use integer;
30
31 my $specfile   = $ARGV[0];
32 my $target_dir = $ARGV[1];
33
34 our $arch;
35 our %reg_classes;
36 our %cpu;
37
38 # include spec file
39
40 my $return;
41
42 use strict "subs";
43 unless ($return = do $specfile) {
44         die "Fatal error: couldn't parse $specfile: $@" if $@;
45         die "Fatal error: couldn't do $specfile: $!"    unless defined $return;
46         die "Fatal error: couldn't run $specfile"       unless $return;
47 }
48 use strict "subs";
49
50 my $target_c   = $target_dir."/gen_".$arch."_regalloc_if.c";
51 my $target_h   = $target_dir."/gen_".$arch."_regalloc_if.h";
52
53 # helper function
54 sub translate_reg_type {
55         my $t = shift;
56
57         if ($t == 0) {
58                 return "arch_register_type_none";
59         }
60         else {
61                 my @types;
62
63                 if ($t & 1) {
64                         push(@types, "arch_register_type_caller_save");
65                 }
66
67                 if ($t & 2) {
68                         push(@types, "arch_register_type_callee_save");
69                 }
70
71                 if ($t & 4) {
72                         push(@types, "arch_register_type_ignore");
73                 }
74
75                 if ($t & 8) {
76                         push(@types, "arch_register_type_joker");
77                 }
78
79                 if ($t & 16) {
80                         push(@types, "arch_register_type_virtual");
81                 }
82
83                 if ($t & 32) {
84                         push(@types, "arch_register_type_state");
85                 }
86
87                 return join(" | ", @types);
88         }
89 }
90
91 # stacks for output
92 my @obst_regtypes_def; # stack for the register type variables definitions
93 my @obst_regtypes_decl;# stack for the register type variables declarations
94 my @obst_regclasses;   # stack for the register class variables
95 my @obst_classdef;     # stack to define a name for a class index
96 my @obst_regdef;       # stack to define a name for a register index
97 my @obst_reginit;      # stack for the register type inits
98 my @obst_req;          # stack for the register requirements
99 my @obst_limit_func;   # stack for functions to return a subset of a register class
100 my @obst_header_all;   # stack for some extern struct defs needed for bearch_$arch include
101
102 my $numregs;
103 my $class_ptr;
104 my $class_idx = 0;
105
106 my $tmp;
107
108 my %reg2class;
109 my %regclass2len;
110
111 push(@obst_classdef, "enum reg_classes {\n");
112
113 my $class_mode;
114
115 # generate register type and class variable, init function and default requirements
116 foreach my $class_name (keys(%reg_classes)) {
117         my @class         = @{ $reg_classes{"$class_name"} };
118         my $old_classname = $class_name;
119
120         $class_name = $arch."_".$class_name;
121         $numregs    = "N_".$class_name."_REGS";
122         $class_ptr  = "&".$arch."_reg_classes[CLASS_".$class_name."]";
123         my $flags = pop(@class);
124         $class_mode  = $flags->{"mode"};
125         my $class_flags = $flags->{"flags"};
126         my $flags_prepared = "";
127
128         if(defined($class_flags)) {
129                 my $first = 1;
130                 foreach my $flag (split(/\|/, $class_flags)) {
131                         if(!$first) {
132                                 $flags_prepared .= "|";
133                         } else {
134                                 $first = 0;
135                         }
136                         $flags_prepared .= "arch_register_class_flag_$flag";
137                 }
138         } else {
139                 $flags_prepared = "0";
140         }
141
142         push(@obst_regtypes_decl, "extern const arch_register_t ${class_name}_regs[$numregs];\n");
143
144         push(@obst_classdef, "\tCLASS_$class_name = $class_idx,\n");
145         push(@obst_regclasses, "{ $class_idx, \"$class_name\", $numregs, NULL, ".$class_name."_regs, $flags_prepared }");
146
147         my $idx = 0;
148         push(@obst_reginit, "\t/* set largest possible mode for '$class_name' */\n");
149         push(@obst_reginit, "\t$arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n\n");
150         push(@obst_regtypes_def, "const arch_register_t ${class_name}_regs[$numregs] = {\n");
151
152         push(@obst_regdef, "enum reg_${class_name}_indices {\n");
153         foreach (@class) {
154                 my $ucname = uc($_->{"name"});
155                 my $type = translate_reg_type($_->{"type"});
156                 # realname is name if not set by user
157                 $_->{"realname"} = $_->{"name"} if (! exists($_->{"realname"}));
158                 my $realname = $_->{realname};
159                 my $execunitvarname = get_execunit_variable_name($_->{"unit"});
160
161
162                 $reg2class{$_->{"name"}} = { "class" => $old_classname, "index" => $idx }; # remember reg to class for later use
163                 push(@obst_regdef, "\tREG_${ucname},\n");
164
165                 push(@obst_regtypes_def, "\t{\n");
166                 push(@obst_regtypes_def, "\t\t\"$realname\",\n");
167                 push(@obst_regtypes_def, "\t\t$class_ptr,\n");
168                 push(@obst_regtypes_def, "\t\tREG_${ucname},\n");
169                 push(@obst_regtypes_def, "\t\t$type,\n");
170                 push(@obst_regtypes_def, "\t\t$execunitvarname\n");
171                 push(@obst_regtypes_def, "\t},\n");
172
173                 $idx++;
174         }
175         push(@obst_regtypes_def, "};\n");
176
177         $regclass2len{$old_classname} = $idx;
178         push(@obst_regdef, "\t$numregs = $idx\n");
179         push(@obst_regdef, "};\n\n");
180
181         $class_idx++;
182 }
183
184 push(@obst_classdef, "\tN_CLASSES = ".scalar(keys(%reg_classes))."\n");
185 push(@obst_classdef, "};\n\n");
186
187 $tmp = uc($arch);
188
189 # generate header (external usage) file
190 open(OUT, ">$target_h") || die("Fatal error: Could not open $target_h, reason: $!\n");
191
192 my $creation_time = localtime(time());
193
194 print OUT<<EOF;
195 /**
196  * \@file
197  * \@brief Contains additional external requirements defs for external includes.
198  * \@note   DO NOT EDIT THIS FILE, your changes will be lost.
199  *         Edit $specfile instead.
200  *         created by: $0 $specfile $target_dir
201  * \@date   $creation_time
202  */
203 #ifndef FIRM_BE_${tmp}_GEN_${tmp}_REGALLOC_IF_H
204 #define FIRM_BE_${tmp}_GEN_${tmp}_REGALLOC_IF_H
205
206 #include "../bearch.h"
207 #include "${arch}_nodes_attr.h"
208
209 EOF
210
211 print OUT @obst_regdef, "\n";
212
213 print OUT @obst_classdef, "\n";
214
215 print OUT @obst_regtypes_decl, "\n";
216
217 print OUT "extern arch_register_class_t $arch\_reg_classes[N_CLASSES];\n\n";
218
219 print OUT "void ".$arch."_register_init(void);\n\n";
220
221 print OUT @obst_header_all, "\n";
222
223 print OUT "\n#endif\n";
224
225 close(OUT);
226
227
228
229 # generate c file
230 open(OUT, ">$target_c") || die("Fatal error: Could not open $target_c, reason: $!\n");
231
232 $creation_time = localtime(time());
233
234 print OUT<<EOF;
235 /**
236  * \@file
237  * \@brief  The generated interface for the register allocator.
238  *          Contains register classes and types and register constraints
239  *          for all nodes where constraints were given in spec.
240  * \@note    DO NOT EDIT THIS FILE, your changes will be lost.
241  *          Edit $specfile instead.
242  *          created by: $0 $specfile $target_dir
243  * \$date    $creation_time
244  */
245 #ifdef HAVE_CONFIG_H
246 #include "config.h"
247 #endif
248
249 #include "gen_${arch}_regalloc_if.h"
250 #include "gen_${arch}_machine.h"
251 #include "bearch_${arch}_t.h"
252 #include "${arch}_map_regs.h"
253 #include "irmode.h"
254
255 EOF
256
257 print OUT "arch_register_class_t ${arch}_reg_classes[] = {\n\t".join(",\n\t", @obst_regclasses)."\n};\n\n";
258
259 print OUT @obst_regtypes_def, "\n";
260
261 print OUT "void ${arch}_register_init(void) {\n";
262 print OUT @obst_reginit;
263 print OUT "}\n\n";
264
265 print OUT @obst_limit_func;
266
267 print OUT @obst_req;
268
269 close(OUT);
270
271 ###
272 # Gets the variable name for the execution unit assigned to this register.
273 ###
274 sub get_execunit_variable_name {
275         my $unit    = shift;
276         my $name    = "NULL";
277         my $uc_arch = uc($arch);
278
279         if ($unit) {
280                 my $found = 0;
281 SRCH:   foreach my $cur_type (keys(%cpu)) {
282                         foreach my $cur_unit (@{ $cpu{"$cur_type"} }) {
283                                 if ($unit eq $cur_unit) {
284                                         my $tp_name   = "$arch\_execution_units_$cur_type";
285                                         my $unit_name = "$uc_arch\_EXECUNIT_TP_$cur_type\_$unit";
286                                         $name  = "&".$tp_name."[".$unit_name."]";
287                                         $found = 1;
288                                         last SRCH;
289                                 }
290                         }
291                 }
292
293                 if (! $found) {
294                         print STDERR "Invalid execution unit $unit specified!\n";
295                 }
296         }
297
298         return $name;
299 }