helper functions for doing custom abi construction in codeselection phase
[libfirm] / ir / be / beabihelper.c
1 /*
2  * Copyright (C) 1995-2008 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       Helper functions for handling ABI constraints in the code
23  *              selection phase.
24  * @author      Matthias Braun
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include "beabihelper.h"
30 #include "bearch.h"
31 #include "benode.h"
32 #include "besched.h"
33 #include "ircons.h"
34 #include "iredges.h"
35 #include "irgwalk.h"
36
37 typedef struct reg_flag_t {
38         const arch_register_t *reg;   /**< register at an input position.
39                                            may be NULL in case of memory input */
40         arch_irn_flags_t       flags;
41 } reg_flag_t;
42
43 /**
44  * A register state mapping keeps track of the symbol values (=firm nodes)
45  * to registers. This is usefull when constructing straight line code
46  * which like the function prolog or epilog in some architectures.
47  */
48 typedef struct register_state_mapping_t {
49         ir_node   **value_map;     /**< mapping of state indices to values */
50         int       **reg_index_map; /**< mapping of regclass,regnum to an index
51                                         into the value_map */
52         reg_flag_t *regs;          /**< registers (and memory values) that form a
53                                         state */
54         ir_node    *last_barrier;
55 } register_state_mapping_t;
56
57 struct beabi_helper_env_t {
58         ir_graph                 *irg;
59         register_state_mapping_t  prolog;
60         register_state_mapping_t  epilog;
61 };
62
63 static void prepare_rsm(register_state_mapping_t *rsm,
64                         const arch_env_t *arch_env)
65 {
66         unsigned   n_reg_classes = arch_env_get_n_reg_class(arch_env);
67         unsigned   c;
68         reg_flag_t memory = { NULL, 0 };
69
70         rsm->regs = NEW_ARR_F(reg_flag_t, 0);
71         /* memory input at 0 */
72         ARR_APP1(reg_flag_t, rsm->regs, memory);
73
74         rsm->value_map     = NULL;
75         rsm->reg_index_map = XMALLOCN(int*, n_reg_classes);
76         for (c = 0; c < n_reg_classes; ++c) {
77                 const arch_register_class_t *cls = arch_env_get_reg_class(arch_env, c);
78                 unsigned                     n_regs = arch_register_class_n_regs(cls);
79                 unsigned                     r;
80
81                 rsm->reg_index_map[c] = XMALLOCN(int, n_regs);
82                 for (r = 0; r < n_regs; ++r) {
83                         rsm->reg_index_map[c][r] = -1;
84                 }
85         }
86 }
87
88 static void free_rsm(register_state_mapping_t *rsm, const arch_env_t *arch_env)
89 {
90         unsigned n_reg_classes = arch_env_get_n_reg_class(arch_env);
91         unsigned c;
92
93         for (c = 0; c < n_reg_classes; ++c) {
94                 free(rsm->reg_index_map[c]);
95         }
96
97         free(rsm->reg_index_map);
98         if (rsm->value_map != NULL)
99                 DEL_ARR_F(rsm->value_map);
100         DEL_ARR_F(rsm->regs);
101
102         rsm->regs          = NULL;
103         rsm->reg_index_map = NULL;
104         rsm->value_map     = NULL;
105 }
106
107 static void rsm_clear_regs(register_state_mapping_t *rsm,
108                            const arch_env_t *arch_env)
109 {
110         unsigned   n_reg_classes = arch_env_get_n_reg_class(arch_env);
111         unsigned   c;
112         reg_flag_t memory = { NULL, 0 };
113
114         for (c = 0; c < n_reg_classes; ++c) {
115                 const arch_register_class_t *cls = arch_env_get_reg_class(arch_env, c);
116                 unsigned                     n_regs = arch_register_class_n_regs(cls);
117                 unsigned                     r;
118
119                 for (r = 0; r < n_regs; ++r) {
120                         rsm->reg_index_map[c][r] = -1;
121                 }
122         }
123         ARR_RESIZE(reg_flag_t, rsm->regs, 0);
124         ARR_APP1(reg_flag_t, rsm->regs, memory);
125
126         if (rsm->value_map != NULL) {
127                 DEL_ARR_F(rsm->value_map);
128                 rsm->value_map = NULL;
129         }
130 }
131
132 static void rsm_add_reg(register_state_mapping_t *rsm,
133                         const arch_register_t *reg, arch_irn_flags_t flags)
134 {
135         int        input_idx = ARR_LEN(rsm->regs);
136         int        cls_idx   = reg->reg_class->index;
137         int        reg_idx   = reg->index;
138         reg_flag_t regflag   = { reg, flags };
139
140         /* we must not have used get_value yet */
141         assert(rsm->reg_index_map[cls_idx][reg_idx] == -1);
142         rsm->reg_index_map[cls_idx][reg_idx] = input_idx;
143         ARR_APP1(reg_flag_t, rsm->regs, regflag);
144 }
145
146
147 static ir_node *rsm_get_value(register_state_mapping_t *rsm, int index)
148 {
149         assert(index < ARR_LEN(rsm->value_map));
150         return rsm->value_map[index];
151 }
152
153 static ir_node *rsm_get_reg_value(register_state_mapping_t *rsm,
154                                   const arch_register_t *reg)
155 {
156         int cls_idx   = reg->reg_class->index;
157         int reg_idx   = reg->index;
158         int input_idx = rsm->reg_index_map[cls_idx][reg_idx];
159
160         return rsm_get_value(rsm, input_idx);
161 }
162
163 static void rsm_set_value(register_state_mapping_t *rsm, int index,
164                           ir_node *value)
165 {
166         assert(index < ARR_LEN(rsm->value_map));
167         rsm->value_map[index] = value;
168 }
169
170 static void rsm_set_reg_value(register_state_mapping_t *rsm,
171                               const arch_register_t *reg, ir_node *value)
172 {
173         int cls_idx   = reg->reg_class->index;
174         int reg_idx   = reg->index;
175         int input_idx = rsm->reg_index_map[cls_idx][reg_idx];
176         rsm_set_value(rsm, input_idx, value);
177 }
178
179 static ir_node *rsm_create_barrier(register_state_mapping_t *rsm,
180                                    ir_node *block)
181 {
182         int       n_barrier_outs = ARR_LEN(rsm->regs);
183         ir_node **in             = rsm->value_map;
184         ir_node  *barrier;
185         int       o;
186
187         assert(ARR_LEN(rsm->value_map) == n_barrier_outs);
188
189         barrier = be_new_Barrier(block, n_barrier_outs, in);
190
191         for (o = 0; o < n_barrier_outs; ++o) {
192                 const reg_flag_t      *regflag = &rsm->regs[o];
193                 const arch_register_t *reg     = regflag->reg;
194                 ir_node               *proj;
195                 if (reg == NULL) {
196                         arch_set_out_register_req(barrier, o, arch_no_register_req);
197                         proj = new_r_Proj(barrier, mode_M, o);
198                 } else {
199                         be_set_constr_single_reg_in(barrier, o, reg, 0);
200                         be_set_constr_single_reg_out(barrier, o, reg, regflag->flags);
201                         proj = new_r_Proj(barrier, reg->reg_class->mode, o);
202                 }
203                 rsm->value_map[o] = proj;
204         }
205
206         rsm->last_barrier = barrier;
207
208         return barrier;
209 }
210
211
212
213
214
215 beabi_helper_env_t *be_abihelper_prepare(ir_graph *irg)
216 {
217         const arch_env_t   *arch_env = be_get_irg_arch_env(irg);
218         beabi_helper_env_t *env      = XMALLOCZ(beabi_helper_env_t);
219
220         env->irg = irg;
221         prepare_rsm(&env->prolog, arch_env);
222         prepare_rsm(&env->epilog, arch_env);
223
224         return env;
225 }
226
227 void be_abihelper_finish(beabi_helper_env_t *env)
228 {
229         const arch_env_t *arch_env = be_get_irg_arch_env(env->irg);
230
231         free_rsm(&env->prolog, arch_env);
232         if (env->epilog.reg_index_map != NULL) {
233                 free_rsm(&env->epilog, arch_env);
234         }
235         free(env);
236 }
237
238 void be_prolog_add_reg(beabi_helper_env_t *env, const arch_register_t *reg,
239                        arch_irn_flags_t flags)
240 {
241         rsm_add_reg(&env->prolog, reg, flags);
242 }
243
244 ir_node *be_prolog_create_start(beabi_helper_env_t *env, dbg_info *dbgi,
245                                 ir_node *block)
246 {
247         int      n_start_outs = ARR_LEN(env->prolog.regs);
248         ir_node *start        = be_new_Start(dbgi, block, n_start_outs);
249         int      o;
250
251         assert(env->prolog.value_map == NULL);
252         env->prolog.value_map = NEW_ARR_F(ir_node*, n_start_outs);
253
254         for (o = 0; o < n_start_outs; ++o) {
255                 const reg_flag_t      *regflag = &env->prolog.regs[o];
256                 const arch_register_t *reg     = regflag->reg;
257                 ir_node               *proj;
258                 if (reg == NULL) {
259                         arch_set_out_register_req(start, o, arch_no_register_req);
260                         proj = new_r_Proj(start, mode_M, o);
261                 } else {
262                         be_set_constr_single_reg_out(start, o, regflag->reg,
263                                                      regflag->flags);
264                         arch_irn_set_register(start, o, regflag->reg);
265                         proj = new_r_Proj(start, reg->reg_class->mode, o);
266                 }
267                 env->prolog.value_map[o] = proj;
268         }
269
270         /* start node should really be the first thing constructed */
271         assert(env->prolog.last_barrier == NULL);
272         env->prolog.last_barrier = start;
273
274         return start;
275 }
276
277 ir_node *be_prolog_create_barrier(beabi_helper_env_t *env, ir_node *block)
278 {
279         return rsm_create_barrier(&env->prolog, block);
280 }
281
282 ir_node *be_prolog_get_reg_value(beabi_helper_env_t *env,
283                                  const arch_register_t *reg)
284 {
285         return rsm_get_reg_value(&env->prolog, reg);
286 }
287
288 ir_node *be_prolog_get_memory(beabi_helper_env_t *env)
289 {
290         return rsm_get_value(&env->prolog, 0);
291 }
292
293 void be_prolog_set_reg_value(beabi_helper_env_t *env,
294                              const arch_register_t *reg, ir_node *value)
295 {
296         rsm_set_reg_value(&env->prolog, reg, value);
297 }
298
299 void be_prolog_set_memory(beabi_helper_env_t *env, ir_node *value)
300 {
301         rsm_set_value(&env->prolog, 0, value);
302 }
303
304
305
306 void be_epilog_begin(beabi_helper_env_t *env)
307 {
308         const arch_env_t *arch_env = be_get_irg_arch_env(env->irg);
309         rsm_clear_regs(&env->epilog, arch_env);
310         env->epilog.value_map    = NEW_ARR_F(ir_node*, 1);
311         env->epilog.value_map[0] = NULL;
312 }
313
314 void be_epilog_add_reg(beabi_helper_env_t *env, const arch_register_t *reg,
315                        arch_irn_flags_t flags, ir_node *value)
316 {
317         rsm_add_reg(&env->epilog, reg, flags);
318         ARR_APP1(ir_node*, env->epilog.value_map, value);
319 }
320
321 void be_epilog_set_reg_value(beabi_helper_env_t *env,
322                              const arch_register_t *reg, ir_node *value)
323 {
324         rsm_set_reg_value(&env->epilog, reg, value);
325 }
326
327 void be_epilog_set_memory(beabi_helper_env_t *env, ir_node *value)
328 {
329         rsm_set_value(&env->epilog, 0, value);
330 }
331
332 ir_node *be_epilog_get_reg_value(beabi_helper_env_t *env,
333                                  const arch_register_t *reg)
334 {
335         return rsm_get_reg_value(&env->epilog, reg);
336 }
337
338 ir_node *be_epilog_get_memory(beabi_helper_env_t *env)
339 {
340         return rsm_get_value(&env->epilog, 0);
341 }
342
343 ir_node *be_epilog_create_barrier(beabi_helper_env_t *env, ir_node *block)
344 {
345         return rsm_create_barrier(&env->epilog, block);
346 }
347
348 ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
349                                  ir_node *block)
350 {
351         int       n_return_in = ARR_LEN(env->epilog.regs);
352         ir_node **in          = env->epilog.value_map;
353         int       n_res       = 1; /* TODO */
354         unsigned  pop         = 0; /* TODO */
355         int       i;
356         ir_node  *ret;
357
358         assert(ARR_LEN(env->epilog.value_map) == n_return_in);
359
360         ret = be_new_Return(dbgi, get_irn_irg(block), block, n_res, pop,
361                             n_return_in, in);
362         for (i = 0; i < n_return_in; ++i) {
363                 const reg_flag_t      *regflag = &env->epilog.regs[i];
364                 const arch_register_t *reg     = regflag->reg;
365                 if (reg != NULL) {
366                         be_set_constr_single_reg_in(ret, i, reg, 0);
367                 }
368         }
369
370         rsm_clear_regs(&env->epilog, be_get_irg_arch_env(env->irg));
371         env->epilog.last_barrier = NULL;
372
373         return ret;
374 }
375
376 static void add_missing_keep_walker(ir_node *node, void *data)
377 {
378         int              n_outs, i;
379         unsigned         found_projs = 0;
380         const ir_edge_t *edge;
381         ir_mode         *mode = get_irn_mode(node);
382         ir_node         *last_keep;
383         (void) data;
384         if (mode != mode_T)
385                 return;
386
387         n_outs = arch_irn_get_n_outs(node);
388         if (n_outs <= 0)
389                 return;
390
391         assert(n_outs < (int) sizeof(unsigned) * 8);
392         foreach_out_edge(node, edge) {
393                 ir_node *node = get_edge_src_irn(edge);
394                 int      pn;
395
396                 /* The node could be kept */
397                 if (is_End(node) || is_Anchor(node))
398                         continue;
399
400                 if (get_irn_mode(node) == mode_M)
401                         continue;
402
403                 pn = get_Proj_proj(node);
404                 assert(pn < n_outs);
405                 found_projs |= 1 << pn;
406         }
407
408
409         /* are keeps missing? */
410         last_keep = NULL;
411         for (i = 0; i < n_outs; ++i) {
412                 ir_node                     *block;
413                 ir_node                     *in[1];
414                 const arch_register_req_t   *req;
415                 const arch_register_class_t *cls;
416
417                 if (found_projs & (1 << i)) {
418                         continue;
419                 }
420
421                 req = arch_get_out_register_req(node, i);
422                 cls = req->cls;
423                 if (cls == NULL) {
424                         continue;
425                 }
426
427                 block = get_nodes_block(node);
428                 in[0] = new_r_Proj(node, arch_register_class_mode(cls), i);
429                 if (last_keep != NULL) {
430                         be_Keep_add_node(last_keep, cls, in[0]);
431                 } else {
432                         last_keep = be_new_Keep(block, 1, in);
433                         if (sched_is_scheduled(node)) {
434                                 sched_add_after(node, last_keep);
435                         }
436                 }
437         }
438 }
439
440 void be_add_missing_keeps(ir_graph *irg)
441 {
442         irg_walk_graph(irg, add_missing_keep_walker, NULL, NULL);
443 }