From: Christian Würdig Date: Tue, 13 Dec 2005 15:41:00 +0000 (+0000) Subject: fixed a lot of bugs X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=c34a85e0908c0c2ca1a1fe1e5d9d07c56445f35e;p=libfirm fixed a lot of bugs --- diff --git a/ir/be/scripts/generate_emitter.pl b/ir/be/scripts/generate_emitter.pl index 98beec1d2..d9966ea30 100755 --- a/ir/be/scripts/generate_emitter.pl +++ b/ir/be/scripts/generate_emitter.pl @@ -42,47 +42,95 @@ foreach my $op (keys(%nodes)) { # skip this node description if no emit information is available next if (!$n{"emit"} || length($n{"emit"}) < 1); - $line = "void emit_".$arch."_".$op."(FILE *F, ir_node *n)"; + $line = "void emit_".$arch."_".$op."(ir_node *n, emit_env_t *env)"; push(@obst_header, $line.";\n"); - push(@obst_func, $line." {\n"); + push(@obst_func, $line." {\n FILE *F = env->out;\n"); + my $cio = 0; # check in/out register if needed if (exists($n{"check_inout"}) && $n{"check_inout"} == 1) { push(@obst_func, " equalize_dest_src(F, n);\n\n"); + $cio = 1; } my @emit = split(/\n/, $n{"emit"}); - foreach(@emit) { + foreach my $template (@emit) { # substitute only lines, starting with a '.' - if (/^(\d*)\.\s*/) { + if ($template =~ /^(\d*)\.\s*/) { my @params; - my $regkind; + my $res = ""; + my $res2 = ""; my $indent = " "; # default indent is 2 spaces $indent = " " x $1 if ($1 && $1 > 0); # remove indent, dot and trailing spaces - s/^\d*\.\s*//; + $template =~ s/^\d*\.\s*//; # substitute all format parameter - while (/%(([sd])(\d)|([co]))/) { + while ($template =~ /\%(([asd])(\d)|([com]))/) { + $res .= $`; # get everything before the match + $res2 .= $`; + if ($4 && $4 eq "c") { - push(@params, "node_const_to_str(n)"); + push(@params, "n"); + $res .= "\%c"; + $res2 .= "\%c"; } elsif ($4 && $4 eq "o") { - push(@params, "node_offset_to_str(n)"); + push(@params, "n"); + $res .= "\%o"; + $res2 .= "\%o"; + } + elsif ($4 && $4 eq "m") { + push(@params, "n"); + $res .= "\%m"; + $res2 .= "\%m"; + } + elsif ($2 && $2 eq "s") { + push(@params, "n"); + if ($cio && $3 == 2) { + # check_in_out was set: if (s1 != d1) we + # need to exchange s2 by s1 + $res2 .= "%1s"; # get name for first register + } + else { + $res2 .= "%".$3."s"; # substitute %sx with %xs + } + $res .= "%".$3."s"; # substitute %sx with %xs } - else { - $regkind = ($2 eq "s" ? "source" : "dest"); - push(@params, "get_".$regkind."_reg_name(n, $3)"); + elsif ($2 && $2 eq "d") { + push(@params, "n"); + $res .= "%".$3."d"; # substitute %sx with %xs + $res2 .= "%".$3."d"; # substitute %sx with %xs } - s/%$1/%%\%s/; + elsif ($2 && $2 eq "a") { + push(@params, "get_irn_n(n, ".($3 - 1).")"); + $res .= "%+F"; + $res2 .= "%+F"; + } + + $template = $'; # scan everything after the match } + $res .= $template; # get the remaining string + $res2 .= $template; # get the remaining string + my $parm = ""; $parm = ", ".join(", ", @params) if (@params); - push(@obst_func, $indent.'fprintf(F, "\t'.$_.'\n"'.$parm.');'."\n"); + + if ($cio) { + push(@obst_func, $indent."if (get_irn_arity(n) > 1 && get_$arch\_in_regnr(n, 1) == get_$arch\_out_regnr(n, 0)) {\n"); + push(@obst_func, $indent.' lc_efprintf(ia32_get_arg_env(), F, "\t'.$res2.'\n"'.$parm.');'."\n"); + push(@obst_func, $indent."}\n"); + push(@obst_func, $indent."else {\n"); + push(@obst_func, $indent.' lc_efprintf(ia32_get_arg_env(), F, "\t'.$res.'\n"'.$parm.');'."\n"); + push(@obst_func, $indent."}\n"); + } + else { + push(@obst_func, $indent.'lc_efprintf(ia32_get_arg_env(), F, "\t'.$res.'\n"'.$parm.');'."\n"); + } } else { - push(@obst_func, $_,"\n"); + push(@obst_func, $template,"\n"); } } push(@obst_func, "}\n\n"); @@ -107,6 +155,7 @@ print OUT< 0 ? "in" : "NULL").");\n"; + $temp .= " set_ia32_pncode(res, -1);\n"; + $temp .= " res = optimize_node(res);\n"; + $temp .= " irn_vrfy_irg(res, irg);\n\n"; # set register flags $temp .= " attr = get_ia32_attr(res);\n\n"; @@ -138,18 +156,18 @@ foreach my $op (keys(%nodes)) { if (@in) { $temp .= "\n /* allocate memory for IN register requirements and assigned registers */\n"; - $temp .= " attr->in_req = malloc(".($#in + 1)." * sizeof(arch_register_req_t *)); /* space for in requirements */\n"; + $temp .= " attr->in_req = calloc(".($#in + 1).", sizeof(arch_register_req_t *)); /* space for in requirements */\n"; for ($idx = 0; $idx <= $#in; $idx++) { - $temp .= " attr->in_req[$idx] = &".$op."_reg_req_in_".$idx.";\n"; + $temp .= " attr->in_req[$idx] = ".$op."_reg_req_in_".$idx.";\n"; } } if (@out) { $temp .= "\n /* allocate memory for OUT register requirements and assigned registers */\n"; - $temp .= " attr->out_req = malloc(".($#out + 1)." * sizeof(arch_register_req_t *)); /* space for out requirements */\n"; - $temp .= " attr->slots = calloc(sizeof(arch_register_t *), ".($#out + 1)."); /* space for assigned registers */\n"; + $temp .= " attr->out_req = calloc(".($#out + 1).", sizeof(arch_register_req_t *)); /* space for out requirements */\n"; + $temp .= " attr->slots = calloc(".($#out + 1).", sizeof(arch_register_t *)); /* space for assigned registers */\n"; for ($idx = 0; $idx <= $#out; $idx++) { - $temp .= " attr->out_req[$idx] = &".$op."_reg_req_out_".$idx.";\n"; + $temp .= " attr->out_req[$idx] = ".$op."_reg_req_out_".$idx.";\n"; } $temp .= " attr->n_res = ".($#out + 1).";\n"; } @@ -173,6 +191,13 @@ foreach my $op (keys(%nodes)) { $n{"state"} = "pinned" if (! exists($n{"state"})); $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 = dump_node_$arch;\n"); + + if ($cmp_attr_func) { + push(@obst_new_irop, " ops.node_cmp_attr = cmp_attr_$op;\n"); + } + $temp = " op_$op = new_ir_op(get_next_ir_opcode(), \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"}; $temp .= ", ".translate_arity($arity).", 0, sizeof(asmop_attr), &ops);\n"; push(@obst_new_irop, $temp); @@ -182,6 +207,8 @@ foreach my $op (keys(%nodes)) { open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n"); +print OUT @obst_cmp_attr; +print OUT "\n"; print OUT @obst_opvar; print OUT "\n"; print OUT @obst_get_opvar; @@ -207,9 +234,6 @@ void $arch\_create_opcodes(void) { ir_op_ops ops; - memset(&ops, 0, sizeof(ops)); - ops.dump_node = dump_node_$arch; - ENDOFMAIN print OUT @obst_new_irop; @@ -229,19 +253,24 @@ close(OUT); sub translate_arity { my $arity = shift; - if ($arity == 0) { - return "oparity_zero"; - } - elsif ($arity == 1) { - return "oparity_unary"; - } - elsif ($arity == 1) { - return "oparity_binary"; - } - elsif ($arity == 1) { - return "oparity_trinary"; + 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 { + return "$arity"; + } } else { - return "$arity"; + return "oparity_".$arity; } } diff --git a/ir/be/scripts/generate_regalloc_if.pl b/ir/be/scripts/generate_regalloc_if.pl index b4ab2d5b3..17384159c 100755 --- a/ir/be/scripts/generate_regalloc_if.pl +++ b/ir/be/scripts/generate_regalloc_if.pl @@ -28,8 +28,9 @@ unless ($return = do $specfile) { } use strict "subs"; -my $target_c = $target_dir."/gen_".$arch."_regalloc_if.c.inl"; -my $target_h = $target_dir."/gen_".$arch."_regalloc_if.h"; +my $target_c = $target_dir."/gen_".$arch."_regalloc_if.c"; +my $target_h = $target_dir."/gen_".$arch."_regalloc_if.h"; +my $target_h_t = $target_dir."/gen_".$arch."_regalloc_if_t.h"; # helper function my @rt = ("arch_register_type_none", @@ -41,23 +42,44 @@ my @rt = ("arch_register_type_none", # stacks for output my @obst_regtypes; # stack for the register type variables my @obst_regclasses; # stack for the register class variables -my @obst_classdef; # stack to assign a number to a certain class +my @obst_classdef; # stack to define a name for a class index +my @obst_regdef; # stack to define a name for a register index my @obst_reginit; # stack for the register type inits my @obst_req; # stack for the register requirements my @obst_limit_func; # stack for functions to return a subset of a register class +my @obst_defreq_head; # stack for prototypes of default requirement function +my @obst_header_all; # stack for some extern struct defs needed for bearch_$arch include my $numregs; +my $class_ptr; my $class_idx = 0; +my $tmp; + my %reg2class; -# generate register type and class variable and init function +# there is a default NONE requirement +$tmp = "/* Default NONE register requirements */\n"; +$tmp .= "const arch_register_req_t ia32_default_req_none = {\n"; +$tmp .= " arch_register_req_type_none,\n"; +$tmp .= " NULL,\n"; +$tmp .= " { NULL }\n"; +$tmp .= "};\n\n"; +push(@obst_req, $tmp); + +push(@obst_header_all, "extern arch_register_class_t $arch\_reg_classes[N_CLASSES];\n\n"); +push(@obst_header_all, "extern const arch_register_req_t ia32_default_req_none;\n"); + +push(@obst_classdef, "#define N_CLASSES ".scalar(keys(%reg_classes))."\n"); + +# generate register type and class variable, init function and default requirements foreach my $class_name (keys(%reg_classes)) { my @class = @{ $reg_classes{"$class_name"} }; my $old_classname = $class_name; $class_name = $arch."_".$class_name; $numregs = "N_".$class_name."_REGS"; + $class_ptr = "&".$arch."_reg_classes[CLASS_".$class_name."]"; push(@obst_regtypes, "#define $numregs ".($#class + 1)."\n"); push(@obst_regtypes, "arch_register_t ".$class_name."_regs[$numregs];\n\n"); @@ -65,12 +87,54 @@ foreach my $class_name (keys(%reg_classes)) { push(@obst_classdef, "#define CLASS_$class_name $class_idx\n"); push(@obst_regclasses, "{ \"$class_name\", $numregs, ".$class_name."_regs }"); + # there is a default NORMAL requirement for each class + $tmp = "/* Default NORMAL register requirements for class $class_name */\n"; + $tmp .= "const arch_register_req_t ia32_default_req_$class_name = {\n"; + $tmp .= " arch_register_req_type_normal,\n"; + $tmp .= " $class_ptr,\n"; + $tmp .= " { NULL }\n"; + $tmp .= "};\n\n"; + push(@obst_req, $tmp); + + push(@obst_header_all, "\nextern const arch_register_req_t ia32_default_req_$class_name;\n"); + my $idx = 0; push(@obst_reginit, " /* Init of all registers in class '$class_name' */\n\n"); foreach (@class) { + # For each class we build for each of it's member registers a limit function + # which limits the class to this particular register. We also build the + # corresponding requirement structs. + # We need those functions to set register requirements on demand in transformation + # esp. for Call and RegParams where we can mix int and float parameters. + + my $limit_func_name = $arch."_limit_".$class_name."_".$_->{"name"}; + + # push the function prototype + $tmp = "int $limit_func_name(const ir_node *irn, int pos, bitset_t *bs)"; + push(@obst_defreq_head, $tmp.";\n"); + + # push the function definition + $tmp .= " {\n"; + $tmp .= " bs = bitset_clear_all(bs);\n"; + $tmp .= " bitset_set(bs, REG_".uc($_->{"name"}).");\n"; # REGISTER to index assignment is done some lines down + $tmp .= " return 1;\n"; + $tmp .= "}\n\n"; + push(@obst_limit_func, $tmp); + + # push the default requirement struct + $tmp = "const arch_register_req_t ia32_default_req_$class_name\_".$_->{"name"}." = {\n"; + $tmp .= " arch_register_req_type_limited,\n"; + $tmp .= " $class_ptr,\n"; + $tmp .= " { $limit_func_name }\n"; + $tmp .= "};\n\n"; + push(@obst_req, $tmp); + + push(@obst_header_all, "extern const arch_register_req_t ia32_default_req_$class_name\_".$_->{"name"}.";\n"); + $reg2class{$_->{"name"}} = { "class" => $old_classname, "index" => $idx }; # remember reg to class for later use + push(@obst_regdef, "#define REG_".uc($_->{"name"})." $idx\n"); push(@obst_reginit, " ".$class_name."_regs[$idx].name = \"".$_->{"name"}."\";\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].reg_class = &$arch\_reg_classes[CLASS_$class_name];\n"); + push(@obst_reginit, " ".$class_name."_regs[$idx].reg_class = $class_ptr;\n"); push(@obst_reginit, " ".$class_name."_regs[$idx].index = $idx;\n"); push(@obst_reginit, " ".$class_name."_regs[$idx].type = ".$rt[$_->{"type"}].";\n\n"); $idx++; @@ -79,6 +143,8 @@ foreach my $class_name (keys(%reg_classes)) { $class_idx++; } +push(@obst_header_all, "\n/* node specific requirements */\n"); + # generate node-register constraints foreach my $op (keys(%nodes)) { my %n = %{ $nodes{"$op"} }; @@ -89,6 +155,8 @@ foreach my $op (keys(%nodes)) { push(@obst_req, "/* IN requirements for '$op' */\n"); + # we need to remember the classes of the IN constraints for + # OUT constraints like "in_s1" my @inidx_class; # check for argument requirements @@ -98,15 +166,19 @@ foreach my $op (keys(%nodes)) { for (my $idx = 0; $idx <= $#in; $idx++) { my $class = undef; - push(@obst_req, "static const arch_register_req_t ".$op."_reg_req_in_$idx = {\n"); + my $tmp2 = "const arch_register_req_t _".$op."_reg_req_in_$idx = "; + + $tmp = "const arch_register_req_t *".$op."_reg_req_in_$idx = "; + + push(@obst_header_all, "extern const arch_register_req_t *".$op."_reg_req_in_$idx;\n"); if ($in[$idx] eq "none") { push(@inidx_class, "none"); - push(@obst_req, " arch_register_req_type_none,\n NULL,\n { NULL }"); + $tmp .= "&ia32_default_req_none;\n"; } elsif (is_reg_class($in[$idx])) { push(@inidx_class, $in[$idx]); - push(@obst_req, " arch_register_req_type_normal,\n &$arch\_reg_classes[CLASS_$arch\_".$in[$idx]."],\n { NULL }"); + $tmp .= "&ia32_default_req_".$arch."_".$in[$idx].";\n"; } else { $class = build_subset_class_func($op, $idx, 1, $in[$idx]); @@ -114,10 +186,13 @@ foreach my $op (keys(%nodes)) { die("Could not build subset for IN requirements '$op' pos $idx ... exiting.\n"); } push(@inidx_class, $class); - push(@obst_req, " arch_register_req_type_limited,\n &$arch\_reg_classes[CLASS_$arch\_".$class."],\n { limit_reg_".$op."_in_".$idx." }"); + $tmp .= "&_".$op."_reg_req_in_$idx;\n"; + $tmp2 .= " {\n arch_register_req_type_limited,\n &$arch\_reg_classes[CLASS_$arch\_".$class."],\n { limit_reg_".$op."_in_".$idx." }\n};\n"; + + $tmp = $tmp2.$tmp; } - push(@obst_req, "\n};\n\n"); + push(@obst_req, $tmp."\n"); } } @@ -130,47 +205,58 @@ foreach my $op (keys(%nodes)) { for (my $idx = 0; $idx <= $#out; $idx++) { my $class = undef; - push(@obst_req, "static const arch_register_req_t ".$op."_reg_req_out_$idx = {\n"); + my $tmp2 = "const arch_register_req_t _".$op."_reg_req_out_$idx = "; + + $tmp = "const arch_register_req_t *".$op."_reg_req_out_$idx = "; + + push(@obst_header_all, "extern const arch_register_req_t *".$op."_reg_req_out_$idx;\n"); if ($out[$idx] eq "none") { - push(@obst_req, " arch_register_req_type_none,\n NULL,\n { NULL }"); + $tmp .= "&ia32_default_req_none;\n"; } elsif (is_reg_class($out[$idx])) { - push(@obst_req, " arch_register_req_type_normal,\n &$arch\_reg_classes[CLASS_$arch\_".$out[$idx]."],\n { NULL }"); + $tmp .= "&ia32_default_req_".$arch."_".$out[$idx].";\n"; } elsif ($out[$idx] =~ /^(!)?in_s(\d+)/) { # this is a "should be (un)equal to register at in_X" - push(@obst_req, " arch_register_req_type_".($1 ? "un" : "")."equal,\n"); - push(@obst_req, " &$arch\_reg_classes[CLASS_$arch\_".$inidx_class[$2 - 1]."],\n"); - push(@obst_req, " { ".($2 - 1)." }"); + $tmp .= "&_".$op."_reg_req_out_$idx;\n"; + $tmp2 .= " {\n"; + $tmp2 .= " arch_register_req_type_".($1 ? "un" : "")."equal,\n"; + $tmp2 .= " &$arch\_reg_classes[CLASS_$arch\_".$inidx_class[$2 - 1]."],\n"; + $tmp2 .= " { ".($2 - 1)." }\n};\n"; + + $tmp = $tmp2.$tmp } else { $class = build_subset_class_func($op, $idx, 0, $out[$idx]); if (!defined $class) { die("Could not build subset for OUT requirements '$op' pos $idx ... exiting.\n"); } - push(@obst_req, " arch_register_req_type_limited,\n &$arch\_reg_classes[CLASS_$arch\_".$class."],\n { limit_reg_".$op."_out_".$idx." }"); + $tmp .= "&_".$op."_reg_req_out_$idx;\n"; + $tmp2 .= " {\n arch_register_req_type_limited,\n &$arch\_reg_classes[CLASS_$arch\_".$class."],\n { limit_reg_".$op."_out_".$idx." }\n};\n"; + + $tmp = $tmp2.$tmp } - push(@obst_req, "\n};\n\n"); + push(@obst_req, $tmp."\n"); } } } -# generate header file -open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n"); +# generate header _t (internal usage) file +open(OUT, ">$target_h_t") || die("Could not open $target_h_t, reason: $!\n"); my $creation_time = localtime(time()); -my $tmp = uc($arch); +$tmp = uc($arch); print OUT<$target_h") || die("Could not open $target_h, reason: $!\n"); + +$creation_time = localtime(time()); + +print OUT<