2 * This file is part of libFirm.
3 * Copyright (C) 2012 University of Karlsruhe.
8 * @brief Implements several optimizations for ARM.
19 #include "bepeephole.h"
22 #include "arm_optimize.h"
23 #include "gen_arm_regalloc_if.h"
24 #include "gen_arm_new_nodes.h"
25 #include "arm_nodes_attr.h"
26 #include "arm_new_nodes.h"
28 static unsigned arm_ror(unsigned v, unsigned ror)
30 return (v << (32 - ror)) | (v >> ror);
34 * construct 8bit values and rot amounts for a value.
36 void arm_gen_vals_from_word(unsigned int value, arm_vals *result)
40 /* TODO: not optimal yet, as we only "shift" the value and don't take advantage of rotations */
42 /* special case: we prefer shift amount 0 */
44 result->values[0] = value;
52 while ( (value & 0x3) == 0) {
57 result->values[result->ops] = value & 0xFF;
58 result->rors[result->ops] = (32-initial) % 32;
67 * Returns non.zero if the given offset can be directly encoded into an ARM
70 static int allowed_arm_immediate(int offset, arm_vals *result)
72 arm_gen_vals_from_word(offset, result);
73 return result->ops <= 1;
77 * Fix an IncSP node if the offset gets too big
79 static void peephole_be_IncSP(ir_node *node)
89 /* first optimize incsp->incsp combinations */
90 node = be_peephole_IncSP_IncSP(node);
92 offset = be_get_IncSP_offset(node);
93 /* can be transformed into Add OR Sub */
98 if (allowed_arm_immediate(offset, &v))
101 be_set_IncSP_offset(node, sign * arm_ror(v.values[0], v.rors[0]));
104 block = get_nodes_block(node);
105 for (cnt = 1; cnt < v.ops; ++cnt) {
106 int value = sign * arm_ror(v.values[cnt], v.rors[cnt]);
107 ir_node *incsp = be_new_IncSP(&arm_registers[REG_SP], block, node,
109 sched_add_after(node, incsp);
113 /* reattach IncSP users */
115 node = sched_next(first);
116 foreach_out_edge_safe(first, edge) {
117 ir_node *user = get_edge_src_irn(edge);
118 int pos = get_edge_src_pos(edge);
121 set_irn_n(user, pos, last);
126 * creates the address by Adds
128 static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v)
130 dbg_info *dbgi = get_irn_dbg_info(node);
131 ir_node *block = get_nodes_block(node);
135 ptr = new_bd_arm_Add_imm(dbgi, block, frame, v->values[0], v->rors[0]);
136 arch_set_irn_register(ptr, &arm_registers[REG_R12]);
137 sched_add_before(node, ptr);
139 for (cnt = 1; cnt < v->ops; ++cnt) {
140 ir_node *next = new_bd_arm_Add_imm(dbgi, block, ptr, v->values[cnt],
142 arch_set_irn_register(next, &arm_registers[REG_R12]);
143 sched_add_before(node, next);
150 * creates the address by Subs
152 static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v)
154 dbg_info *dbgi = get_irn_dbg_info(node);
155 ir_node *block = get_nodes_block(node);
159 ptr = new_bd_arm_Sub_imm(dbgi, block, frame, v->values[0], v->rors[0]);
160 arch_set_irn_register(ptr, &arm_registers[REG_R12]);
161 sched_add_before(node, ptr);
163 for (cnt = 1; cnt < v->ops; ++cnt) {
164 ir_node *next = new_bd_arm_Sub_imm(dbgi, block, ptr, v->values[cnt],
166 arch_set_irn_register(next, &arm_registers[REG_R12]);
167 sched_add_before(node, next);
173 /** fix frame addresses which are too big */
174 static void peephole_arm_FrameAddr(ir_node *node)
176 arm_SymConst_attr_t *attr = get_arm_SymConst_attr(node);
177 int offset = attr->fp_offset;
182 if (allowed_arm_immediate(offset, &v))
185 base = get_irn_n(node, n_arm_FrameAddr_base);
186 /* TODO: suboptimal */
187 ptr = gen_ptr_add(node, base, &v);
190 set_irn_n(node, n_arm_FrameAddr_base, ptr);
194 * Fix stackpointer relative stores if the offset gets too big
196 static void peephole_arm_Str_Ldr(ir_node *node)
198 arm_load_store_attr_t *attr = get_arm_load_store_attr(node);
199 int offset = attr->offset;
204 if (allowed_arm_immediate(offset, &v))
207 /* we should only have too big offsets for frame entities */
208 if (!attr->is_frame_entity) {
210 "POSSIBLE ARM BACKEND PROBLEM: offset in Store too big\n");
217 if (is_arm_Str(node)) {
218 ptr = get_irn_n(node, n_arm_Str_ptr);
220 assert(is_arm_Ldr(node));
221 ptr = get_irn_n(node, n_arm_Ldr_ptr);
225 ptr = gen_ptr_add(node, ptr, &v);
227 ptr = gen_ptr_sub(node, ptr, &v);
230 /* TODO: sub-optimal, the last offset could probably be left inside the
232 if (is_arm_Str(node)) {
233 set_irn_n(node, n_arm_Str_ptr, ptr);
235 assert(is_arm_Ldr(node));
236 set_irn_n(node, n_arm_Ldr_ptr, ptr);
242 * Register a peephole optimization function.
244 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
246 assert(op->ops.generic == NULL);
247 op->ops.generic = (op_func)func;
250 /* Perform peephole-optimizations. */
251 void arm_peephole_optimization(ir_graph *irg)
253 /* register peephole optimizations */
254 ir_clear_opcodes_generic_func();
255 register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
256 register_peephole_optimisation(op_arm_Str, peephole_arm_Str_Ldr);
257 register_peephole_optimisation(op_arm_Ldr, peephole_arm_Str_Ldr);
258 register_peephole_optimisation(op_arm_FrameAddr, peephole_arm_FrameAddr);
260 be_peephole_opt(irg);