change backend node specification to use whole words instead of cryptical 1-char...
[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 $regtypes_def; # stack for the register type variables definitions
93 my $regtypes_decl;# stack for the register type variables declarations
94 my @regclasses;   # stack for the register class variables
95 my $classdef;     # stack to define a name for a class index
96 my $regdef;       # stack to define a name for a register index
97 my $reginit;      # stack for the register type inits
98 my $single_constraints_decls;
99 my $single_constraints;
100
101 my $numregs;
102 my $class_ptr;
103 my $class_idx = 0;
104
105 my $tmp;
106
107 my %regclass2len = ();
108 my %reg2class = ();
109
110 $classdef .= "enum reg_classes {\n";
111
112 my $class_mode;
113
114 foreach my $class_name (keys(%reg_classes)) {
115         my @class = @{ $reg_classes{"$class_name"} };
116
117         my $idx = 0;
118         foreach (@class) {
119                 if (defined($_->{name})) {
120                         $reg2class{$_->{name}} = {
121                                 "class" => $class_name,
122                                 "index" => $idx
123                         };
124                 }
125                 $idx++;
126         }
127         $regclass2len{$class_name} = $idx;
128 }
129
130 sub get_limited_array {
131         my $reg      = shift;
132         my $regclass = $reg2class{"$reg"}{"class"};
133         my $ucname   = uc($reg);
134         my $result   = "{ ";
135
136         my $limitedbitsetlen = $regclass2len{$regclass};
137         my $arraylen         = ($limitedbitsetlen+31) / 32;
138         my $first            = 1;
139         for (my $i = 0; $i < $arraylen; ++$i) {
140                 if ($first) {
141                         $first = 0;
142                 } else {
143                         $result .= ", ";
144                 }
145
146                 my $index = $reg2class{"$reg"}{"index"};
147                 if ($index >= $i*32 && $index < ($i+1)*32) {
148                         if ($i > 0) {
149                                 $result .= "(1 << (REG_${ucname} % 32))";
150                         } else {
151                                 $result .= "(1 << REG_${ucname})";
152                         }
153                 } else {
154                         $result .= "0";
155                 }
156         }
157         $result .= " }";
158 }
159
160 # generate register type and class variable, init function and default requirements
161 foreach my $class_name (keys(%reg_classes)) {
162         my @class         = @{ $reg_classes{"$class_name"} };
163         my $old_classname = $class_name;
164
165         $class_name = $arch."_".$class_name;
166         $numregs    = "N_".$class_name."_REGS";
167         $class_ptr  = "&".$arch."_reg_classes[CLASS_".$class_name."]";
168         my $flags = pop(@class);
169         $class_mode  = $flags->{"mode"};
170         my $class_flags = $flags->{"flags"};
171         my $flags_prepared = "";
172
173         if(defined($class_flags)) {
174                 my $first = 1;
175                 foreach my $flag (split(/\|/, $class_flags)) {
176                         if(!$first) {
177                                 $flags_prepared .= "|";
178                         } else {
179                                 $first = 0;
180                         }
181                         $flags_prepared .= "arch_register_class_flag_$flag";
182                 }
183         } else {
184                 $flags_prepared = "0";
185         }
186
187         $single_constraints_decls .= <<EOF;
188 static const arch_register_req_t ${arch}_class_reg_req_${old_classname};
189 EOF
190
191         $single_constraints .= <<EOF;
192 static const arch_register_req_t ${arch}_class_reg_req_${old_classname} = {
193         arch_register_req_type_normal,
194         &${arch}_reg_classes[CLASS_${arch}_${old_classname}],
195         NULL,
196         0,
197         0
198 };
199 EOF
200
201         $regtypes_decl .= "extern const arch_register_t ${class_name}_regs[$numregs];\n";
202
203         $classdef .= "\tCLASS_$class_name = $class_idx,\n";
204         push(@regclasses, "{ $class_idx, \"$class_name\", $numregs, NULL, ".$class_name."_regs, $flags_prepared, &${arch}_class_reg_req_${old_classname} }");
205
206         my $idx = 0;
207         $reginit .= "\t$arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n";
208         $regtypes_def .= "const arch_register_t ${class_name}_regs[$numregs] = {\n";
209
210         $regdef .= "enum reg_${class_name}_indices {\n";
211         foreach (@class) {
212                 my $name = $_->{"name"};
213                 my $ucname = uc($name);
214                 my $type = translate_reg_type($_->{"type"});
215                 # realname is name if not set by user
216                 $_->{"realname"} = $_->{"name"} if (! exists($_->{"realname"}));
217                 my $realname = $_->{realname};
218
219                 $regdef .= "\tREG_${ucname},\n";
220
221                 $regtypes_def .= <<EOF;
222         {
223                 "${realname}",
224                 ${class_ptr},
225                 REG_${ucname},
226                 ${type},
227                 &${arch}_single_reg_req_${old_classname}_${name}
228         },
229 EOF
230
231                 my $limitedarray = get_limited_array($name);
232                 $single_constraints .= <<EOF;
233 static const unsigned ${arch}_limited_${old_classname}_${name} [] = ${limitedarray};
234 static const arch_register_req_t ${arch}_single_reg_req_${old_classname}_${name} = {
235         arch_register_req_type_limited,
236         ${class_ptr},
237         ${arch}_limited_${old_classname}_${name},
238         0,
239         0
240 };
241 EOF
242
243                 $idx++;
244         }
245         $regtypes_def .= "};\n";
246
247         $regdef .= "\t$numregs = $idx\n";
248         $regdef .= "};\n\n";
249
250         $class_idx++;
251 }
252
253 $classdef .= "\tN_CLASSES = ".scalar(keys(%reg_classes))."\n";
254 $classdef .= "};\n\n";
255
256 $tmp = uc($arch);
257
258 # generate header (external usage) file
259 open(OUT, ">$target_h") || die("Fatal error: Could not open $target_h, reason: $!\n");
260
261 my $creation_time = localtime(time());
262
263 print OUT<<EOF;
264 /**
265  * \@file
266  * \@brief Contains additional external requirements defs for external includes.
267  * \@note   DO NOT EDIT THIS FILE, your changes will be lost.
268  *         Edit $specfile instead.
269  *         created by: $0 $specfile $target_dir
270  * \@date   $creation_time
271  */
272 #ifndef FIRM_BE_${tmp}_GEN_${tmp}_REGALLOC_IF_H
273 #define FIRM_BE_${tmp}_GEN_${tmp}_REGALLOC_IF_H
274
275 #include "../bearch.h"
276 #include "${arch}_nodes_attr.h"
277
278 ${regdef}
279 ${classdef}
280 ${regtypes_decl}
281
282 extern arch_register_class_t ${arch}_reg_classes[N_CLASSES];
283
284 void ${arch}_register_init(void);
285 unsigned ${arch}_get_n_regs(void);
286
287 #endif
288 EOF
289 close(OUT);
290
291
292 # generate c file
293 open(OUT, ">$target_c") || die("Fatal error: Could not open $target_c, reason: $!\n");
294
295 $creation_time = localtime(time());
296
297 print OUT<<EOF;
298 /**
299  * \@file
300  * \@brief  The generated interface for the register allocator.
301  *          Contains register classes and types and register constraints
302  *          for all nodes where constraints were given in spec.
303  * \@note    DO NOT EDIT THIS FILE, your changes will be lost.
304  *          Edit $specfile instead.
305  *          created by: $0 $specfile $target_dir
306  * \$date    $creation_time
307  */
308 #include "config.h"
309
310 #include "gen_${arch}_regalloc_if.h"
311 #include "gen_${arch}_machine.h"
312 #include "bearch_${arch}_t.h"
313 #include "irmode.h"
314
315 ${single_constraints_decls}
316 EOF
317
318 print OUT "arch_register_class_t ${arch}_reg_classes[] = {\n\t".join(",\n\t", @regclasses)."\n};\n\n";
319
320 print OUT<<EOF;
321 ${single_constraints}
322 ${regtypes_def}
323
324 void ${arch}_register_init(void)
325 {
326 ${reginit}
327 }
328 EOF
329 close(OUT);
330
331 ###
332 # Gets the variable name for the execution unit assigned to this register.
333 ###
334 sub get_execunit_variable_name {
335         my $unit    = shift;
336         my $name    = "NULL";
337         my $uc_arch = uc($arch);
338
339         if ($unit) {
340                 my $found = 0;
341 SRCH:   foreach my $cur_type (keys(%cpu)) {
342                         foreach my $cur_unit (@{ $cpu{"$cur_type"} }) {
343                                 if ($unit eq $cur_unit) {
344                                         my $tp_name   = "$arch\_execution_units_$cur_type";
345                                         my $unit_name = "$uc_arch\_EXECUNIT_TP_$cur_type\_$unit";
346                                         $name  = "&".$tp_name."[".$unit_name."]";
347                                         $found = 1;
348                                         last SRCH;
349                                 }
350                         }
351                 }
352
353                 if (! $found) {
354                         print STDERR "Invalid execution unit $unit specified!\n";
355                 }
356         }
357
358         return $name;
359 }