new name for register requirement
[libfirm] / ir / be / scripts / generate_emitter.pl
1 #!/usr/bin/perl -w
2
3 # This script generates C code which emits assembler code for the
4 # assembler ir nodes. It takes a "emit" key from the node specification
5 # and substitutes lines starting with . with a corresponding fprintf().
6 # Creation: 2005/11/07
7 # $Id$
8
9 use strict;
10 use Data::Dumper;
11
12 my $specfile   = $ARGV[0];
13 my $target_dir = $ARGV[1];
14
15 our $arch;
16 our %nodes;
17
18 # include spec file
19
20 my $return;
21
22 no strict "subs";
23 unless ($return = do $specfile) {
24   warn "couldn't parse $specfile: $@" if $@;
25   warn "couldn't do $specfile: $!"    unless defined $return;
26   warn "couldn't run $specfile"       unless $return;
27 }
28 use strict "subs";
29
30 my $target_c = $target_dir."/gen_".$arch."_emitter.c";
31 my $target_h = $target_dir."/gen_".$arch."_emitter.h";
32
33 # stacks for output
34 my @obst_func;   # stack for the emit functions
35 my @obst_header;  # stack for the function prototypes
36
37 my $line;
38
39 foreach my $op (keys(%nodes)) {
40   my %n = %{ $nodes{"$op"} };
41
42   # skip this node description if no emit information is available
43   next if (!$n{"emit"} || length($n{"emit"}) < 1);
44
45   $line = "void emit_".$arch."_".$op."(ir_node *n, emit_env_t *env)";
46   push(@obst_header, $line.";\n");
47   push(@obst_func, $line." {\n  FILE *F = env->out;\n");
48
49   my $cio = 0;
50   # check in/out register if needed
51   if (exists($n{"check_inout"}) && $n{"check_inout"} == 1) {
52     push(@obst_func, "  equalize_dest_src(F, n);\n\n");
53     $cio = 1;
54   }
55
56   my @emit = split(/\n/, $n{"emit"});
57
58   foreach my $template (@emit) {
59     # substitute only lines, starting with a '.'
60     if ($template =~ /^(\d*)\.\s*/) {
61       my @params;
62       my $res    = "";
63       my $res2   = "";
64       my $indent = "  "; # default indent is 2 spaces
65
66       $indent = " " x $1 if ($1 && $1 > 0);
67       # remove indent, dot and trailing spaces
68       $template =~ s/^\d*\.\s*//;
69       # substitute all format parameter
70       while ($template =~ /\%(([asd])(\d)|([com]))/) {
71         $res  .= $`;      # get everything before the match
72         $res2 .= $`;
73
74         if ($4 && $4 eq "c") {
75           push(@params, "n");
76           $res  .= "\%c";
77           $res2 .= "\%c";
78         }
79         elsif ($4 && $4 eq "o") {
80           push(@params, "n");
81           $res  .= "\%o";
82           $res2 .= "\%o";
83         }
84         elsif ($4 && $4 eq "m") {
85           push(@params, "n");
86           $res  .= "\%m";
87           $res2 .= "\%m";
88         }
89         elsif ($2 && $2 eq "s") {
90           push(@params, "n");
91           if ($cio && $3 == 2) {
92             # check_in_out was set: if (s1 != d1) we
93             # need to exchange s2 by s1
94             $res2 .= "%1s"; # get name for first register
95           }
96           else {
97             $res2 .= "%".$3."s"; # substitute %sx with %xs
98           }
99           $res .= "%".$3."s"; # substitute %sx with %xs
100         }
101         elsif ($2 && $2 eq "d") {
102           push(@params, "n");
103           $res  .= "%".$3."d"; # substitute %sx with %xs
104           $res2 .= "%".$3."d"; # substitute %sx with %xs
105         }
106         elsif ($2 && $2 eq "a") {
107           push(@params, "get_irn_n(n, ".($3 - 1).")");
108           $res  .= "%+F";
109           $res2 .= "%+F";
110         }
111
112         $template = $'; # scan everything after the match
113       }
114       $res  .= $template; # get the remaining string
115       $res2 .= $template; # get the remaining string
116
117       my $parm = "";
118       $parm = ", ".join(", ", @params) if (@params);
119
120       if ($cio) {
121         push(@obst_func, $indent."if (get_irn_arity(n) > 1 && get_$arch\_in_regnr(n, 1) == get_$arch\_out_regnr(n, 0)) {\n");
122         push(@obst_func, $indent.'  lc_efprintf(ia32_get_arg_env(), F, "\t'.$res2.'\n"'.$parm.');'."\n");
123         push(@obst_func, $indent."}\n");
124         push(@obst_func, $indent."else {\n");
125         push(@obst_func, $indent.'  lc_efprintf(ia32_get_arg_env(), F, "\t'.$res.'\n"'.$parm.');'."\n");
126         push(@obst_func, $indent."}\n");
127       }
128       else {
129         push(@obst_func, $indent.'lc_efprintf(ia32_get_arg_env(), F, "\t'.$res.'\n"'.$parm.');'."\n");
130       }
131     }
132     else {
133       push(@obst_func, $template,"\n");
134     }
135   }
136   push(@obst_func, "}\n\n");
137 }
138
139 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
140
141 my $creation_time = localtime(time());
142
143 my $tmp = uc($arch);
144
145 print OUT<<EOF;
146 #ifndef _GEN_$tmp\_EMITTER_H_
147 #define _GEN_$tmp\_EMITTER_H_
148
149 /**
150  * Function prototypes for the emitter functions.
151  * DO NOT EDIT THIS FILE, your changes will be lost.
152  * Edit $specfile instead.
153  * created by: $0 $specfile $target_dir
154  * date:       $creation_time
155  */
156
157 #include "irnode.h"
158 #include "$arch\_emitter.h"
159
160 EOF
161
162 print OUT @obst_header;
163
164 print OUT "#endif /* _GEN_$tmp\_EMITTER_H_ */\n";
165
166 close(OUT);
167
168 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
169
170 $creation_time = localtime(time());
171
172 print OUT<<EOF;
173 /**
174  * Generated functions to emit code for assembler ir nodes.
175  * DO NOT EDIT THIS FILE, your changes will be lost.
176  * Edit $specfile instead.
177  * created by: $0 $specfile $target_dir
178  * date:       $creation_time
179  */
180
181 #include <stdio.h>
182
183 #include "irnode.h"
184 #include "gen_$arch\_emitter.h"
185 #include "$arch\_new_nodes.h"
186
187 EOF
188
189 print OUT @obst_func;
190
191 close(OUT);