Let foreach_out_edge_kind() and foreach_out_edge_kind_safe() declare their iterator...
[libfirm] / ir / be / sparc / sparc_stackframe.c
1 /*
2  * Copyright (C) 1995-2010 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  * @brief   Manage addressing into the stackframe
23  * @author  Matthias Braun
24  */
25 #include "config.h"
26
27 #include "firm_types.h"
28 #include "irnode_t.h"
29 #include "bearch_sparc_t.h"
30 #include "sparc_new_nodes.h"
31 #include "sparc_cconv.h"
32 #include "bitfiddle.h"
33 #include "bearch.h"
34 #include "benode.h"
35 #include "besched.h"
36
37 static void set_irn_sp_bias(ir_node *node, int new_bias)
38 {
39         if (be_is_IncSP(node)) {
40                 be_set_IncSP_offset(node, new_bias);
41         } else if (is_sparc_Save(node)) {
42                 sparc_attr_t *attr = get_sparc_attr(node);
43                 attr->immediate_value = -new_bias;
44         } else if (is_sparc_Restore(node)) {
45                 sparc_attr_t *attr = get_sparc_attr(node);
46                 attr->immediate_value = new_bias;
47         }
48 }
49
50 static void process_bias(ir_node *block, bool sp_relative, int bias,
51                          int free_bytes)
52 {
53         ir_node *irn;
54
55         mark_Block_block_visited(block);
56
57         /* process schedule */
58         sched_foreach(block, irn) {
59                 int irn_bias;
60
61                 /* set bias to nodes with entities */
62                 ir_entity *entity = arch_get_frame_entity(irn);
63                 if (entity != NULL) {
64                         int offset = get_entity_offset(entity);
65                         if (sp_relative)
66                                 offset += bias + SPARC_MIN_STACKSIZE;
67                         arch_set_frame_offset(irn, offset);
68                 }
69
70                 irn_bias = arch_get_sp_bias(irn);
71                 if (irn_bias == 0) {
72                         /* do nothing */
73                 } else if (irn_bias == SP_BIAS_RESET) {
74                         bias = 0;
75                 } else {
76                         /* adjust values to respect stack alignment */
77                         int new_bias_unaligned;
78                         int new_bias_aligned;
79                         irn_bias -= free_bytes;
80
81                         new_bias_unaligned = bias + irn_bias;
82                         new_bias_aligned
83                                 = round_up2(new_bias_unaligned, SPARC_STACK_ALIGNMENT);
84                         free_bytes = new_bias_aligned - new_bias_unaligned;
85                         set_irn_sp_bias(irn, new_bias_aligned - bias);
86                         bias = new_bias_aligned;
87                 }
88         }
89
90 #ifndef NDEBUG
91         if (block == get_irg_end_block(get_irn_irg(block))) {
92                 assert(bias == 0);
93         }
94 #endif
95
96         /* continue at the successor blocks */
97         foreach_block_succ(block, edge) {
98                 ir_node *succ = get_edge_src_irn(edge);
99                 if (Block_block_visited(succ))
100                         continue;
101                 process_bias(succ, sp_relative, bias, free_bytes);
102         }
103 }
104
105 static void adjust_entity_offsets(ir_type *type, long offset)
106 {
107         size_t n_members = get_compound_n_members(type);
108         size_t i;
109
110         for (i = 0; i < n_members; ++i) {
111                 ir_entity *member        = get_compound_member(type, i);
112                 int        member_offset = get_entity_offset(member);
113                 set_entity_offset(member, member_offset + offset);
114         }
115 }
116
117 /**
118  * Perform some fixups for variadic functions.
119  * To make the rest of the frontend code easier to understand we add
120  * "dummy" parameters until the number of parameters transmitted in registers.
121  * (because otherwise the backend wouldn't store the value of the register
122  *  parameters into memory for the VLA magic)
123  */
124 bool sparc_variadic_fixups(ir_graph *irg, calling_convention_t *cconv)
125 {
126         ir_entity *entity = get_irg_entity(irg);
127         ir_type   *mtp    = get_entity_type(entity);
128         if (get_method_variadicity(mtp) != variadicity_variadic)
129                 return false;
130
131         if (cconv->n_param_regs >= SPARC_N_PARAM_REGS)
132                 return false;
133
134         {
135         size_t         n_params     = get_method_n_params(mtp);
136         type_dbg_info *dbgi         = get_type_dbg_info(mtp);
137         size_t         n_ress       = get_method_n_ress(mtp);
138         size_t         new_n_params
139                 = n_params + (SPARC_N_PARAM_REGS - cconv->n_param_regs);
140         ir_type       *new_mtp      = new_d_type_method(new_n_params, n_ress, dbgi);
141         ir_mode       *gp_reg_mode  = sparc_reg_classes[CLASS_sparc_gp].mode;
142         ir_type       *gp_reg_type  = get_type_for_mode(gp_reg_mode);
143         ir_type       *frame_type   = get_irg_frame_type(irg);
144         size_t         i;
145
146         for (i = 0; i < n_ress; ++i) {
147                 ir_type *type = get_method_res_type(mtp, i);
148                 set_method_res_type(new_mtp, i, type);
149         }
150         for (i = 0; i < n_params; ++i) {
151                 ir_type *type = get_method_param_type(mtp, i);
152                 set_method_param_type(new_mtp, i, type);
153         }
154         for ( ; i < new_n_params; ++i) {
155                 set_method_param_type(new_mtp, i, gp_reg_type);
156                 new_parameter_entity(frame_type, i, gp_reg_type);
157         }
158
159         set_method_variadicity(new_mtp, get_method_variadicity(mtp));
160         set_method_calling_convention(new_mtp, get_method_calling_convention(mtp));
161         set_method_additional_properties(new_mtp, get_method_additional_properties(mtp));
162         set_higher_type(new_mtp, mtp);
163
164         set_entity_type(entity, new_mtp);
165         }
166         return true;
167 }
168
169 static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv,
170                                  ir_type *between_type)
171 {
172         ir_entity       *va_start_entity = NULL;
173         const ir_entity *entity          = get_irg_entity(irg);
174         const ir_type   *mtp             = get_entity_type(entity);
175         size_t           n_params        = get_method_n_params(mtp);
176         ir_entity      **param_map       = ALLOCANZ(ir_entity*, n_params);
177
178         ir_type *frame_type      = get_irg_frame_type(irg);
179         size_t   n_frame_members = get_compound_n_members(frame_type);
180         size_t   f;
181         size_t   i;
182
183         ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
184
185         /* search for existing value_param entities */
186         for (f = n_frame_members; f > 0; ) {
187                 ir_entity *member = get_compound_member(frame_type, --f);
188                 size_t     num;
189
190                 if (!is_parameter_entity(member))
191                         continue;
192                 num = get_entity_parameter_number(member);
193                 if (num == IR_VA_START_PARAMETER_NUMBER) {
194                         if (va_start_entity != NULL)
195                                 panic("multiple va_start entities found (%+F,%+F)",
196                                       va_start_entity, member);
197                         va_start_entity = member;
198                         continue;
199                 }
200                 assert(num < n_params);
201                 if (param_map[num] != NULL)
202                         panic("multiple entities for parameter %u in %+F found", f, irg);
203
204                 param_map[num] = member;
205                 /* move to new arg_type */
206                 set_entity_owner(member, res);
207         }
208
209         /* calculate offsets/create missing entities */
210         for (i = 0; i < n_params; ++i) {
211                 reg_or_stackslot_t *param  = &cconv->parameters[i];
212                 ir_entity          *entity = param_map[i];
213
214                 if (param->reg0 != NULL) {
215                         /* use reserved spill space on between type */
216                         if (entity != NULL) {
217                                 long offset = SPARC_PARAMS_SPILL_OFFSET + i * SPARC_REGISTER_SIZE;
218                                 assert(i < SPARC_N_PARAM_REGS);
219                                 set_entity_owner(entity, between_type);
220                                 set_entity_offset(entity, offset);
221                         }
222                         continue;
223                 }
224
225                 if (entity == NULL)
226                         entity = new_parameter_entity(res, i, param->type);
227                 param->entity = entity;
228                 set_entity_offset(entity, param->offset);
229         }
230
231         if (va_start_entity != NULL) {
232                 /* sparc_variadic_fixups() fiddled with our type, find out the
233                  * original number of parameters */
234                 ir_type *non_lowered   = get_higher_type(mtp);
235                 size_t   orig_n_params = get_method_n_params(non_lowered);
236                 long     offset;
237                 assert(get_method_variadicity(mtp) == variadicity_variadic);
238                 if (orig_n_params < n_params) {
239                         assert(param_map[orig_n_params] != NULL);
240                         offset = get_entity_offset(param_map[orig_n_params]);
241                         set_entity_owner(va_start_entity, between_type);
242                         set_entity_offset(va_start_entity, offset);
243                 } else {
244                         set_entity_owner(va_start_entity, res);
245                         set_entity_offset(va_start_entity, cconv->param_stack_size);
246                 }
247         }
248         set_type_size_bytes(res, cconv->param_stack_size);
249
250         return res;
251 }
252
253 void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv)
254 {
255         be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
256         ir_type           *between_type;
257         memset(layout, 0, sizeof(*layout));
258
259         between_type = new_type_class(new_id_from_str("sparc_between_type"));
260         if (cconv->omit_fp) {
261                 set_type_size_bytes(between_type, 0);
262         } else {
263                 set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
264         }
265
266         layout->frame_type     = get_irg_frame_type(irg);
267         layout->between_type   = between_type;
268         layout->arg_type       = compute_arg_type(irg, cconv, between_type);
269         layout->initial_offset = 0;
270         layout->initial_bias   = 0;
271         layout->sp_relative    = cconv->omit_fp;
272
273         assert(N_FRAME_TYPES == 3);
274         layout->order[0] = layout->frame_type;
275         layout->order[1] = layout->between_type;
276         layout->order[2] = layout->arg_type;
277 }
278
279 /* Assign entity offsets, to all stack-related entities.
280  * The offsets are relative to the begin of the stack frame.
281  */
282 void sparc_adjust_stack_entity_offsets(ir_graph *irg)
283 {
284         be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
285
286         /* initially the stackpointer points to the begin of our stackframe.
287          * Situation at the begin of our function:
288          *
289          *      high address |-----------------------------|
290          *                   |            ...              |
291          *          arg-type |         stackarg 1          |
292          *                   |         stackarg 0          |
293          *                   |-----------------------------|
294          *                   | space for storing regarg0-5 |
295          *      between type | pointer to aggregate return |
296          *                   |      16 words save are      |
297          *  stack pointer -> |-----------------------------|
298          *                   |    high end of stackframe   |
299          *                   |            ...              |
300          *                   |    low end of stackframe    |
301          *      low address  |-----------------------------|
302          */
303         ir_type *between_type = layout->between_type;
304         unsigned between_size = get_type_size_bytes(between_type);
305
306         ir_type *frame_type  = get_irg_frame_type(irg);
307         unsigned frame_size  = get_type_size_bytes(frame_type);
308         unsigned frame_align = get_type_alignment_bytes(frame_type);
309
310         /* There's the tricky case of the stackframe size not being a multiple
311          * of the alignment. There are 2 variants:
312          *
313          * - frame-pointer relative addressing:
314          *   Increase frame_size in case it is not a multiple of the alignment as we
315          *   address entities from the "top" with negative offsets
316          * - stack-pointer relative addressing:
317          *   Stackframesize + SPARC_MIN_STACK_SIZE has to be aligned. Increase
318          *   frame_size accordingly.
319          */
320         if (!layout->sp_relative) {
321                 frame_size = (frame_size + frame_align-1) & ~(frame_align-1);
322         } else {
323                 unsigned misalign = (SPARC_MIN_STACKSIZE+frame_size) % frame_align;
324                 frame_size += misalign;
325         }
326         set_type_size_bytes(frame_type, frame_size);
327
328         ir_type *arg_type = layout->arg_type;
329
330         adjust_entity_offsets(frame_type, -(long)frame_size);
331         /* no need to adjust between type, it's already at 0 */
332         adjust_entity_offsets(arg_type, between_size);
333 }
334
335 void sparc_fix_stack_bias(ir_graph *irg)
336 {
337         bool sp_relative = be_get_irg_stack_layout(irg)->sp_relative;
338
339         ir_node *start_block = get_irg_start_block(irg);
340
341         ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED);
342         inc_irg_block_visited(irg);
343         process_bias(start_block, sp_relative, 0, 0);
344         ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED);
345 }