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
28 #include "firm_types.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"
38 static void set_irn_sp_bias(ir_node *node, int new_bias)
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;
51 static void process_bias(ir_node *block, bool sp_relative, int bias, int free_bytes)
53 const ir_edge_t *edge;
56 mark_Block_block_visited(block);
58 /* process schedule */
59 sched_foreach(block, irn) {
62 /* set bias to nodes with entities */
63 ir_entity *entity = arch_get_frame_entity(irn);
65 int offset = get_entity_offset(entity);
68 arch_set_frame_offset(irn, offset);
71 irn_bias = arch_get_sp_bias(irn);
74 } else if (irn_bias == SP_BIAS_RESET) {
77 /* adjust values to respect stack alignment */
78 int new_bias_unaligned;
80 irn_bias -= free_bytes;
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;
91 if (block == get_irg_end_block(get_irn_irg(block))) {
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))
101 process_bias(succ, sp_relative, bias, free_bytes);
105 static void adjust_entity_offsets(ir_type *type, long offset)
107 size_t n_members = get_compound_n_members(type);
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);
117 static ir_type *compute_arg_type(ir_graph *irg, calling_convention_t *cconv)
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);
124 ir_type *frame_type = get_irg_frame_type(irg);
125 size_t n_frame_members = get_compound_n_members(frame_type);
129 ir_type *res = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
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);
135 const reg_or_stackslot_t *param;
137 if (!is_parameter_entity(member))
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);
144 param = &cconv->parameters[num];
145 if (param->reg0 != NULL)
148 param_map[num] = member;
149 /* move to new arg_type */
150 set_entity_owner(member, res);
153 for (i = 0; i < n_params; ++i) {
154 reg_or_stackslot_t *param = &cconv->parameters[i];
157 if (param->reg0 != NULL)
159 entity = param_map[i];
161 entity = new_parameter_entity(res, i, param->type);
162 param->entity = entity;
163 set_entity_offset(entity, param->offset);
165 set_type_size_bytes(res, cconv->param_stack_size);
170 void sparc_create_stacklayout(ir_graph *irg, calling_convention_t *cconv)
172 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
173 ir_type *between_type;
174 memset(layout, 0, sizeof(*layout));
176 between_type = new_type_class(new_id_from_str("sparc_between_type"));
177 set_type_size_bytes(between_type, SPARC_MIN_STACKSIZE);
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;
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;
192 /* Assign entity offsets, to all stack-related entities.
193 * The offsets are relative to the begin of the stack frame.
195 static void process_frame_types(ir_graph *irg)
197 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
199 /* initially the stackpointer points to the begin of our stackframe.
200 * Situation at the begin of our function:
202 * high address |-----------------------------|
204 * arg-type | stackarg 1 |
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 |
213 * | low end of stackframe |
214 * low address |-----------------------------|
216 ir_type *between_type = layout->between_type;
217 unsigned between_size = get_type_size_bytes(between_type);
219 ir_type *frame_type = get_irg_frame_type(irg);
220 unsigned frame_size = get_type_size_bytes(frame_type);
222 ir_type *arg_type = layout->arg_type;
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);
229 void sparc_fix_stack_bias(ir_graph *irg)
231 ir_node *start_block = get_irg_start_block(irg);
233 process_frame_types(irg);
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);