generate_regalloc_if.pl 8.8 KB
Newer Older
1
2
#!/usr/bin/perl -w

Christian Würdig's avatar
Christian Würdig committed
3
#
Michael Beck's avatar
Michael Beck committed
4
# Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#
# This file is part of libFirm.
#
# This file may be distributed and/or modified under the terms of the
# GNU General Public License version 2 as published by the Free Software
# Foundation and appearing in the file LICENSE.GPL included in the
# packaging of this file.
#
# Licensees holding valid libFirm Professional Edition licenses may use
# this file in accordance with the libFirm Commercial License.
# Agreement provided with the Software.
#
# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE.
#

Christian Würdig's avatar
Christian Würdig committed
22
23
# This script generates C code which creates ands sets up functions and
# data structures for the register allocator.
24
25
26
27
28
# Creation: 2005/11/14
# $Id$

use strict;
use Data::Dumper;
Matthias Braun's avatar
Matthias Braun committed
29
use integer;
30
31
32
33
34
35

my $specfile   = $ARGV[0];
my $target_dir = $ARGV[1];

our $arch;
our %reg_classes;
36
our %cpu;
37
38
39
40
41

# include spec file

my $return;

Matthias Braun's avatar
Matthias Braun committed
42
use strict "subs";
43
unless ($return = do $specfile) {
44
45
46
	die "Fatal error: couldn't parse $specfile: $@" if $@;
	die "Fatal error: couldn't do $specfile: $!"    unless defined $return;
	die "Fatal error: couldn't run $specfile"       unless $return;
47
48
49
}
use strict "subs";

Christian Würdig's avatar
Christian Würdig committed
50
51
my $target_c   = $target_dir."/gen_".$arch."_regalloc_if.c";
my $target_h   = $target_dir."/gen_".$arch."_regalloc_if.h";
52

53
54
55
56
57
58
59
60
61
62
63
64
65
66
# helper function
sub translate_reg_type {
	my $t = shift;

	if ($t == 0) {
		return "arch_register_type_none";
	}
	else {
		my @types;

		if ($t & 1) {
			push(@types, "arch_register_type_ignore");
		}

67
		if ($t & 2) {
68
69
70
			push(@types, "arch_register_type_joker");
		}

71
		if ($t & 4) {
72
73
74
			push(@types, "arch_register_type_virtual");
		}

75
		if ($t & 8) {
Matthias Braun's avatar
Matthias Braun committed
76
77
78
			push(@types, "arch_register_type_state");
		}

79
80
81
		return join(" | ", @types);
	}
}
82
83

# stacks for output
84
85
86
87
88
my $regtypes_def; # stack for the register type variables definitions
my $regtypes_decl;# stack for the register type variables declarations
my @regclasses;   # stack for the register class variables
my $classdef;     # stack to define a name for a class index
my $regdef;       # stack to define a name for a register index
89
90
my $regdef2;
my $regcounts;
91
92
93
my $reginit;      # stack for the register type inits
my $single_constraints_decls;
my $single_constraints;
94

Christian Würdig's avatar
Christian Würdig committed
95
my $class_ptr;
96
97
my $class_idx = 0;

98
99
my %regclass2len = ();
my %reg2class = ();
Christian Würdig's avatar
Christian Würdig committed
100

101
$classdef .= "enum reg_classes {\n";
Christian Würdig's avatar
Christian Würdig committed
102

103
my $class_mode;
104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
foreach my $class_name (keys(%reg_classes)) {
	my @class = @{ $reg_classes{"$class_name"} };

	my $idx = 0;
	foreach (@class) {
		if (defined($_->{name})) {
			$reg2class{$_->{name}} = {
				"class" => $class_name,
				"index" => $idx
			};
		}
		$idx++;
	}
	$regclass2len{$class_name} = $idx;
}

sub get_limited_array {
	my $reg      = shift;
	my $regclass = $reg2class{"$reg"}{"class"};
	my $ucname   = uc($reg);
	my $result   = "{ ";

	my $limitedbitsetlen = $regclass2len{$regclass};
	my $arraylen         = ($limitedbitsetlen+31) / 32;
129
130
	my $firstreg         = uc($reg_classes{$regclass}[0]->{"name"});
	my $classuc          = uc($regclass);
131
132
133
134
135
136
137
138
139
140
141
	my $first            = 1;
	for (my $i = 0; $i < $arraylen; ++$i) {
		if ($first) {
			$first = 0;
		} else {
			$result .= ", ";
		}

		my $index = $reg2class{"$reg"}{"index"};
		if ($index >= $i*32 && $index < ($i+1)*32) {
			if ($i > 0) {
142
				$result .= "(1 << (REG_${classuc}_${ucname} % 32))";
143
			} else {
144
				$result .= "(1 << REG_${classuc}_${ucname})";
145
146
147
148
149
150
151
152
			}
		} else {
			$result .= "0";
		}
	}
	$result .= " }";
}

Christian Würdig's avatar
Christian Würdig committed
153
# generate register type and class variable, init function and default requirements
154
foreach my $class_name (keys(%reg_classes)) {
155
156
157
158
159
	my @class         = @{ $reg_classes{"$class_name"} };
	my $old_classname = $class_name;

	$class_name = $arch."_".$class_name;
	$class_ptr  = "&".$arch."_reg_classes[CLASS_".$class_name."]";
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
	my $flags = pop(@class);
	$class_mode  = $flags->{"mode"};
	my $class_flags = $flags->{"flags"};
	my $flags_prepared = "";

	if(defined($class_flags)) {
		my $first = 1;
		foreach my $flag (split(/\|/, $class_flags)) {
			if(!$first) {
				$flags_prepared .= "|";
			} else {
				$first = 0;
			}
			$flags_prepared .= "arch_register_class_flag_$flag";
		}
	} else {
176
		$flags_prepared = "arch_register_class_flag_none";
177
	}
178

179
180
181
182
183
184
	$single_constraints .= <<EOF;
static const arch_register_req_t ${arch}_class_reg_req_${old_classname} = {
	arch_register_req_type_normal,
	&${arch}_reg_classes[CLASS_${arch}_${old_classname}],
	NULL,
	0,
185
186
	0,
	1
187
188
189
190
};
EOF

	$classdef .= "\tCLASS_$class_name = $class_idx,\n";
191
192
193
	my $numregs = @class;
	my $first_reg = "&${arch}_registers[REG_". uc($class[0]->{"name"}) . "]";
	push(@regclasses, "{ $class_idx, \"$class_name\", $numregs, NULL, $first_reg, $flags_prepared, &${arch}_class_reg_req_${old_classname} }");
194
195

	my $idx = 0;
196
	$reginit .= "\t$arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n";
197
	my $lastreg;
198
	foreach (@class) {
199
		my $name   = $_->{"name"};
200
		my $ucname = uc($name);
201
202
		my $type   = "arch_register_type_none";
		$type = translate_reg_type($_->{"type"}) if (exists($_->{"type"}));
203
204
		# realname is name if not set by user
		$_->{"realname"} = $_->{"name"} if (! exists($_->{"realname"}));
205
		my $realname = $_->{realname};
206
		my $classuc = uc($old_classname);
207

208
209
		$regdef  .= "\tREG_${ucname},\n";
		$regdef2 .= "\tREG_${classuc}_${ucname} = $idx,\n";
210

211
212
213
214
		$regtypes_def .= <<EOF;
	{
		"${realname}",
		${class_ptr},
215
		REG_${classuc}_${ucname},
216
217
218
219
220
		REG_${ucname},
		${type},
		&${arch}_single_reg_req_${old_classname}_${name}
	},
EOF
221

222
223
		my $limitedarray = get_limited_array($name);
		$single_constraints .= <<EOF;
224
static const unsigned ${arch}_limited_${old_classname}_${name} [] = ${limitedarray};
225
226
227
228
229
static const arch_register_req_t ${arch}_single_reg_req_${old_classname}_${name} = {
	arch_register_req_type_limited,
	${class_ptr},
	${arch}_limited_${old_classname}_${name},
	0,
230
231
	0,
	1
232
233
};
EOF
234

235
		$lastreg = $ucname;
236
237
		$idx++;
	}
238
	$regcounts .= "\tN_${class_name}_REGS = $numregs,\n";
239
240

	$class_idx++;
241
242
}

243
my $archuc = uc($arch);
244

245
246
$classdef .= "\tN_${archuc}_CLASSES = ".scalar(keys(%reg_classes))."\n";
$classdef .= "};\n\n";
247

Christian Würdig's avatar
Christian Würdig committed
248
# generate header (external usage) file
249
open(OUT, ">$target_h") || die("Fatal error: Could not open $target_h, reason: $!\n");
Christian Würdig's avatar
Christian Würdig committed
250

251
my $creation_time = localtime(time());
Christian Würdig's avatar
Christian Würdig committed
252
253
254

print OUT<<EOF;
/**
255
256
257
258
259
260
 * \@file
 * \@brief Contains additional external requirements defs for external includes.
 * \@note   DO NOT EDIT THIS FILE, your changes will be lost.
 *         Edit $specfile instead.
 *         created by: $0 $specfile $target_dir
 * \@date   $creation_time
Christian Würdig's avatar
Christian Würdig committed
261
 */
262
263
#ifndef FIRM_BE_${archuc}_GEN_${archuc}_REGALLOC_IF_H
#define FIRM_BE_${archuc}_GEN_${archuc}_REGALLOC_IF_H
Christian Würdig's avatar
Christian Würdig committed
264

265
#include "../bearch.h"
Matthias Braun's avatar
Matthias Braun committed
266
#include "${arch}_nodes_attr.h"
Christian Würdig's avatar
Christian Würdig committed
267

Michael Beck's avatar
Michael Beck committed
268
/** global register indices for ${arch} registers */
269
enum reg_indices {
270
${regdef}
271
272
	N_${archuc}_REGISTERS
};
Michael Beck's avatar
Michael Beck committed
273
/** local register indices for ${arch} registers */
274
275
276
277
enum {
${regdef2}
};

Michael Beck's avatar
Michael Beck committed
278
/** number of registers in ${arch} register classes. */
279
280
281
enum {
${regcounts}
};
282
${classdef}
283

284
285
286
extern const arch_register_t ${arch}_registers[N_${archuc}_REGISTERS];

extern arch_register_class_t ${arch}_reg_classes[N_${archuc}_CLASSES];
287

288
void ${arch}_register_init(void);
289

290
291
#endif
EOF
Christian Würdig's avatar
Christian Würdig committed
292
293
close(OUT);

294

Christian Würdig's avatar
Christian Würdig committed
295
# generate c file
296
open(OUT, ">$target_c") || die("Fatal error: Could not open $target_c, reason: $!\n");
297
298
299
300
301

$creation_time = localtime(time());

print OUT<<EOF;
/**
302
303
304
305
306
307
308
309
 * \@file
 * \@brief  The generated interface for the register allocator.
 *          Contains register classes and types and register constraints
 *          for all nodes where constraints were given in spec.
 * \@note    DO NOT EDIT THIS FILE, your changes will be lost.
 *          Edit $specfile instead.
 *          created by: $0 $specfile $target_dir
 * \$date    $creation_time
310
 */
311
#include "config.h"
Matthias Braun's avatar
Matthias Braun committed
312

Matthias Braun's avatar
Matthias Braun committed
313
314
315
#include "gen_${arch}_regalloc_if.h"
#include "gen_${arch}_machine.h"
#include "bearch_${arch}_t.h"
316
#include "irmode.h"
317

318
${single_constraints}
319
320
EOF

321
print OUT "arch_register_class_t ${arch}_reg_classes[] = {\n\t".join(",\n\t", @regclasses)."\n};\n\n";
322

323
print OUT<<EOF;
324

Michael Beck's avatar
Michael Beck committed
325
/** The array of all registers in the ${arch} architecture, sorted by its global index.*/
326
const arch_register_t ${arch}_registers[] = {
327
${regtypes_def}
328
};
329

Michael Beck's avatar
Michael Beck committed
330
331
332
/**
 * Initializes ${arch} register classes.
 */
333
334
335
336
337
void ${arch}_register_init(void)
{
${reginit}
}
EOF
338
339
close(OUT);

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
###
# Gets the variable name for the execution unit assigned to this register.
###
sub get_execunit_variable_name {
	my $unit    = shift;
	my $name    = "NULL";
	my $uc_arch = uc($arch);

	if ($unit) {
		my $found = 0;
SRCH:	foreach my $cur_type (keys(%cpu)) {
			foreach my $cur_unit (@{ $cpu{"$cur_type"} }) {
				if ($unit eq $cur_unit) {
					my $tp_name   = "$arch\_execution_units_$cur_type";
					my $unit_name = "$uc_arch\_EXECUNIT_TP_$cur_type\_$unit";
					$name  = "&".$tp_name."[".$unit_name."]";
					$found = 1;
					last SRCH;
				}
			}
		}

		if (! $found) {
			print STDERR "Invalid execution unit $unit specified!\n";
		}
	}

	return $name;
}