extended default constructor with register requirement initialisation
[libfirm] / ir / be / scripts / generate_new_opcodes.pl
1 #!/usr/bin/perl -w
2
3 # This script generates the C code which creates the irop's and
4 # their coresponding node constructors for all operations in a given spec
5 # so they can be used as normal firm nodes.
6 # Creation: 2005/10/19
7 # $Id$
8
9 use strict;
10 use Data::Dumper;
11
12 my $specfile   = $ARGV[0];
13 my $target_dir = $ARGV[1];
14 my $state      = 1;
15 my $cur_op     = "";
16 my $line_nr    = 0;
17
18 our $arch;
19 our %nodes;
20
21 # include spec file
22
23 my $return;
24
25 no strict "subs";
26 unless ($return = do $specfile) {
27   warn "couldn't parse $specfile: $@" if $@;
28   warn "couldn't do $specfile: $!"    unless defined $return;
29   warn "couldn't run $specfile"       unless $return;
30 }
31 use strict "subs";
32
33 my $target_c = $target_dir."/gen_".$arch."_new_nodes.c.inl";
34 my $target_h = $target_dir."/gen_".$arch."_new_nodes.h.inl";
35
36 #print Dumper(%nodes);
37
38 # create c code file from specs
39
40 my @obst_opvar;       # stack for the "ir_op *op_<arch>_<op-name> = NULL;" statements
41 my @obst_get_opvar;   # stack for the get_op_<arch>_<op-name>() functions
42 my @obst_constructor; # stack for node constructor functions
43 my @obst_new_irop;    # stack for the new_ir_op calls
44 my @obst_header;      # stack for function prototypes
45 my @obst_is_archirn;  # stack for the is_$arch_irn() function
46 my $temp;
47 my $orig_op;
48 my $arity;
49
50 push(@obst_header, "void ".$arch."_create_opcodes(void);\n");
51
52 foreach my $op (keys(%nodes)) {
53   my %n = %{ $nodes{"$op"} };
54
55   $orig_op = $op;
56   $op      = $arch."_".$op;
57   $arity   = $n{"arity"};
58
59   push(@obst_opvar, "ir_op *op_$op = NULL;\n");
60   push(@obst_get_opvar, "ir_op *get_op_$op(void)   { return op_$op; }\n");
61   push(@obst_get_opvar, "int    is_$op(const ir_node *n) { return get_irn_op(n) == op_$op; }\n\n");
62
63   push(@obst_is_archirn, "is_$op(node)");
64
65   push(@obst_header, "int is_$op(const ir_node *n);\n");
66
67   $n{"comment"} =~ s/^"|"$//g;
68   $n{"comment"} = "/* ".$n{"comment"}." */\n";
69   push(@obst_constructor, $n{"comment"});
70
71   # create constructor head
72   my $complete_args = "";
73   my $arg_names     = "";
74   $temp = "ir_node *new_rd_$op(dbg_info *db, ir_graph *irg, ir_node *block";
75   if (!exists($n{"args"}) || $n{"args"} eq "DEFAULT") { # default args
76     if ($n{"arity"} !~ /^[0-3]$/) {
77       print "DEFAULT args require arity 0,1,2 or 3! Ignoring op $orig_op!\n";
78       next;
79     }
80     for (my $i = 1; $i <= $n{"arity"}; $i++) {
81       $complete_args .= ", ir_node *op".$i;
82       $arg_names     .= ", op".$i;
83     }
84     $complete_args .= ", ir_mode *mode";
85     $arg_names     .= ", mode";
86   }
87   else { # user defined args
88     for my $href (@{ $n{"args"} }) {
89       $href->{"type"} .= " " if ($href->{"type"} !~ / [*]?$/); # put a space between name and type if there is none at the end
90       $complete_args  .= ", ".$href->{"type"}.$href->{"name"};
91       $arg_names      .= ", ".$href->{"name"};
92     }
93   }
94   $complete_args = substr($complete_args, 2);
95   $temp .= ", $complete_args)";
96   push(@obst_constructor, $temp." {\n");
97   push(@obst_header, $temp.";\n");
98
99   # emit constructor code
100   if (!exists($n{"rd_constructor"}) || $n{"rd_constructor"} eq "DEFAULT") { # default constructor
101     if ($n{"arity"} !~ /^[0-3]$/) {
102       print "DEFAULT rd_constructor requires arity 0,1,2 or 3! Ignoring op $orig_op!\n";
103       next;
104     }
105     $temp  = "  asmop_attr *attr;\n";
106     $temp .= "  ir_node *res;\n";
107     $temp .= "  ir_node *in[$arity];\n" if ($arity > 0);
108     $temp .= "\n";
109     $temp .= "  if (!op_$op) {\n";
110     $temp .= "    assert(0);\n";
111     $temp .= "    return NULL;\n";
112     $temp .= "  }\n\n";
113     for (my $i = 1; $i <= $arity; $i++) {
114       $temp .= "  in[".($i - 1)."] = op".$i.";\n";
115     }
116     $temp .= "  res = new_ir_node(db, irg, block, op_$op, mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
117     $temp .= "  res = optimize_node(res);\n";
118     $temp .= "  irn_vrfy_irg(res, irg);\n\n";
119
120     # set register flags
121     $temp .= "  attr = (asmop_attr *)get_irn_generic_attr(res);\n\n";
122     $temp .= "  attr->flags  = 0;                                 /* clear flags */\n";
123     if (!exists($n{"spill"}) || $n{"spill"} == 1) {
124       $temp .= "  attr->flags |= arch_irn_flags_spillable;          /* op is spillable */\n";
125     }
126     if (exists($n{"remat"}) && $n{"remat"} == 1) {
127       $temp .= "  attr->flags |= arch_irn_flags_rematerializable;   /* op can be easily recalulated */\n";
128     }
129
130     # allocate memory and set pointer to register requirements
131     if (exists($n{"reg_req"})) {
132       my %req = %{ $n{"reg_req"} };
133       my $idx;
134
135       undef my @in;
136       @in = @{ $req{"in"} } if (exists($req{"in"}));
137       undef my @out;
138       @out = @{ $req{"out"} } if exists(($req{"out"}));
139
140       if (@in) {
141         $temp .= "\n  /* allocate memory for IN register requirements and assigned registers */\n";
142         $temp .= "  attr->in_req    = malloc(".($#in + 1)." * sizeof(arch_register_req_t *)); /* space for in requirements */\n";
143         $temp .= "  attr->in        = malloc(".($#in + 1)." * sizeof(arch_register_t *));     /* space for assigned register to arguments */\n";
144         for ($idx = 0; $idx <= $#in; $idx++) {
145           $temp .= "  attr->in_req[$idx] = &".$op."_reg_req_in_".$idx.";\n";
146         }
147       }
148
149       if (@out) {
150         $temp .= "\n  /* allocate memory for OUT register requirements and assigned registers */\n";
151         $temp .= "  attr->out_req    = malloc(".($#out + 1)." * sizeof(arch_register_req_t *)); /* space for out requirements */\n";
152         $temp .= "  attr->out        = calloc(sizeof(arch_register_t *), ".($#out + 1).");     /* space for assigned register to results */\n";
153         for ($idx = 0; $idx <= $#out; $idx++) {
154           $temp .= "  attr->out_req[$idx] = &".$op."_reg_req_out_".$idx.";\n";
155         }
156         $temp .= "  attr->n_res      = ".($#out + 1).";\n";
157       }
158       else {
159         $temp .= "  attr->n_res      = 0;\n";
160       }
161     }
162
163     $temp .= "\n  return res;\n";
164
165     push(@obst_constructor, $temp);
166   }
167   else { # user defined constructor
168     push(@obst_constructor, $n{"rd_constructor"});
169   }
170
171   # close constructor function
172   push(@obst_constructor, "}\n\n");
173
174   # set default values for state and flags if not given
175   $n{"state"}    = "pinned" if (! exists($n{"state"}));
176   $n{"op_flags"} = "N"      if (! exists($n{"op_flags"}));
177
178   $temp  = "  op_$op = new_ir_op(get_next_ir_opcode(), \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
179   $temp .= ", ".translate_arity($arity).", 0, sizeof(asmop_attr), &ops);\n";
180   push(@obst_new_irop, $temp);
181 }
182
183 # emit the code
184
185 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
186
187 print OUT @obst_opvar;
188 print OUT "\n";
189 print OUT @obst_get_opvar;
190 print OUT "\n";
191 print OUT "int is_".$arch."_irn(const ir_node *node) {\n  if (".join(" ||\n      ", @obst_is_archirn).")\n    return 1;\n  else\n    return 0;\n}\n\n";
192 print OUT @obst_constructor;
193
194 print OUT<<ENDOFMAIN;
195 /**
196  * Creates the $arch specific firm operations
197  * needed for the assembler irgs.
198  */
199 void $arch\_create_opcodes(void) {
200 #define N   irop_flag_none
201 #define L   irop_flag_labeled
202 #define C   irop_flag_commutative
203 #define X   irop_flag_cfopcode
204 #define I   irop_flag_ip_cfopcode
205 #define F   irop_flag_fragile
206 #define Y   irop_flag_forking
207 #define H   irop_flag_highlevel
208 #define c   irop_flag_constlike
209
210   ir_op_ops ops;
211
212   memset(&ops, 0, sizeof(ops));
213
214   /* enter our modified dumper */
215   ops.dump_node = dump_node_$arch;
216
217 ENDOFMAIN
218
219 print OUT @obst_new_irop;
220 print OUT "}\n";
221
222 close(OUT);
223
224 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
225
226 print OUT @obst_header;
227
228 close(OUT);
229
230 ###
231 # Translates numeric arity into string constant.
232 ###
233 sub translate_arity {
234   my $arity = shift;
235
236   if    ($arity == 0) {
237     return "oparity_zero";
238   }
239   elsif ($arity == 1) {
240     return "oparity_unary";
241   }
242   elsif ($arity == 1) {
243     return "oparity_binary";
244   }
245   elsif ($arity == 1) {
246     return "oparity_trinary";
247   }
248   else {
249     return "$arity";
250   }
251 }