generate emitter functions from spec
[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 my $target_c = $target_dir."/new_nodes.c";
19 my $target_h = $target_dir."/new_nodes.h";
20
21 our $arch;
22 our %nodes;
23
24 # include spec file
25
26 my $return;
27
28 no strict "subs";
29 unless ($return = do $specfile) {
30   warn "couldn't parse $specfile: $@" if $@;
31   warn "couldn't do $specfile: $!"    unless defined $return;
32   warn "couldn't run $specfile"       unless $return;
33 }
34 use strict "subs";
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 $temp;
46 my $orig_op;
47 my $arity;
48
49 push(@obst_header, "void create_bearch_asm_opcodes(void);");
50
51 foreach my $op (keys(%nodes)) {
52   my %n = %{ $nodes{"$op"} };
53
54   $orig_op = $op;
55   $op      = $arch."_".$op;
56   $arity   = $n{"arity"};
57
58   push(@obst_opvar, "ir_op *op_$op = NULL;\n");
59   push(@obst_get_opvar, "ir_op *get_op_$op(void)   { return op_$op; }\n");
60   push(@obst_get_opvar, "int    is_$op(ir_node *n) { return get_irn_op(n) == op_$op ? 1 : 0; }\n\n");
61
62   push(@obst_header, "int is_$op(ir_node *n);\n");
63
64   $n{"comment"} =~ s/^"|"$//g;
65   $n{"comment"} = "/* ".$n{"comment"}." */\n";
66   push(@obst_constructor, $n{"comment"});
67
68   # create constructor head
69   my $complete_args = "";
70   my $arg_names     = "";
71   $temp = "ir_node *new_rd_$op(dbg_info *db, ir_graph *irg, ir_node *block";
72   if (!exists($n{"args"}) || $n{"args"} eq "DEFAULT") { # default args
73     if ($n{"arity"} !~ /^[0-3]$/) {
74       print "DEFAULT args require arity 0,1,2 or 3! Ignoring op $orig_op!\n";
75       next;
76     }
77     for (my $i = 1; $i <= $n{"arity"}; $i++) {
78       $complete_args .= ", ir_node *op".$i;
79       $arg_names     .= ", op".$i;
80     }
81     $complete_args .= ", ir_mode *mode";
82     $arg_names     .= ", mode";
83   }
84   else { # user defined args
85     for my $href (@{ $n{"args"} }) {
86       $complete_args .= ", ".$href->{"type"}.$href->{"name"};
87       $arg_names     .= ", ".$href->{"name"};
88     }
89   }
90   $complete_args = substr($complete_args, 2);
91   $temp .= ", $complete_args)";
92   push(@obst_constructor, $temp." {\n");
93   push(@obst_header, $temp.";\n");
94
95   # emit constructor code
96   if (!exists($n{"rd_constructor"}) || $n{"rd_constructor"} eq "DEFAULT") { # default constructor
97     if ($n{"arity"} !~ /^[0-3]$/) {
98       print "DEFAULT rd_constructor requires arity 0,1,2 or 3! Ignoring op $orig_op!\n";
99       next;
100     }
101     $temp  = "  ir_node *res;\n";
102     $temp .= "  ir_node *in[$arity];\n" if ($arity > 0);
103     $temp .= "\n";
104     $temp .= "  if (!op_$op) {\n";
105     $temp .= "    assert(0);\n";
106     $temp .= "    return NULL;\n";
107     $temp .= "  }\n\n";
108     for (my $i = 1; $i <= $arity; $i++) {
109       $temp .= "  in[".($i - 1)."] = op".$i.";\n";
110     }
111     $temp .= "  res = new_ir_node(db, irg, block, op_$op, mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
112     $temp .= "  res = optimize_node(res);\n";
113     $temp .= "  irn_vrfy_irg(res, irg);\n";
114     $temp .= "  return res;\n";
115
116     push(@obst_constructor, $temp);
117   }
118   else { # user defined constructor
119     push(@obst_constructor, $n{"rd_constructor"});
120   }
121
122   # close constructor function
123   push(@obst_constructor, "}\n\n");
124
125 #  # create the _r and _d wrapper
126 #  $temp  = "ir_node *new_r_$op(ir_graph *irg, ir_node *block, $complete_args)";
127 #  push(@obst_header, $temp.";\n");
128 #  $temp .= " {\n";
129 #  $temp .= "  return new_rd_$op(NULL, irg, block".$arg_names.");\n";
130 #  $temp .= "}\n\n";
131 #  push(@obst_constructor, $temp);
132 #
133 #  $temp  = "ir_node *new_d_$op(dbg_info *db, $complete_args)";
134 #  push(@obst_header, $temp.";\n");
135 #  $temp .= " {\n";
136 #  $temp .= "  return new_rd_$op(db, current_ir_graph, current_ir_graph->current_block".$arg_names.");\n";
137 #  $temp .= "}\n\n";
138 #  push(@obst_constructor, $temp);
139 #
140 #  $temp  = "ir_node *new_$op($complete_args)";
141 #  push(@obst_header, $temp.";\n");
142 #  $temp .= " {\n";
143 #  $temp .= "  return new_d_$op(NULL".$arg_names.");\n";
144 #  $temp .= "}\n\n";
145 #  push(@obst_constructor, $temp);
146
147   # construct the new_ir_op calls
148
149   # set default values for state and flags if not given
150   $n{"state"}    = "pinned" if (! exists($n{"state"}));
151   $n{"op_flags"} = "N"      if (! exists($n{"op_flags"}));
152
153   my $arity_str = $arity == 0 ? "zero" : ($arity == 1 ? "unary" : ($arity == 2 ? "binary" : ($arity == 3 ? "trinary" : $arity)));
154   $temp  = "  op_$op = new_ir_op(get_next_ir_opcode(), \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
155   $temp .= ", oparity_".$arity_str.", 0, sizeof(asmop_attr), &ops);\n";
156   push(@obst_new_irop, $temp);
157 }
158
159 # emit the code
160 my $creation_time = localtime(time());
161
162 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
163
164 print OUT<<ENDOFHEADER;
165 /**
166  * This file implements the creation of the achitecture specific firm opcodes
167  * and the coresponding node constructors for the $arch assembler irg.
168  * DO NOT EDIT THIS FILE, your changes will be lost.
169  * Edit $specfile instead.
170  * created by: $0 $specfile $target_dir
171  * date:       $creation_time
172  */
173
174 #ifdef HAVE_CONFIG_H
175 #include "config.h"
176 #endif
177
178 #include <stdlib.h>
179
180 #include "irprog_t.h"
181 #include "irgraph_t.h"
182 #include "irnode_t.h"
183 #include "irmode_t.h"
184 #include "ircons_t.h"
185 #include "iropt_t.h"
186 #include "firm_common_t.h"
187 #include "irvrfy_t.h"
188
189 #include "../firm2arch_nodes_attr.h"
190 #include "../bearch_firm.h"
191
192 #include "new_nodes.h"
193 #include "dump_support.inl"
194
195 /**
196  * Return the tarval of an immediate operation or NULL in case of SymConst
197  */
198 tarval *get_Immop_tarval(ir_node *node) {
199   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
200   if (attr->tp == asmop_Const)
201     return attr->data.tv;
202   else
203     return NULL;
204 }
205
206 /**
207  * Return the old_ir attribute.
208  */
209 ir_node *get_old_ir(ir_node *node) {
210   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
211   return attr->data.old_ir;
212 }
213
214 /**
215  * Copy the attributes from an Imm to an Immop (Add_i, Sub_i, ...) node
216  */
217 void set_Immop_attr(ir_node *node, ir_node *imm) {
218   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
219   assert(is_Imm(imm) && "Need Imm to set Immop attr");
220
221   imm_attr_t *ia = (imm_attr_t *)get_irn_generic_attr(imm);
222   if (ia->tp == imm_Const) {
223     attr->tp      = asmop_Const;
224     attr->data.tv = ia->data.tv;
225   }
226   else {
227     attr->tp          = asmop_SymConst;
228     attr->data.old_ir = ia->data.symconst;
229   }
230 }
231
232 /**
233  * Sets the attributes of an immediate operation to the specified tarval
234  */
235 void set_Immop_attr_tv(ir_node *node, tarval *tv) {
236   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
237
238   attr->tp         = asmop_Const;
239   attr->data.tv    = tv;
240 }
241
242 /**
243  * Sets the offset for a Lea.
244  */
245 void set_ia32_Lea_offs(ir_node *node, tarval *offs) {
246   assert(is_ia32_Lea(node) && "Cannot set offset in non-Lea node.");
247
248   asmop_attr *attr  = (asmop_attr *)get_irn_generic_attr(node);
249   attr->data.offset = offs;
250 }
251
252 /**
253  * Gets the offset for a Lea.
254  */
255 tarval *get_ia32_Lea_offs(ir_node *node) {
256   assert(is_ia32_Lea(node) && "Cannot get offset for a non-Lea node.");
257
258   asmop_attr *attr  = (asmop_attr *)get_irn_generic_attr(node);
259   return attr->data.offset;
260 }
261
262 ENDOFHEADER
263
264 print OUT @obst_opvar;
265 print OUT "\n";
266 print OUT @obst_get_opvar;
267 print OUT "\n";
268 print OUT @obst_constructor;
269
270 print OUT<<ENDOFMAIN;
271 /**
272  * Creates the architecture specific firm operations
273  * needed for the assembler irgs.
274  */
275 void create_bearch_asm_opcodes(void) {
276 #define N   irop_flag_none
277 #define L   irop_flag_labeled
278 #define C   irop_flag_commutative
279 #define X   irop_flag_cfopcode
280 #define I   irop_flag_ip_cfopcode
281 #define F   irop_flag_fragile
282 #define Y   irop_flag_forking
283 #define H   irop_flag_highlevel
284 #define c   irop_flag_constlike
285
286   ir_op_ops ops;
287
288   memset(&ops, 0, sizeof(ops));
289
290   /* enter our modified dumper */
291   ops.dump_node = dump_node_ia32;
292
293 ENDOFMAIN
294
295 print OUT @obst_new_irop;
296 print OUT "}\n";
297
298 close(OUT);
299
300 $creation_time = localtime(time());
301
302 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
303 print OUT<<EOF;
304 #ifndef NEW_NODES_H
305 #define NEW_NODES_H
306
307 /**
308  * Function prototypes for the assembler ir node constructors.
309  * DO NOT EDIT THIS FILE, your changes will be lost.
310  * Edit $specfile instead.
311  * created by: $0 $specfile $target_dir
312  * date:       $creation_time
313  */
314
315 tarval  *get_Immop_tarval(ir_node *node);
316 ir_node *get_old_ir(ir_node *node);
317 void    set_Immop_attr(ir_node *node, ir_node *imm);
318 void    set_Immop_attr_tv(ir_node *node, tarval *tv);
319 void    set_ia32_Lea_offs(ir_node *node, tarval *offs);
320 tarval  *get_ia32_Lea_offs(ir_node *node);
321
322 EOF
323
324 print OUT @obst_header;
325 print OUT "\n#endif\n";
326
327 close(OUT);