support for custom attribute types on nodes
[libfirm] / ir / be / scripts / generate_new_opcodes.pl
index 86b5a1c..b10546d 100755 (executable)
@@ -1,5 +1,24 @@
 #!/usr/bin/perl -w
 
+#
+# Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+#
+# 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.
+#
+
 # 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.
@@ -18,6 +37,9 @@ my $line_nr    = 0;
 our $arch;
 our $additional_opcodes;
 our %nodes;
+our %cpu;
+our $default_cmp_attr;
+our $default_attr_type;
 
 # include spec file
 
@@ -25,15 +47,19 @@ my $return;
 
 no strict "subs";
 unless ($return = do $specfile) {
-       warn "couldn't parse $specfile: $@" if $@;
-       warn "couldn't do $specfile: $!"    unless defined $return;
-       warn "couldn't run $specfile"       unless $return;
+       die "couldn't parse $specfile: $@" if $@;
+       die "couldn't do $specfile: $!"    unless defined $return;
+       die "couldn't run $specfile"       unless $return;
 }
 use strict "subs";
 
 my $target_c = $target_dir."/gen_".$arch."_new_nodes.c.inl";
 my $target_h = $target_dir."/gen_".$arch."_new_nodes.h";
 
+if(!defined($default_attr_type)) {
+       $default_attr_type = "${arch}_attr_t";
+}
+
 #print Dumper(%nodes);
 #print Dumper(%operands);
 
@@ -59,14 +85,30 @@ $n_opcodes += $additional_opcodes if (defined($additional_opcodes));
 
 push(@obst_header, "void ".$arch."_create_opcodes(void);\n");
 
+# create default compare function
+if(defined($default_cmp_attr)) {
+       my $cmpcode = $default_cmp_attr;
+       push(@obst_cmp_attr, "static int default_cmp_attr(ir_node *a, ir_node *b) {\n");
+       if($cmpcode =~ m/attr_a/) {
+               push(@obst_cmp_attr, "\t${default_attr_type} *attr_a = get_irn_generic_attr(a);\n");
+       }
+       if($cmpcode =~ m/attr_b/) {
+               push(@obst_cmp_attr, "\t${default_attr_type} *attr_b = get_irn_generic_attr(b);\n");
+       }
+       push(@obst_cmp_attr, "\t${cmpcode}\n");
+       push(@obst_cmp_attr, "}\n\n");
+}
+
 push(@obst_enum_op, "typedef enum _$arch\_opcodes {\n");
 foreach my $op (keys(%nodes)) {
-       my %n = %{ $nodes{"$op"} };
-       my $tuple = 0;
-       my $n_res = 0;
+       my %n        = %{ $nodes{"$op"} };
+       my $known_mode;
+       my $n_res    = 0;
+       my $num_outs = 0;
+       my @out_flags;
 
        # determine arity from in requirements
-       $arity = 0;
+       $arity = exists($n{"arity"}) ? $n{"arity"} : 0;
        if (exists($n{"reg_req"}) && exists($n{"reg_req"}{"in"})) {
                $arity = scalar(@{ $n{"reg_req"}{"in"} });
        }
@@ -75,20 +117,49 @@ foreach my $op (keys(%nodes)) {
        $op      = $arch."_".$op;
        $temp    = "";
 
+       # define some proj numbers
        if (exists($n{"outs"})) {
                undef my @outs;
-               @outs = @{ $n{"outs"} };
+
+               @outs     = @{ $n{"outs"} };
+               $num_outs = $#outs + 1;
+
                push(@obst_proj, "\nenum pn_$op {\n");
+
                for (my $idx = 0; $idx <= $#outs; $idx++) {
-                       push(@obst_proj, "  pn_$op\_".$outs[$idx]." = $idx,\n");
+                       # 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))*)//;
+                       }
+                       push(@obst_proj, "\tpn_$op\_".$outs[$idx]." = $idx,\n");
                }
+
+               push(@obst_proj, "};\n");
+               # outs have names, it must be a mode_T node
+               $known_mode = "mode_T";
+       }
+       if (exists($n{"ins"})) {
+               undef my @ins;
+
+               @ins = @{ $n{"ins"} };
+               my $num_ins = $#ins + 1;
+
+               push(@obst_proj, "\nenum n_$op {\n");
+
+               for (my $idx = 0; $idx <= $#ins; $idx++) {
+                       push(@obst_proj, "\tn_${op}_".$ins[$idx]." = $idx,\n");
+               }
+
                push(@obst_proj, "};\n");
-               $tuple = 1;
+       }
+       if (exists($n{"mode"})) {
+               $known_mode = $n{"mode"};
        }
 
        push(@obst_opvar, "ir_op *op_$op = NULL;\n");
        push(@obst_get_opvar, "ir_op *get_op_$op(void)         { return op_$op; }\n");
-       push(@obst_get_opvar, "int    is_$op(const ir_node *n) { return get_irn_opcode(n) == iro_$op; }\n\n");
+       push(@obst_get_opvar, "int    is_$op(const ir_node *n) { return get_$arch\_irn_opcode(n) == iro_$op; }\n\n");
 
        push(@obst_is_archirn, "is_$op(node)");
 
@@ -96,16 +167,30 @@ foreach my $op (keys(%nodes)) {
        push(@obst_header, "ir_op *get_op_$op(void);\n");
        push(@obst_header, "int is_$op(const ir_node *n);\n");
 
-       $cmp_attr_func = 0;
+       my $attr_type= $n{"attr_type"};
+       if(!defined($attr_type)) {
+               $attr_type = $default_attr_type;
+       }
+
+       my $cmp_attr_func;
+       if(defined($default_cmp_attr)) {
+               $cmp_attr_func = "default_cmp_attr";
+       }
        # create compare attribute function if needed
        if (exists($n{"cmp_attr"})) {
+               my $cmpcode = $n{"cmp_attr"};
+
                push(@obst_cmp_attr, "static int cmp_attr_$op(ir_node *a, ir_node *b) {\n");
-               push(@obst_cmp_attr, "  $arch\_attr_t *attr_a = get_$arch\_attr(a);\n");
-               push(@obst_cmp_attr, "  $arch\_attr_t *attr_b = get_$arch\_attr(b);\n");
-               push(@obst_cmp_attr, $n{"cmp_attr"});
+               if($cmpcode =~ m/attr_a/) {
+                       push(@obst_cmp_attr, "\t${attr_type} *attr_a = get_irn_generic_attr(a);\n");
+               }
+               if($cmpcode =~ m/attr_b/) {
+                       push(@obst_cmp_attr, "\t${attr_type} *attr_b = get_irn_generic_attr(b);\n");
+               }
+               push(@obst_cmp_attr, "\t${cmpcode}\n");
                push(@obst_cmp_attr, "}\n\n");
 
-               $cmp_attr_func = 1;
+               $cmp_attr_func = "cmp_attr_${op}";
        }
 
        if (exists($n{"rd_constructor"}) && $n{"rd_constructor"} =~ /^NONE$/i) {
@@ -132,7 +217,7 @@ foreach my $op (keys(%nodes)) {
                                $complete_args .= ", ir_node *op".$i;
                                $arg_names     .= ", op".$i;
                        }
-                       if ($tuple == 0) {
+                       if (!defined($known_mode)) {
                                $complete_args .= ", ir_mode *mode";
                                $arg_names     .= ", mode";
                        }
@@ -163,10 +248,17 @@ foreach my $op (keys(%nodes)) {
                                next;
                        }
 
-                       $temp  = "  ir_node *res;\n";
-                       $temp .= "  ir_node *in[$arity];\n" if ($arity > 0);
-                       $temp .= "  int flags = 0;\n";
-                       $temp .= "  $arch\_attr_t *attr;\n" if (exists($n{"init_attr"}));
+                       $temp  = "\tir_node *res;\n";
+                       $temp .= "\tir_node *in[$arity];\n" if ($arity > 0);
+                       $temp .= "\tint flags = 0;\n";
+                       $temp .= "\t${attr_type} *attr;\n" if (exists($n{"init_attr"}));
+
+                       my $exec_units = "NULL";
+                       # set up static variables for cpu execution unit assigments
+                       if (exists($n{"units"})) {
+                               $temp .= gen_execunit_list_initializer($n{"units"});
+                               $exec_units = "_exec_units";
+                       }
 
                        undef my $in_req_var;
                        undef my $out_req_var;
@@ -183,44 +275,47 @@ foreach my $op (keys(%nodes)) {
 
                                if (@in) {
                                        $in_req_var = "_in_req_$op";
-                                       $temp .= "  static const $arch\_register_req_t *".$in_req_var."[] =\n  {\n";
+                                       $temp .= "\tstatic const arch_register_req_t *".$in_req_var."[] =\n";
+                                       $temp .= "\t{\n";
                                        for ($idx = 0; $idx <= $#in; $idx++) {
-                                               $temp .= "    ".$op."_reg_req_in_".$idx.",\n";
+                                               $temp .= "\t\t&".$op."_reg_req_in_".$idx.",\n";
                                        }
-                                       $temp .= "  };\n";
+                                       $temp .= "\t};\n";
                                }
 
                                if (@out) {
                                        $out_req_var = "_out_req_$op";
 
-                                       $temp .= "  static const $arch\_register_req_t *".$out_req_var."[] =\n  {\n";
+                                       $temp .= "\tstatic const arch_register_req_t *".$out_req_var."[] =\n";
+                                       $temp .= "\t{\n";
                                        for ($idx = 0; $idx <= $#out; $idx++) {
-                                               $temp .= "    ".$op."_reg_req_out_".$idx.",\n";
+                                               $temp .= "\t\t&".$op."_reg_req_out_".$idx.",\n";
                                        }
-                                       $temp .= "  };\n";
+                                       $temp .= "\t};\n";
                                }
                        }
 
                        $temp .= "\n";
-                       $temp .= "  if (!op_$op) {\n";
-                       $temp .= "    assert(0);\n";
-                       $temp .= "    return NULL;\n";
-                       $temp .= "  }\n\n";
+                       $temp .= "\tassert(op_$op != NULL);\n\n";
+
                        for (my $i = 1; $i <= $arity; $i++) {
-                               $temp .= "  in[".($i - 1)."] = op".$i.";\n";
+                               $temp .= "\tin[".($i - 1)."] = op".$i.";\n";
                        }
 
                        # set flags
                        if (exists($n{"irn_flags"})) {
                                foreach my $flag (split(/\|/, $n{"irn_flags"})) {
                                        if ($flag eq "R") {
-                                               $temp .= "  flags |= arch_irn_flags_rematerializable;   /* op can be easily recalculated */\n";
+                                               $temp .= "\tflags |= arch_irn_flags_rematerializable;   /* op can be easily recalculated */\n";
                                        }
                                        elsif ($flag eq "N") {
-                                               $temp .= "  flags |= arch_irn_flags_dont_spill;         /* op is NOT spillable */\n";
+                                               $temp .= "\tflags |= arch_irn_flags_dont_spill;         /* op is NOT spillable */\n";
                                        }
                                        elsif ($flag eq "I") {
-                                               $temp .= "  flags |= arch_irn_flags_ignore;             /* ignore op for register allocation */\n";
+                                               $temp .= "\tflags |= arch_irn_flags_ignore;             /* ignore op for register allocation */\n";
+                                       }
+                                       elsif ($flag eq "S") {
+                                               $temp .= "\tflags |= arch_irn_flags_modify_sp;          /* op modifies stack pointer */\n";
                                        }
                                }
                        }
@@ -244,33 +339,66 @@ foreach my $op (keys(%nodes)) {
                                }
 
                                if (@out) {
-                                       $out_param = $out_req_var.", ".($#out + 1);
-                                       $n_res     = $#out;
+                                       $n_res     = $#out + 1;
+                                       $out_param = "$out_req_var, $exec_units, $n_res";
                                }
                                else {
-                                       $out_param = "NULL, 0";
+                                       $out_param = "NULL, $exec_units, 0";
                                }
                        }
-                       $temp .= "\n  /* create node */\n";
+                       else {
+                               $in_param  = "NULL";
+                               $out_param = "NULL, $exec_units, 0";
+                       }
+                       $temp .= "\n\t/* create node */\n";
+
+                       my $latency = 1;
+                       if (exists($n{"latency"})) {
+                               $latency = $n{"latency"};
+                       }
+
                        my $mode = "mode";
-                       if ($tuple == 1) {
-                               $mode = "mode_T";
+                       if (defined($known_mode)) {
+                               $mode = $known_mode;
+                       }
+                       $temp .= "\tres = new_ir_node(db, irg, block, op_$op, $mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
+
+                       $temp .= "\n\t/* init node attributes */\n";
+                       $temp .= "\tinit_$arch\_attributes(res, flags, $in_param, $out_param, $latency);\n";
+
+                       # set flags for outs
+                       if ($#out_flags >= 0) {
+                               $temp .= "\n\t/* set flags for outs */\n";
+                               for (my $idx = 0; $idx <= $#out_flags; $idx++) {
+                                       my $flags  = "";
+                                       my $prefix = "";
+
+                                       foreach my $flag (split(/\|/, $out_flags[$idx])) {
+                                               if ($flag eq "I") {
+                                                       $flags .= $prefix."arch_irn_flags_ignore";
+                                                       $prefix = " | ";
+                                               }
+                                               elsif ($flag eq "S") {
+                                                       $flags .= $prefix."arch_irn_flags_modify_sp";
+                                                       $prefix = " | ";
+                                               }
+                                       }
+
+                                       $temp .= "\tset_$arch\_out_flags(res, $flags, $idx);\n";
+                               }
                        }
-                       $temp .= "  res = new_ir_node(db, irg, block, op_$op, $mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
 
-                       $temp .= "\n  /* init node attributes */\n";
-                       $temp .= "  init_$arch\_attributes(res, flags, $in_param, $out_param);\n";
 
                        if (exists($n{"init_attr"})) {
-                               $temp .= "  attr = get_$arch\_attr(res);\n";
+                               $temp .= "\tattr = get_$arch\_attr(res);\n";
                                $temp .= $n{"init_attr"}."\n";
                        }
 
-                       $temp .= "\n  /* optimize node */\n";
-                       $temp .= "  res = optimize_node(res);\n";
-                       $temp .= "  irn_vrfy_irg(res, irg);\n\n";
+                       $temp .= "\n\t/* optimize node */\n";
+                       $temp .= "\tres = optimize_node(res);\n";
+                       $temp .= "\tirn_vrfy_irg(res, irg);\n\n";
 
-                       $temp .= "\n  return res;\n";
+                       $temp .= "\n\treturn res;\n";
 
                        push(@obst_constructor, $temp);
                }
@@ -287,23 +415,24 @@ foreach my $op (keys(%nodes)) {
        $n{"op_flags"} = "N"      if (! exists($n{"op_flags"}));
 
 
-       push(@obst_new_irop, "\n  memset(&ops, 0, sizeof(ops));\n");
-       push(@obst_new_irop, "  ops.dump_node     = $arch\_dump_node;\n");
+       push(@obst_new_irop, "\n\tmemset(&ops, 0, sizeof(ops));\n");
+       push(@obst_new_irop, "\tops.dump_node     = $arch\_dump_node;\n");
 
-       if ($cmp_attr_func) {
-               push(@obst_new_irop, "  ops.node_cmp_attr = cmp_attr_$op;\n");
+       if (defined($cmp_attr_func)) {
+               push(@obst_new_irop, "\tops.node_cmp_attr = ${cmp_attr_func};\n");
        }
 
        $n_opcodes++;
-       $temp  = "  op_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
-       $temp .= "|M, ".translate_arity($arity).", 0, sizeof($arch\_attr_t) + $n_res * sizeof(arch_register_t *), &ops);\n";
+       $temp  = "\top_$op = new_ir_op(cur_opcode + iro_$op, \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
+       $temp .= "|M, ".translate_arity($arity).", 0, sizeof(${attr_type}) + $n_res * sizeof(arch_register_t *), &ops);\n";
        push(@obst_new_irop, $temp);
-       push(@obst_enum_op, "  iro_$op,\n");
+       push(@obst_new_irop, "\tset_op_tag(op_$op, &$arch\_op_tag);\n");
+       push(@obst_enum_op, "\tiro_$op,\n");
 
        push(@obst_header, "\n");
 }
-push(@obst_enum_op, "  iro_$arch\_last_generated,\n");
-push(@obst_enum_op, "  iro_$arch\_last = iro_$arch\_last_generated");
+push(@obst_enum_op, "\tiro_$arch\_last_generated,\n");
+push(@obst_enum_op, "\tiro_$arch\_last = iro_$arch\_last_generated");
 push(@obst_enum_op, " + $additional_opcodes") if (defined($additional_opcodes));
 push(@obst_enum_op, "\n} $arch\_opcodes;\n\n");
 
@@ -319,37 +448,56 @@ print OUT "\n";
 print OUT @obst_get_opvar;
 print OUT "\n";
 
-print OUT<<ENDOFISIRN;
+print OUT<<EOF;
 
 static int $arch\_opcode_start = -1;
 static int $arch\_opcode_end   = -1;
 
+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 "static unsigned $arch\_op_tag = FOURCC('$a', '$b', '$c', '$d');\n";
+
+print OUT<<ENDOFISIRN;
+
 /** Return the opcode number of the first $arch opcode. */
 int get_$arch\_opcode_first(void) {
-  return $arch\_opcode_start;
+       return $arch\_opcode_start;
 }
 
 /** Return the opcode number of the last $arch opcode + 1. */
 int get_$arch\_opcode_last(void) {
-  return $arch\_opcode_end;
+       return $arch\_opcode_end;
 }
 
-/** Return non-zero if the given node is a $arch machine node. */
+/** Return 1 if the given node is a $arch machine node, 0 otherwise */
 int is_$arch\_irn(const ir_node *node) {
-  unsigned opc = (unsigned)get_irn_opcode(node);
-
-  assert($arch\_opcode_start > 0 && "missing opcode init");
-  assert($arch\_opcode_end > 0 && "missing opcode init");
-
-  if (opc - (unsigned)$arch\_opcode_start < (unsigned)($arch\_opcode_end - $arch\_opcode_start))
-    return 1;
-
-  return 0;
+       return get_op_tag(get_irn_op(node)) == &$arch\_op_tag;
 }
 
 int get_$arch\_irn_opcode(const ir_node *node) {
-  assert(is_$arch\_irn(node));
-  return get_irn_opcode(node) - $arch\_opcode_start;
+       if (is_$arch\_irn(node))
+               return get_irn_opcode(node) - $arch\_opcode_start;
+       return -1;
 }
 
 ENDOFISIRN
@@ -376,16 +524,23 @@ void $arch\_create_opcodes(void) {
 #define O   irop_flag_machine_op
 #define R   (irop_flag_user << 0)
 
-  ir_op_ops ops;
-  int cur_opcode = get_next_ir_opcodes(iro_$arch\_last);
+       ir_op_ops  ops;
+       int        cur_opcode;
+       static int run_once = 0;
+
+       if (run_once)
+               return;
+       run_once = 1;
+
+       cur_opcode = get_next_ir_opcodes(iro_$arch\_last);
 
-  $arch\_opcode_start = cur_opcode;
+       $arch\_opcode_start = cur_opcode;
 ENDOFMAIN
 
 print OUT @obst_new_irop;
 print OUT "\n";
-print OUT "  $arch\_register_additional_opcodes(cur_opcode);\n" if (defined($additional_opcodes));
-print OUT "  $arch\_opcode_end = cur_opcode + iro_$arch\_last";
+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";
 print OUT " + $additional_opcodes" if (defined($additional_opcodes));
 print OUT ";\n";
 print OUT "}\n";
@@ -394,8 +549,23 @@ close(OUT);
 
 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
 
-print OUT "#ifndef __GEN_$arch\_NEW_NODES_H__\n";
-print OUT "#define __GEN_$arch\_NEW_NODES_H__\n\n";
+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
+
 print OUT @obst_enum_op;
 print OUT "int is_$arch\_irn(const ir_node *node);\n\n";
 print OUT "int get_$arch\_opcode_first(void);\n";
@@ -403,7 +573,10 @@ print OUT "int get_$arch\_opcode_last(void);\n";
 print OUT "int get_$arch\_irn_opcode(const ir_node *node);\n";
 print OUT @obst_header;
 print OUT @obst_proj;
-print OUT "\n#endif /* __GEN_$arch\_NEW_NODES_H__ */\n";
+
+print OUT <<EOF;
+#endif
+EOF
 
 close(OUT);
 
@@ -427,10 +600,78 @@ sub translate_arity {
                        return "oparity_trinary";
                }
                else {
-                       return "$arity";
+                       return "oparity_any";
                }
        }
        else {
                return "oparity_".$arity;
        }
 }
+
+###
+# Return the list of pointers for the given execution units.
+###
+sub gen_execunit_list_initializer {
+       my $units   = shift;
+       my $uc_arch = uc($arch);
+       my $ret     = "";
+       my $ret2    = "";
+       my %init;
+
+       foreach my $unit (@{ $units }) {
+               if ($unit eq "DUMMY") {
+                       push(@{ $init{"DUMMY"} }, "\t\t&be_machine_execution_units_DUMMY[0]");
+               }
+               elsif (exists($cpu{"$unit"})) {
+                       # operation can be executed on all units of this type
+                       # -> add them all
+                       my $tp_name = "$arch\_execution_units_$unit";
+                       my $idx     = 0;
+                       foreach (@{ $cpu{"$unit"} }) {
+                               next if ($idx++ == 0);  # skip first element (it's not a unit)
+                               my $unit_name = "$uc_arch\_EXECUNIT_TP_$unit\_$_";
+                               push(@{ $init{"$unit"} }, "\t\t&".$tp_name."[".$unit_name."]");
+                       }
+               }
+               else {
+                       # operation can be executed only a certain unit
+                       # -> find corresponding unit type
+                       my $found = 0;
+TP_SEARCH:     foreach my $cur_type (keys(%cpu)) {
+                               foreach my $cur_unit (@{ $cpu{"$cur_type"} }) {
+                                       if ($unit eq $cur_unit) {
+                                               my $tp_name   = "$arch\_execution_units_$cur_type";
+                                               my $unit_name = "$uc_arch\_EXECUNIT_TP_$cur_type\_$unit";
+                                               push(@{ $init{"$unit"} }, "\t\t&".$tp_name."[".$unit_name."]");
+                                               $found = 1;
+                                               last TP_SEARCH;
+                                       }
+                               }
+                       }
+
+                       if (! $found) {
+                               print STDERR "Invalid execution unit $unit specified!\n";
+                       }
+               }
+       }
+
+       # prepare the 2-dim array init
+       foreach my $key (keys(%init)) {
+               $ret .= "\tstatic const be_execution_unit_t *_allowed_units_".$key."[] =\n";
+               $ret .= "\t{\n";
+               foreach (@{ $init{"$key"} }) {
+                       $ret .= "$_,\n";
+               }
+               $ret .= "\t\tNULL\n";
+               $ret .= "\t};\n";
+               $ret2 .= "\t\t_allowed_units_$key,\n";
+       }
+       $ret2 .= "\t\tNULL\n";
+
+       $ret .= "\tstatic const be_execution_unit_t **_exec_units[] =\n";
+       $ret .= "\t{\n";
+       $ret .= $ret2;
+       $ret .= "\t};\n";
+
+       return $ret;
+}