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"
48 #include "../bepeephole.h"
49 #include "../benode.h"
50 #include "../besched.h"
52 static void finish_sparc_Save(ir_node *node)
54 sparc_attr_t *attr = get_sparc_attr(node);
55 int offset = attr->immediate_value;
56 ir_node *schedpoint = node;
63 if (sparc_is_value_imm_encodeable(offset))
66 /* uhh only works for the imm variant yet */
67 assert(get_irn_arity(node) == 1);
69 block = get_nodes_block(node);
70 dbgi = get_irn_dbg_info(node);
71 stack = get_irn_n(node, n_sparc_Save_stack);
72 entity = attr->immediate_value_entity;
73 new_save = new_bd_sparc_Save_imm(dbgi, block, stack, entity, 0);
74 arch_set_irn_register(new_save, &sparc_registers[REG_SP]);
77 sched_add_after(node, new_save);
78 schedpoint = new_save;
79 while (offset > SPARC_IMMEDIATE_MAX || offset < SPARC_IMMEDIATE_MIN) {
81 stack = be_new_IncSP(&sparc_registers[REG_SP], block, stack,
82 SPARC_IMMEDIATE_MIN, 0);
83 offset -= -SPARC_IMMEDIATE_MIN;
85 stack = be_new_IncSP(&sparc_registers[REG_SP], block, stack,
86 -SPARC_IMMEDIATE_MIN, 0);
87 offset -= SPARC_IMMEDIATE_MIN;
89 sched_add_after(schedpoint, stack);
92 attr = get_sparc_attr(new_save);
93 attr->immediate_value = offset;
94 be_peephole_exchange(node, stack);
98 * sparc immediates are limited. Split IncSP with bigger immediates if
101 static void finish_be_IncSP(ir_node *node)
104 int offset = be_get_IncSP_offset(node);
105 ir_node *sp = be_get_IncSP_pred(node);
108 /* we might have to break the IncSP apart if the constant has become too
115 if (sparc_is_value_imm_encodeable(-offset))
118 /* split incsp into multiple instructions */
119 block = get_nodes_block(node);
120 while (offset > -SPARC_IMMEDIATE_MIN) {
121 sp = be_new_IncSP(&sparc_registers[REG_SP], block, sp,
122 sign * -SPARC_IMMEDIATE_MIN, 0);
123 sched_add_before(node, sp);
124 offset -= -SPARC_IMMEDIATE_MIN;
127 be_set_IncSP_pred(node, sp);
128 be_set_IncSP_offset(node, sign*offset);
132 * adjust sp-relative offsets. Split into multiple instructions if offset
133 * exceeds sparc immediate range.
135 static void finish_sparc_FrameAddr(ir_node *node)
137 /* adapt to sparc stack magic */
138 sparc_attr_t *attr = get_sparc_attr(node);
139 int offset = attr->immediate_value;
140 ir_node *base = get_irn_n(node, n_sparc_FrameAddr_base);
141 dbg_info *dbgi = get_irn_dbg_info(node);
142 ir_node *block = get_nodes_block(node);
145 = arch_get_irn_register(base) == &sparc_registers[REG_SP];
147 offset += SPARC_MIN_STACKSIZE;
155 if (offset > -SPARC_IMMEDIATE_MIN) {
156 ir_entity *entity = attr->immediate_value_entity;
157 ir_node *new_frameaddr
158 = new_bd_sparc_FrameAddr(dbgi, block, base, entity, 0);
159 ir_node *schedpoint = node;
160 const arch_register_t *reg = arch_get_irn_register(node);
162 sched_add_after(schedpoint, new_frameaddr);
163 schedpoint = new_frameaddr;
164 arch_set_irn_register(new_frameaddr, reg);
165 base = new_frameaddr;
167 while (offset > -SPARC_IMMEDIATE_MIN) {
169 base = new_bd_sparc_Sub_imm(dbgi, block, base, NULL,
170 SPARC_IMMEDIATE_MIN);
172 base = new_bd_sparc_Add_imm(dbgi, block, base, NULL,
173 SPARC_IMMEDIATE_MIN);
175 arch_set_irn_register(base, reg);
176 sched_add_after(schedpoint, base);
179 offset -= -SPARC_IMMEDIATE_MIN;
182 be_peephole_exchange(node, base);
183 attr = get_sparc_attr(new_frameaddr);
185 attr->immediate_value = sign*offset;
188 static void finish_sparc_LdSt(ir_node *node)
190 sparc_load_store_attr_t *attr = get_sparc_load_store_attr(node);
191 if (attr->is_frame_entity) {
194 if (is_sparc_Ld(node) || is_sparc_Ldf(node)) {
195 base = get_irn_n(node, n_sparc_Ld_ptr);
197 assert(is_sparc_St(node) || is_sparc_Stf(node));
198 base = get_irn_n(node, n_sparc_St_ptr);
200 sp_relative = arch_get_irn_register(base) == &sparc_registers[REG_SP];
202 attr->base.immediate_value += SPARC_MIN_STACKSIZE;
206 static void peephole_be_IncSP(ir_node *node)
209 node = be_peephole_IncSP_IncSP(node);
210 if (!be_is_IncSP(node))
213 pred = be_get_IncSP_pred(node);
214 if (is_sparc_Save(pred) && be_has_only_one_user(pred)) {
215 int offset = -be_get_IncSP_offset(node);
216 sparc_attr_t *attr = get_sparc_attr(pred);
217 attr->immediate_value += offset;
218 be_peephole_exchange(node, pred);
222 static void peephole_sparc_FrameAddr(ir_node *node)
224 /* the peephole code currently doesn't allow this since it changes
225 * the register. Find out why and how to workaround this... */
227 const sparc_attr_t *attr = get_sparc_attr_const(node);
228 if (attr->immediate_value == 0) {
229 ir_node *base = get_irn_n(node, n_sparc_FrameAddr_base);
230 be_peephole_exchange(node, base);
236 static void finish_be_Return(ir_node *node)
238 ir_node *schedpoint = node;
240 /* see that there is no code between Return and restore, if there is move
241 * it in front of the restore */
243 if (!sched_has_prev(schedpoint))
245 schedpoint = sched_prev(schedpoint);
246 if (is_sparc_Restore(schedpoint) || is_sparc_RestoreZero(schedpoint))
249 restore = schedpoint;
250 schedpoint = sched_prev(node);
251 /* move all code between return and restore up */
252 while (schedpoint != restore) {
253 ir_node *next_schedpoint = sched_prev(schedpoint);
254 sched_remove(schedpoint);
255 sched_add_before(restore, schedpoint);
256 schedpoint = next_schedpoint;
260 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
262 assert(op->ops.generic == NULL);
263 op->ops.generic = (op_func) func;
266 void sparc_finish(ir_graph *irg)
268 clear_irp_opcodes_generic_func();
269 register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
270 register_peephole_optimisation(op_sparc_FrameAddr, peephole_sparc_FrameAddr);
271 be_peephole_opt(irg);
273 clear_irp_opcodes_generic_func();
274 register_peephole_optimisation(op_be_IncSP, finish_be_IncSP);
275 register_peephole_optimisation(op_be_Return, finish_be_Return);
276 register_peephole_optimisation(op_sparc_FrameAddr, finish_sparc_FrameAddr);
277 register_peephole_optimisation(op_sparc_Ld, finish_sparc_LdSt);
278 register_peephole_optimisation(op_sparc_Ldf, finish_sparc_LdSt);
279 register_peephole_optimisation(op_sparc_Save, finish_sparc_Save);
280 register_peephole_optimisation(op_sparc_St, finish_sparc_LdSt);
281 register_peephole_optimisation(op_sparc_Stf, finish_sparc_LdSt);
282 be_peephole_opt(irg);