2 * This file is part of libFirm.
3 * Copyright (C) 2012 University of Karlsruhe.
8 * @author Sebastian Hack, Matthias Braun
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
24 #include "bessaconstr.h"
31 int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent,
34 ir_type *t = get_entity_owner(ent);
35 int ofs = get_entity_offset(ent);
39 /* Find the type the entity is contained in. */
40 for (index = 0; index < N_FRAME_TYPES; ++index) {
41 if (frame->order[index] == t)
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]);
47 /* correct the offset by the initial position of the frame pointer */
48 ofs -= frame->initial_offset;
50 /* correct the offset with the current bias. */
57 * Retrieve the entity with given offset from a frame type.
59 static ir_entity *search_ent_with_offset(ir_type *t, int offset)
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)
72 static void stack_frame_compute_initial_offset(be_stack_layout_t *frame)
74 ir_type *base = frame->between_type;
75 ir_entity *ent = search_ent_with_offset(base, 0);
78 frame->initial_offset = get_type_size_bytes(frame->frame_type);
80 frame->initial_offset = be_get_stack_entity_offset(frame, ent, 0);
85 * Walker: finally lower all Sels of outer frame or parameter
88 static void lower_outer_frame_sels(ir_node *sel, void *ctx)
93 be_stack_layout_t *layout;
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);
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);
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);
117 ptr = new_rd_Add(dbgi, bl, ptr, cnst, mode);
124 * A helper struct for the bias walker.
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. */
132 * Fix all stack accessing operations in the block bl.
134 * @param bl the block to process
135 * @param real_bias the bias value
137 * @return the bias at the end of this block
139 static int process_stack_bias(ir_node *bl, int real_bias)
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);
147 sched_foreach(bl, irn) {
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
155 ir_entity *ent = arch_get_frame_entity(irn);
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);
163 * If the node modifies the stack pointer by a constant offset,
164 * record that in the bias.
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);
176 be_set_IncSP_offset(irn, ofs + alignment - delta);
177 real_bias += alignment - delta;
180 /* adjust so real_bias corresponds with wanted_bias */
181 int delta = wanted_bias - real_bias;
184 be_set_IncSP_offset(irn, ofs + delta);
191 ofs = arch_get_sp_bias(irn);
192 if (ofs == SP_BIAS_RESET) {
202 assert(real_bias == wanted_bias);
207 * Block-Walker: fix all stack offsets for all blocks
208 * except the start block
210 static void stack_bias_walker(ir_node *bl, void *data)
212 bias_walk *bw = (bias_walk*)data;
213 if (bl != bw->start_block) {
214 process_stack_bias(bl, bw->start_block_bias);
218 void be_abi_fix_stack_bias(ir_graph *irg)
220 be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
225 stack_frame_compute_initial_offset(stack_layout);
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);
231 /* fix the bias is all other blocks */
232 irg_block_walk_graph(irg, stack_bias_walker, NULL, &bw);
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);
242 irg_walk_graph(irg, NULL, lower_outer_frame_sels, NULL);
247 typedef struct fix_stack_walker_env_t {
249 } fix_stack_walker_env_t;
252 * Walker. Collect all stack modifying nodes.
254 static void collect_stack_nodes_walker(ir_node *node, void *data)
256 fix_stack_walker_env_t *const env = (fix_stack_walker_env_t*)data;
258 if (get_irn_mode(node) == mode_T)
261 arch_register_req_t const *const req = arch_get_irn_register_req(node);
262 if (!arch_register_req_is(req, produces_sp))
265 ARR_APP1(ir_node*, env->sp_nodes, node);
268 void be_abi_fix_stack_nodes(ir_graph *irg)
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;
277 fix_stack_walker_env_t walker_env;
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;
285 struct obstack *const obst = be_get_be_obst(irg);
286 birg->sp_req = sp_req = be_create_reg_req(obst, sp, type);
289 walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0);
291 irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env);
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
297 len = ARR_LEN(walker_env.sp_nodes);
299 DEL_ARR_F(walker_env.sp_nodes);
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));
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]);
314 be_ssa_construction_update_liveness_phis(&senv, lv);
317 phis = be_ssa_construction_get_new_phis(&senv);
319 /* set register requirements for stack 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);
326 be_ssa_construction_destroy(&senv);
327 DEL_ARR_F(walker_env.sp_nodes);
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 */
335 ir_node *end = get_irg_end(irg);
336 int arity = get_irn_arity(end);
338 for (i = arity-1; i >= 0; --i) {
339 ir_node *in = get_irn_n(end, i);
340 if (!be_is_IncSP(in)) {
344 remove_End_keepalive(end, in);
345 if (get_irn_n_edges(in) == 0) {