9eeea853887c802530a2d8c59415967ba310853c
[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  * Copy the attributes from an Imm to an Immop (Add_i, Sub_i, ...) node
208  */
209 void set_Immop_attr(ir_node *node, ir_node *imm) {
210   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
211   assert(is_Imm(imm) && "Need Imm to set Immop attr");
212
213   imm_attr_t *ia = (imm_attr_t *)get_irn_generic_attr(imm);
214   if (ia->tp == imm_Const) {
215     attr->tp      = asmop_Const;
216     attr->data.tv = ia->data.tv;
217   }
218   else {
219     attr->tp            = asmop_SymConst;
220     attr->data.symconst = ia->data.symconst;
221   }
222 }
223
224 /**
225  * Sets the attributes of an immediate operation to the specified tarval
226  */
227 void set_Immop_attr_tv(ir_node *node, tarval *tv) {
228   asmop_attr *attr = (asmop_attr *)get_irn_generic_attr(node);
229
230   attr->tp         = asmop_Const;
231   attr->data.tv    = tv;
232 }
233
234 /**
235  * Sets the offset for a Lea.
236  */
237 void set_ia32_Lea_offs(ir_node *node, tarval *offs) {
238   assert(is_ia32_Lea(node) && "Cannot set offset in non-Lea node.");
239
240   asmop_attr *attr  = (asmop_attr *)get_irn_generic_attr(node);
241   attr->data.offset = offs;
242 }
243
244 /**
245  * Gets the offset for a Lea.
246  */
247 tarval *get_ia32_Lea_offs(ir_node *node) {
248   assert(is_ia32_Lea(node) && "Cannot get offset for a non-Lea node.");
249
250   asmop_attr *attr  = (asmop_attr *)get_irn_generic_attr(node);
251   return attr->data.offset;
252 }
253
254 ENDOFHEADER
255
256 print OUT @obst_opvar;
257 print OUT "\n";
258 print OUT @obst_get_opvar;
259 print OUT "\n";
260 print OUT @obst_constructor;
261
262 print OUT<<ENDOFMAIN;
263 /**
264  * Creates the architecture specific firm operations
265  * needed for the assembler irgs.
266  */
267 void create_bearch_asm_opcodes(void) {
268 #define N   irop_flag_none
269 #define L   irop_flag_labeled
270 #define C   irop_flag_commutative
271 #define X   irop_flag_cfopcode
272 #define I   irop_flag_ip_cfopcode
273 #define F   irop_flag_fragile
274 #define Y   irop_flag_forking
275 #define H   irop_flag_highlevel
276 #define c   irop_flag_constlike
277
278   ir_op_ops ops;
279
280   memset(&ops, 0, sizeof(ops));
281
282   /* enter our modified dumper */
283   ops.dump_node = dump_node_ia32;
284
285 ENDOFMAIN
286
287 print OUT @obst_new_irop;
288 print OUT "}\n";
289
290 close(OUT);
291
292 $creation_time = localtime(time());
293
294 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
295 print OUT<<EOF;
296 #ifndef NEW_NODES_H
297 #define NEW_NODES_H
298
299 /**
300  * Function prototypes for the assembler ir node constructors.
301  * DO NOT EDIT THIS FILE, your changes will be lost.
302  * Edit $specfile instead.
303  * created by: $0 $specfile $target_dir
304  * date:       $creation_time
305  */
306
307 tarval *get_Immop_tarval(ir_node *node);
308 void    set_Immop_attr(ir_node *node, ir_node *imm);
309 void    set_Immop_attr_tv(ir_node *node, tarval *tv);
310 void    set_ia32_Lea_offs(ir_node *node, tarval *offs);
311 tarval *get_ia32_Lea_offs(ir_node *node);
312
313 EOF
314
315 print OUT @obst_header;
316 print OUT "\n#endif\n";
317
318 close(OUT);