generate_regalloc_if.pl 16.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/perl -w

# This script generates C code which emits assembler code for the
# assembler ir nodes. It takes a "emit" key from the node specification
# and substitutes lines starting with . with a corresponding fprintf().
# Creation: 2005/11/14
# $Id$

use strict;
use Data::Dumper;

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

our $arch;
our %reg_classes;
our %nodes;

# include spec file

my $return;

no strict "subs";
unless ($return = do $specfile) {
25
26
27
	warn "couldn't parse $specfile: $@" if $@;
	warn "couldn't do $specfile: $!"    unless defined $return;
	warn "couldn't run $specfile"       unless $return;
28
29
30
}
use strict "subs";

Christian Würdig's avatar
Christian Würdig committed
31
32
33
my $target_c   = $target_dir."/gen_".$arch."_regalloc_if.c";
my $target_h   = $target_dir."/gen_".$arch."_regalloc_if.h";
my $target_h_t = $target_dir."/gen_".$arch."_regalloc_if_t.h";
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 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_caller_save");
		}

		if ($t & 2) {
			push(@types, "arch_register_type_callee_save");
		}

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

		return join(" | ", @types);
	}
}
60
61
62
63

# stacks for output
my @obst_regtypes;     # stack for the register type variables
my @obst_regclasses;   # stack for the register class variables
Christian Würdig's avatar
Christian Würdig committed
64
65
my @obst_classdef;     # stack to define a name for a class index
my @obst_regdef;       # stack to define a name for a register index
66
67
68
my @obst_reginit;      # stack for the register type inits
my @obst_req;          # stack for the register requirements
my @obst_limit_func;   # stack for functions to return a subset of a register class
Christian Würdig's avatar
Christian Würdig committed
69
70
my @obst_defreq_head;  # stack for prototypes of default requirement function
my @obst_header_all;   # stack for some extern struct defs needed for bearch_$arch include
71
my @obst_requirement_def;  # stack for requirement name defines
72
73

my $numregs;
Christian Würdig's avatar
Christian Würdig committed
74
my $class_ptr;
75
76
my $class_idx = 0;

Christian Würdig's avatar
Christian Würdig committed
77
78
my $tmp;

79
80
my %reg2class;

Christian Würdig's avatar
Christian Würdig committed
81
82
# there is a default NONE requirement
$tmp = "/* Default NONE register requirements */\n";
83
84
$tmp .= "const $arch\_register_req_t $arch\_default_req_none = {\n";
$tmp .= "  {\n";
85
86
87
88
89
90
$tmp .= "    arch_register_req_type_none,  /* register type  */\n";
$tmp .= "    NULL,                         /* register class */\n";
$tmp .= "    NULL,                         /* limit function */\n";
$tmp .= "    NULL,                         /* limit environment */\n";
$tmp .= "    NULL,                         /* node for same */\n";
$tmp .= "    NULL                          /* node for different */\n";
91
$tmp .= "  },\n";
92
93
$tmp .= "  0,                              /* same pos */\n";
$tmp .= "  0                               /* different pos */\n";
Christian Würdig's avatar
Christian Würdig committed
94
95
$tmp .= "};\n\n";
push(@obst_req, $tmp);
96
push(@obst_header_all, "extern const $arch\_register_req_t $arch\_default_req_none;\n");
Christian Würdig's avatar
Christian Würdig committed
97
98
99

push(@obst_classdef, "#define N_CLASSES ".scalar(keys(%reg_classes))."\n");

100
my $class_mode;
101

Christian Würdig's avatar
Christian Würdig committed
102
# generate register type and class variable, init function and default requirements
103
foreach my $class_name (keys(%reg_classes)) {
104
105
106
107
108
109
	my @class         = @{ $reg_classes{"$class_name"} };
	my $old_classname = $class_name;

	$class_name = $arch."_".$class_name;
	$numregs    = "N_".$class_name."_REGS";
	$class_ptr  = "&".$arch."_reg_classes[CLASS_".$class_name."]";
110
	$class_mode = pop(@class)->{"mode"};
111
112
113
114
115

	push(@obst_regtypes, "#define $numregs ".($#class + 1)."\n");
	push(@obst_regtypes, "arch_register_t ".$class_name."_regs[$numregs];\n\n");

	push(@obst_classdef, "#define CLASS_$class_name $class_idx\n");
116
	push(@obst_regclasses, "{ \"$class_name\", $numregs, NULL, ".$class_name."_regs }");
117
118
119
120
121
122
123

	# there is a default NORMAL requirement for each class
	$tmp  = "/* Default NORMAL register requirements for class $class_name */\n";
	$tmp .= "const $arch\_register_req_t $arch\_default_req_$class_name = {\n";
	$tmp .= "  {\n";
	$tmp .= "    arch_register_req_type_normal,\n";
	$tmp .= "    $class_ptr,\n";
124
125
126
127
	$tmp .= "    NULL,                    /* limit function */ \n";
	$tmp .= "    NULL,                    /* limit environment */\n";
	$tmp .= "    NULL,                    /* node for same */\n";
	$tmp .= "    NULL                     /* node for different */\n";
128
	$tmp .= "  },\n";
129
130
	$tmp .= "  0,                         /* same pos */\n";
	$tmp .= "  0                          /* different pos */\n";
131
132
	$tmp .= "};\n\n";
	push(@obst_req, $tmp);
133
	push(@obst_header_all, "extern const $arch\_register_req_t $arch\_default_req_$class_name;\n");
134
135
136

	my $idx = 0;
	push(@obst_reginit, "  /* Init of all registers in class '$class_name' */\n\n");
137
138
	push(@obst_reginit, "  /* set largest possible mode for '$class_name' */\n");
	push(@obst_reginit, "  $arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n\n");
139
140
141
142
143
144
145
146
147
148
	foreach (@class) {
		# For each class we build for each of it's member registers a limit function
		# which limits the class to this particular register. We also build the
		# corresponding requirement structs.
		# We need those functions to set register requirements on demand in transformation
		# esp. for Call and RegParams where we can mix int and float parameters.

		my $limit_func_name = $arch."_limit_".$class_name."_".$_->{"name"};

		# push the function prototype
Christian Würdig's avatar
Christian Würdig committed
149
		$tmp = "void $limit_func_name(void *_unused, bitset_t *bs)";
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
		push(@obst_defreq_head, $tmp.";\n");

		# push the function definition
		$tmp .= " {\n";
		$tmp .= "    bs = bitset_clear_all(bs);\n";
		$tmp .= "    bitset_set(bs, REG_".uc($_->{"name"}).");\n";  # REGISTER to index assignment is done some lines down
		$tmp .= "}\n\n";
		push(@obst_limit_func, $tmp);

		# push the default requirement struct
		$tmp  = "const $arch\_register_req_t $arch\_default_req_$class_name\_".$_->{"name"}." = {\n";
		$tmp .= "  {\n";
		$tmp .= "    arch_register_req_type_limited,\n";
		$tmp .= "    $class_ptr,\n";
		$tmp .= "    $limit_func_name,\n";
165
166
167
		$tmp .= "    NULL,                     /* limit environment */\n";
		$tmp .= "    NULL,                     /* node for same */\n";
		$tmp .= "    NULL                      /* node for different */\n";
168
		$tmp .= "  },\n";
169
170
		$tmp .= "  0,                          /* same pos */\n";
		$tmp .= "  0                           /* different pos */\n";
171
172
		$tmp .= "};\n\n";
		push(@obst_req, $tmp);
173
		push(@obst_header_all,"extern const $arch\_register_req_t $arch\_default_req_$class_name\_".$_->{"name"}.";\n");
174
175
176
177
178
179

		$reg2class{$_->{"name"}} = { "class" => $old_classname, "index" => $idx }; # remember reg to class for later use
		push(@obst_regdef, "#define REG_".uc($_->{"name"})." $idx\n");
		push(@obst_reginit, "  ".$class_name."_regs[$idx].name      = \"".$_->{"name"}."\";\n");
		push(@obst_reginit, "  ".$class_name."_regs[$idx].reg_class = $class_ptr;\n");
		push(@obst_reginit, "  ".$class_name."_regs[$idx].index     = $idx;\n");
180
		push(@obst_reginit, "  ".$class_name."_regs[$idx].type      = ".translate_reg_type($_->{"type"}).";\n");
181
		push(@obst_reginit, "\n");
182
183
184
185
		$idx++;
	}

	$class_idx++;
186
187
188
189
}

# generate node-register constraints
foreach my $op (keys(%nodes)) {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
	my %n = %{ $nodes{"$op"} };

	next if (!exists($n{"reg_req"}));

	$op = $arch."_".$op;

	push(@obst_req, "/* IN requirements for '$op' */\n");
	# check for argument requirements
	if (exists($n{"reg_req"}{"in"})) {
		generate_requirements(\%n, $op, "in");
	}

	push(@obst_req, "/* OUT requirements for '$op' */\n");
	# check for result requirements
	if (exists($n{"reg_req"}{"out"})) {
		generate_requirements(\%n, $op, "out");
	}
207
208
209
210
}



Christian Würdig's avatar
Christian Würdig committed
211
212
# generate header _t (internal usage) file
open(OUT, ">$target_h_t") || die("Could not open $target_h_t, reason: $!\n");
213
214
215

my $creation_time = localtime(time());

Christian Würdig's avatar
Christian Würdig committed
216
$tmp = uc($arch);
217
218

print OUT<<EOF;
Christian Würdig's avatar
Christian Würdig committed
219
220
#ifndef _GEN_$tmp\_REGALLOC_IF_T_H_
#define _GEN_$tmp\_REGALLOC_IF_T_H_
221
222

/**
Christian Würdig's avatar
Christian Würdig committed
223
 * Generated register classes from spec.
224
225
226
227
228
229
230
231
232
 *
 * DO NOT EDIT THIS FILE, your changes will be lost.
 * Edit $specfile instead.
 * created by: $0 $specfile $target_dir
 * date:       $creation_time
 */

EOF

233
print OUT @obst_requirement_def;
234

Christian Würdig's avatar
Christian Würdig committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
print OUT "\n#endif /* _GEN_$tmp\_REGALLOC_IF_T_H_ */\n";



# generate header (external usage) file
open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");

$creation_time = localtime(time());

print OUT<<EOF;
#ifndef _GEN_$tmp\_REGALLOC_IF_H_
#define _GEN_$tmp\_REGALLOC_IF_H_

/**
 * Contains additional external requirements defs for external includes.
 *
 * DO NOT EDIT THIS FILE, your changes will be lost.
 * Edit $specfile instead.
 * created by: $0 $specfile $target_dir
 * date:       $creation_time
 */

257
258
#include "../bearch.h"
#include "$arch\_nodes_attr.h"
Christian Würdig's avatar
Christian Würdig committed
259
260
261

EOF

262
263
264
265
266
267
268
269
270
271
272
273
274
print OUT @obst_regdef, "\n";

print OUT @obst_classdef, "\n";

print OUT @obst_regtypes, "\n";

print OUT "extern arch_register_class_t $arch\_reg_classes[N_CLASSES];\n\n";

print OUT "void ".$arch."_register_init(void *isa_ptr);\n\n";

print OUT @obst_header_all, "\n";

print OUT @obst_defreq_head, "\n";
Christian Würdig's avatar
Christian Würdig committed
275

276
277
print OUT "\n#endif /* _GEN_$tmp\_REGALLOC_IF_H_ */\n";

Christian Würdig's avatar
Christian Würdig committed
278
279
close(OUT);

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298


# generate c inline file
open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");

$creation_time = localtime(time());

print OUT<<EOF;
/**
 * The generated interface for the register allocator.
 * Contains register classes and types and register constraints
 * for all nodes where constraints were given in spec.
 *
 * DO NOT EDIT THIS FILE, your changes will be lost.
 * Edit $specfile instead.
 * created by: $0 $specfile $target_dir
 * date:       $creation_time
 */

299
#include "gen_$arch\_regalloc_if.h"
300
301
#include "bearch_$arch\_t.h"   /* we need this to put the caller saved registers into the isa set */
#include "$arch\_map_regs.h"
302
#include "irmode.h"
303
304
305
306
307

EOF

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

308
print OUT "void ".$arch."_register_init(void *isa_ptr) {\n";
309
310
311
312
print OUT @obst_reginit;
print OUT "}\n\n";

print OUT @obst_limit_func;
313

314
315
316
317
print OUT @obst_req;

close(OUT);

318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
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
###
# Remember the register class for each index in the given requirements.
# We need this information for requirements like "in_sX" or "out_dX"
# @return array of classes corresponding to the requirement for each index
###
sub build_inout_idx_class {
	my $n     = shift;
	my $op    = shift;
	my $inout = shift;
	my @idx_class;

	if (exists($n->{"reg_req"}{"$inout"})) {
		my @reqs = @{ $n->{"reg_req"}{"$inout"} };

		for (my $idx = 0; $idx <= $#reqs; $idx++) {
			my $class = undef;

			if ($reqs[$idx] eq "none") {
				$class = "none";
			}
			elsif (is_reg_class($reqs[$idx])) {
				$class = $reqs[$idx];
			}
			else {
				my @regs = split(/ /, $reqs[$idx]);
GET_CLASS:		foreach my $reg (@regs) {
					if ($reg =~ /!?(in|out)\_r\d+/) {
						$class = "UNKNOWN_CLASS";
					}
					else {
						$class = get_reg_class($reg);
						if (!defined $class) {
							die("Could not get ".uc($inout)." register class for '$op' pos $idx (reg $reg) ... exiting.\n");
						}
						else {
							last GET_CLASS;
						} # !defined class
					} # if (reg =~ ...
				} # foreach
			} # if

			push(@idx_class, $class);
		} # for
	} # if

	return @idx_class;
}
365

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
###
# Generates the requirements for the given description
###
sub generate_requirements {
	my $n     = shift;
	my $op    = shift;
	my $inout = shift;

	# get classes for the complementary direction
	my $outin     = ($inout eq "in") ? "out" : "in";

	my @reqs = @{ $n->{"reg_req"}{"$inout"} };

	for (my $idx = 0; $idx <= $#reqs; $idx++) {
		my $class = undef;

		my $tmp2 = "const $arch\_register_req_t _".$op."_reg_req_$inout\_$idx = ";
383
		my $tmp  = "#define ".$op."_reg_req_$inout\_$idx ";
384
385

		if ($reqs[$idx] eq "none") {
386
			$tmp .= "&$arch\_default_req_none\n";
387
388
		}
		elsif (is_reg_class($reqs[$idx])) {
389
			$tmp .= "&$arch\_default_req_".$arch."_".$reqs[$idx]."\n";
390
391
392
		}
		else {
			my @req_type_mask;
393
394
			my ($class, $has_limit, $same_pos, $different_pos) = build_subset_class_func($n, $op, $idx, (($inout eq "in") ? 1 : 0), $reqs[$idx]);

395
396
397
			if (!defined($class)) {
				die("Could not build subset for ".uc($inout)." requirements '$op' pos $idx ... exiting.\n");
			}
398

399
400
401
			if ($has_limit) {
				push(@req_type_mask, "arch_register_req_type_limited");
			}
402
403
			if (defined($same_pos)) {
				push(@req_type_mask, "arch_register_req_type_should_be_same");
404
			}
405
406
407
408
			if (defined($different_pos)) {
				push(@req_type_mask, "arch_register_req_type_should_be_different");
			}

409
			$tmp  .= "&_".$op."_reg_req_$inout\_$idx\n";
410
			$tmp2 .= "{\n";
411
412
413
			$tmp2 .= "  {\n";
			$tmp2 .= "    ".join(" | ", @req_type_mask).",\n";
			$tmp2 .= "    &$arch\_reg_classes[CLASS_$arch\_".$class."],\n";
414
			$tmp2 .= "    ".($has_limit ? "limit_reg_".$op."_$inout\_".$idx : "NULL").",\n";
415
416
417
			$tmp2 .= "    NULL,        /* limit environment */\n";
			$tmp2 .= "    NULL,        /* same node */\n";
			$tmp2 .= "    NULL         /* different node */\n";
418
			$tmp2 .= "  },\n";
419
420
421
			$tmp2 .= "  ".(defined($same_pos) ? $same_pos : "0").",\n";
			$tmp2 .= "  ".(defined($different_pos) ? $different_pos : "0")."\n";
			$tmp2 .= "};\n";
422

423
424
			push(@obst_req, $tmp2."\n");
			push(@obst_header_all, "extern const $arch\_register_req_t _".$op."_reg_req_$inout\_$idx;\n");
425
426
		}

427
		push(@obst_requirement_def, $tmp);
428
429
430
	}

}
431
432
433
434
435
436

###
# Determines whether $name is a specified register class or not.
# @return 1 if name is register class, 0 otherwise
###
sub is_reg_class {
437
438
439
	my $name = shift;
	return 1 if exists($reg_classes{"$name"});
	return 0;
440
441
442
443
444
445
446
}

###
# Returns the register class for a given register.
# @return class or undef
###
sub get_reg_class {
447
	my $reg = shift;
448
	$reg = substr($reg, 1) if ($reg =~ /!.*/);
449
450
	return $reg2class{"$reg"}{"class"} if (exists($reg2class{"$reg"}));
	return undef;
451
452
453
454
455
456
457
}

###
# Returns the index of a given register within it's register class.
# @return index or undef
###
sub get_reg_index {
458
459
460
	my $reg = shift;
	return $reg2class{"$reg"}{"index"} if (exists($reg2class{"$reg"}));
	return undef;
461
462
463
464
465
}

###
# Generates the function for a given $op and a given IN-index
# which returns a subset of possible register from a register class
466
467
# @return classname from which the subset is derived or undef and
#         pos which corresponds to in/out reference position or undef
468
469
###
sub build_subset_class_func {
470
471
472
473
474
	my $neg           = undef;
	my $class         = undef;
	my $has_limit     = 0;
	my $same_pos      = undef;
	my $different_pos = undef;
475
	my $temp;
476
	my @temp_obst;
477
478


479
480
481
482
483
	# build function header
	my $n   = shift;
	my $op  = shift;
	my $idx = shift;
	my $in  = shift;
484
485
486
487
488
489
490
491
492

	my $outin = $in ? "out" : "in";
	my @regs  = split(/ /, shift);

	my @idx_class = build_inout_idx_class($n, $op, $outin);

	# set/unset registers
CHECK_REQS: foreach (@regs) {
		if (/(!)?$outin\_r(\d+)/) {
493
			if (($1 && defined($different_pos)) || (!$1 && defined($same_pos))) {
494
				print STDERR "Multiple in/out references of same type in one requirement not allowed.\n";
495
496
				return (undef, undef, undef, undef);
			}
497
498
499
500
501
502
503
504

			if ($1) {
				$different_pos = $in ? -$2 : $2 - 1;
			}
			else {
				$same_pos = $in ? -$2 : $2 - 1;
			}

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
			$class = $idx_class[$2 - 1];
			next CHECK_REQS;
		}

		# check for negate
		if (substr($_, 0, 1) eq "!") {
			if (defined($neg) && $neg == 0) {
				# we have seen a positiv constraint as first one but this one is negative
				# this doesn't make sense
				print STDERR "Mixed positive and negative constraints for the same slot are not allowed.\n";
				return (undef, undef, undef, undef);
			}

			if (!defined($neg)) {
				$has_limit = 1;
				push(@temp_obst, "  bs = bitset_set_all(bs);     /* allow all register (negative constraints given) */\n");
			}

			$_   = substr($_, 1); # skip '!'
			$neg = 1;
		}
		else {
			if (defined($neg) && $neg == 1) {
				# we have seen a negative constraint as first one but this one is positive
				# this doesn't make sense
				print STDERR "Mixed positive and negative constraints for the same slot are not allowed.\n";
				return (undef, undef, undef, undef);
			}

			if (!defined($neg)) {
				$has_limit = 1;
				push(@temp_obst, "  bs = bitset_clear_all(bs);   /* disallow all register (positive constraints given) */\n");
			}
			$neg = 0;
		}

		# check if register belongs to one of the given classes
		$temp = get_reg_class($_);
		if (!defined($temp)) {
			print STDERR "Unknown register '$_'!\n";
			return (undef, undef, undef, undef);
		}

		# set class
		if (!defined($class)) {
			$class = $temp;
		}
		elsif ($class ne $temp) {
			# all registers must belong to the same class
			print STDERR "Registerclass mismatch. '$_' is not member of class '$class'.\n";
			return (undef, undef, undef, undef);
		}

		if ($neg == 1) {
			$has_limit = 1;
			push(@temp_obst, "  bitset_clear(bs, ".get_reg_index($_).");         /* disallow $_ */\n");
		}
		else {
			$has_limit = 1;
			push(@temp_obst, "  bitset_set(bs, ".get_reg_index($_).");           /* allow $_ */\n");
		}
	}

	if ($has_limit == 1) {
569
570
		push(@obst_header_all, "void limit_reg_".$op."_".($in ? "in" : "out")."_".$idx."(void *_unused, bitset_t *bs);\n");

571
		push(@obst_limit_func, "/* limit the possible registers for ".($in ? "IN" : "OUT")." $idx at op $op */\n");
Christian Würdig's avatar
Christian Würdig committed
572
		push(@obst_limit_func, "void limit_reg_".$op."_".($in ? "in" : "out")."_".$idx."(void *_unused, bitset_t *bs) {\n");
573
574
575
576
		push(@obst_limit_func, @temp_obst);
		push(@obst_limit_func, "}\n\n");
	}

577
	return ($class, $has_limit, $same_pos, $different_pos);
578
}