2 * Copyright (C) 1995-2008 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 Implements several optimizations for ARM.
23 * @author Michael Beck
34 #include "bepeephole.h"
37 #include "arm_optimize.h"
38 #include "gen_arm_regalloc_if.h"
39 #include "gen_arm_new_nodes.h"
40 #include "arm_nodes_attr.h"
41 #include "arm_new_nodes.h"
43 static arm_code_gen_t *cg;
45 static unsigned arm_ror(unsigned v, unsigned ror)
47 return (v << (32 - ror)) | (v >> ror);
51 * construct 8bit values and rot amounts for a value.
53 void arm_gen_vals_from_word(unsigned int value, arm_vals *result)
57 /* TODO: not optimal yet, as we only "shift" the value and don't take advantage of rotations */
59 /* special case: we prefer shift amount 0 */
61 result->values[0] = value;
69 while ( (value & 0x3) == 0) {
74 result->values[result->ops] = value & 0xFF;
75 result->rors[result->ops] = (32-initial) % 32;
84 * Returns non.zero if the given offset can be directly encoded into an ARM
87 static int allowed_arm_immediate(int offset, arm_vals *result)
89 arm_gen_vals_from_word(offset, result);
90 return result->ops <= 1;
94 * Fix an IncSP node if the offset gets too big
96 static void peephole_be_IncSP(ir_node *node)
105 const ir_edge_t *edge;
106 const ir_edge_t *next;
108 /* first optimize incsp->incsp combinations */
109 node = be_peephole_IncSP_IncSP(node);
111 offset = be_get_IncSP_offset(node);
112 /* can be transformed into Add OR Sub */
117 if (allowed_arm_immediate(offset, &v))
120 be_set_IncSP_offset(node, sign * arm_ror(v.values[0], v.rors[0]));
123 block = get_nodes_block(node);
124 for (cnt = 1; cnt < v.ops; ++cnt) {
125 int value = sign * arm_ror(v.values[cnt], v.rors[cnt]);
126 ir_node *next = be_new_IncSP(&arm_gp_regs[REG_SP], block, node,
128 sched_add_after(node, next);
132 /* reattach IncSP users */
134 node = sched_next(first);
135 foreach_out_edge_safe(first, edge, next) {
136 ir_node *user = get_edge_src_irn(edge);
137 int pos = get_edge_src_pos(edge);
140 set_irn_n(user, pos, last);
145 * creates the address by Adds
147 static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v)
149 dbg_info *dbgi = get_irn_dbg_info(node);
150 ir_node *block = get_nodes_block(node);
154 ptr = new_bd_arm_Add_imm(dbgi, block, frame, v->values[0], v->rors[0]);
155 arch_set_irn_register(ptr, &arm_gp_regs[REG_R12]);
156 sched_add_before(node, ptr);
158 for (cnt = 1; cnt < v->ops; ++cnt) {
159 ir_node *next = new_bd_arm_Add_imm(dbgi, block, ptr, v->values[cnt],
161 arch_set_irn_register(next, &arm_gp_regs[REG_R12]);
162 sched_add_before(node, next);
169 * creates the address by Subs
171 static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v)
173 dbg_info *dbgi = get_irn_dbg_info(node);
174 ir_node *block = get_nodes_block(node);
178 ptr = new_bd_arm_Sub_imm(dbgi, block, frame, v->values[0], v->rors[0]);
179 arch_set_irn_register(ptr, &arm_gp_regs[REG_R12]);
180 sched_add_before(node, ptr);
182 for (cnt = 1; cnt < v->ops; ++cnt) {
183 ir_node *next = new_bd_arm_Sub_imm(dbgi, block, ptr, v->values[cnt],
185 arch_set_irn_register(next, &arm_gp_regs[REG_R12]);
186 sched_add_before(node, next);
192 /** fix frame addresses which are too big */
193 static void peephole_arm_FrameAddr(ir_node *node)
195 arm_SymConst_attr_t *attr = get_arm_SymConst_attr(node);
196 int offset = attr->fp_offset;
201 if (allowed_arm_immediate(offset, &v))
204 base = get_irn_n(node, n_arm_FrameAddr_base);
205 /* TODO: suboptimal */
206 ptr = gen_ptr_add(node, base, &v);
209 set_irn_n(node, n_arm_FrameAddr_base, ptr);
213 * Fix stackpointer relative stores if the offset gets too big
215 static void peephole_arm_Str_Ldr(ir_node *node)
217 arm_load_store_attr_t *attr = get_arm_load_store_attr(node);
218 int offset = attr->offset;
223 if (allowed_arm_immediate(offset, &v))
226 /* we should only have too big offsets for frame entities */
227 if (!attr->is_frame_entity) {
229 "POSSIBLE ARM BACKEND PROBLEM: offset in Store too big\n");
236 if (is_arm_Str(node)) {
237 ptr = get_irn_n(node, n_arm_Str_ptr);
239 assert(is_arm_Ldr(node));
240 ptr = get_irn_n(node, n_arm_Ldr_ptr);
244 ptr = gen_ptr_add(node, ptr, &v);
246 ptr = gen_ptr_sub(node, ptr, &v);
249 /* TODO: sub-optimal, the last offset could probably be left inside the
251 if (is_arm_Str(node)) {
252 set_irn_n(node, n_arm_Str_ptr, ptr);
254 assert(is_arm_Ldr(node));
255 set_irn_n(node, n_arm_Ldr_ptr, ptr);
261 * Register a peephole optimization function.
263 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
265 assert(op->ops.generic == NULL);
266 op->ops.generic = (op_func)func;
269 /* Perform peephole-optimizations. */
270 void arm_peephole_optimization(arm_code_gen_t *new_cg)
274 /* register peephole optimizations */
275 clear_irp_opcodes_generic_func();
276 register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
277 register_peephole_optimisation(op_arm_Str, peephole_arm_Str_Ldr);
278 register_peephole_optimisation(op_arm_Ldr, peephole_arm_Str_Ldr);
279 register_peephole_optimisation(op_arm_FrameAddr, peephole_arm_FrameAddr);
281 be_peephole_opt(cg->birg);