2 * Copyright (C) 1995-2010 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 * @brief Manage addressing into the stackframe
23 * @author Matthias Braun
29 #include "firm_types.h"
31 #include "bearch_sparc_t.h"
32 #include "sparc_new_nodes.h"
33 #include "sparc_cconv.h"
34 #include "bitfiddle.h"
39 static void set_irn_sp_bias(ir_node *node, int new_bias)
41 if (be_is_IncSP(node)) {
42 be_set_IncSP_offset(node, new_bias);
43 } else if (is_sparc_Save(node)) {
44 sparc_attr_t *attr = get_sparc_attr(node);
45 attr->immediate_value = -new_bias;
46 } else if (is_sparc_Restore(node)) {
47 sparc_attr_t *attr = get_sparc_attr(node);
48 attr->immediate_value = new_bias;
52 static void process_bias(ir_node *block, bool sp_relative, int bias,
55 mark_Block_block_visited(block);
57 /* process schedule */
58 sched_foreach(block, irn) {
61 /* set bias to nodes with entities */
62 ir_entity *entity = arch_get_frame_entity(irn);
64 int offset = get_entity_offset(entity);
66 offset += bias + SPARC_MIN_STACKSIZE;
67 arch_set_frame_offset(irn, offset);
70 /* The additional alignment bytes cannot be used
71 * anymore after alloca. */
72 if (is_sparc_SubSP(irn)) {
74 } else if (is_sparc_AddSP(irn)) {
75 assert(free_bytes == 0);
78 irn_bias = arch_get_sp_bias(irn);
81 } else if (irn_bias == SP_BIAS_RESET) {
84 /* adjust values to respect stack alignment */
85 int new_bias_unaligned;
87 irn_bias -= free_bytes;
89 new_bias_unaligned = bias + irn_bias;
91 = round_up2(new_bias_unaligned, SPARC_STACK_ALIGNMENT);
92 free_bytes = new_bias_aligned - new_bias_unaligned;
93 set_irn_sp_bias(irn, new_bias_aligned - bias);
94 bias = new_bias_aligned;
99 if (block == get_irg_end_block(get_irn_irg(block))) {
104 /* continue at the successor blocks */
105 foreach_block_succ(block, edge) {
106 ir_node *succ = get_edge_src_irn(edge);
107 if (Block_block_visited(succ))
109 process_bias(succ, sp_relative, bias, free_bytes);
113 static void adjust_entity_offsets(ir_type *type, long offset)
115 size_t n_members = get_compound_n_members(type);
118 for (i = 0; i < n_members; ++i) {
119 ir_entity *member = get_compound_member(type, i);
120 int member_offset = get_entity_offset(member);
121 set_entity_offset(member, member_offset + offset);
126 * Perform some fixups for variadic functions.
127 * To make the rest of the frontend code easier to understand we add
128 * "dummy" parameters until the number of parameters transmitted in registers.
129 * (because otherwise the backend wouldn't store the value of the register
130 * parameters into memory for the VLA magic)
132 bool sparc_variadic_fixups(ir_graph *irg, calling_convention_t *cconv)
134 ir_entity *entity = get_irg_entity(irg);
135 ir_type *mtp = get_entity_type(entity);
136 if (get_method_variadicity(mtp) != variadicity_variadic)
139 if (cconv->n_param_regs >= SPARC_N_PARAM_REGS)
143 size_t n_params = get_method_n_params(mtp);
144 type_dbg_info *dbgi = get_type_dbg_info(mtp);
145 size_t n_ress = get_method_n_ress(mtp);
147 = n_params + (SPARC_N_PARAM_REGS - cconv->n_param_regs);
148 ir_type *new_mtp = new_d_type_method(new_n_params, n_ress, dbgi);
149 ir_mode *gp_reg_mode = sparc_reg_classes[CLASS_sparc_gp].mode;
150 ir_type *gp_reg_type = get_type_for_mode(gp_reg_mode);
151 ir_type *frame_type = get_irg_frame_type(irg);
154 for (i = 0; i < n_ress; ++i) {
155 ir_type *type = get_method_res_type(mtp, i);
156 set_method_res_type(new_mtp, i, type);
158 for (i = 0; i < n_params; ++i) {
159 ir_type *type = get_method_param_type(mtp, i);
160 set_method_param_type(new_mtp, i, type);
162 for ( ; i < new_n_params; ++i) {
163 set_method_param_type(new_mtp, i, gp_reg_type);
164 new_parameter_entity(frame_type, i, gp_reg_type);
167 set_method_variadicity(new_mtp, get_method_variadicity(mtp));
168 set_method_calling_convention(new_mtp, get_method_calling_convention(mtp));
169 set_method_additional_properties(new_mtp, get_method_additional_properties(mtp));
170 set_higher_type(new_mtp, mtp);
172 set_entity_type(entity, new_mtp);
177 static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv,
178 ir_type *between_type)
180 ir_entity *va_start_entity = NULL;
181 const ir_entity *entity = get_irg_entity(irg);
182 const ir_type *mtp = get_entity_type(entity);
183 size_t n_params = get_method_n_params(mtp);
184 ir_entity **param_map = ALLOCANZ(ir_entity*, n_params);
186 ir_type *frame_type = get_irg_frame_type(irg);
187 size_t n_frame_members = get_compound_n_members(frame_type);
191 ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
193 /* search for existing value_param entities */
194 for (f = n_frame_members; f > 0; ) {
195 ir_entity *member = get_compound_member(frame_type, --f);
198 if (!is_parameter_entity(member))
200 num = get_entity_parameter_number(member);
201 if (num == IR_VA_START_PARAMETER_NUMBER) {
202 if (va_start_entity != NULL)
203 panic("multiple va_start entities found (%+F,%+F)",
204 va_start_entity, member);
205 va_start_entity = member;
208 assert(num < n_params);
209 if (param_map[num] != NULL)
210 panic("multiple entities for parameter %u in %+F found", f, irg);
212 param_map[num] = member;
213 /* move to new arg_type */
214 set_entity_owner(member, res);
217 /* calculate offsets/create missing entities */
218 for (i = 0; i < n_params; ++i) {
219 reg_or_stackslot_t *param = &cconv->parameters[i];
220 ir_entity *entity = param_map[i];
222 if (param->reg0 != NULL) {
223 /* use reserved spill space on between type */
224 if (entity != NULL) {
225 long offset = SPARC_PARAMS_SPILL_OFFSET + i * SPARC_REGISTER_SIZE;
226 assert(i < SPARC_N_PARAM_REGS);
227 set_entity_owner(entity, between_type);
228 set_entity_offset(entity, offset);
234 entity = new_parameter_entity(res, i, param->type);
235 param->entity = entity;
236 set_entity_offset(entity, param->offset);
239 if (va_start_entity != NULL) {
240 /* sparc_variadic_fixups() fiddled with our type, find out the
241 * original number of parameters */
242 ir_type *non_lowered = get_higher_type(mtp);
243 size_t orig_n_params = get_method_n_params(non_lowered);
245 assert(get_method_variadicity(mtp) == variadicity_variadic);
246 if (orig_n_params < n_params) {
247 assert(param_map[orig_n_params] != NULL);
248 offset = get_entity_offset(param_map[orig_n_params]);
249 set_entity_owner(va_start_entity, between_type);
250 set_entity_offset(va_start_entity, offset);
252 set_entity_owner(va_start_entity, res);
253 set_entity_offset(va_start_entity, cconv->param_stack_size);
256 set_type_size_bytes(res, cconv->param_stack_size);
261 void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv)
263 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
264 ir_type *between_type;
265 memset(layout, 0, sizeof(*layout));
267 between_type = new_type_class(new_id_from_str("sparc_between_type"));
268 if (cconv->omit_fp) {
269 set_type_size_bytes(between_type, 0);
271 set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
274 layout->frame_type = get_irg_frame_type(irg);
275 layout->between_type = between_type;
276 layout->arg_type = compute_arg_type(irg, cconv, between_type);
277 layout->initial_offset = 0;
278 layout->initial_bias = 0;
279 layout->sp_relative = cconv->omit_fp;
281 assert(N_FRAME_TYPES == 3);
282 layout->order[0] = layout->frame_type;
283 layout->order[1] = layout->between_type;
284 layout->order[2] = layout->arg_type;
287 /* Assign entity offsets, to all stack-related entities.
288 * The offsets are relative to the begin of the stack frame.
290 void sparc_adjust_stack_entity_offsets(ir_graph *irg)
292 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
294 /* initially the stackpointer points to the begin of our stackframe.
295 * Situation at the begin of our function:
297 * high address |-----------------------------|
299 * arg-type | stackarg 1 |
301 * |-----------------------------|
302 * | space for storing regarg0-5 |
303 * between type | pointer to aggregate return |
304 * | 16 words save are |
305 * stack pointer -> |-----------------------------|
306 * | high end of stackframe |
308 * | low end of stackframe |
309 * low address |-----------------------------|
311 ir_type *between_type = layout->between_type;
312 unsigned between_size = get_type_size_bytes(between_type);
314 ir_type *frame_type = get_irg_frame_type(irg);
315 unsigned frame_size = get_type_size_bytes(frame_type);
316 unsigned frame_align = get_type_alignment_bytes(frame_type);
318 /* There's the tricky case of the stackframe size not being a multiple
319 * of the alignment. There are 2 variants:
321 * - frame-pointer relative addressing:
322 * Increase frame_size in case it is not a multiple of the alignment as we
323 * address entities from the "top" with negative offsets
324 * - stack-pointer relative addressing:
325 * Stackframesize + SPARC_MIN_STACK_SIZE has to be aligned. Increase
326 * frame_size accordingly.
328 if (!layout->sp_relative) {
329 frame_size = (frame_size + frame_align-1) & ~(frame_align-1);
331 unsigned misalign = (SPARC_MIN_STACKSIZE+frame_size) % frame_align;
332 frame_size += misalign;
334 set_type_size_bytes(frame_type, frame_size);
336 ir_type *arg_type = layout->arg_type;
338 adjust_entity_offsets(frame_type, -(long)frame_size);
339 /* no need to adjust between type, it's already at 0 */
340 adjust_entity_offsets(arg_type, between_size);
343 void sparc_fix_stack_bias(ir_graph *irg)
345 bool sp_relative = be_get_irg_stack_layout(irg)->sp_relative;
347 ir_node *start_block = get_irg_start_block(irg);
349 ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED);
350 inc_irg_block_visited(irg);
351 process_bias(start_block, sp_relative, 0, 0);
352 ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED);