make firm compilable with a c++ compiler
[libfirm] / ir / be / bestack.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  * @author      Sebastian Hack, Matthias Braun
23  * @version     $Id$
24  *
25  * Handling of the stack frame. It is composed of three types:
26  * 1) The type of the arguments which are pushed on the stack.
27  * 2) The "between type" which consists of stuff the call of the
28  *    function pushes on the stack (like the return address and
29  *    the old base pointer for ia32).
30  * 3) The Firm frame type which consists of all local variables
31  *    and the spills.
32  */
33 #include "config.h"
34
35 #include "bestack.h"
36 #include "beirg.h"
37 #include "besched.h"
38 #include "benode.h"
39 #include "bessaconstr.h"
40
41 #include "ircons_t.h"
42 #include "irnode_t.h"
43 #include "irgwalk.h"
44 #include "irgmod.h"
45
46 int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent,
47                                int bias)
48 {
49         ir_type *t = get_entity_owner(ent);
50         int ofs    = get_entity_offset(ent);
51
52         int index;
53
54         /* Find the type the entity is contained in. */
55         for (index = 0; index < N_FRAME_TYPES; ++index) {
56                 if (frame->order[index] == t)
57                         break;
58                 /* Add the size of all the types below the one of the entity to the entity's offset */
59                 ofs += get_type_size_bytes(frame->order[index]);
60         }
61
62         /* correct the offset by the initial position of the frame pointer */
63         ofs -= frame->initial_offset;
64
65         /* correct the offset with the current bias. */
66         ofs += bias;
67
68         return ofs;
69 }
70
71 /**
72  * Retrieve the entity with given offset from a frame type.
73  */
74 static ir_entity *search_ent_with_offset(ir_type *t, int offset)
75 {
76         int i, n;
77
78         for (i = 0, n = get_compound_n_members(t); i < n; ++i) {
79                 ir_entity *ent = get_compound_member(t, i);
80                 if (get_entity_offset(ent) == offset)
81                         return ent;
82         }
83
84         return NULL;
85 }
86
87 static int stack_frame_compute_initial_offset(be_stack_layout_t *frame)
88 {
89         ir_type  *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type;
90         ir_entity *ent = search_ent_with_offset(base, 0);
91
92         if (ent == NULL) {
93                 frame->initial_offset
94                         = frame->stack_dir < 0 ? get_type_size_bytes(frame->frame_type) : get_type_size_bytes(frame->between_type);
95         } else {
96                 frame->initial_offset = be_get_stack_entity_offset(frame, ent, 0);
97         }
98
99         return frame->initial_offset;
100 }
101
102 /**
103  * Walker: finally lower all Sels of outer frame or parameter
104  * entities.
105  */
106 static void lower_outer_frame_sels(ir_node *sel, void *ctx)
107 {
108         ir_node           *ptr;
109         ir_entity         *ent;
110         ir_type           *owner;
111         be_stack_layout_t *layout;
112         ir_graph          *irg;
113         (void) ctx;
114
115         if (! is_Sel(sel))
116                 return;
117
118         ent    = get_Sel_entity(sel);
119         owner  = get_entity_owner(ent);
120         ptr    = get_Sel_ptr(sel);
121         irg    = get_irn_irg(sel);
122         layout = be_get_irg_stack_layout(irg);
123
124         if (owner == layout->frame_type || owner == layout->arg_type) {
125                 /* found access to outer frame or arguments */
126                 int offset = be_get_stack_entity_offset(layout, ent, 0);
127
128                 if (offset != 0) {
129                         ir_node  *bl   = get_nodes_block(sel);
130                         dbg_info *dbgi = get_irn_dbg_info(sel);
131                         ir_mode  *mode = get_irn_mode(sel);
132                         ir_mode  *mode_UInt = get_reference_mode_unsigned_eq(mode);
133                         ir_node  *cnst = new_r_Const_long(current_ir_graph, mode_UInt, offset);
134
135                         ptr = new_rd_Add(dbgi, bl, ptr, cnst, mode);
136                 }
137                 exchange(sel, ptr);
138         }
139 }
140
141 /**
142  * A helper struct for the bias walker.
143  */
144 typedef struct bias_walk {
145         int           start_block_bias;  /**< The bias at the end of the start block. */
146         int           between_size;
147         ir_node      *start_block;  /**< The start block of the current graph. */
148 } bias_walk;
149
150 /**
151  * Fix all stack accessing operations in the block bl.
152  *
153  * @param bl         the block to process
154  * @param real_bias  the bias value
155  *
156  * @return the bias at the end of this block
157  */
158 static int process_stack_bias(ir_node *bl, int real_bias)
159 {
160         int                wanted_bias = real_bias;
161         ir_graph          *irg         = get_Block_irg(bl);
162         be_stack_layout_t *layout      = be_get_irg_stack_layout(irg);
163         bool               sp_relative = layout->sp_relative;
164         const arch_env_t  *arch_env    = be_get_irg_arch_env(irg);
165         ir_node           *irn;
166
167         sched_foreach(bl, irn) {
168                 int ofs;
169
170                 /*
171                    Check, if the node relates to an entity on the stack frame.
172                    If so, set the true offset (including the bias) for that
173                    node.
174                  */
175                 ir_entity *ent = arch_get_frame_entity(irn);
176                 if (ent != NULL) {
177                         int bias   = sp_relative ? real_bias : 0;
178                         int offset = be_get_stack_entity_offset(layout, ent, bias);
179                         arch_set_frame_offset(irn, offset);
180                 }
181
182                 /*
183                  * If the node modifies the stack pointer by a constant offset,
184                  * record that in the bias.
185                  */
186                 ofs = arch_get_sp_bias(irn);
187
188                 if (be_is_IncSP(irn)) {
189                         /* fill in real stack frame size */
190                         if (ofs == BE_STACK_FRAME_SIZE_EXPAND) {
191                                 ir_type *frame_type = get_irg_frame_type(irg);
192                                 ofs = (int) get_type_size_bytes(frame_type);
193                                 be_set_IncSP_offset(irn, ofs);
194                         } else if (ofs == BE_STACK_FRAME_SIZE_SHRINK) {
195                                 ir_type *frame_type = get_irg_frame_type(irg);
196                                 ofs = - (int)get_type_size_bytes(frame_type);
197                                 be_set_IncSP_offset(irn, ofs);
198                         } else {
199                                 if (be_get_IncSP_align(irn)) {
200                                         /* patch IncSP to produce an aligned stack pointer */
201                                         ir_type *between_type = layout->between_type;
202                                         int      between_size = get_type_size_bytes(between_type);
203                                         int      alignment    = 1 << arch_env->stack_alignment;
204                                         int      delta        = (real_bias + ofs + between_size) & (alignment - 1);
205                                         assert(ofs >= 0);
206                                         if (delta > 0) {
207                                                 be_set_IncSP_offset(irn, ofs + alignment - delta);
208                                                 real_bias += alignment - delta;
209                                         }
210                                 } else {
211                                         /* adjust so real_bias corresponds with wanted_bias */
212                                         int delta = wanted_bias - real_bias;
213                                         assert(delta <= 0);
214                                         if (delta != 0) {
215                                                 be_set_IncSP_offset(irn, ofs + delta);
216                                                 real_bias += delta;
217                                         }
218                                 }
219                         }
220                 }
221
222                 real_bias   += ofs;
223                 wanted_bias += ofs;
224         }
225
226         assert(real_bias == wanted_bias);
227         return real_bias;
228 }
229
230 /**
231  * Block-Walker: fix all stack offsets for all blocks
232  * except the start block
233  */
234 static void stack_bias_walker(ir_node *bl, void *data)
235 {
236         bias_walk *bw = (bias_walk*)data;
237         if (bl != bw->start_block) {
238                 process_stack_bias(bl, bw->start_block_bias);
239         }
240 }
241
242 void be_abi_fix_stack_bias(ir_graph *irg)
243 {
244         be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
245         ir_type           *frame_tp;
246         int                i;
247         bias_walk          bw;
248
249         stack_frame_compute_initial_offset(stack_layout);
250
251         /* Determine the stack bias at the end of the start block. */
252         bw.start_block_bias = process_stack_bias(get_irg_start_block(irg),
253                                                  stack_layout->initial_bias);
254         bw.between_size     = get_type_size_bytes(stack_layout->between_type);
255
256         /* fix the bias is all other blocks */
257         bw.start_block = get_irg_start_block(irg);
258         irg_block_walk_graph(irg, stack_bias_walker, NULL, &bw);
259
260         /* fix now inner functions: these still have Sel node to outer
261            frame and parameter entities */
262         frame_tp = get_irg_frame_type(irg);
263         for (i = get_class_n_members(frame_tp) - 1; i >= 0; --i) {
264                 ir_entity *ent = get_class_member(frame_tp, i);
265                 ir_graph  *irg = get_entity_irg(ent);
266
267                 if (irg != NULL) {
268                         irg_walk_graph(irg, NULL, lower_outer_frame_sels, NULL);
269                 }
270         }
271 }
272
273 typedef struct fix_stack_walker_env_t {
274         ir_node **sp_nodes;
275 } fix_stack_walker_env_t;
276
277 /**
278  * Walker. Collect all stack modifying nodes.
279  */
280 static void collect_stack_nodes_walker(ir_node *node, void *data)
281 {
282         ir_node                   *insn = node;
283         fix_stack_walker_env_t    *env  = (fix_stack_walker_env_t*)data;
284         const arch_register_req_t *req;
285
286         if (is_Proj(node)) {
287                 insn = get_Proj_pred(node);
288         }
289
290         if (arch_irn_get_n_outs(insn) == 0)
291                 return;
292         if (get_irn_mode(node) == mode_T)
293                 return;
294
295         req = arch_get_register_req_out(node);
296         if (! (req->type & arch_register_req_type_produces_sp))
297                 return;
298
299         ARR_APP1(ir_node*, env->sp_nodes, node);
300 }
301
302 void be_abi_fix_stack_nodes(ir_graph *irg)
303 {
304         be_lv_t                   *lv       = be_get_irg_liveness(irg);
305         const arch_env_t          *arch_env = be_get_irg_arch_env(irg);
306         be_irg_t                  *birg     = be_birg_from_irg(irg);
307         const arch_register_req_t *sp_req   = birg->sp_req;
308         const arch_register_t     *sp       = arch_env->sp;
309         be_ssa_construction_env_t  senv;
310         int i, len;
311         ir_node **phis;
312         fix_stack_walker_env_t walker_env;
313
314         if (sp_req == NULL) {
315                 struct obstack      *obst = be_get_be_obst(irg);
316                 arch_register_req_t *new_sp_req;
317                 unsigned            *limited_bitset;
318
319                 new_sp_req        = OALLOCZ(obst, arch_register_req_t);
320                 new_sp_req->type  = arch_register_req_type_limited
321                                   | arch_register_req_type_produces_sp;
322                 new_sp_req->cls   = arch_register_get_class(arch_env->sp);
323                 new_sp_req->width = 1;
324
325                 limited_bitset = rbitset_obstack_alloc(obst, new_sp_req->cls->n_regs);
326                 rbitset_set(limited_bitset, arch_register_get_index(sp));
327                 new_sp_req->limited = limited_bitset;
328
329                 if (!rbitset_is_set(birg->allocatable_regs, sp->global_index)) {
330                         new_sp_req->type |= arch_register_req_type_ignore;
331                 }
332
333                 sp_req = new_sp_req;
334                 birg->sp_req = new_sp_req;
335         }
336
337         walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0);
338
339         irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env);
340
341         /* nothing to be done if we didn't find any node, in fact we mustn't
342          * continue, as for endless loops incsp might have had no users and is bad
343          * now.
344          */
345         len = ARR_LEN(walker_env.sp_nodes);
346         if (len == 0) {
347                 DEL_ARR_F(walker_env.sp_nodes);
348                 return;
349         }
350
351         be_ssa_construction_init(&senv, irg);
352         be_ssa_construction_add_copies(&senv, walker_env.sp_nodes,
353                                    ARR_LEN(walker_env.sp_nodes));
354         be_ssa_construction_fix_users_array(&senv, walker_env.sp_nodes,
355                                             ARR_LEN(walker_env.sp_nodes));
356
357         if (lv != NULL) {
358                 len = ARR_LEN(walker_env.sp_nodes);
359                 for (i = 0; i < len; ++i) {
360                         be_liveness_update(lv, walker_env.sp_nodes[i]);
361                 }
362                 be_ssa_construction_update_liveness_phis(&senv, lv);
363         }
364
365         phis = be_ssa_construction_get_new_phis(&senv);
366
367         /* set register requirements for stack phis */
368         len = ARR_LEN(phis);
369         for (i = 0; i < len; ++i) {
370                 ir_node *phi = phis[i];
371                 be_set_phi_reg_req(phi, sp_req);
372                 arch_set_irn_register(phi, arch_env->sp);
373         }
374         be_ssa_construction_destroy(&senv);
375
376         DEL_ARR_F(walker_env.sp_nodes);
377 }