e08043fa168666cefd498871c37e44835dc6313b
[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  * @version $Id$
25  */
26 #include "config.h"
27
28 #include "firm_types.h"
29 #include "irnode_t.h"
30 #include "bearch_sparc_t.h"
31 #include "sparc_new_nodes.h"
32 #include "sparc_cconv.h"
33 #include "bitfiddle.h"
34 #include "../bearch.h"
35 #include "../benode.h"
36 #include "../besched.h"
37
38 static void set_irn_sp_bias(ir_node *node, int new_bias)
39 {
40         if (be_is_IncSP(node)) {
41                 be_set_IncSP_offset(node, new_bias);
42         } else if (is_sparc_Save(node)) {
43                 sparc_attr_t *attr = get_sparc_attr(node);
44                 attr->immediate_value = -new_bias;
45         } else if (is_sparc_Restore(node)) {
46                 sparc_attr_t *attr = get_sparc_attr(node);
47                 attr->immediate_value = new_bias;
48         }
49 }
50
51 static void process_bias(ir_node *block, bool sp_relative, int bias, int free_bytes)
52 {
53         const ir_edge_t *edge;
54         ir_node         *irn;
55
56         mark_Block_block_visited(block);
57
58         /* process schedule */
59         sched_foreach(block, irn) {
60                 int irn_bias;
61
62                 /* set bias to nodes with entities */
63                 ir_entity *entity = arch_get_frame_entity(irn);
64                 if (entity != NULL) {
65                         int offset = get_entity_offset(entity);
66                         if (sp_relative)
67                                 offset -= bias;
68                         arch_set_frame_offset(irn, offset);
69                 }
70
71                 irn_bias = arch_get_sp_bias(irn);
72                 if (irn_bias == 0) {
73                         /* do nothing */
74                 } else if (irn_bias == SP_BIAS_RESET) {
75                         bias = 0;
76                 } else {
77                         /* adjust values to respect stack alignment */
78                         int new_bias_unaligned;
79                         int new_bias_aligned;
80                         irn_bias -= free_bytes;
81
82                         new_bias_unaligned = bias + irn_bias;
83                         new_bias_aligned   = round_up2(new_bias_unaligned, 8);
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 static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv)
118 {
119         ir_entity  *entity    = get_irg_entity(irg);
120         ir_type    *mtp       = get_entity_type(entity);
121         size_t      n_params  = get_method_n_params(mtp);
122         ir_entity **param_map = ALLOCANZ(ir_entity*, n_params);
123
124         ir_type *frame_type      = get_irg_frame_type(irg);
125         size_t   n_frame_members = get_compound_n_members(frame_type);
126         size_t   f;
127         size_t   i;
128
129         ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
130
131         /* search for existing value_param entities */
132         for (f = n_frame_members; f > 0; ) {
133                 ir_entity *member = get_compound_member(frame_type, --f);
134                 size_t     num;
135                 const reg_or_stackslot_t *param;
136
137                 if (!is_parameter_entity(member))
138                         continue;
139                 num = get_entity_parameter_number(member);
140                 assert(num < n_params);
141                 if (param_map[num] != NULL)
142                         panic("multiple entities for parameter %u in %+F found", f, irg);
143
144                 param = &cconv->parameters[num];
145                 if (param->reg0 != NULL)
146                         continue;
147
148                 param_map[num] = member;
149                 /* move to new arg_type */
150                 set_entity_owner(member, res);
151         }
152
153         for (i = 0; i < n_params; ++i) {
154                 reg_or_stackslot_t *param = &cconv->parameters[i];
155                 ir_entity          *entity;
156
157                 if (param->reg0 != NULL)
158                         continue;
159                 entity = param_map[i];
160                 if (entity == NULL)
161                         entity = new_parameter_entity(res, i, param->type);
162                 param->entity = entity;
163                 set_entity_offset(entity, param->offset);
164         }
165         set_type_size_bytes(res, cconv->param_stack_size);
166
167         return res;
168 }
169
170 void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv)
171 {
172         be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
173         ir_type           *between_type;
174         memset(layout, 0, sizeof(*layout));
175
176         between_type = new_type_class(new_id_from_str("sparc_between_type"));
177         set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
178
179         layout->frame_type     = get_irg_frame_type(irg);
180         layout->between_type   = between_type;
181         layout->arg_type       = compute_arg_type(irg, cconv);
182         layout->initial_offset = 0;
183         layout->initial_bias   = 0;
184         layout->sp_relative    = cconv->omit_fp;
185
186         assert(N_FRAME_TYPES == 3);
187         layout->order[0] = layout->frame_type;
188         layout->order[1] = layout->between_type;
189         layout->order[2] = layout->arg_type;
190 }
191
192 /* Assign entity offsets, to all stack-related entities.
193  * The offsets are relative to the begin of the stack frame.
194  */
195 static void process_frame_types(ir_graph *irg)
196 {
197         be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
198
199         /* initially the stackpointer points to the begin of our stackframe.
200          * Situation at the begin of our function:
201          *
202          *      high address |-----------------------------|
203          *                   |            ...              |
204          *          arg-type |         stackarg 1          |
205          *                   |         stackarg 0          |
206          *                   |-----------------------------|
207          *                   | space for storing regarg0-5 |
208          *      between type | pointer to aggregate return |
209          *                   |      16 words save are      |
210          *  stack pointer -> |-----------------------------|
211          *                   |    high end of stackframe   |
212          *                   |            ...              |
213          *                   |    low end of stackframe    |
214          *      low address  |-----------------------------|
215          */
216         ir_type *between_type = layout->between_type;
217         unsigned between_size = get_type_size_bytes(between_type);
218
219         ir_type *frame_type = get_irg_frame_type(irg);
220         unsigned frame_size = get_type_size_bytes(frame_type);
221
222         ir_type *arg_type = layout->arg_type;
223
224         adjust_entity_offsets(frame_type, -(long)frame_size);
225         /* no need to adjust between type, it's already at 0 */
226         adjust_entity_offsets(arg_type, between_size);
227 }
228
229 void sparc_fix_stack_bias(ir_graph *irg)
230 {
231         ir_node           *start_block  = get_irg_start_block(irg);
232
233         process_frame_types(irg);
234
235         ir_reserve_resources(irg, IR_RESOURCE_BLOCK_VISITED);
236         inc_irg_block_visited(irg);
237         process_bias(start_block, be_get_irg_stack_layout(irg)->sp_relative, 0, 0);
238         ir_free_resources(irg, IR_RESOURCE_BLOCK_VISITED);
239 }