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