2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
22 * @author Sebastian Hack, Matthias Braun
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
39 #include "bessaconstr.h"
46 int be_get_stack_entity_offset(be_stack_layout_t *frame, ir_entity *ent,
49 ir_type *t = get_entity_owner(ent);
50 int ofs = get_entity_offset(ent);
54 /* Find the type the entity is contained in. */
55 for (index = 0; index < N_FRAME_TYPES; ++index) {
56 if (frame->order[index] == t)
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]);
62 /* correct the offset by the initial position of the frame pointer */
63 ofs -= frame->initial_offset;
65 /* correct the offset with the current bias. */
72 * Retrieve the entity with given offset from a frame type.
74 static ir_entity *search_ent_with_offset(ir_type *t, int offset)
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)
87 static int stack_frame_compute_initial_offset(be_stack_layout_t *frame)
89 ir_type *base = frame->stack_dir < 0 ? frame->between_type : frame->frame_type;
90 ir_entity *ent = search_ent_with_offset(base, 0);
94 = frame->stack_dir < 0 ? get_type_size_bytes(frame->frame_type) : get_type_size_bytes(frame->between_type);
96 frame->initial_offset = be_get_stack_entity_offset(frame, ent, 0);
99 return frame->initial_offset;
103 * Walker: finally lower all Sels of outer frame or parameter
106 static void lower_outer_frame_sels(ir_node *sel, void *ctx)
111 be_stack_layout_t *layout;
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);
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);
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);
135 ptr = new_rd_Add(dbgi, bl, ptr, cnst, mode);
142 * A helper struct for the bias walker.
145 int start_block_bias; /**< The bias at the end of the start block. */
147 ir_node *start_block; /**< The start block of the current graph. */
151 * Fix all stack accessing operations in the block bl.
153 * @param bl the block to process
154 * @param real_bias the bias value
156 * @return the bias at the end of this block
158 static int process_stack_bias(ir_node *bl, int real_bias)
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);
167 sched_foreach(bl, irn) {
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
175 ir_entity *ent = arch_get_frame_entity(irn);
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);
183 * If the node modifies the stack pointer by a constant offset,
184 * record that in the bias.
186 ofs = arch_get_sp_bias(irn);
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);
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);
207 be_set_IncSP_offset(irn, ofs + alignment - delta);
208 real_bias += alignment - delta;
211 /* adjust so real_bias corresponds with wanted_bias */
212 int delta = wanted_bias - real_bias;
215 be_set_IncSP_offset(irn, ofs + delta);
226 assert(real_bias == wanted_bias);
231 * Block-Walker: fix all stack offsets for all blocks
232 * except the start block
234 static void stack_bias_walker(ir_node *bl, void *data)
236 struct bias_walk *bw = data;
237 if (bl != bw->start_block) {
238 process_stack_bias(bl, bw->start_block_bias);
242 void be_abi_fix_stack_bias(ir_graph *irg)
244 be_stack_layout_t *stack_layout = be_get_irg_stack_layout(irg);
249 stack_frame_compute_initial_offset(stack_layout);
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);
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);
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);
268 irg_walk_graph(irg, NULL, lower_outer_frame_sels, NULL);
273 typedef struct fix_stack_walker_env_t {
275 } fix_stack_walker_env_t;
278 * Walker. Collect all stack modifying nodes.
280 static void collect_stack_nodes_walker(ir_node *node, void *data)
282 ir_node *insn = node;
283 fix_stack_walker_env_t *env = data;
284 const arch_register_req_t *req;
287 insn = get_Proj_pred(node);
290 if (arch_irn_get_n_outs(insn) == 0)
292 if (get_irn_mode(node) == mode_T)
295 req = arch_get_register_req_out(node);
296 if (! (req->type & arch_register_req_type_produces_sp))
299 ARR_APP1(ir_node*, env->sp_nodes, node);
302 void be_abi_fix_stack_nodes(ir_graph *irg)
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 be_ssa_construction_env_t senv;
311 fix_stack_walker_env_t walker_env;
313 if (sp_req == NULL) {
314 struct obstack *obst = be_get_be_obst(irg);
315 arch_register_req_t *new_sp_req;
316 unsigned *limited_bitset;
318 new_sp_req = OALLOCZ(obst, arch_register_req_t);
319 new_sp_req->type = arch_register_req_type_limited
320 | arch_register_req_type_produces_sp;
321 new_sp_req->cls = arch_register_get_class(arch_env->sp);
322 new_sp_req->width = 1;
324 limited_bitset = rbitset_obstack_alloc(obst, new_sp_req->cls->n_regs);
325 rbitset_set(limited_bitset, arch_register_get_index(arch_env->sp));
326 new_sp_req->limited = limited_bitset;
327 if (arch_env->sp->type & arch_register_type_ignore) {
328 new_sp_req->type |= arch_register_req_type_ignore;
332 birg->sp_req = new_sp_req;
335 walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0);
337 irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env);
339 /* nothing to be done if we didn't find any node, in fact we mustn't
340 * continue, as for endless loops incsp might have had no users and is bad
343 len = ARR_LEN(walker_env.sp_nodes);
345 DEL_ARR_F(walker_env.sp_nodes);
349 be_ssa_construction_init(&senv, irg);
350 be_ssa_construction_add_copies(&senv, walker_env.sp_nodes,
351 ARR_LEN(walker_env.sp_nodes));
352 be_ssa_construction_fix_users_array(&senv, walker_env.sp_nodes,
353 ARR_LEN(walker_env.sp_nodes));
356 len = ARR_LEN(walker_env.sp_nodes);
357 for (i = 0; i < len; ++i) {
358 be_liveness_update(lv, walker_env.sp_nodes[i]);
360 be_ssa_construction_update_liveness_phis(&senv, lv);
363 phis = be_ssa_construction_get_new_phis(&senv);
365 /* set register requirements for stack phis */
367 for (i = 0; i < len; ++i) {
368 ir_node *phi = phis[i];
369 be_set_phi_reg_req(phi, sp_req);
370 arch_set_irn_register(phi, arch_env->sp);
372 be_ssa_construction_destroy(&senv);
374 DEL_ARR_F(walker_env.sp_nodes);