generate_new_opcodes.pl 29.6 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
# 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];

our $arch;
our %nodes;
35
our $default_attr_type;
36
our $default_cmp_attr;
37
our $default_copy_attr;
38
our %init_attr;
39
our $custom_init_attr_func;
40
our %compare_attr;
41
our %copy_attr;
42
our %reg_classes;
43
our %custom_irn_flags;
44
45
46
47
48
49
50

# include spec file

my $return;

no strict "subs";
unless ($return = do $specfile) {
51
52
53
	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;
54
55
56
}
use strict "subs";

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

60
61
62
if(!defined($default_attr_type)) {
	$default_attr_type = "${arch}_attr_t";
}
Matthias Braun's avatar
Matthias Braun committed
63
if(! %init_attr) {
64
	%init_attr = (
65
		"$default_attr_type" => "\tinit_${arch}_attributes(res, irn_flags_, in_reqs, n_res);",
66
67
	);
}
68
69
70
if(!defined($default_cmp_attr)) {
	$default_cmp_attr = "${arch}_compare_attr";
}
Matthias Braun's avatar
Matthias Braun committed
71
if(! %compare_attr) {
72
73
74
75
	%compare_attr = (
		"${default_attr_type}" => "${default_cmp_attr}",
	);
}
76

77
78
# create c code file from specs

79
80
81
82
83
84
85
86
87
88
89
my $obst_limit_func  = ""; #
my $obst_reg_reqs    = ""; #
my $obst_opvar       = ""; # buffer for the "ir_op *op_<arch>_<op-name> = NULL;" statements
my $obst_get_opvar   = ""; # buffer for the get_op_<arch>_<op-name>() functions
my $obst_constructor = ""; # buffer for node constructor functions
my $obst_new_irop    = ""; # buffer for the new_ir_op calls
my $obst_free_irop   = ""; # buffer for free_ir_op calls
my $obst_enum_op     = ""; # buffer for creating the <arch>_opcode enum
my $obst_header      = ""; # buffer for function prototypes
my $obst_cmp_attr    = ""; # buffer for the compare attribute functions
my $obst_proj        = ""; # buffer for the pn_ numbers
90
91
my $orig_op;
my $arity;
Christian Würdig's avatar
Christian Würdig committed
92
my $cmp_attr_func;
93
my $temp;
94
my $n_opcodes = 0;    # number of opcodes
95
96
my $ARITY_VARIABLE = -1;
my $ARITY_DYNAMIC  = -2;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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;
}

123

124
$obst_header .= "void ${arch}_create_opcodes(const arch_irn_ops_t *be_ops);\n";
Matthias Braun's avatar
Matthias Braun committed
125
$obst_header .= "void ${arch}_free_opcodes(void);\n";
126

127
128
129
130
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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;
	}
173
174
175
	if ($out_arity != 0 && $out_arity != 1 && !defined($known_mode)) {
		$known_mode = "mode_T";
	}
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

	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;
236
	arch_irn_flags_t irn_flags_ = arch_irn_flags_none;
237
238
239
240
EOF

	if($arity == $ARITY_DYNAMIC) {
		$temp .= <<EOF;
241
242
	int      const   arity      = -1;
	ir_node  const **in         = NULL;
243
244
245
246
EOF
	} elsif($arity == $ARITY_VARIABLE) {
	} else {
		$temp .= <<EOF;
247
	int      const   arity      = $arity;
248
249
250
EOF
		if($arity > 0) {
			$temp .= <<EOF;
251
	ir_node         *in[$arity];
252
253
254
EOF
		} else {
			$temp .= <<EOF;
255
	ir_node        **in         = NULL;
256
257
258
259
260
EOF
		}
	}
	if($out_arity == $ARITY_DYNAMIC) {
		$temp .= <<EOF;
261
	int      const   n_res      = -1;
262
263
264
265
EOF
	} elsif($out_arity == $ARITY_VARIABLE) {
	} else {
		$temp .= <<EOF;
266
	int      const   n_res      = ${out_arity};
267
268
269
270
271
272
273
274
275
276
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
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;
323
	info->out_infos[${idx}].req = &${reqstruct};
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
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};

	$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";
355
		my %known_irn_flags = (
356
357
358
359
360
361
			"none"             => "arch_irn_flag_none",
			"dont_spill"       => "arch_irn_flag_dont_spill",
			"rematerializable" => "arch_irn_flag_rematerializable",
			"modify_flags"     => "arch_irn_flag_modify_flags",
			"simple_jump"      => "arch_irn_flag_simple_jump",
			"not_scheduled"    => "arch_irn_flag_not_scheduled",
362
		);
Matthias Braun's avatar
Matthias Braun committed
363
		if (%custom_irn_flags) {
364
365
			%known_irn_flags = (%known_irn_flags, %custom_irn_flags);
		}
366
367
368
		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";
369
			} else {
370
				$temp .= "\tirn_flags_ |= " . $known_irn_flags{$flag} . ";\n";
371
372
373
374
375
376
			}
		}
		$temp .= "\n";
	}

	# lookup init function
377
	my $attr_init_code = "(void)in;(void)irn_flags_;(void)in_reqs;(void)n_res;";
378
379
380
381
382
	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}'";
		}
383
384
385
386
387
388
389
390
391
392
393
	}
	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 */
394
395
396
397
398
399
400
401
402
403
	ir_graph *irg  = get_irn_irg(block);
	ir_op    *op   = op_${arch}_${op};
EOF
	if (defined($known_mode)) {
		$temp .= <<EOF;
	ir_mode  *mode = ${known_mode};
EOF
	}
	$temp .= <<EOF;
	ir_node  *res  = new_ir_node(dbgi, irg, block, op, mode, arity, in);
404
405

	/* init node attributes */
406
407
408
409
410
EOF
	if ($attr_type ne "") {
		$temp .= <<EOF;
	${attr_type} *attr = (${attr_type}*)get_irn_generic_attr(res);
	(void) attr; /* avoid potential warning */
Matthias Braun's avatar
Matthias Braun committed
411
412
413
414
415
416
EOF
	}
	my $fixed = $on->{fixed};
	if (defined($fixed)) {
		$temp .= <<EOF;
	${fixed}
417
418
419
EOF
	}
	$temp .= <<EOF;
420
	${attr_init_code}
421
422
423
EOF
	if ($custominit ne "") {
		$temp .= <<EOF;
424
	${custominit}
425
426
427
428
EOF
	}
	$temp .= <<EOF;
	backend_info_t *info = be_get_info(res);
429
	(void) info; /* avoid potential warning */
430
${set_out_reqs}
431
432
433
434
435
436
437
438
439
EOF

	if (exists($n->{"init_attr"})) {
		$temp .= "\t".$n->{"init_attr"}."\n";
	}

	$temp .= <<EOF;
	/* optimize node */
	res = optimize_node(res);
Matthias Braun's avatar
Matthias Braun committed
440
	verify_new_node(irg, res);
441
442
443
444
445
446
447
448
449
450

	return res;
EOF

	$obst_constructor .= $temp;

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

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
my @node_attrs = (
	"args",
	"arity",
	"attr",
	"comment",
	"custominit",
	"init_attr",
	"ins",
	"irn_flags",
	"mode",
	"out_arity",
	"outs",
	"reg_req",
);

466
$obst_enum_op .= "typedef enum ${arch}_opcodes {\n";
467
foreach my $op (keys(%nodes)) {
468
	my %n        = %{ $nodes{"$op"} };
469
	my $known_mode;
470
	my $num_outs = 0;
471
	my $out_arity;
472
	my @out_flags;
Christian Würdig's avatar
Christian Würdig committed
473

474
475
476
477
478
	# determine arity
	$arity = 0;
	if(exists($n{"arity"})) {
		$arity = $n{"arity"};
	} elsif (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
479
		$arity = scalar(@{ $n{"reg_req"}{"in"} });
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
	} 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;
502
503
	}

Christian Würdig's avatar
Christian Würdig committed
504
505
	$orig_op = $op;
	$op      = $arch."_".$op;
506
	$temp    = "";
Christian Würdig's avatar
Christian Würdig committed
507

508
	# define proj numbers and in numbers
509
510
	if (exists($n{"outs"})) {
		undef my @outs;
511

512
		@outs = @{ $n{"outs"} };
513
		if($out_arity >= 0 && scalar(@outs) != $out_arity) {
514
			die "Fatal error: Op ${op} has different number of outs and out_arity\n";
515
516
		}

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

519
		if ($num_outs > 0) {
520
			$obst_proj .= "\ntypedef enum pn_$op {\n";
521
522
523
524
525
526
527
528

			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";
529
530
			}

531
			$obst_proj .= "} pn_${op};\n";
532
		}
533
		# outs have names, it must be a mode_T node
534
535
536
		if (!defined($n{mode})) {
			$n{mode} = "mode_T";
		}
537
	}
538
539
540
541
	if (exists($n{"ins"})) {
		undef my @ins;

		@ins = @{ $n{"ins"} };
542
		if($arity >= 0 && scalar(@ins) != $arity) {
543
			die "Fatal error: Op ${op} has different number of ins and arity\n";
544
		}
545

546
		if ($#ins >= 0) {
547
			$obst_proj .= "\ntypedef enum n_$op {\n";
548
549
550
			for (my $idx = 0; $idx <= $#ins; $idx++) {
				$obst_proj .= "\tn_${op}_".$ins[$idx]." = ${idx},\n";
			}
551
			$obst_proj .= "} n_$op;\n";
552
		}
553
554
	}

555
	# Create opcode
556
	$obst_opvar     .= "ir_op *op_$op = NULL;\n";
557
558
	$obst_get_opvar .= "bool is_$op(const ir_node *n)\n";
	$obst_get_opvar .= "{\n";
559
560
	$obst_get_opvar .= "\treturn get_irn_op(n) == op_$op;\n";
	$obst_get_opvar .= "}\n\n";
Christian Würdig's avatar
Christian Würdig committed
561

562
563
	$obst_header .= <<EOF;
extern ir_op *op_${op};
564
bool is_${op}(const ir_node *n);
565
EOF
Christian Würdig's avatar
Christian Würdig committed
566

567
	my $attr_type= $n{attr_type};
568
569
	if(!defined($attr_type)) {
		$attr_type = $default_attr_type;
570
		$n{attr_type} = $attr_type;
571
572
	}

573
574
575
576
577
578
	# determine hash function
	my $hash_func;
	if (exists($n{"hash_func"})) {
		$hash_func = $n{"hash_func"};
	}

579
	# determine compare function
Matthias Braun's avatar
Matthias Braun committed
580
581
582
583
	my $cmp_attr_func;
	if (exists($n{"cmp_attr"})) {
		my $cmpcode = $n{"cmp_attr"};

584
585
		$obst_cmp_attr .= "static int cmp_attr_$op(const ir_node *a, const ir_node *b)\n";
		$obst_cmp_attr .= "{\n";
Matthias Braun's avatar
Matthias Braun committed
586
		if($cmpcode =~ m/attr_a/) {
587
			$obst_cmp_attr .= "\tconst ${attr_type} *attr_a = get_irn_generic_attr_const(a);\n";
588
		} else {
589
			$obst_cmp_attr .= "\t(void) a;\n";
Matthias Braun's avatar
Matthias Braun committed
590
591
		}
		if($cmpcode =~ m/attr_b/) {
592
			$obst_cmp_attr .= "\tconst ${attr_type} *attr_b = get_irn_generic_attr_const(b);\n";
593
		} else {
594
			$obst_cmp_attr .= "\t(void) b;\n";
595
		}
596
597
		$obst_cmp_attr .= "\t${cmpcode}\n";
		$obst_cmp_attr .= "}\n\n";
Christian Würdig's avatar
Christian Würdig committed
598

Matthias Braun's avatar
Matthias Braun committed
599
		$cmp_attr_func = "cmp_attr_${op}";
600
601
	} elsif ($attr_type eq "") {
		$cmp_attr_func = "NULL";
602
603
604
605
	} else {
		if(defined($compare_attr{${attr_type}})) {
			$cmp_attr_func = $compare_attr{${attr_type}};
		} else {
606
			die "Fatal error: No compare function defined for ${attr_type} attributes.";
607
		}
Christian Würdig's avatar
Christian Würdig committed
608
609
	}

610
611
612
	my %constructors;
	if (exists($n{constructors})) {
		%constructors = %{ $n{constructors} };
613
	} else {
614
615
		# Create 1 default constructor
		my %constructor = ();
616
		foreach my $a (@node_attrs) {
617
618
			if (defined($n{$a})) {
				$constructor{$a} = $n{$a};
Christian Würdig's avatar
Christian Würdig committed
619
620
			}
		}
621
622
		%constructors = ( "" => \%constructor );
	}
623

624
625
626
	foreach my $constr (keys(%constructors)) {
		my %cstr = %{ $constructors{$constr} };
		# Copy some values from outer node if they don't exists in the constr
627
		foreach my $a (@node_attrs) {
628
629
			if (!defined($cstr{$a}) && defined($n{$a})) {
				$cstr{$a} = $n{$a};
630
			}
Christian Würdig's avatar
Christian Würdig committed
631
		}
632
633
		create_constructor($orig_op, $constr, \%cstr, \%n);
	}
Christian Würdig's avatar
Christian Würdig committed
634
635

	# set default values for state and flags if not given
636
637
638
639
	$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
640

641
	my %known_flags = map { $_ => 1 } (
Matthias Braun's avatar
Matthias Braun committed
642
643
644
		"none", "commutative", "cfopcode", "unknown_jump", "fragile", "forking",
		"constlike", "keep", "start_block", "uses_memory", "dump_noblock",
		"cse_neutral"
645
	);
Matthias Braun's avatar
Matthias Braun committed
646
	my $is_fragile = 0;
647
648
649
650
	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
651
652
653
		if ($flag eq "fragile") {
			$is_fragile = 1;
		}
654
655
656
657
	}
	my @mapped = map { "irop_flag_$_" } @{$n{"op_flags"}};
	my $op_flags = join('|', @mapped);

658
659
660
661
662
	my $attr_size = "0";
	if ($attr_type ne "") {
		$attr_size = "sizeof(${attr_type})"
	}

663
	$n_opcodes++;
Matthias Braun's avatar
Matthias Braun committed
664
	$temp  = "\top = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", $op_flags";
665
	$temp .= ", ".translate_arity($arity).", -1, ${attr_size});\n";
666
667
668
	$obst_new_irop .= $temp;
	$obst_new_irop .= "\top->ops.be_ops        = be_ops;\n";
	$obst_new_irop .= "\top->ops.dump_node     = ${dump_func};\n";
669
	if (defined($cmp_attr_func)) {
670
		$obst_new_irop .= "\top->ops.node_cmp_attr = ${cmp_attr_func};\n";
671
672
673
	}
	my $copy_attr_func = $copy_attr{$attr_type};
	if (!defined($copy_attr_func)) {
674
675
		# don't set a copy_attr function if the node has no additional attributes.
		if ($attr_type ne "") {
676
677
678
679
			$copy_attr_func = $default_copy_attr;
		}
	}
	if (defined($copy_attr_func)) {
680
		$obst_new_irop .= "\top->ops.copy_attr     = ${copy_attr_func};\n";
681
682
	}
	if (defined($hash_func)) {
683
		$obst_new_irop .= "\top->ops.hash          = ${hash_func};\n";
684
685
	}

Matthias Braun's avatar
Matthias Braun committed
686
	if ($is_fragile) {
687
688
		$obst_new_irop .= "\tir_op_set_memory_index(op, n_${op}_mem);\n";
		$obst_new_irop .= "\tir_op_set_fragile_indices(op, pn_${op}_X_regular, pn_${op}_X_except);\n";
Matthias Braun's avatar
Matthias Braun committed
689
	}
690
	$obst_new_irop .= "\tset_op_tag(op, $arch\_op_tag);\n";
Matthias Braun's avatar
Matthias Braun committed
691
	if(defined($n{op_attr_init})) {
692
		$obst_new_irop .= "\t".$n{op_attr_init}."\n";
693
	}
694
	$obst_new_irop .= "\top_${op} = op;\n";
695

696
	$obst_free_irop .= "\tfree_ir_op(op_$op); op_$op = NULL;\n";
Matthias Braun's avatar
Matthias Braun committed
697

698
	$obst_enum_op .= "\tiro_$op,\n";
Christian Würdig's avatar
Christian Würdig committed
699

700
	$obst_header .= "\n";
701
}
702
703
$obst_enum_op .= "\tiro_$arch\_last\n";
$obst_enum_op .= "} $arch\_opcodes;\n\n";
704
705
706

# emit the code

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

709
print OUT<<EOF;
710
711
712
#include "gen_$arch\_regalloc_if.h"
#include "irverify_t.h"
#include "fourcc.h"
713
#include "irgopt.h"
714
715
716
717

$obst_cmp_attr
$obst_opvar
$obst_get_opvar
718

719
static int $arch\_opcode_start = -1;
720

721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
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));
}

743
print OUT <<END;
744

745
/** A tag for the $arch opcodes. */
746
#define $arch\_op_tag FOURCC('$a', '$b', '$c', '$d')
Michael Beck's avatar
Michael Beck committed
747
748

/** Return 1 if the given opcode is a $arch machine op, 0 otherwise */
749
750
int is_$arch\_op(const ir_op *op)
{
751
	return get_op_tag(op) == $arch\_op_tag;
Michael Beck's avatar
Michael Beck committed
752
753
}

754
/** Return 1 if the given node is a $arch machine node, 0 otherwise */
755
756
int is_$arch\_irn(const ir_node *node)
{
Michael Beck's avatar
Michael Beck committed
757
	return is_$arch\_op(get_irn_op(node));
758
759
}

760
761
762
763
int get_$arch\_irn_opcode(const ir_node *node)
{
	assert(is_$arch\_irn(node));
	return get_irn_opcode(node) - $arch\_opcode_start;
764
765
}

766
767
768
#ifdef BIT
#undef BIT
#endif
769
#define BIT(x)  (1 << (x))
770

771
772
$obst_limit_func
$obst_reg_reqs
773
774
$obst_constructor

775
/**
776
 * Creates the $arch specific Firm machine operations
777
778
 * needed for the assembler irgs.
 */
Matthias Braun's avatar
Matthias Braun committed
779
780
void $arch\_create_opcodes(const arch_irn_ops_t *be_ops)
{
781
782
	ir_op *op;
	int    cur_opcode = get_next_ir_opcodes(iro_$arch\_last);
783

784
	$arch\_opcode_start = cur_opcode;
785
$obst_new_irop
Matthias Braun's avatar
Matthias Braun committed
786
787
788
789
}

void $arch\_free_opcodes(void)
{
790
$obst_free_irop
Matthias Braun's avatar
Matthias Braun committed
791
}
792
END
793
794
795

close(OUT);

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

798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
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

813
$obst_enum_op
814
int is_${arch}_irn(const ir_node *node);
815
int is_${arch}_op(const ir_op *op);
816
817
818
819
820

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

821
822
#endif
EOF
823
824

close(OUT);
825
826
827
828
829

###
# Translates numeric arity into string constant.
###
sub translate_arity {
Christian Würdig's avatar
Christian Würdig committed
830
831
832
	my $arity = shift;

	if ($arity =~ /^\d+$/) {
833
		return "oparity_any";
834
835
836
837
838
	} elsif ($arity == $ARITY_VARIABLE) {
		return "oparity_variable";
	} elsif ($arity == $ARITY_DYNAMIC) {
		return "oparity_dynamic";
	} else {
839
		die "Fatal error: Unknown arity $arity";
Christian Würdig's avatar
Christian Würdig committed
840
	}
841
}
842

843
sub mangle_requirements {
844
845
	my $reqs  = shift;
	my $class = shift;
846
	my $flags = shift;
847
848
849
850
851
852
853
854

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

	@alternatives = sort @alternatives;

855
	my $name = $class."_".join('_', @alternatives);
856
857
858
859
	if (defined($flags)) {
		$flags =~ s/\|/_/g;
		$name .= "_$flags";
	}
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885

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

###
886
# Returns the index of a given register within its register class.
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
# @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;
913
			my ($req,) = split(/:/, $reqs[$idx]);
914

915
			if ($req eq "none") {
916
				$class = "none";
917
918
			} elsif (is_reg_class($req)) {
				$class = $req;
919
			} else {
920
				my @regs = split(/ /, $req);
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
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) {
							die("Fatal error: Could not get ".uc($inout)." register class for '$op' pos $idx (reg $reg) ... exiting.\n");
						} else {
							last GET_CLASS;
						} # !defined class
					} # if (reg =~ ...
				} # foreach
			} # if

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

	return @idx_class;
}

###
# Generates the function for a given $op and a given IN-index
# which returns a subset of possible register from a register class
# @return classname from which the subset is derived or undef and
#         pos which corresponds to in/out reference position or undef
###
sub build_subset_class_func {
	my $neg           = undef;
	my $class         = undef;
	my $has_limit     = 0;
	my $limit_name;
953
954
	my $same_pos      = 0;
	my $different_pos = 0;
955
956
957
958
959
960
961
962
963
964
965
966
967
	my $temp;
	my @obst_init;
	my @obst_limits;
	my @obst_ignore;
	my @limit_array;
	my $limit_reqs;   #used for name mangling

	# build function header
	my $node  = shift;
	my $op    = shift;
	my $idx   = shift;
	my $is_in = shift;
	my @regs  = split(/ /, shift);
968
	my $flags = shift;
969
970
971
972
973

	my @idx_class = build_inout_idx_class($node, $op, !$is_in);

	# set/unset registers
CHECK_REQS: foreach (@regs) {
974
		if (!$is_in && /(!)?in_r(\d+)/) {
975
976
977
978
979
980
981
982
			my $bit_pos = 1 << ($2 - 1);
			if ($different_pos & $bit_pos) {
				if ($1) {
					print STDERR "duplicate !in constraint\n";
				} else {
					print STDERR "conflicting !in and in constraints\n";
				}
				return (undef, undef, undef, undef);
983
984
			}

985
986
987
			if ($same_pos & $bit_pos) {
				if ($1) {
					print STDERR "conflicting !in and in constraints\n";
988
				} else {
989
					print STDERR "duplicate in constraint\n";
990
				}
991
992
993
994
995
996
997
				return (undef, undef, undef, undef);
			}

			if ($1) {
				$different_pos |= $bit_pos;
			} else {
				$same_pos      |= $bit_pos;
998
999
1000
			}

			$class = $idx_class[$2 - 1];
For faster browsing, not all history is shown. View entire blame