#! /usr/bin/env perl # # This file is part of libFirm. # Copyright (C) 2014 University of Karlsruhe. # # This script generates C code which creates ands sets up functions and # data structures for the register allocator. use integer; use strict; use warnings; my $specfile = $ARGV[0]; my $target_dir = $ARGV[1]; our $arch; our %reg_classes; # include spec file unless (my $return = do "${specfile}") { 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; } # stacks for output my $regtypes_def; # stack for the register type variables definitions my $regclasses; # stack for the register class variables my $classdef; # stack to define a name for a class index my $reqdecls; my $regdef; # stack to define a name for a register index my $regdef2; my $regcounts; my $reginit; # stack for the register type inits my $single_constraints; my %regclass2len = (); my %reg2class = (); foreach my $class_name (sort(keys(%reg_classes))) { my $regs = $reg_classes{$class_name}{registers}; my $idx = 0; foreach (@$regs) { if (defined(my $name = $_->{name})) { $reg2class{$name} = { "class" => $class_name, "index" => $idx }; } $idx++; } $regclass2len{$class_name} = $idx; } sub get_limited_array { my ($reg) = @_; my $result = "{ "; my $sep = ""; my $regclass = $reg2class{$reg}{class}; my $classuc = uc($regclass); my $ucname = uc($reg); my $limitedbitsetlen = $regclass2len{$regclass}; my $arraylen = ($limitedbitsetlen + 31) / 32; for (my $i = 0; $i < $arraylen; ++$i) { $result .= $sep; $sep = ", "; my $index = $reg2class{$reg}{index}; if ($i * 32 <= $index && $index < ($i + 1) * 32) { if ($i > 0) { $result .= "(1U << (REG_${classuc}_${ucname} % 32))"; } else { $result .= "(1U << REG_${classuc}_${ucname})"; } } else { $result .= "0"; } } $result .= " }"; } sub has_flag { my ($what, $list) = @_; return (defined($list) && grep { $_ eq $what } $list) ? "true" : "false"; } # generate register type and class variable, init function and default requirements foreach my $class_name (sort(keys(%reg_classes))) { my $class = $reg_classes{$class_name}; my $arch_class_name = "${arch}_$class_name"; my $class_req = "${arch}_class_reg_req_$class_name"; my $class_enum = "CLASS_$arch_class_name"; my $class_ptr = "&${arch}_reg_classes[$class_enum]"; my $class_mode = $class->{mode}; $single_constraints .= <{registers}; my $numregs = @$regs; my $uname = uc($regs->[0]->{name}); $regclasses .= <{flags})) { foreach my $flag ($class->{flags}) { $regclasses .= "\t\t.$flag = true,\n"; } } $regclasses .= "\t},\n"; $reginit .= "\t$arch\_reg_classes[$class_enum].mode = $class_mode;\n"; $regdef2 .= "enum {\n"; foreach (@$regs) { my $name = $_->{name}; # realname is name if not set by user my $realname = $_->{realname} // $name; my $single_req = "${arch}_single_reg_req_${class_name}_${name}"; my $classuc = uc($class_name); my $ucname = uc($name); my $local_idx = "REG_${classuc}_$ucname"; my $global_idx = "REG_$ucname"; my $dwarf_number = $_->{dwarf} // 0; my $encoding = $_->{encoding} // $local_idx; my $is_virtual = has_flag("virtual", $_->{type}); $regdef .= "\t$global_idx,\n"; $regdef2 .= "\t$local_idx,\n"; $regtypes_def .= <", $target_h) // die("Fatal error: Could not open $target_h, reason: $!\n"); print OUT <", $target_c) // die("Fatal error: Could not open $target_c, reason: $!\n"); print OUT <