generate_new_opcodes.pl 34.7 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.
#

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# This script generates the C code which creates the irop's and
# their coresponding node constructors for all operations in a given spec
# so they can be used as normal firm nodes.
# Creation: 2005/10/19

use strict;
use Data::Dumper;

my $specfile   = $ARGV[0];
my $target_dir = $ARGV[1];
my $state      = 1;
my $cur_op     = "";
my $line_nr    = 0;

our $arch;
37
our $additional_opcodes;
38
our %nodes;
39
our %operands;
40
our %cpu;
41
our $default_op_attr_type;
42
our $default_attr_type;
43
our $default_cmp_attr;
44
our $default_copy_attr;
45
our %init_attr;
46
our $custom_init_attr_func;
47
our %compare_attr;
48
our %copy_attr;
49
our %reg_classes;
50
our %custom_irn_flags;
51
52
53
54
55
56
57

# include spec file

my $return;

no strict "subs";
unless ($return = do $specfile) {
58
59
60
	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;
61
62
63
}
use strict "subs";

64
my $target_c = $target_dir."/gen_".$arch."_new_nodes.c.inl";
Christian Würdig's avatar
Christian Würdig committed
65
my $target_h = $target_dir."/gen_".$arch."_new_nodes.h";
66

67
68
69
if(!defined($default_attr_type)) {
	$default_attr_type = "${arch}_attr_t";
}
70
71
if(!defined(%init_attr)) {
	%init_attr = (
72
		"$default_attr_type" => "\tinit_${arch}_attributes(res, irn_flags_, in_reqs, exec_units, n_res);",
73
74
	);
}
75
76
77
78
79
80
81
82
if(!defined($default_cmp_attr)) {
	$default_cmp_attr = "${arch}_compare_attr";
}
if(!defined(%compare_attr)) {
	%compare_attr = (
		"${default_attr_type}" => "${default_cmp_attr}",
	);
}
83

Matthias Braun's avatar
Matthias Braun committed
84
85
# Operands are really just nodes with some special constraints, we check
# these and create new entries in the nodes hashmap
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
foreach my $op (keys(%operands)) {
	my %operand = %{ $operands{"$op"} };
	my %op_node;

	# constraints
	if(defined($operand{op_flags})) { die "Fatal error: operands can't have op_flags ($op)"; }
	if(defined($operand{cmp_attr})) { die "Fatal error: cmp_attr not allowed for operands ($op)"; }
	if(defined($operand{mode})) { die "Operand must not have a mode defined ($op)"; }
	if(defined($operand{out_arity})) { die "operand must not have out_arity defined ($op)"; }
	if(defined($nodes{$op})) { die "$op defined as operand and as node"; };


	foreach my $flag (keys(%operand)) {
		$op_node{$flag} = $operand{$flag};
	}
	$op_node{op_flags} = "O";
	$op_node{cmp_attr} = 'return 1;';
Michael Beck's avatar
Michael Beck committed
103
	$op_node{mode}     = 'mode_ANY';
104
105
106
107

	$nodes{$op} = \%op_node;
}

108
#print Dumper(%nodes);
109
#print Dumper(%operands);
110
111
112

# create c code file from specs

113
114
my @obst_limit_func;
my @obst_reg_reqs;
115
116
my @obst_opvar;       # stack for the "ir_op *op_<arch>_<op-name> = NULL;" statements
my @obst_get_opvar;   # stack for the get_op_<arch>_<op-name>() functions
117
my $obst_constructor; # stack for node constructor functions
118
my @obst_new_irop;    # stack for the new_ir_op calls
119
my @obst_enum_op;     # stack for creating the <arch>_opcode enum
120
my $obst_header;      # stack for function prototypes
121
my @obst_is_archirn;  # stack for the is_$arch_irn() function
Christian Würdig's avatar
Christian Würdig committed
122
my @obst_cmp_attr;    # stack for the compare attribute functions
123
my $obst_proj = "";   # stack for the pn_ numbers
124
125
my $orig_op;
my $arity;
Christian Würdig's avatar
Christian Würdig committed
126
my $cmp_attr_func;
127
my $temp;
128
my $n_opcodes = 0;    # number of opcodes
129
130
my $ARITY_VARIABLE = -1;
my $ARITY_DYNAMIC  = -2;
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
my %requirements = ();
my %limit_bitsets = ();
my %reg2class = ();
my %regclass2len = ();

# build register->class hashes
foreach my $class_name (keys(%reg_classes)) {
	my @class         = @{ $reg_classes{"$class_name"} };
	my $old_classname = $class_name;

	pop(@class);

	$class_name = $arch."_".$class_name;

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

	$regclass2len{$old_classname} = $idx;
}

157

158
159
160
# for registering additional opcodes
$n_opcodes += $additional_opcodes if (defined($additional_opcodes));

161
$obst_header .= "void ${arch}_create_opcodes(const arch_irn_ops_t *be_ops);\n";
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
sub create_constructor {
	my $op   = shift;
	my $name = shift;
	my $n    = shift;
	my $on   = shift;
	my $known_mode;

	my $suffix = "";
	if ($name ne "") {
		$suffix = "_${name}";
	}

	# determine mode
	if (exists($n->{mode})) {
		$known_mode = $n->{mode};
	}

	# determine arity
	my $arity = 0;
	if(exists($n->{"arity"})) {
		$arity = $n->{"arity"};
	} elsif (exists($n->{"reg_req"}) && exists($n->{"reg_req"}{"in"})) {
		$arity = scalar(@{ $n->{"reg_req"}{"in"} });
	} elsif (exists($n->{"ins"})) {
		$arity = scalar(@{ $n->{"ins"} });
	}
	if($arity eq "variable") {
		$arity = $ARITY_VARIABLE;
	} elsif($arity eq "dynamic") {
		$arity = $ARITY_DYNAMIC;
	}

	# determine out arity
	my $out_arity = 0;
	if(exists($n->{"out_arity"})) {
		$out_arity = $n->{"out_arity"};
	} elsif (exists($n->{"reg_req"}) && exists($n->{"reg_req"}{"out"})) {
		$out_arity = scalar(@{ $n->{"reg_req"}{"out"} });
	} elsif (exists($n->{"outs"})) {
		$out_arity = scalar(@{ $n->{"outs"} });
	}
	if($out_arity eq "variable") {
		$out_arity = $ARITY_VARIABLE;
	} elsif($out_arity eq "dynamic") {
		$out_arity = $ARITY_DYNAMIC;
	}
209
210
211
	if ($out_arity != 0 && $out_arity != 1 && !defined($known_mode)) {
		$known_mode = "mode_T";
	}
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271

	my $comment = $n->{"comment"};
	if(!exists($n->{"comment"})) {
		$comment = "construct ${orig_op} node";
	}
	$comment =
		"/**\n".
		" * ${comment}\n".
		" */\n";

	$obst_constructor .= $comment;

	# create constructor head
	my $complete_args = "";
	$temp             = "";

	$temp = "ir_node *new_bd_${arch}_${op}${suffix}(dbg_info *dbgi, ir_node *block";
	if (!exists($n->{"args"})) { # default args
		if ($arity == $ARITY_VARIABLE) {
			$complete_args = ", int arity, ir_node *in[]";
		} elsif ($arity == $ARITY_DYNAMIC) {
			$complete_args = "";
		} else {
			for (my $i = 0; $i < $arity; $i++) {
				my $opname = "op${i}";
				if (exists($n->{"ins"})) {
					my @ins = @{ $n->{"ins"} };
					$opname = $ins[$i];
				}

				$complete_args .= ", ir_node *${opname}";
			}
		}
		if ($out_arity == $ARITY_VARIABLE) {
			$complete_args .= ", int n_res";
		}

		if (!defined($known_mode)) {
			$complete_args .= ", ir_mode *mode";
		}
	} else { # user defined args
		for my $href (@{ $n->{"args"} }) {
			$href->{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end
			$complete_args  .= ", ".$href->{"type"}.$href->{"name"};
		}
	}

	# we have additional attribute arguements
	if (exists($n->{"attr"})) {
		$complete_args .= ", ".$n->{"attr"};
	}

	$temp .= "$complete_args)";
	$obst_constructor .= "${temp}\n{\n";

	$obst_header .= $comment;
	$obst_header .= "${temp};\n";

	# emit constructor code
	$temp = <<EOF;
272
273
274
	ir_graph         *irg        = get_irn_irg(block);
	ir_op            *op         = op_${arch}_${op};
	arch_irn_flags_t  irn_flags_ = arch_irn_flags_none;
275
	ir_node          *res;
276
	backend_info_t   *info;
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
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
365
366
367
368
369
370
371
372
373
374
375
376
377
EOF

	if($arity == $ARITY_DYNAMIC) {
		$temp .= <<EOF;
	int             arity   = -1;
	ir_node       **in      = NULL;
EOF
	} elsif($arity == $ARITY_VARIABLE) {
	} else {
		$temp .= <<EOF;
	int             arity   = $arity;
EOF
		if($arity > 0) {
			$temp .= <<EOF;
	ir_node        *in[$arity];
EOF
		} else {
			$temp .= <<EOF;
	ir_node       **in      = NULL;
EOF
		}
	}
	if($out_arity == $ARITY_DYNAMIC) {
		$temp .= <<EOF;
	int             n_res   = -1;
EOF
	} elsif($out_arity == $ARITY_VARIABLE) {
	} else {
		$temp .= <<EOF;
	int             n_res   = ${out_arity};
EOF
	}

	if (defined($known_mode)) {
		$temp .= <<EOF;
	ir_mode        *mode    = ${known_mode};
EOF
	}

	# set up static variables for cpu execution unit assigments
	if (exists($n->{"units"})) {
		$temp .= gen_execunit_list_initializer($n->{"units"});
	} else {
		$temp .= <<EOF;
	static const be_execution_unit_t ***exec_units = NULL;
EOF
	}

	undef my $in_req_var;
	undef my $out_req_var;

	my $set_out_reqs = "";

	# set up static variables for requirements and registers
	if (exists($n->{"reg_req"})) {
		my %req = %{ $n->{"reg_req"} };
		my $idx;

		undef my @in;
		@in = @{ $req{"in"} } if (exists($req{"in"}));
		undef my @out;
		@out = @{ $req{"out"} } if exists(($req{"out"}));

		for(my $idx = 0; $idx < $#in; $idx++) {
			my $req = $in[$idx];
			generate_requirements($req, $n, "${arch}_${op}", $idx, 1);
		}
		for(my $idx = 0; $idx < $#out; $idx++) {
			my $req = $out[$idx];
			generate_requirements($req, $n, "${arch}_${op}", $idx, 0);
		}

		if (@in) {
			if($arity >= 0 && scalar(@in) != $arity) {
				die "Fatal error: Arity and number of in requirements don't match for ${op}\n";
			}

			$temp .= "\tstatic const arch_register_req_t *in_reqs[] =\n";
			$temp .= "\t{\n";
			for ($idx = 0; $idx <= $#in; $idx++) {
				my $req = $in[$idx];
				my $reqstruct = generate_requirements($req, $n, "${arch}_${op}", $idx, 1);
				$temp .= "\t\t& ${reqstruct},\n";
			}
			$temp .= "\t};\n";
		} else {
			if($arity > 0) {
				die "Fatal error: need in requirements for ${op}\n";
			}
			$temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n";
		}

		if (@out) {
			if($out_arity >= 0 && scalar(@out) != $out_arity) {
				die "Fatal error: Out-Arity and number of out requirements don't match for ${op}\n";
			}

			for ($idx = 0; $idx <= $#out; $idx++) {
				my $req = $out[$idx];
				my $reqstruct = generate_requirements($req, $n, "${arch}_${op}", $idx, 0);
				$set_out_reqs .= <<EOF;
378
	info->out_infos[${idx}].req = &${reqstruct};
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
EOF
			}
		} else {
			if($out_arity > 0) {
				die "Fatal error: need out requirements for ${op}\n";
			}
		}
	} else {
		$temp .= "\tstatic const arch_register_req_t **in_reqs = NULL;\n";
	}
	my $attr_type = $on->{attr_type};
	if(exists($n->{"init_attr"})) {
		$temp .= "\t${attr_type} *attr;\n";
	}

	$temp .= "\n";

	if($arity > 0) {
		$temp .= "\t/* construct in array */\n";
		for (my $i = 0; $i < $arity; $i++) {
			my $opname = "op${i}";
			if (exists($n->{"ins"})) {
				my @ins = @{ $n->{"ins"} };
				$opname = $ins[$i];
			}

			$temp .= "\tin[${i}] = ${opname};\n";
		}
		$temp .= "\n";
	}

	# set flags
	if (exists($n->{"irn_flags"})) {
		$temp .= "\t/* flags */\n";
413
414
415
416
417
418
		my %known_irn_flags = (
			"none"             => "arch_irn_flags_none",
			"dont_spill"       => "arch_irn_flags_dont_spill",
			"rematerializable" => "arch_irn_flags_rematerializable",
			"modify_flags"     => "arch_irn_flags_modify_flags",
			"simple_jump"      => "arch_irn_flags_simple_jump",
419
			"not_scheduled"    => "arch_irn_flags_not_scheduled",
420
		);
421
422
423
		if (defined(%custom_irn_flags)) {
			%known_irn_flags = (%known_irn_flags, %custom_irn_flags);
		}
424
425
426
		foreach my $flag (@{$n->{"irn_flags"}}) {
			if (not defined($known_irn_flags{$flag})) {
				print STDERR "WARNING: irn_flag '$flag' in opcode $op is unknown\n";
427
			} else {
428
				$temp .= "\tirn_flags_ |= " . $known_irn_flags{$flag} . ";\n";
429
430
431
432
433
434
			}
		}
		$temp .= "\n";
	}

	# lookup init function
435
	my $attr_init_code = "(void)in;(void)exec_units;(void)irn_flags_;(void)in_reqs;(void)n_res;";
436
437
438
439
440
	if ($attr_type ne "") {
		$attr_init_code = $init_attr{$attr_type};
		if(!defined($attr_init_code)) {
			die "Fatal error: Couldn't find attribute initialisation code for type '${attr_type}'";
		}
441
442
443
444
445
446
447
448
449
450
451
452
	}
	my $custominit = "";
	if(defined($custom_init_attr_func)) {
		$custominit .= &$custom_init_attr_func($n, $on, "${arch}_${op}");
	}
	if(defined($n->{custominit})) {
		$custominit .= $n->{custominit};
	}

	$temp .= <<EOF;
	/* create node */
	assert(op != NULL);
453
	res = new_ir_node(dbgi, irg, block, op, mode, arity, in);
454
455
456
457
458

	/* init node attributes */
	${attr_init_code}
	${custominit}
	info = be_get_info(res);
459
	(void) info; /* avoid potential warning */
460
${set_out_reqs}
461
462
463
464

EOF

	if (exists($n->{"init_attr"})) {
465
		$temp .= "\tattr = (${attr_type}*)get_irn_generic_attr(res);\n";
466
		$temp .= "\t(void) attr; /* avoid potential warning */\n";
467
468
469
470
471
472
		$temp .= "\t".$n->{"init_attr"}."\n";
	}

	$temp .= <<EOF;
	/* optimize node */
	res = optimize_node(res);
473
	irn_verify_irg(res, irg);
474
475
476
477
478
479
480
481
482
483

	return res;
EOF

	$obst_constructor .= $temp;

	# close constructor function
	$obst_constructor .= "}\n\n";
}

484
push(@obst_enum_op, "typedef enum ${arch}_opcodes {\n");
485
foreach my $op (keys(%nodes)) {
486
	my %n        = %{ $nodes{"$op"} };
487
	my $known_mode;
488
	my $num_outs = 0;
489
	my $out_arity;
490
	my @out_flags;
Christian Würdig's avatar
Christian Würdig committed
491

492
493
494
495
496
	# determine arity
	$arity = 0;
	if(exists($n{"arity"})) {
		$arity = $n{"arity"};
	} elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
497
		$arity = scalar(@{ $n{"reg_req"}{"in"} });
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
	} elsif (exists($n{"ins"})) {
		$arity = scalar(@{ $n{"ins"} });
	}
	if($arity eq "variable") {
		$arity = $ARITY_VARIABLE;
	} elsif($arity eq "dynamic") {
		$arity = $ARITY_DYNAMIC;
	}

	# determine out arity
	$out_arity = 0;
	if(exists($n{"out_arity"})) {
		$out_arity = $n{"out_arity"};
	} elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"out"})) {
		$out_arity = scalar(@{ $n{"reg_req"}{"out"} });
	} elsif (exists($n{"outs"})) {
		$out_arity = scalar(@{ $n{"outs"} });
	}
	if($out_arity eq "variable") {
		$out_arity = $ARITY_VARIABLE;
	} elsif($out_arity eq "dynamic") {
		$out_arity = $ARITY_DYNAMIC;
520
521
	}

Christian Würdig's avatar
Christian Würdig committed
522
523
	$orig_op = $op;
	$op      = $arch."_".$op;
524
	$temp    = "";
Christian Würdig's avatar
Christian Würdig committed
525

526
	# define proj numbers and in numbers
527
528
	if (exists($n{"outs"})) {
		undef my @outs;
529

530
		@outs = @{ $n{"outs"} };
531
		if($out_arity >= 0 && scalar(@outs) != $out_arity) {
532
			die "Fatal error: Op ${op} has different number of outs and out_arity\n";
533
534
		}

Christian Würdig's avatar
Christian Würdig committed
535
		$num_outs = $#outs + 1;
536

537
538
539
540
541
542
543
544
545
546
		if ($num_outs > 0) {
			$obst_proj .= "\nenum pn_${op} {\n";

			for (my $idx = 0; $idx <= $#outs; $idx++) {
				# check, if we have additional flags annotated to out
				if ($outs[$idx] =~ /:((S|I)(\|(S|I))*)/) {
					push(@out_flags, $1);
					$outs[$idx] =~ s/:((S|I)(\|(S|I))*)//;
				}
				$obst_proj .= "\tpn_${op}_".$outs[$idx]." = ${idx},\n";
547
548
			}

549
550
			$obst_proj .= "};\n";
		}
551
		# outs have names, it must be a mode_T node
552
553
554
		if (!defined($n{mode})) {
			$n{mode} = "mode_T";
		}
555
	}
556
557
558
559
	if (exists($n{"ins"})) {
		undef my @ins;

		@ins = @{ $n{"ins"} };
560
		if($arity >= 0 && scalar(@ins) != $arity) {
561
			die "Fatal error: Op ${op} has different number of ins and arity\n";
562
		}
563

564
565
566
567
568
569
		if ($#ins >= 0) {
			$obst_proj .= "\nenum n_$op {\n";
			for (my $idx = 0; $idx <= $#ins; $idx++) {
				$obst_proj .= "\tn_${op}_".$ins[$idx]." = ${idx},\n";
			}
			$obst_proj .= "};\n";
570
		}
571
572
	}

573
	# Create opcode
Christian Würdig's avatar
Christian Würdig committed
574
	push(@obst_opvar, "ir_op *op_$op = NULL;\n");
575
	push(@obst_get_opvar, "ir_op *get_op_$op(void)         { return op_$op; }\n");
576
	push(@obst_get_opvar, "int    is_$op(const ir_node *n) { return get_$arch\_irn_opcode(n) == iro_$op; }\n\n");
Christian Würdig's avatar
Christian Würdig committed
577
578
579

	push(@obst_is_archirn, "is_$op(node)");

580
581
582
583
584
	$obst_header .= <<EOF;
extern ir_op *op_${op};
ir_op *get_op_${op}(void);
int is_${op}(const ir_node *n);
EOF
Christian Würdig's avatar
Christian Würdig committed
585

586
	my $attr_type= $n{attr_type};
587
588
	if(!defined($attr_type)) {
		$attr_type = $default_attr_type;
589
		$n{attr_type} = $attr_type;
590
591
	}

592
593
594
595
596
597
	# determine hash function
	my $hash_func;
	if (exists($n{"hash_func"})) {
		$hash_func = $n{"hash_func"};
	}

598
	# determine compare function
Matthias Braun's avatar
Matthias Braun committed
599
600
601
602
	my $cmp_attr_func;
	if (exists($n{"cmp_attr"})) {
		my $cmpcode = $n{"cmp_attr"};

603
		push(@obst_cmp_attr, "static int cmp_attr_$op(const ir_node *a, const ir_node *b) {\n");
Matthias Braun's avatar
Matthias Braun committed
604
		if($cmpcode =~ m/attr_a/) {
605
			push(@obst_cmp_attr, "\tconst ${attr_type} *attr_a = get_irn_generic_attr_const(a);\n");
606
607
		} else {
			push(@obst_cmp_attr, "\t(void) a;\n");
Matthias Braun's avatar
Matthias Braun committed
608
609
		}
		if($cmpcode =~ m/attr_b/) {
610
			push(@obst_cmp_attr, "\tconst ${attr_type} *attr_b = get_irn_generic_attr_const(b);\n");
611
612
		} else {
			push(@obst_cmp_attr, "\t(void) b;\n");
613
		}
Matthias Braun's avatar
Matthias Braun committed
614
		push(@obst_cmp_attr, "\t${cmpcode}\n");
Christian Würdig's avatar
Christian Würdig committed
615
616
		push(@obst_cmp_attr, "}\n\n");

Matthias Braun's avatar
Matthias Braun committed
617
		$cmp_attr_func = "cmp_attr_${op}";
618
619
	} elsif ($attr_type eq "") {
		$cmp_attr_func = "NULL";
620
621
622
623
	} else {
		if(defined($compare_attr{${attr_type}})) {
			$cmp_attr_func = $compare_attr{${attr_type}};
		} else {
624
			die "Fatal error: No compare function defined for ${attr_type} attributes.";
625
		}
Christian Würdig's avatar
Christian Würdig committed
626
627
	}

628
629
630
	my %constructors;
	if (exists($n{constructors})) {
		%constructors = %{ $n{constructors} };
631
	} else {
632
633
634
635
636
637
638
		# Create 1 default constructor
		my %constructor = ();
		foreach my $a ("comment", "ins", "outs", "args", "attr", "units",
				"reg_req", "init_attr", "irn_flags", "mode", "arity",
				"out_arity", "custominit") {
			if (defined($n{$a})) {
				$constructor{$a} = $n{$a};
Christian Würdig's avatar
Christian Würdig committed
639
640
			}
		}
641
642
		%constructors = ( "" => \%constructor );
	}
643

644
645
646
647
648
649
650
	foreach my $constr (keys(%constructors)) {
		my %cstr = %{ $constructors{$constr} };
		# Copy some values from outer node if they don't exists in the constr
		foreach my $a ("ins", "outs", "irn_flags", "mode", "args", "attr",
		               "custominit") {
			if (!defined($cstr{$a}) && defined($n{$a})) {
				$cstr{$a} = $n{$a};
651
			}
Christian Würdig's avatar
Christian Würdig committed
652
		}
653
654
		create_constructor($orig_op, $constr, \%cstr, \%n);
	}
Christian Würdig's avatar
Christian Würdig committed
655
656

	# set default values for state and flags if not given
657
658
659
660
	$n{"state"}     = "floats" if (! exists($n{"state"}));
	$n{"op_flags"}  = ["none"] if (! exists($n{"op_flags"}));
	$n{"dump_func"} = "${arch}_dump_node" if (!exists($n{"dump_func"}));
	my $dump_func = $n{"dump_func"};
Christian Würdig's avatar
Christian Würdig committed
661

662
	push(@obst_new_irop, "\n\tmemset(&ops, 0, sizeof(ops));\n");
Matthias Braun's avatar
Matthias Braun committed
663
	push(@obst_new_irop, "\tops.be_ops        = be_ops;\n");
664
	push(@obst_new_irop, "\tops.dump_node     = ${dump_func};\n");
Christian Würdig's avatar
Christian Würdig committed
665

Matthias Braun's avatar
Matthias Braun committed
666
667
	if (defined($cmp_attr_func)) {
		push(@obst_new_irop, "\tops.node_cmp_attr = ${cmp_attr_func};\n");
Christian Würdig's avatar
Christian Würdig committed
668
	}
669
670
	my $copy_attr_func = $copy_attr{$attr_type};
	if (!defined($copy_attr_func)) {
671
672
673
674
675
		if ($attr_type eq "") {
			$copy_attr_func = "NULL";
		} else {
			$copy_attr_func = $default_copy_attr;
		}
676
677
678
679
	}
	if (defined($copy_attr_func)) {
		push(@obst_new_irop, "\tops.copy_attr = ${copy_attr_func};\n");
	}
680
681
682
	if (defined($hash_func)) {
		push(@obst_new_irop, "\tops.hash = ${hash_func};\n");
	}
Christian Würdig's avatar
Christian Würdig committed
683

684
	my %known_flags = map { $_ => 1 } (
685
686
687
688
		"none", "labeled", "commutative", "cfopcode", "unknown_jump", "fragile",
		"forking", "highlevel", "constlike", "always_opt", "keep",
		"start_block", "uses_memory", "dump_noblock", "dump_noinput",
		"machine", "machine_op", "cse_neutral"
689
	);
Matthias Braun's avatar
Matthias Braun committed
690
	my $is_fragile = 0;
691
692
693
694
	foreach my $flag (@{$n{"op_flags"}}) {
		if (not defined($known_flags{$flag})) {
			print STDERR "WARNING: Flag '$flag' in opcode $op is unknown\n";
		}
Matthias Braun's avatar
Matthias Braun committed
695
696
697
		if ($flag eq "fragile") {
			$is_fragile = 1;
		}
698
699
700
701
	}
	my @mapped = map { "irop_flag_$_" } @{$n{"op_flags"}};
	my $op_flags = join('|', @mapped);

702
703
704
705
706
	my $attr_size = "0";
	if ($attr_type ne "") {
		$attr_size = "sizeof(${attr_type})"
	}

707
	$n_opcodes++;
708
	$temp  = "\top_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", $op_flags";
709
	$temp .= "|irop_flag_machine, ".translate_arity($arity).", 0, ${attr_size}, &ops);\n";
Christian Würdig's avatar
Christian Würdig committed
710
	push(@obst_new_irop, $temp);
Matthias Braun's avatar
Matthias Braun committed
711
712
713
	if ($is_fragile) {
		push(@obst_new_irop, "\tir_op_set_fragile_indices(op_${op}, n_${op}_mem, pn_${op}_X_regular, pn_${op}_X_except);\n");
	}
714
	push(@obst_new_irop, "\tset_op_tag(op_$op, $arch\_op_tag);\n");
715
	if(defined($default_op_attr_type)) {
716
		push(@obst_new_irop, "\tattr = &attrs[iro_$op];\n");
717
718
719
720
721
722
		if(defined($n{op_attr_init})) {
			push(@obst_new_irop, "\t".$n{op_attr_init}."\n");
		}
		push(@obst_new_irop, "\tset_op_attr(op_$op, attr);\n");
	}

723
	push(@obst_enum_op, "\tiro_$op,\n");
Christian Würdig's avatar
Christian Würdig committed
724

725
	$obst_header .= "\n";
726
}
727
728
push(@obst_enum_op, "\tiro_$arch\_last_generated,\n");
push(@obst_enum_op, "\tiro_$arch\_last = iro_$arch\_last_generated");
729
730
push(@obst_enum_op, " + $additional_opcodes") if (defined($additional_opcodes));
push(@obst_enum_op, "\n} $arch\_opcodes;\n\n");
731
732
733

# emit the code

734
open(OUT, ">$target_c") || die("Fatal error: Could not open $target_c, reason: $!\n");
735

736
737
738
print OUT "#include \"gen_$arch\_regalloc_if.h\"\n";
print OUT "#include \"irverify_t.h\"\n";
print OUT "\n";
Christian Würdig's avatar
Christian Würdig committed
739
740
print OUT @obst_cmp_attr;
print OUT "\n";
741
742
743
744
print OUT @obst_opvar;
print OUT "\n";
print OUT @obst_get_opvar;
print OUT "\n";
745

746
print OUT<<EOF;
747

748
749
static int $arch\_opcode_start = -1;
static int $arch\_opcode_end   = -1;
750

751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
EOF

# build the FOURCC arguments from $arch

my ($a, $b, $c, $d) = ('\0', '\0', '\0', '\0');

if (length($arch) >= 1) {
	$a = uc(substr($arch, 0, 1));
}

if (length($arch) >= 2) {
	$b = uc(substr($arch, 1, 1));
}

if (length($arch) >= 3) {
	$c = uc(substr($arch, 2, 1));
}

if (length($arch) >= 4) {
	$d = uc(substr($arch, 3, 1));
}

print OUT<<ENDOFISIRN;

Michael Beck's avatar
Michael Beck committed
775
/** A tag for the $arch opcodes. Note that the address is used as a tag value, NOT the FOURCC code. */
776
#define $arch\_op_tag FOURCC('$a', '$b', '$c', '$d')
Michael Beck's avatar
Michael Beck committed
777

778
779
/** Return the opcode number of the first $arch opcode. */
int get_$arch\_opcode_first(void) {
780
	return $arch\_opcode_start;
781
782
}

783
784
/** Return the opcode number of the last $arch opcode + 1. */
int get_$arch\_opcode_last(void) {
785
	return $arch\_opcode_end;
786
787
}

Michael Beck's avatar
Michael Beck committed
788
789
/** Return 1 if the given opcode is a $arch machine op, 0 otherwise */
int is_$arch\_op(const ir_op *op) {
790
	return get_op_tag(op) == $arch\_op_tag;
Michael Beck's avatar
Michael Beck committed
791
792
}

793
/** Return 1 if the given node is a $arch machine node, 0 otherwise */
794
int is_$arch\_irn(const ir_node *node) {
Michael Beck's avatar
Michael Beck committed
795
	return is_$arch\_op(get_irn_op(node));
796
797
}

798
int get_$arch\_irn_opcode(const ir_node *node) {
799
800
801
	if (is_$arch\_irn(node))
		return get_irn_opcode(node) - $arch\_opcode_start;
	return -1;
802
803
}

804
805
ENDOFISIRN

806
807
808
809
print OUT <<END;
#ifdef BIT
#undef BIT
#endif
810
#define BIT(x)  (1 << (x))
811
812
813
814
815
816
817
818
819

END

print OUT @obst_limit_func;
print OUT "\n";

print OUT @obst_reg_reqs;
print OUT "\n";

820
print OUT<<ENDOFMAIN;
821
822
$obst_constructor

823
/**
824
 * Creates the $arch specific Firm machine operations
825
826
 * needed for the assembler irgs.
 */
Matthias Braun's avatar
Matthias Braun committed
827
void $arch\_create_opcodes(const arch_irn_ops_t *be_ops) {
828
829
830
	ir_op_ops  ops;
	int        cur_opcode;
	static int run_once = 0;
831
832
ENDOFMAIN

833
834
	if (defined($default_op_attr_type)) {
		print OUT "\t$default_op_attr_type *attr, *attrs;\n";
835
836
837
	}

print OUT<<ENDOFMAIN;
838
839
840
841
842
843

	if (run_once)
		return;
	run_once = 1;

	cur_opcode = get_next_ir_opcodes(iro_$arch\_last);
844

845
	$arch\_opcode_start = cur_opcode;
846
847
ENDOFMAIN

848
	if (defined($default_op_attr_type)) {
849
		print OUT "\tattrs = XMALLOCNZ(${default_op_attr_type}, iro_${arch}_last);\n";
850
851
	}

852
print OUT @obst_new_irop;
853
print OUT "\n";
854
855
print OUT "\t$arch\_register_additional_opcodes(cur_opcode);\n" if (defined($additional_opcodes));
print OUT "\t$arch\_opcode_end = cur_opcode + iro_$arch\_last";
856
857
print OUT " + $additional_opcodes" if (defined($additional_opcodes));
print OUT ";\n";
858
859
860
861
print OUT "}\n";

close(OUT);

862
open(OUT, ">$target_h") || die("Fatal error: Could not open $target_h, reason: $!\n");
863

864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
my $creation_time = localtime(time());
my $tmp = uc($arch);

print OUT<<EOF;
/**
 * \@file
 * \@brief Function prototypes for the new opcode functions.
 * \@note  DO NOT EDIT THIS FILE, your changes will be lost.
 *        Edit $specfile instead.
 *        created by: $0 $specfile $target_dir
 * \@date  $creation_time
 */
#ifndef FIRM_BE_${tmp}_GEN_${tmp}_NEW_NODES_H
#define FIRM_BE_${tmp}_GEN_${tmp}_NEW_NODES_H

EOF

881
print OUT @obst_enum_op;
882
print OUT <<EOF;
883
int is_${arch}_irn(const ir_node *node);
884
int is_${arch}_op(const ir_op *op);
885
886
887
888
889
890
891

int get_${arch}_opcode_first(void);
int get_${arch}_opcode_last(void);
int get_${arch}_irn_opcode(const ir_node *node);
${obst_header}
${obst_proj}

892
893
#endif
EOF
894
895

close(OUT);
896
897
898
899
900

###
# Translates numeric arity into string constant.
###
sub translate_arity {
Christian Würdig's avatar
Christian Würdig committed
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
	my $arity = shift;

	if ($arity =~ /^\d+$/) {
		if    ($arity == 0) {
			return "oparity_zero";
		}
		elsif ($arity == 1) {
			return "oparity_unary";
		}
		elsif ($arity == 2) {
			return "oparity_binary";
		}
		elsif ($arity == 3) {
			return "oparity_trinary";
		}
		else {
917
			return "oparity_any";
Christian Würdig's avatar
Christian Würdig committed
918
		}
919
920
921
922
923
	} elsif ($arity == $ARITY_VARIABLE) {
		return "oparity_variable";
	} elsif ($arity == $ARITY_DYNAMIC) {
		return "oparity_dynamic";
	} else {
924
		die "Fatal error: Unknown arity $arity";
Christian Würdig's avatar
Christian Würdig committed
925
	}
926
}
927
928
929
930

###
# Return the list of pointers for the given execution units.
###
931
sub gen_execunit_list_initializer {
932
933
934
	my $units   = shift;
	my $uc_arch = uc($arch);
	my $ret     = "";
935
936
	my $ret2    = "";
	my %init;
937
938

	foreach my $unit (@{ $units }) {
939
		if ($unit eq "DUMMY") {
940
			push(@{ $init{"DUMMY"} }, "\t\t&be_machine_execution_units_DUMMY[0]");
941
942
		}
		elsif (exists($cpu{"$unit"})) {
943
944
945
			# operation can be executed on all units of this type
			# -> add them all
			my $tp_name = "$arch\_execution_units_$unit";
Christian Würdig's avatar
Christian Würdig committed
946
			my $idx     = 0;
947
			foreach (@{ $cpu{"$unit"} }) {
Christian Würdig's avatar
Christian Würdig committed
948
				next if ($idx++ == 0);  # skip first element (it's not a unit)
949
				my $unit_name = "$uc_arch\_EXECUNIT_TP_$unit\_$_";
950
				push(@{ $init{"$unit"} }, "\t\t&".$tp_name."[".$unit_name."]");
951
952
953
954
955
956
957
958
959
960
961
			}
		}
		else {
			# operation can be executed only a certain unit
			# -> find corresponding unit type
			my $found = 0;
TP_SEARCH:	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";
962
						push(@{ $init{"$unit"} }, "\t\t&".$tp_name."[".$unit_name."]");
963
						$found = 1;
964
965
966
967
968
969
970
971
972
973
974
						last TP_SEARCH;
					}
				}
			}

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

975
976
	# prepare the 2-dim array init
	foreach my $key (keys(%init)) {
977
		$ret .= "\tstatic const be_execution_unit_t *allowed_units_".$key."[] =\n";
978
		$ret .= "\t{\n";
979
980
981
		foreach (@{ $init{"$key"} }) {
			$ret .= "$_,\n";
		}
982
983
		$ret .= "\t\tNULL\n";
		$ret .= "\t};\n";
984
		$ret2 .= "\t\tallowed_units_$key,\n";
985
	}
986
	$ret2 .= "\t\tNULL\n";
987

988
	$ret .= "\tstatic const be_execution_unit_t **exec_units[] =\n";
989
990
991
	$ret .= "\t{\n";
	$ret .= $ret2;
	$ret .= "\t};\n";
992
993
994

	return $ret;
}
995
996

sub mangle_requirements {
997
998
	my $reqs  = shift;
	my $class = shift;
999
	my $flags = shift;
1000

For faster browsing, not all history is shown. View entire blame