generate_new_opcodes.pl 32.9 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";
}
Matthias Braun's avatar
Matthias Braun committed
70
if(! %init_attr) {
71
	%init_attr = (
72
		"$default_attr_type" => "\tinit_${arch}_attributes(res, irn_flags_, in_reqs, n_res);",
73
74
	);
}
75
76
77
if(!defined($default_cmp_attr)) {
	$default_cmp_attr = "${arch}_compare_attr";
}
Matthias Braun's avatar
Matthias Braun committed
78
if(! %compare_attr) {
79
80
81
82
	%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
Matthias Braun's avatar
Matthias Braun committed
119
my @obst_free_irop;   # stack for free_ir_op calls
120
my @obst_enum_op;     # stack for creating the <arch>_opcode enum
121
my $obst_header;      # stack for function prototypes
122
my @obst_is_archirn;  # stack for the is_$arch_irn() function
Christian Würdig's avatar
Christian Würdig committed
123
my @obst_cmp_attr;    # stack for the compare attribute functions
124
my $obst_proj = "";   # stack for the pn_ numbers
125
126
my $orig_op;
my $arity;
Christian Würdig's avatar
Christian Würdig committed
127
my $cmp_attr_func;
128
my $temp;
129
my $n_opcodes = 0;    # number of opcodes
130
131
my $ARITY_VARIABLE = -1;
my $ARITY_DYNAMIC  = -2;
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
157
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;
}

158

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

162
$obst_header .= "void ${arch}_create_opcodes(const arch_irn_ops_t *be_ops);\n";
Matthias Braun's avatar
Matthias Braun committed
163
$obst_header .= "void ${arch}_free_opcodes(void);\n";
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
209
210
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;
	}
211
212
213
	if ($out_arity != 0 && $out_arity != 1 && !defined($known_mode)) {
		$known_mode = "mode_T";
	}
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
272
273

	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;
274
275
276
	ir_graph         *irg        = get_irn_irg(block);
	ir_op            *op         = op_${arch}_${op};
	arch_irn_flags_t  irn_flags_ = arch_irn_flags_none;
277
	ir_node          *res;
278
	backend_info_t   *info;
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
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
	}

	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;
371
	info->out_infos[${idx}].req = &${reqstruct};
372
373
374
375
376
377
378
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
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";
406
407
408
409
410
411
		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",
412
			"not_scheduled"    => "arch_irn_flags_not_scheduled",
413
		);
Matthias Braun's avatar
Matthias Braun committed
414
		if (%custom_irn_flags) {
415
416
			%known_irn_flags = (%known_irn_flags, %custom_irn_flags);
		}
417
418
419
		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";
420
			} else {
421
				$temp .= "\tirn_flags_ |= " . $known_irn_flags{$flag} . ";\n";
422
423
424
425
426
427
			}
		}
		$temp .= "\n";
	}

	# lookup init function
428
	my $attr_init_code = "(void)in;(void)irn_flags_;(void)in_reqs;(void)n_res;";
429
430
431
432
433
	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}'";
		}
434
435
436
437
438
439
440
441
442
443
444
445
	}
	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);
446
	res = new_ir_node(dbgi, irg, block, op, mode, arity, in);
447
448
449
450
451

	/* init node attributes */
	${attr_init_code}
	${custominit}
	info = be_get_info(res);
452
	(void) info; /* avoid potential warning */
453
${set_out_reqs}
454
455
456
457

EOF

	if (exists($n->{"init_attr"})) {
458
		$temp .= "\tattr = (${attr_type}*)get_irn_generic_attr(res);\n";
459
		$temp .= "\t(void) attr; /* avoid potential warning */\n";
460
461
462
463
464
465
		$temp .= "\t".$n->{"init_attr"}."\n";
	}

	$temp .= <<EOF;
	/* optimize node */
	res = optimize_node(res);
466
	irn_verify_irg(res, irg);
467
468
469
470
471
472
473
474
475
476

	return res;
EOF

	$obst_constructor .= $temp;

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

477
push(@obst_enum_op, "typedef enum ${arch}_opcodes {\n");
478
foreach my $op (keys(%nodes)) {
479
	my %n        = %{ $nodes{"$op"} };
480
	my $known_mode;
481
	my $num_outs = 0;
482
	my $out_arity;
483
	my @out_flags;
Christian Würdig's avatar
Christian Würdig committed
484

485
486
487
488
489
	# determine arity
	$arity = 0;
	if(exists($n{"arity"})) {
		$arity = $n{"arity"};
	} elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
490
		$arity = scalar(@{ $n{"reg_req"}{"in"} });
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
	} 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;
513
514
	}

Christian Würdig's avatar
Christian Würdig committed
515
516
	$orig_op = $op;
	$op      = $arch."_".$op;
517
	$temp    = "";
Christian Würdig's avatar
Christian Würdig committed
518

519
	# define proj numbers and in numbers
520
521
	if (exists($n{"outs"})) {
		undef my @outs;
522

523
		@outs = @{ $n{"outs"} };
524
		if($out_arity >= 0 && scalar(@outs) != $out_arity) {
525
			die "Fatal error: Op ${op} has different number of outs and out_arity\n";
526
527
		}

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

530
531
532
533
534
535
536
537
538
539
		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";
540
541
			}

542
543
			$obst_proj .= "};\n";
		}
544
		# outs have names, it must be a mode_T node
545
546
547
		if (!defined($n{mode})) {
			$n{mode} = "mode_T";
		}
548
	}
549
550
551
552
	if (exists($n{"ins"})) {
		undef my @ins;

		@ins = @{ $n{"ins"} };
553
		if($arity >= 0 && scalar(@ins) != $arity) {
554
			die "Fatal error: Op ${op} has different number of ins and arity\n";
555
		}
556

557
558
559
560
561
562
		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";
563
		}
564
565
	}

566
	# Create opcode
Christian Würdig's avatar
Christian Würdig committed
567
	push(@obst_opvar, "ir_op *op_$op = NULL;\n");
568
	push(@obst_get_opvar, "ir_op *get_op_$op(void)         { return op_$op; }\n");
569
	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
570
571
572

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

573
574
575
576
577
	$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
578

579
	my $attr_type= $n{attr_type};
580
581
	if(!defined($attr_type)) {
		$attr_type = $default_attr_type;
582
		$n{attr_type} = $attr_type;
583
584
	}

585
586
587
588
589
590
	# determine hash function
	my $hash_func;
	if (exists($n{"hash_func"})) {
		$hash_func = $n{"hash_func"};
	}

591
	# determine compare function
Matthias Braun's avatar
Matthias Braun committed
592
593
594
595
	my $cmp_attr_func;
	if (exists($n{"cmp_attr"})) {
		my $cmpcode = $n{"cmp_attr"};

596
		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
597
		if($cmpcode =~ m/attr_a/) {
598
			push(@obst_cmp_attr, "\tconst ${attr_type} *attr_a = get_irn_generic_attr_const(a);\n");
599
600
		} else {
			push(@obst_cmp_attr, "\t(void) a;\n");
Matthias Braun's avatar
Matthias Braun committed
601
602
		}
		if($cmpcode =~ m/attr_b/) {
603
			push(@obst_cmp_attr, "\tconst ${attr_type} *attr_b = get_irn_generic_attr_const(b);\n");
604
605
		} else {
			push(@obst_cmp_attr, "\t(void) b;\n");
606
		}
Matthias Braun's avatar
Matthias Braun committed
607
		push(@obst_cmp_attr, "\t${cmpcode}\n");
Christian Würdig's avatar
Christian Würdig committed
608
609
		push(@obst_cmp_attr, "}\n\n");

Matthias Braun's avatar
Matthias Braun committed
610
		$cmp_attr_func = "cmp_attr_${op}";
611
612
	} elsif ($attr_type eq "") {
		$cmp_attr_func = "NULL";
613
614
615
616
	} else {
		if(defined($compare_attr{${attr_type}})) {
			$cmp_attr_func = $compare_attr{${attr_type}};
		} else {
617
			die "Fatal error: No compare function defined for ${attr_type} attributes.";
618
		}
Christian Würdig's avatar
Christian Würdig committed
619
620
	}

621
622
623
	my %constructors;
	if (exists($n{constructors})) {
		%constructors = %{ $n{constructors} };
624
	} else {
625
626
627
628
629
630
631
		# 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
632
633
			}
		}
634
635
		%constructors = ( "" => \%constructor );
	}
636

637
638
639
640
641
642
643
	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};
644
			}
Christian Würdig's avatar
Christian Würdig committed
645
		}
646
647
		create_constructor($orig_op, $constr, \%cstr, \%n);
	}
Christian Würdig's avatar
Christian Würdig committed
648
649

	# set default values for state and flags if not given
650
651
652
653
	$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
654

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

Matthias Braun's avatar
Matthias Braun committed
659
660
	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
661
	}
662
663
	my $copy_attr_func = $copy_attr{$attr_type};
	if (!defined($copy_attr_func)) {
664
665
666
667
668
		if ($attr_type eq "") {
			$copy_attr_func = "NULL";
		} else {
			$copy_attr_func = $default_copy_attr;
		}
669
670
671
672
	}
	if (defined($copy_attr_func)) {
		push(@obst_new_irop, "\tops.copy_attr = ${copy_attr_func};\n");
	}
673
674
675
	if (defined($hash_func)) {
		push(@obst_new_irop, "\tops.hash = ${hash_func};\n");
	}
Christian Würdig's avatar
Christian Würdig committed
676

677
	my %known_flags = map { $_ => 1 } (
678
679
680
		"none", "labeled", "commutative", "cfopcode", "unknown_jump", "fragile",
		"forking", "highlevel", "constlike", "always_opt", "keep",
		"start_block", "uses_memory", "dump_noblock", "dump_noinput",
681
		"cse_neutral"
682
	);
Matthias Braun's avatar
Matthias Braun committed
683
	my $is_fragile = 0;
684
685
686
687
	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
688
689
690
		if ($flag eq "fragile") {
			$is_fragile = 1;
		}
691
692
693
694
	}
	my @mapped = map { "irop_flag_$_" } @{$n{"op_flags"}};
	my $op_flags = join('|', @mapped);

695
696
697
698
699
	my $attr_size = "0";
	if ($attr_type ne "") {
		$attr_size = "sizeof(${attr_type})"
	}

700
	$n_opcodes++;
701
	$temp  = "\top_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", $op_flags";
702
	$temp .= ", ".translate_arity($arity).", 0, ${attr_size}, &ops);\n";
Christian Würdig's avatar
Christian Würdig committed
703
	push(@obst_new_irop, $temp);
Matthias Braun's avatar
Matthias Braun committed
704
	if ($is_fragile) {
705
706
		push(@obst_new_irop, "\tir_op_set_memory_index(op_${op}, n_${op}_mem);\n");
		push(@obst_new_irop, "\tir_op_set_fragile_indices(op_${op}, pn_${op}_X_regular, pn_${op}_X_except);\n");
Matthias Braun's avatar
Matthias Braun committed
707
	}
708
	push(@obst_new_irop, "\tset_op_tag(op_$op, $arch\_op_tag);\n");
709
	if(defined($default_op_attr_type)) {
710
		push(@obst_new_irop, "\tattr = &attrs[iro_$op];\n");
711
712
713
714
715
716
		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");
	}

Matthias Braun's avatar
Matthias Braun committed
717
718
	push(@obst_free_irop, "\tfree_ir_op(op_$op); op_$op = NULL;\n");

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

721
	$obst_header .= "\n";
722
}
723
724
push(@obst_enum_op, "\tiro_$arch\_last_generated,\n");
push(@obst_enum_op, "\tiro_$arch\_last = iro_$arch\_last_generated");
725
726
push(@obst_enum_op, " + $additional_opcodes") if (defined($additional_opcodes));
push(@obst_enum_op, "\n} $arch\_opcodes;\n\n");
727
728
729

# emit the code

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

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

743
print OUT<<EOF;
744

745
746
static int $arch\_opcode_start = -1;
static int $arch\_opcode_end   = -1;
747

748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
772
/** A tag for the $arch opcodes. Note that the address is used as a tag value, NOT the FOURCC code. */
773
#define $arch\_op_tag FOURCC('$a', '$b', '$c', '$d')
Michael Beck's avatar
Michael Beck committed
774

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

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

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

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

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

801
802
ENDOFISIRN

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

END

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

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

817
print OUT<<ENDOFMAIN;
818
819
$obst_constructor

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

830
831
	if (defined($default_op_attr_type)) {
		print OUT "\t$default_op_attr_type *attr, *attrs;\n";
832
833
834
	}

print OUT<<ENDOFMAIN;
835
836

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

838
	$arch\_opcode_start = cur_opcode;
839
840
ENDOFMAIN

841
	if (defined($default_op_attr_type)) {
842
		print OUT "\tattrs = XMALLOCNZ(${default_op_attr_type}, iro_${arch}_last);\n";
843
844
	}

845
print OUT @obst_new_irop;
846
print OUT "\n";
847
848
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";
849
850
print OUT " + $additional_opcodes" if (defined($additional_opcodes));
print OUT ";\n";
Matthias Braun's avatar
Matthias Braun committed
851
852
853
854
855
856
857
858
859
860
861
862
print OUT <<ENDOFMAIN;
}

void $arch\_free_opcodes(void)
{
ENDOFMAIN

print OUT @obst_free_irop;

print OUT <<ENDOFMAIN;
}
ENDOFMAIN
863
864
865

close(OUT);

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

868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
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

885
print OUT @obst_enum_op;
886
print OUT <<EOF;
887
int is_${arch}_irn(const ir_node *node);
888
int is_${arch}_op(const ir_op *op);
889
890
891
892
893
894
895

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}

896
897
#endif
EOF
898
899

close(OUT);
900
901
902
903
904

###
# Translates numeric arity into string constant.
###
sub translate_arity {
Christian Würdig's avatar
Christian Würdig committed
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
	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 {
921
			return "oparity_any";
Christian Würdig's avatar
Christian Würdig committed
922
		}
923
924
925
926
927
	} elsif ($arity == $ARITY_VARIABLE) {
		return "oparity_variable";
	} elsif ($arity == $ARITY_DYNAMIC) {
		return "oparity_dynamic";
	} else {
928
		die "Fatal error: Unknown arity $arity";
Christian Würdig's avatar
Christian Würdig committed
929
	}
930
}
931

932
sub mangle_requirements {
933
934
	my $reqs  = shift;
	my $class = shift;
935
	my $flags = shift;
936
937
938
939
940
941
942
943

	my @alternatives = split(/ /, $reqs);
	for(my $idx = 0; $idx < scalar(@alternatives); $idx++) {
		$alternatives[$idx] =~ s/!/not_/g;
	}

	@alternatives = sort @alternatives;

944
	my $name = $class."_".join('_', @alternatives);
945
946
947
948
	if (defined($flags)) {
		$flags =~ s/\|/_/g;
		$name .= "_$flags";
	}
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

	return $name;
}

###
# Determines whether $name is a specified register class or not.
# @return 1 if name is register class, 0 otherwise
###
sub is_reg_class {
    my $name = shift;
    return 1 if exists($reg_classes{"$name"});
    return 0;
}

###
# Returns the register class for a given register.
# @return class or undef
###
sub get_reg_class {
    my $reg = shift;
    $reg = substr($reg, 1) if ($reg =~ /!.*/);
    return $reg2class{"$reg"}{"class"} if (exists($reg2class{"$reg"}));
    return undef;
}

###
975
# Returns the index of a given register within its register class.
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# @return index or undef
###
sub get_reg_index {
    my $reg = shift;
    return $reg2class{"$reg"}{"index"} if (exists($reg2class{"$reg"}));
    return undef;
}

###
# 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 $is_in = shift;
	my @idx_class;

	my $inout = ($is_in ? "in" : "out");

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

		for (my $idx = 0; $idx <= $#reqs; $idx++) {
For faster browsing, not all history is shown. View entire blame