443f8fb2c49e33f0dd3883e1fecdfddc168cffa5
[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
61   $n{"comment"} =~ s/^"|"$//g;
62   $n{"comment"} = "/* ".$n{"comment"}." */\n";
63   push(@obst_constructor, $n{"comment"});
64
65   # create constructor head
66   my $complete_args = "";
67   my $arg_names     = "";
68   $temp = "ir_node *new_rd_$op(dbg_info *db, ir_graph *irg, ir_node *block";
69   if ($n{"args"} eq "DEFAULT") { # default args
70     if ($n{"arity"} !~ /^[0-3]$/) {
71       print "DEFAULT args require arity 0,1,2 or 3! Ignoring op $orig_op!\n";
72       next;
73     }
74     for (my $i = 1; $i <= $n{"arity"}; $i++) {
75       $complete_args .= ", ir_node *op".$i;
76       $arg_names     .= ", op".$i;
77     }
78     $complete_args .= ", ir_mode *mode";
79     $arg_names     .= ", mode";
80   }
81   else { # user defined args
82     for my $href (@{ $n{"args"} }) {
83       $complete_args .= ", ".$href->{"type"}.$href->{"name"};
84       $arg_names     .= ", ".$href->{"name"};
85     }
86   }
87   $complete_args = substr($complete_args, 2);
88   $temp .= ", $complete_args)";
89   push(@obst_constructor, $temp." {\n");
90   push(@obst_header, $temp.";\n");
91
92   # emit constructor code
93   if ($n{"rd_constructor"} eq "DEFAULT") { # default constructor
94     if ($n{"arity"} !~ /^[0-3]$/) {
95       print "DEFAULT rd_constructor requires arity 0,1,2 or 3! Ignoring op $orig_op!\n";
96       next;
97     }
98     $temp  = "  ir_node *res;\n";
99     $temp .= "  ir_node *in[$arity];\n" if ($arity > 0);
100     $temp .= "\n";
101     $temp .= "  if (!op_$op) {\n";
102     $temp .= "    assert(0);\n";
103     $temp .= "    return NULL;\n";
104     $temp .= "  }\n\n";
105     for (my $i = 1; $i <= $arity; $i++) {
106       $temp .= "  in[".($i - 1)."] = op".$i.";\n";
107     }
108     $temp .= "  res = new_ir_node(db, irg, block, op_$op, mode, $arity, ".($arity > 0 ? "in" : "NULL").");\n";
109     $temp .= "  res = optimize_node(res);\n";
110     $temp .= "  irn_vrfy_irg(res, irg);\n";
111     $temp .= "  return res;\n";
112
113     push(@obst_constructor, $temp);
114   }
115   else { # user defined constructor
116     push(@obst_constructor, $n{"rd_constructor"});
117   }
118
119   # close constructor function
120   push(@obst_constructor, "}\n\n");
121
122   # create the _r and _d wrapper
123   $temp  = "ir_node *new_r_$op(ir_graph *irg, ir_node *block, $complete_args)";
124   push(@obst_header, $temp.";\n");
125   $temp .= " {\n";
126   $temp .= "  return new_rd_$op(NULL, irg, block".$arg_names.");\n";
127   $temp .= "}\n\n";
128   push(@obst_constructor, $temp);
129
130   $temp  = "ir_node *new_d_$op(dbg_info *db, $complete_args)";
131   push(@obst_header, $temp.";\n");
132   $temp .= " {\n";
133   $temp .= "  return new_rd_$op(db, current_ir_graph, current_ir_graph->current_block".$arg_names.");\n";
134   $temp .= "}\n\n";
135   push(@obst_constructor, $temp);
136
137   $temp  = "ir_node *new_$op($complete_args)";
138   push(@obst_header, $temp.";\n");
139   $temp .= " {\n";
140   $temp .= "  return new_d_$op(NULL".$arg_names.");\n";
141   $temp .= "}\n\n";
142   push(@obst_constructor, $temp);
143
144   # construct the new_ir_op calls
145   my $arity_str = $arity == 0 ? "zero" : ($arity == 1 ? "unary" : ($arity == 2 ? "binary" : ($arity == 3 ? "trinary" : $arity)));
146   $temp  = "  op_$op = new_ir_op(get_next_ir_opcode(), \"$op\", op_pin_state_".$n{"state"}.", ".$n{"op_flags"};
147   $temp .= ", oparity_".$arity_str.", 0, sizeof(asmop_attr), NULL);\n";
148   push(@obst_new_irop, $temp);
149 }
150
151 # emit the code
152 my $creation_time = localtime(time());
153
154 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
155
156 print OUT<<ENDOFHEADER;
157 /**
158  * This file implements the creation of the achitecture specific firm opcodes
159  * and the coresponding node constructors for the $arch assembler irg.
160  * DO NOT EDIT THIS FILE, your changes will be lost.
161  * Edit $specfile instead.
162  * created by: $0 $specfile $target_dir
163  * date:       $creation_time
164  */
165
166 #ifdef HAVE_CONFIG_H
167 #include "config.h"
168 #endif
169
170 #include <stdlib.h>
171
172 #include "irprog_t.h"
173 #include "irgraph_t.h"
174 #include "irnode_t.h"
175 #include "irmode_t.h"
176 #include "ircons_t.h"
177 #include "iropt_t.h"
178 #include "firm_common_t.h"
179 #include "irvrfy_t.h"
180
181 #include "../firm2arch_nodes_attr.h"
182
183 #include "new_nodes.h"
184
185 ENDOFHEADER
186
187 print OUT @obst_opvar;
188 print OUT "\n";
189 print OUT @obst_get_opvar;
190 print OUT "\n";
191 print OUT @obst_constructor;
192
193 print OUT<<ENDOFMAIN;
194 /**
195  * Creates the architecture specific firm operations
196  * needed for the assembler irgs.
197  */
198 void create_bearch_asm_opcodes(void) {
199 #define N   irop_flag_none
200 #define L   irop_flag_labeled
201 #define C   irop_flag_commutative
202 #define X   irop_flag_cfopcode
203 #define I   irop_flag_ip_cfopcode
204 #define F   irop_flag_fragile
205 #define Y   irop_flag_forking
206 #define H   irop_flag_highlevel
207 #define c   irop_flag_constlike
208
209 ENDOFMAIN
210
211 print OUT @obst_new_irop;
212 print OUT "}\n";
213
214 close(OUT);
215
216 $creation_time = localtime(time());
217
218 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
219 print OUT<<EOF;
220 #ifndef NEW_NODES_H
221 #define NEW_NODES_H
222
223 /**
224  * Function prototypes for the assembler ir node constructors.
225  * DO NOT EDIT THIS FILE, your changes will be lost.
226  * Edit $specfile instead.
227  * created by: $0 $specfile $target_dir
228  * date:       $creation_time
229  */
230
231 EOF
232
233 print OUT @obst_header;
234 print OUT "\n#endif\n";
235
236 close(OUT);