b6ef2359d4cf7dbf9c2d0b12d9f009d8712a8bef
[libfirm] / ir / be / bedump_minir.c
1 /*
2  * Copyright (C) 2010 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Dump MinIR format for register coalescing
23  * @author      Matthias Braun
24  * @version     $Id$
25  */
26 #include "config.h"
27
28 #include <stdbool.h>
29
30 #include "irgwalk.h"
31 #include "iredges_t.h"
32 #include "bearch.h"
33 #include "besched.h"
34 #include "bedump_minir.h"
35
36 typedef enum yaml_state_t {
37         STATE_BLOCK_MAPPING,
38         STATE_BLOCK_SEQUENCE,
39         STATE_LIST,
40         STATE_MAPPING,
41         STATE_EXPECT_VALUE
42 } yaml_state_t;
43
44 static const arch_env_t *arch_env;
45 static FILE             *out;
46 static int               indent;
47 static bool              had_list_item;
48 static bool              had_dict_item;
49 static bool              no_newline;
50 static unsigned          state_pos;
51 static yaml_state_t      state_stack[1024];
52 static yaml_state_t      state;
53
54 static void init_yaml(FILE *new_out)
55 {
56         out       = new_out;
57         indent    = 0;
58         state_pos = 0;
59         state     = STATE_BLOCK_MAPPING;
60 }
61
62 static void exit_yaml(void)
63 {
64         assert(indent == 0);
65         assert(state_pos == 0);
66         fputs("\n", out);
67 }
68
69 static void push_state(yaml_state_t new_state)
70 {
71         assert(state_pos < sizeof(state_stack)/sizeof(yaml_state_t));
72         state_stack[state_pos++] = state;
73         state = new_state;
74 }
75
76 static void pop_state(void)
77 {
78         assert(state_pos > 0);
79         state = state_stack[--state_pos];
80 }
81
82 static void newline(void)
83 {
84         int i;
85
86         if (no_newline) {
87                 no_newline = false;
88                 return;
89         }
90
91         fputc('\n', out);
92         for (i = 0; i < indent; ++i) {
93                 fputs("  ", out);
94         }
95 }
96
97 static void list_item(void);
98 static void mapping_item(const char *name);
99
100 static void start(const char *name)
101 {
102         if (name != NULL) {
103                 mapping_item(name);
104         } else if (state == STATE_LIST || state == STATE_BLOCK_SEQUENCE) {
105                 list_item();
106         }
107
108         assert(state == STATE_EXPECT_VALUE);
109         pop_state();
110 }
111
112 static void begin_block_sequence(const char *name)
113 {
114         start(name);
115         push_state(STATE_BLOCK_SEQUENCE);
116 }
117
118 static void end_block_sequence(const char *name)
119 {
120         (void) name;
121         assert(state == STATE_BLOCK_SEQUENCE);
122         pop_state();
123 }
124
125 static void begin_block_mapping(const char *name)
126 {
127         start(name);
128         ++indent;
129         push_state(STATE_BLOCK_MAPPING);
130         if (name == NULL) {
131                 no_newline = true;
132         }
133 }
134
135 static void end_block_mapping(const char *name)
136 {
137         (void) name;
138         --indent;
139         assert(state == STATE_BLOCK_MAPPING);
140         pop_state();
141 }
142
143 static void mapping_item(const char *name)
144 {
145         if (state == STATE_BLOCK_MAPPING) {
146                 newline();
147         } else {
148                 assert(state == STATE_MAPPING);
149                 if (had_dict_item)
150                         fputs(", ", out);
151                 had_dict_item = true;
152         }
153         fprintf(out, "%s: ", name);
154         push_state(STATE_EXPECT_VALUE);
155 }
156
157 static void list_item(void)
158 {
159         if (state == STATE_BLOCK_SEQUENCE) {
160                 newline();
161                 fputs("- ", out);
162         } else {
163                 assert(state == STATE_LIST);
164                 if (had_list_item)
165                         fputs(", ", out);
166                 had_list_item = true;
167         }
168         push_state(STATE_EXPECT_VALUE);
169 }
170
171 static void value(const char *val)
172 {
173         if (state == STATE_BLOCK_SEQUENCE
174                         || state == STATE_LIST) {
175                 list_item();
176         }
177
178         assert(state == STATE_EXPECT_VALUE);
179         pop_state();
180         fputs(val, out);
181 }
182
183 static void key_value(const char *name, const char *val)
184 {
185         mapping_item(name);
186         value(val);
187 }
188
189 static void begin_list(const char *name)
190 {
191         start(name);
192         fputs("[", out);
193         had_list_item = false;
194         push_state(STATE_LIST);
195 }
196
197 static void end_list(const char *name)
198 {
199         fputs("]", out);
200         (void) name;
201         assert(state == STATE_LIST);
202         pop_state();
203 }
204
205 static void begin_mapping(const char *name)
206 {
207         start(name);
208         fputs("{", out);
209         had_dict_item = false;
210         push_state(STATE_MAPPING);
211 }
212
213 static void end_mapping(const char *name)
214 {
215         fputs("}", out);
216         (void) name;
217         assert(state == STATE_MAPPING);
218         pop_state();
219 }
220
221 static void print_regclasses(void)
222 {
223         int n_classes = arch_env_get_n_reg_class(arch_env);
224         int c;
225
226         begin_block_sequence("regclasses");
227         for (c = 0; c < n_classes; ++c) {
228                 int                          n_regs;
229                 int                          r;
230                 const arch_register_class_t *cls = arch_env_get_reg_class(arch_env, c);
231                 if (arch_register_class_flags(cls) & arch_register_class_flag_manual_ra)
232                         continue;
233
234                 n_regs = arch_register_class_n_regs(cls);
235
236                 begin_block_mapping(NULL);
237
238                 key_value("name", cls->name);
239                 begin_list("registers");
240                 for (r = 0; r < n_regs; ++r) {
241                         const arch_register_t *reg = arch_register_for_index(cls, r);
242                         value(reg->name);
243                 }
244                 end_list("registers");
245
246                 begin_block_mapping("flags");
247                 for (r = 0; r < n_regs; ++r) {
248                         const arch_register_t *reg  = arch_register_for_index(cls, r);
249                         unsigned               type = reg->type;
250                         if (type & arch_register_type_ignore) {
251                                 begin_list(reg->name);
252                                 value("reserved");
253                                 value("nossa"); /* do we need this? */
254                                 end_list(reg->name);
255                         }
256                 }
257                 end_block_mapping("flags");
258
259                 end_block_mapping(NULL);
260         }
261         end_block_sequence("regclasses");
262 }
263
264 static void print_value_name(ir_node *node)
265 {
266         char name[128];
267         const arch_register_req_t *req = arch_get_register_req_out(node);
268         snprintf(name, sizeof(name), "V%ld.%s", get_irn_node_nr(node),
269                  req->cls->name);
270
271         value(name);
272 }
273
274 static void print_node(ir_node *node)
275 {
276         ir_op *op = get_irn_op(node);
277         int    arity;
278         int    i;
279
280         begin_mapping(NULL);
281
282         mapping_item("op");
283         value(get_op_name(op));
284
285         mapping_item("defs");
286         begin_list(NULL);
287         if (get_irn_mode(node) == mode_T) {
288                 const ir_edge_t *edge;
289                 foreach_out_edge(node, edge) {
290                         ir_node *proj = get_edge_src_irn(edge);
291                         const arch_register_req_t *req = arch_get_register_req_out(proj);
292
293                         if (req->cls == NULL || (req->type & arch_register_req_type_ignore))
294                                 continue;
295
296                         list_item();
297                         print_value_name(proj);
298                 }
299         } else {
300                 const arch_register_req_t *req = arch_get_register_req_out(node);
301                 if (req->cls != NULL && !(req->type & arch_register_req_type_ignore)) {
302                         list_item();
303                         print_value_name(node);
304                 }
305         }
306         end_list(NULL);
307
308         mapping_item("uses");
309         begin_list(NULL);
310         arity = get_irn_arity(node);
311         for (i = 0; i < arity; ++i) {
312                 const arch_register_req_t *req = arch_get_register_req(node, i);
313                 ir_node                   *op  = get_irn_n(node, i);
314
315                 if (req->cls == NULL || (req->type & arch_register_req_type_ignore))
316                         continue;
317
318                 list_item();
319                 print_value_name(op);
320         }
321         end_list(NULL);
322
323         end_mapping(NULL);
324 }
325
326 static void dump_block(ir_node *block, void *data)
327 {
328         ir_graph *irg = get_irn_irg(block);
329         ir_node  *node;
330         (void) data;
331
332         begin_block_mapping(NULL);
333
334         if (block == get_irg_start_block(irg)) {
335                 key_value("label", "start");
336         } else if (block == get_irg_end_block(irg)) {
337                 key_value("label", "end");
338         } else {
339                 char name[128];
340                 snprintf(name, sizeof(name), "BB%ld", get_irn_node_nr(block));
341                 key_value("label", name);
342         }
343
344         begin_block_sequence("ops");
345
346         sched_foreach(block, node) {
347                 print_node(node);
348         }
349
350         end_block_sequence("ops");
351
352         end_block_mapping(NULL);
353 }
354
355 static void print_function(ir_graph *irg)
356 {
357         ir_entity *entity = get_irg_entity(irg);
358
359         begin_block_mapping(NULL);
360
361         key_value("label", get_entity_name(entity));
362         begin_list("entries"); value("start"); end_list("entries");
363         begin_list("exit");    value("end");   end_list("exit");
364
365         begin_block_sequence("bbs");
366         irg_block_walk_graph(irg, dump_block, NULL, NULL);
367         end_block_sequence("bbs");
368
369         end_block_mapping(NULL);
370 }
371
372 void be_export_minir(const arch_env_t *new_arch_env, FILE *out, ir_graph *irg)
373 {
374         arch_env = new_arch_env;
375         init_yaml(out);
376
377         print_regclasses();
378
379         begin_block_sequence("functions");
380         print_function(irg);
381         end_block_sequence("functions");
382
383         exit_yaml();
384 }