From 0f0b70bee67238a0226380ddce061cfe50e6c8fc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20W=C3=BCrdig?= Date: Tue, 22 Nov 2005 10:10:33 +0000 Subject: [PATCH] generating register class definitions and register constraint structs --- ir/be/scripts/generate_regalloc_if.pl | 338 ++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100755 ir/be/scripts/generate_regalloc_if.pl diff --git a/ir/be/scripts/generate_regalloc_if.pl b/ir/be/scripts/generate_regalloc_if.pl new file mode 100755 index 000000000..b4ab2d5b3 --- /dev/null +++ b/ir/be/scripts/generate_regalloc_if.pl @@ -0,0 +1,338 @@ +#!/usr/bin/perl -w + +# This script generates C code which emits assembler code for the +# assembler ir nodes. It takes a "emit" key from the node specification +# and substitutes lines starting with . with a corresponding fprintf(). +# Creation: 2005/11/14 +# $Id$ + +use strict; +use Data::Dumper; + +my $specfile = $ARGV[0]; +my $target_dir = $ARGV[1]; + +our $arch; +our %reg_classes; +our %nodes; + +# include spec file + +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; +} +use strict "subs"; + +my $target_c = $target_dir."/gen_".$arch."_regalloc_if.c.inl"; +my $target_h = $target_dir."/gen_".$arch."_regalloc_if.h"; + +# helper function +my @rt = ("arch_register_type_none", + "arch_register_type_write_invariant", + "arch_register_type_caller_saved", + "arch_register_type_callee_saved", + "arch_register_type_ignore"); + +# 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_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 $numregs; +my $class_idx = 0; + +my %reg2class; + +# generate register type and class variable and init function +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"; + + push(@obst_regtypes, "#define $numregs ".($#class + 1)."\n"); + push(@obst_regtypes, "arch_register_t ".$class_name."_regs[$numregs];\n\n"); + + push(@obst_classdef, "#define CLASS_$class_name $class_idx\n"); + push(@obst_regclasses, "{ \"$class_name\", $numregs, ".$class_name."_regs }"); + + my $idx = 0; + push(@obst_reginit, " /* Init of all registers in class '$class_name' */\n\n"); + foreach (@class) { + $reg2class{$_->{"name"}} = { "class" => $old_classname, "index" => $idx }; # remember reg to class for later use + 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].index = $idx;\n"); + push(@obst_reginit, " ".$class_name."_regs[$idx].type = ".$rt[$_->{"type"}].";\n\n"); + $idx++; + } + + $class_idx++; +} + +# generate node-register constraints +foreach my $op (keys(%nodes)) { + my %n = %{ $nodes{"$op"} }; + + next if (!exists($n{"reg_req"})); + + $op = $arch."_".$op; + + push(@obst_req, "/* IN requirements for '$op' */\n"); + + my @inidx_class; + + # check for argument requirements + if (exists($n{"reg_req"}{"in"})) { + my @in = @{ $n{"reg_req"}{"in"} }; + + 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"); + + if ($in[$idx] eq "none") { + push(@inidx_class, "none"); + push(@obst_req, " arch_register_req_type_none,\n NULL,\n { NULL }"); + } + 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 }"); + } + else { + $class = build_subset_class_func($op, $idx, 1, $in[$idx]); + if (!defined $class) { + 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." }"); + } + + push(@obst_req, "\n};\n\n"); + } + } + + push(@obst_req, "/* OUT requirements for '$op' */\n"); + + # check for result requirements + if (exists($n{"reg_req"}{"out"})) { + my @out = @{ $n{"reg_req"}{"out"} }; + + 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"); + + if ($out[$idx] eq "none") { + push(@obst_req, " arch_register_req_type_none,\n NULL,\n { NULL }"); + } + elsif (is_reg_class($out[$idx])) { + push(@obst_req, " arch_register_req_type_normal,\n &$arch\_reg_classes[CLASS_$arch\_".$out[$idx]."],\n { NULL }"); + } + 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)." }"); + } + 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." }"); + } + + push(@obst_req, "\n};\n\n"); + } + } +} + + + +# generate header file +open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n"); + +my $creation_time = localtime(time()); + +my $tmp = uc($arch); + +print OUT<$target_c") || die("Could not open $target_c, reason: $!\n"); + +$creation_time = localtime(time()); + +print OUT<