generate_new_opcodes.pl 32.5 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++;
Matthias Braun's avatar
Matthias Braun committed
701
	$temp  = "\top = 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) {
Matthias Braun's avatar
Matthias Braun committed
705
706
707
708
709
710
		push(@obst_new_irop, "\tir_op_set_memory_index(op, n_${op}_mem);\n");
		push(@obst_new_irop, "\tir_op_set_fragile_indices(op, pn_${op}_X_regular, pn_${op}_X_except);\n");
	}
	push(@obst_new_irop, "\tset_op_tag(op, $arch\_op_tag);\n");
	if(defined($n{op_attr_init})) {
		push(@obst_new_irop, "\t".$n{op_attr_init}."\n");
711
	}
Matthias Braun's avatar
Matthias Braun committed
712
	push(@obst_new_irop, "\top_${op} = op;\n");
713

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

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

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

# emit the code

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

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

740
print OUT<<EOF;
741

742
743
static int $arch\_opcode_start = -1;
static int $arch\_opcode_end   = -1;
744

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

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

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

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

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

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

798
799
ENDOFISIRN

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

END

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

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

814
print OUT<<ENDOFMAIN;
815
816
$obst_constructor

817
/**
818
 * Creates the $arch specific Firm machine operations
819
820
 * needed for the assembler irgs.
 */
Matthias Braun's avatar
Matthias Braun committed
821
822
void $arch\_create_opcodes(const arch_irn_ops_t *be_ops)
{
823
	ir_op_ops  ops;
Matthias Braun's avatar
Matthias Braun committed
824
825
	ir_op     *op;
	int        cur_opcode = get_next_ir_opcodes(iro_$arch\_last);
826

827
	$arch\_opcode_start = cur_opcode;
828
829
830
ENDOFMAIN

print OUT @obst_new_irop;
831
print OUT "\n";
832
833
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";
834
835
print OUT " + $additional_opcodes" if (defined($additional_opcodes));
print OUT ";\n";
Matthias Braun's avatar
Matthias Braun committed
836
837
838
839
840
841
842
843
844
845
846
847
print OUT <<ENDOFMAIN;
}

void $arch\_free_opcodes(void)
{
ENDOFMAIN

print OUT @obst_free_irop;

print OUT <<ENDOFMAIN;
}
ENDOFMAIN
848
849
850

close(OUT);

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

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
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

870
print OUT @obst_enum_op;
871
print OUT <<EOF;
872
int is_${arch}_irn(const ir_node *node);
873
int is_${arch}_op(const ir_op *op);
874
875
876
877
878
879
880

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}

881
882
#endif
EOF
883
884

close(OUT);
885
886
887
888
889

###
# Translates numeric arity into string constant.
###
sub translate_arity {
Christian Würdig's avatar
Christian Würdig committed
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
	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 {
906
			return "oparity_any";
Christian Würdig's avatar
Christian Würdig committed
907
		}
908
909
910
911
912
	} elsif ($arity == $ARITY_VARIABLE) {
		return "oparity_variable";
	} elsif ($arity == $ARITY_DYNAMIC) {
		return "oparity_dynamic";
	} else {
913
		die "Fatal error: Unknown arity $arity";
Christian Würdig's avatar
Christian Würdig committed
914
	}
915
}
916

917
sub mangle_requirements {
918
919
	my $reqs  = shift;
	my $class = shift;
920
	my $flags = shift;
921
922
923
924
925
926
927
928

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

	@alternatives = sort @alternatives;

929
	my $name = $class."_".join('_', @alternatives);
930
931
932
933
	if (defined($flags)) {
		$flags =~ s/\|/_/g;
		$name .= "_$flags";
	}
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959

	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;
}

###
960
# Returns the index of a given register within its register class.
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
# @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++) {
			my $class = undef;
987
			my ($req,) = split(/:/, $reqs[$idx]);
988

989
			if ($req eq "none") {
990
				$class = "none";
991
992
			} elsif (is_reg_class($req)) {
				$class = $req;
993
			} else {
994
				my @regs = split(/ /, $req);
995
996
997
998
999
1000
GET_CLASS:		foreach my $reg (@regs) {
					if ($reg =~ /!?(in|out)\_r\d+/ || $reg =~ /!in/) {
						$class = "UNKNOWN_CLASS";
					} else {
						$class = get_reg_class($reg);
						if (!defined $class) {
For faster browsing, not all history is shown. View entire blame