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