sparc_stackframe.c 8.2 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
4
5
6
7
8
9
 */

/**
 * @file
 * @brief   Manage addressing into the stackframe
 * @author  Matthias Braun
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *
 * Logical sparc stacklayout (omitfp==false), situation after a call:
 *
 *        high address |-----------------------------|
 *                     |            ...              |
 *                     |         stackarg 1          |
 *                     |         stackarg 0          |
 * SPARC_MIN_STACKSIZE |-----------------------------|  entity offset 0
 *                     | space for storing regarg0-5 |
 *                     | pointer to aggregate return |
 *                     |      16 words save area     |
 *    stack pointer -> |-----------------------------|
 *                     |    high end of stackframe   |
 *                     |            ...              |
 *                     |    low end of stackframe    |
 *        low address  |-----------------------------|
26
 */
27
28
#include "sparc_bearch_t.h"

29
#include "beirg.h"
Matthias Braun's avatar
Matthias Braun committed
30
#include "panic.h"
31
#include "firm_types.h"
32
#include "iredges_t.h"
33
34
35
36
#include "irnode_t.h"
#include "sparc_new_nodes.h"
#include "sparc_cconv.h"
#include "bitfiddle.h"
37
38
#include "benode.h"
#include "besched.h"
39
40
#include "bestack.h"

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
ir_entity *sparc_get_frame_entity(const ir_node *node)
{
	if (be_is_MemPerm(node))
		return be_get_MemPerm_in_entity(node, 0);
	if (is_sparc_FrameAddr(node)) {
		const sparc_attr_t *attr = get_sparc_attr_const(node);
		return attr->immediate_value_entity;
	}

	if (sparc_has_load_store_attr(node)) {
		const sparc_load_store_attr_t *load_store_attr
			= get_sparc_load_store_attr_const(node);
		if (load_store_attr->is_frame_entity) {
			return load_store_attr->base.immediate_value_entity;
		}
	}

	return NULL;
}

61
static bool node_has_sp_base(ir_node const *const node)
62
{
63
64
65
66
67
68
69
	int input;
	if (is_sparc_FrameAddr(node)) {
		input = n_sparc_FrameAddr_base;
	} else if (is_sparc_Ld(node)) {
		input = n_sparc_Ld_ptr;
	} else if (is_sparc_St(node)) {
		input = n_sparc_St_ptr;
70
71
72
73
	} else if (is_sparc_Ldf(node)) {
		input = n_sparc_Ldf_ptr;
	} else if (is_sparc_Stf(node)) {
		input = n_sparc_Stf_ptr;
74
75
76
	} else {
		panic("Unexpected node %+F", node);
	}
Matthias Braun's avatar
Matthias Braun committed
77
	arch_register_t const *const reg = arch_get_irn_register_in(node, input);
78
79
	return reg == &sparc_registers[REG_SP];
}
80

81
82
83
84
85
86
static void sparc_determine_frameoffset(ir_node *const node,
                                        int const sp_offset)
{
	if (is_sparc_FrameAddr(node)) {
		sparc_attr_t    *const attr   = get_sparc_attr(node);
		ir_entity const *const entity = attr->immediate_value_entity;
87
		if (entity != NULL) {
88
89
			attr->immediate_value += get_entity_offset(entity);
			if (node_has_sp_base(node))
Matthias Braun's avatar
Matthias Braun committed
90
				attr->immediate_value += sp_offset + SPARC_MIN_STACKSIZE;
91
		}
92
	} else if (sparc_has_load_store_attr(node)) {
93
94
95
96
97
98
99
100
		sparc_load_store_attr_t *const attr = get_sparc_load_store_attr(node);
		if (!attr->is_frame_entity)
			return;
		ir_entity const *const entity
			= attr->base.immediate_value_entity;
		if (entity != NULL) {
			attr->base.immediate_value += get_entity_offset(entity);
			if (node_has_sp_base(node))
Matthias Braun's avatar
Matthias Braun committed
101
				attr->base.immediate_value += sp_offset + SPARC_MIN_STACKSIZE;
102
		}
103
104
105
	} else if (be_is_MemPerm(node)) {
		ir_graph *irg = get_irn_irg(node);
		if (sparc_get_irg_data(irg)->omit_fp)
Matthias Braun's avatar
Matthias Braun committed
106
			be_set_MemPerm_offset(node, sp_offset + SPARC_MIN_STACKSIZE);
107
	}
108
}
109

110
111
112
static void sparc_sp_sim(ir_node *const node, stack_pointer_state_t *state)
{
	sparc_determine_frameoffset(node, state->offset);
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127
	if (is_sparc_Save(node)) {
		sparc_attr_t *const attr = get_sparc_attr(node);
		if (get_irn_arity(node) == 3)
			panic("no support for _reg variant yet");

		/* Adjust for alignment */
		assert(state->misalign == 0);
		int const prev_offset = state->offset;
		int const new_offset  = prev_offset - state->align_padding
		                        - attr->immediate_value;
		int const aligned     = round_up2(new_offset, 1u << state->p2align);
		attr->immediate_value = -(aligned - prev_offset);
		state->align_padding  = aligned - new_offset;
		state->offset         = aligned;
128
129
	} else if (is_sparc_SubSP(node) || is_sparc_AddSP(node)) {
		state->align_padding = 0;
130
131
132
	} else if (is_sparc_RestoreZero(node)) {
		state->offset        = 0;
		state->align_padding = 0;
133
134
135
	}
}

136
void sparc_fix_stack_bias(ir_graph *irg)
137
{
Manuel Mohr's avatar
Manuel Mohr committed
138
139
	unsigned const misalign = 0;
	be_sim_stack_pointer(irg, misalign, SPARC_PO2_STACK_ALIGNMENT,
140
	                     sparc_sp_sim);
141
142
}

143
144
145
146
147
148
149
/**
 * Perform some fixups for variadic functions.
 * To make the rest of the frontend code easier to understand we add
 * "dummy" parameters until the number of parameters transmitted in registers.
 * (because otherwise the backend wouldn't store the value of the register
 *  parameters into memory for the VLA magic)
 */
Matthias Braun's avatar
Matthias Braun committed
150
bool sparc_variadic_fixups(ir_graph *irg, calling_convention_t *cconv)
151
{
Matthias Braun's avatar
Matthias Braun committed
152
153
	ir_entity *entity = get_irg_entity(irg);
	ir_type   *mtp    = get_entity_type(entity);
154
	if (!is_method_variadic(mtp))
Matthias Braun's avatar
Matthias Braun committed
155
156
157
158
159
		return false;

	if (cconv->n_param_regs >= SPARC_N_PARAM_REGS)
		return false;

160
161
162
163
164
165
	size_t                    const n_params     = get_method_n_params(mtp);
	size_t                    const n_ress       = get_method_n_ress(mtp);
	size_t                    const new_n_params = n_params + (SPARC_N_PARAM_REGS - cconv->n_param_regs);
	unsigned                  const cc_mask      = get_method_calling_convention(mtp);
	mtp_additional_properties const props        = get_method_additional_properties(mtp);
	ir_type                  *const new_mtp      = new_type_method(new_n_params, n_ress, true, cc_mask, props);
Christoph Mallon's avatar
Christoph Mallon committed
166
167
168
169
170

	type_dbg_info *const dbgi = get_type_dbg_info(mtp);
	set_type_dbg_info(new_mtp, dbgi);

	for (size_t i = 0; i < n_ress; ++i) {
Matthias Braun's avatar
Matthias Braun committed
171
172
173
		ir_type *type = get_method_res_type(mtp, i);
		set_method_res_type(new_mtp, i, type);
	}
174
	for (size_t i = 0; i < n_params; ++i) {
Matthias Braun's avatar
Matthias Braun committed
175
176
177
		ir_type *type = get_method_param_type(mtp, i);
		set_method_param_type(new_mtp, i, type);
	}
Christoph Mallon's avatar
Christoph Mallon committed
178
179
180
	ir_type *const frame_type  = get_irg_frame_type(irg);
	ir_mode *const gp_reg_mode = sparc_reg_classes[CLASS_sparc_gp].mode;
	ir_type *const gp_reg_type = get_type_for_mode(gp_reg_mode);
181
	for (size_t i = n_params; i < new_n_params; ++i) {
Matthias Braun's avatar
Matthias Braun committed
182
183
184
185
		set_method_param_type(new_mtp, i, gp_reg_type);
		new_parameter_entity(frame_type, i, gp_reg_type);
	}

186
	set_higher_type(new_mtp, mtp);
Matthias Braun's avatar
Matthias Braun committed
187
188
189
190
191

	set_entity_type(entity, new_mtp);
	return true;
}

192
193
void sparc_layout_param_entities(ir_graph *const irg,
                                 calling_convention_t *const cconv)
Matthias Braun's avatar
Matthias Braun committed
194
{
195
196
197
198
199
200
	/* search for existing parameter entities */
	ir_type    *const frame_type = get_irg_frame_type(irg);
	size_t      const n_params   = cconv->n_parameters;
	ir_entity **const param_map  = ALLOCANZ(ir_entity*, n_params);
	for (size_t f = get_compound_n_members(frame_type); f-- > 0; ) {
		ir_entity *const member = get_compound_member(frame_type, f);
201
202
		if (!is_parameter_entity(member))
			continue;
Matthias Braun's avatar
Matthias Braun committed
203

204
		size_t const num = get_entity_parameter_number(member);
205
206
207
208
209
210
211
		assert(num < n_params);
		if (param_map[num] != NULL)
			panic("multiple entities for parameter %u in %+F found", f, irg);

		param_map[num] = member;
	}

Matthias Braun's avatar
Matthias Braun committed
212
	/* calculate offsets/create missing entities */
Matthias Braun's avatar
Matthias Braun committed
213
	for (size_t i = 0; i < n_params; ++i) {
214
215
216
217
218
219
		reg_or_stackslot_t *const param  = &cconv->parameters[i];
		ir_entity          *      entity = param_map[i];
		if (entity == NULL) {
			if (!param->already_stored)
				continue;
			entity = new_parameter_entity(frame_type, i, param->type);
Matthias Braun's avatar
Matthias Braun committed
220
		}
221
222
223
		param->entity = entity;
		set_entity_offset(entity, param->offset);
	}
Matthias Braun's avatar
Matthias Braun committed
224

225
226
227
	ir_entity *const function      = get_irg_entity(irg);
	ir_type   *const function_type = get_entity_type(function);
	if (is_method_variadic(function_type)) {
228
229
230
		ir_type   *unknown       = get_unknown_type();
		ident     *id            = new_id_from_str("$va_start");
		ir_entity *va_start_addr = new_entity(frame_type, id, unknown);
231

Matthias Braun's avatar
Matthias Braun committed
232
233
		/* sparc_variadic_fixups() fiddled with our type, find out the
		 * original number of parameters */
234
		ir_type       *const non_lowered   = get_higher_type(function_type);
235
		size_t         const orig_n_params = get_method_n_params(non_lowered);
Matthias Braun's avatar
Matthias Braun committed
236
		long offset;
Matthias Braun's avatar
Matthias Braun committed
237
238
239
240
		if (orig_n_params < n_params) {
			assert(param_map[orig_n_params] != NULL);
			offset = get_entity_offset(param_map[orig_n_params]);
		} else {
241
			offset = cconv->param_stack_size;
Matthias Braun's avatar
Matthias Braun committed
242
		}
243

244
245
		set_entity_offset(va_start_addr, offset);
		cconv->va_start_addr = va_start_addr;
246
	}
247
}