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 Peephole optimization and legalization of a sparc function
23 * @author Matthias Braun
26 * A note on sparc stackpointer (sp) behaviour:
27 * The ABI expects SPARC_MIN_STACKSIZE bytes to be available at the
28 * stackpointer. This space will be used to spill register windows,
29 * and for spilling va_arg arguments (maybe we can optimize this away for
30 * statically known not-va-arg-functions...)
31 * This in effect means that we allocate that extra space at the function begin
32 * which is easy. But this space isn't really fixed at the beginning of the
33 * stackframe. Instead you should rather imagine the space as always being the
34 * last-thing on the stack.
35 * So when addressing anything stack-specific we have to account for this
36 * area, while our compiler thinks the space is occupied at the beginning
37 * of the stack frame. The code here among other things adjusts these offsets
42 #include "bearch_sparc_t.h"
43 #include "gen_sparc_regalloc_if.h"
44 #include "sparc_new_nodes.h"
49 #include "../bepeephole.h"
50 #include "../benode.h"
51 #include "../besched.h"
53 static void kill_unused_stacknodes(ir_node *node)
55 if (get_irn_n_edges(node) > 0)
58 if (be_is_IncSP(node)) {
61 } else if (is_Phi(node)) {
62 int arity = get_irn_arity(node);
63 ir_node **ins = ALLOCAN(ir_node*, arity);
66 memcpy(ins, get_irn_in(node), arity*sizeof(ins[0]));
69 for (i = 0; i < arity; ++i)
70 kill_unused_stacknodes(ins[i]);
74 static void introduce_epilog(ir_node *ret)
76 const arch_register_t *sp_reg = &sparc_registers[REG_SP];
77 ir_graph *irg = get_irn_irg(ret);
78 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
79 ir_node *block = get_nodes_block(ret);
80 ir_type *frame_type = get_irg_frame_type(irg);
81 unsigned frame_size = get_type_size_bytes(frame_type);
82 int sp_idx = be_find_return_reg_input(ret, sp_reg);
83 ir_node *sp = get_irn_n(ret, sp_idx);
85 if (!layout->sp_relative) {
86 const arch_register_t *fp_reg = &sparc_registers[REG_FRAME_POINTER];
87 ir_node *fp = be_get_initial_reg_value(irg, fp_reg);
88 ir_node *restore = new_bd_sparc_RestoreZero(NULL, block, fp);
89 sched_add_before(ret, restore);
90 arch_set_irn_register(restore, sp_reg);
91 set_irn_n(ret, sp_idx, restore);
93 kill_unused_stacknodes(sp);
95 ir_node *incsp = be_new_IncSP(sp_reg, block, sp, frame_size, 0);
96 set_irn_n(ret, sp_idx, incsp);
97 sched_add_before(ret, incsp);
101 void sparc_introduce_prolog_epilog(ir_graph *irg)
103 const arch_register_t *sp_reg = &sparc_registers[REG_SP];
104 ir_node *start = get_irg_start(irg);
105 be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
106 ir_node *block = get_nodes_block(start);
107 ir_node *initial_sp = be_get_initial_reg_value(irg, sp_reg);
108 ir_node *sp = initial_sp;
109 ir_node *schedpoint = start;
110 ir_type *frame_type = get_irg_frame_type(irg);
111 unsigned frame_size = get_type_size_bytes(frame_type);
113 /* introduce epilog for every return node */
115 ir_node *end_block = get_irg_end_block(irg);
116 int arity = get_irn_arity(end_block);
119 for (i = 0; i < arity; ++i) {
120 ir_node *ret = get_irn_n(end_block, i);
121 assert(be_is_Return(ret));
122 introduce_epilog(ret);
126 while (be_is_Keep(sched_next(schedpoint)))
127 schedpoint = sched_next(schedpoint);
129 if (!layout->sp_relative) {
131 ir_node *save = new_bd_sparc_Save_imm(NULL, block, sp, NULL,
132 -SPARC_MIN_STACKSIZE);
133 arch_set_irn_register(save, sp_reg);
134 sched_add_after(schedpoint, save);
137 incsp = be_new_IncSP(sp_reg, block, save, frame_size, 0);
138 edges_reroute(initial_sp, incsp);
139 set_irn_n(save, n_sparc_Save_stack, initial_sp);
140 sched_add_after(schedpoint, incsp);
143 /* we still need the IncSP even if noone is explicitely using the
144 * value. (TODO: this isn't 100% correct yet, something at the end of
145 * the function should hold the IncSP, even if we use a restore
146 * which just overrides it instead of using the value)
148 if (get_irn_n_edges(incsp) == 0) {
149 ir_node *in[] = { incsp };
150 ir_node *keep = be_new_Keep(block, 1, in);
151 sched_add_after(schedpoint, keep);
154 ir_node *incsp = be_new_IncSP(sp_reg, block, sp, frame_size, 0);
155 edges_reroute(initial_sp, incsp);
156 be_set_IncSP_pred(incsp, sp);
157 sched_add_after(schedpoint, incsp);
161 static void finish_sparc_Save(ir_node *node)
163 sparc_attr_t *attr = get_sparc_attr(node);
164 int offset = attr->immediate_value;
165 ir_node *schedpoint = node;
172 if (sparc_is_value_imm_encodeable(offset))
175 /* uhh only works for the imm variant yet */
176 assert(get_irn_arity(node) == 1);
178 block = get_nodes_block(node);
179 dbgi = get_irn_dbg_info(node);
180 stack = get_irn_n(node, n_sparc_Save_stack);
181 entity = attr->immediate_value_entity;
182 new_save = new_bd_sparc_Save_imm(dbgi, block, stack, entity, 0);
183 arch_set_irn_register(new_save, &sparc_registers[REG_SP]);
186 sched_add_after(node, new_save);
187 schedpoint = new_save;
188 while (offset > SPARC_IMMEDIATE_MAX || offset < SPARC_IMMEDIATE_MIN) {
190 stack = be_new_IncSP(&sparc_registers[REG_SP], block, stack,
191 SPARC_IMMEDIATE_MIN, 0);
192 offset -= -SPARC_IMMEDIATE_MIN;
194 stack = be_new_IncSP(&sparc_registers[REG_SP], block, stack,
195 -SPARC_IMMEDIATE_MIN, 0);
196 offset -= SPARC_IMMEDIATE_MIN;
198 sched_add_after(schedpoint, stack);
201 attr = get_sparc_attr(new_save);
202 attr->immediate_value = offset;
203 be_peephole_exchange(node, stack);
207 * sparc immediates are limited. Split IncSP with bigger immediates if
210 static void finish_be_IncSP(ir_node *node)
213 int offset = be_get_IncSP_offset(node);
214 ir_node *sp = be_get_IncSP_pred(node);
217 /* we might have to break the IncSP apart if the constant has become too
224 if (sparc_is_value_imm_encodeable(-offset))
227 /* split incsp into multiple instructions */
228 block = get_nodes_block(node);
229 while (offset > -SPARC_IMMEDIATE_MIN) {
230 sp = be_new_IncSP(&sparc_registers[REG_SP], block, sp,
231 sign * -SPARC_IMMEDIATE_MIN, 0);
232 sched_add_before(node, sp);
233 offset -= -SPARC_IMMEDIATE_MIN;
236 be_set_IncSP_pred(node, sp);
237 be_set_IncSP_offset(node, sign*offset);
241 * adjust sp-relative offsets. Split into multiple instructions if offset
242 * exceeds sparc immediate range.
244 static void finish_sparc_FrameAddr(ir_node *node)
246 /* adapt to sparc stack magic */
247 sparc_attr_t *attr = get_sparc_attr(node);
248 int offset = attr->immediate_value;
249 ir_node *base = get_irn_n(node, n_sparc_FrameAddr_base);
250 dbg_info *dbgi = get_irn_dbg_info(node);
251 ir_node *block = get_nodes_block(node);
254 = arch_get_irn_register(base) == &sparc_registers[REG_SP];
256 offset += SPARC_MIN_STACKSIZE;
264 if (offset > -SPARC_IMMEDIATE_MIN) {
265 ir_entity *entity = attr->immediate_value_entity;
266 ir_node *new_frameaddr
267 = new_bd_sparc_FrameAddr(dbgi, block, base, entity, 0);
268 ir_node *schedpoint = node;
269 const arch_register_t *reg = arch_get_irn_register(node);
271 sched_add_after(schedpoint, new_frameaddr);
272 schedpoint = new_frameaddr;
273 arch_set_irn_register(new_frameaddr, reg);
274 base = new_frameaddr;
276 while (offset > -SPARC_IMMEDIATE_MIN) {
278 base = new_bd_sparc_Sub_imm(dbgi, block, base, NULL,
279 SPARC_IMMEDIATE_MIN);
281 base = new_bd_sparc_Add_imm(dbgi, block, base, NULL,
282 SPARC_IMMEDIATE_MIN);
284 arch_set_irn_register(base, reg);
285 sched_add_after(schedpoint, base);
288 offset -= -SPARC_IMMEDIATE_MIN;
291 be_peephole_exchange(node, base);
292 attr = get_sparc_attr(new_frameaddr);
294 attr->immediate_value = sign*offset;
297 static void finish_sparc_LdSt(ir_node *node)
299 sparc_load_store_attr_t *attr = get_sparc_load_store_attr(node);
300 if (attr->is_frame_entity) {
303 if (is_sparc_Ld(node) || is_sparc_Ldf(node)) {
304 base = get_irn_n(node, n_sparc_Ld_ptr);
306 assert(is_sparc_St(node) || is_sparc_Stf(node));
307 base = get_irn_n(node, n_sparc_St_ptr);
309 sp_relative = arch_get_irn_register(base) == &sparc_registers[REG_SP];
311 attr->base.immediate_value += SPARC_MIN_STACKSIZE;
315 static void peephole_be_IncSP(ir_node *node)
318 node = be_peephole_IncSP_IncSP(node);
319 if (!be_is_IncSP(node))
322 pred = be_get_IncSP_pred(node);
323 if (is_sparc_Save(pred) && be_has_only_one_user(pred)) {
324 int offset = -be_get_IncSP_offset(node);
325 sparc_attr_t *attr = get_sparc_attr(pred);
326 attr->immediate_value += offset;
327 be_peephole_exchange(node, pred);
331 static void peephole_sparc_FrameAddr(ir_node *node)
333 /* the peephole code currently doesn't allow this since it changes
334 * the register. Find out why and how to workaround this... */
336 const sparc_attr_t *attr = get_sparc_attr_const(node);
337 if (attr->immediate_value == 0) {
338 ir_node *base = get_irn_n(node, n_sparc_FrameAddr_base);
339 be_peephole_exchange(node, base);
345 static void finish_be_Return(ir_node *node)
347 ir_node *schedpoint = node;
349 /* see that there is no code between Return and restore, if there is move
350 * it in front of the restore */
352 if (!sched_has_prev(schedpoint))
354 schedpoint = sched_prev(schedpoint);
355 if (is_sparc_Restore(schedpoint) || is_sparc_RestoreZero(schedpoint))
358 restore = schedpoint;
359 schedpoint = sched_prev(node);
360 /* move all code between return and restore up */
361 while (schedpoint != restore) {
362 ir_node *next_schedpoint = sched_prev(schedpoint);
363 sched_remove(schedpoint);
364 sched_add_before(restore, schedpoint);
365 schedpoint = next_schedpoint;
369 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
371 assert(op->ops.generic == NULL);
372 op->ops.generic = (op_func) func;
375 void sparc_finish(ir_graph *irg)
377 /* perform peephole optimizations */
378 clear_irp_opcodes_generic_func();
379 register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
380 register_peephole_optimisation(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
381 be_peephole_opt(irg);
383 /* perform legalizations (mostly fix nodes with too big immediates) */
384 clear_irp_opcodes_generic_func();
385 register_peephole_optimisation(op_be_IncSP, finish_be_IncSP);
386 register_peephole_optimisation(op_be_Return, finish_be_Return);
387 register_peephole_optimisation(op_sparc_FrameAddr, finish_sparc_FrameAddr);
388 register_peephole_optimisation(op_sparc_Ld, finish_sparc_LdSt);
389 register_peephole_optimisation(op_sparc_Ldf, finish_sparc_LdSt);
390 register_peephole_optimisation(op_sparc_Save, finish_sparc_Save);
391 register_peephole_optimisation(op_sparc_St, finish_sparc_LdSt);
392 register_peephole_optimisation(op_sparc_Stf, finish_sparc_LdSt);
393 be_peephole_opt(irg);