eeb432d782d55cb66e36cb63314f0a4c87684aa0
[libfirm] / ir / be / scripts / generate_emitter_new.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 our $specfile;
13 our $target_dir;
14
15 our $arch;
16 our %nodes;
17 our %emit_templates;
18
19 my $target_c = $target_dir."/gen_".$arch."_emitter.c";
20 my $target_h = $target_dir."/gen_".$arch."_emitter.h";
21
22 # stacks for output
23 my @obst_func;   # stack for the emit functions
24 my @obst_register;  # stack for emitter register code
25 my $line;
26
27 sub create_emitter {
28         my $result = shift;
29         my $indent = shift;
30         my $template = shift;
31         our %emit_templates;
32         our $arch;
33
34         my @tokens = ($template =~ m/[^\%]+|\%[a-zA-Z_][a-zA-Z0-9_]*|\%./g);
35         push(@{$result}, "${indent}${arch}_emit_char(env, '\t');\n");
36         for (@tokens) {
37                 SWITCH: {
38                         if (/%\./)      { last SWITCH; }
39                         if (/%%/)       { push(@{$result}, "${indent}${arch}_emit_char(env, '%');\n"); last SWITCH; }
40                         if (/%(.+)/)    {
41                                 if(defined($emit_templates{$1})) {
42                                         push(@{$result}, "${indent}$emit_templates{$1}\n");
43                                 } else {
44                                         print "Warning: No emit_template defined for '$1'\n";
45                                         push(@{$result}, "${indent}$1(env, node);\n");
46                                 }
47                                 last SWITCH;
48                         }
49                         push(@{$result}, "${indent}${arch}_emit_cstring(env, \"$_\");\n");
50                 }
51         }
52         push(@{$result}, "${indent}${arch}_emit_finish_line(env, node);\n");
53 }
54
55
56
57 foreach my $op (keys(%nodes)) {
58         my %n = %{ $nodes{"$op"} };
59
60         # skip this node description if no emit information is available
61         next if (!defined($n{"emit"}));
62
63         $line = "static void emit_".$arch."_".$op."(${arch}_emit_env_t *env, const ir_node *node)";
64
65         push(@obst_register, "  BE_EMIT($op);\n");
66
67         if($n{"emit"} eq "") {
68                 push(@obst_func, $line." {\n");
69                 push(@obst_func, "}\n\n");
70                 next;
71         }
72
73         push(@obst_func, $line." {\n");
74         my @emit = split(/\n/, $n{"emit"});
75
76         foreach my $template (@emit) {
77                 # substitute only lines, starting with a '.'
78                 if ($template =~ /^(\s*)\.\s*(.*)/) {
79                         my $indent = "\t$1";
80                         create_emitter(\@obst_func, $indent, $2);
81                 } else {
82                         push(@obst_func, "\t$template\n");
83                 }
84         }
85
86         push(@obst_func, "}\n\n");
87 }
88
89 open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n");
90
91 my $creation_time = localtime(time());
92
93 my $tmp = uc($arch);
94
95 print OUT<<EOF;
96 #ifndef _GEN_$tmp\_EMITTER_H_
97 #define _GEN_$tmp\_EMITTER_H_
98
99 /**
100  * Function prototypes for the emitter functions.
101  * DO NOT EDIT THIS FILE, your changes will be lost.
102  * Edit $specfile instead.
103  * created by: $0 $specfile $target_dir
104  * date:       $creation_time
105  */
106
107 #include "irnode.h"
108 #include "$arch\_emitter.h"
109
110 void $arch\_register_spec_emitters(void);
111
112 #endif /* _GEN_$tmp\_EMITTER_H_ */
113
114 EOF
115
116 close(OUT);
117
118 open(OUT, ">$target_c") || die("Could not open $target_c, reason: $!\n");
119
120 $creation_time = localtime(time());
121
122 print OUT<<EOF;
123 /**
124  * Generated functions to emit code for assembler ir nodes.
125  * DO NOT EDIT THIS FILE, your changes will be lost.
126  * Edit $specfile instead.
127  * created by: $0 $specfile $target_dir
128  * date:       $creation_time
129  */
130 #ifdef HAVE_CONFIG_H
131 #include <config.h>
132 #endif
133
134 #include <stdio.h>
135
136 #include "irnode.h"
137 #include "irop_t.h"
138 #include "irprog_t.h"
139
140 #include "gen_${arch}_emitter.h"
141 #include "${arch}_new_nodes.h"
142 #include "${arch}_emitter.h"
143
144 EOF
145
146 print OUT @obst_func;
147
148 print OUT<<EOF;
149 /**
150  * Enters the emitter functions for handled nodes into the generic
151  * pointer of an opcode.
152  */
153 void $arch\_register_spec_emitters(void) {
154
155 #define BE_EMIT(a) op_$arch\_##a->ops.generic = (op_func)emit_$arch\_##a
156
157   /* generated emitter functions */
158 EOF
159
160 print OUT @obst_register;
161
162 print OUT<<EOF;
163
164 #undef BE_EMIT
165 }
166
167 EOF
168
169 close(OUT);