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
35 #include "bepeephole.h"
38 #include "arm_optimize.h"
39 #include "gen_arm_regalloc_if.h"
40 #include "gen_arm_new_nodes.h"
42 static const arch_env_t *arch_env;
43 static arm_code_gen_t *cg;
45 /** Execute ARM ROL. */
46 static unsigned arm_rol(unsigned v, unsigned rol) {
47 return (v << rol) | (v >> (32 - rol));
51 * construct 8bit values and rot amounts for a value.
53 void arm_gen_vals_from_word(unsigned int value, arm_vals *result)
57 memset(result, 0, sizeof(*result));
59 /* special case: we prefer shift amount 0 */
61 result->values[0] = value;
68 unsigned v = arm_rol(value, 8) & 0xFFFFFF;
77 shf = (initial + shf - 8) & 0x1F;
78 result->values[result->ops] = v;
79 result->shifts[result->ops] = shf;
82 value ^= arm_rol(v, shf) >> initial;
92 * Encodes an immediate with shifter operand
94 unsigned int arm_encode_imm_w_shift(unsigned int shift, unsigned int immediate) {
95 return immediate | ((shift>>1)<<8);
99 * Decode an immediate with shifter operand
101 unsigned int arm_decode_imm_w_shift(long imm_value) {
102 unsigned l = (unsigned)imm_value;
103 unsigned rol = (l & ~0xFF) >> 7;
105 return arm_rol(l & 0xFF, rol);
109 * Creates a Mov node.
111 static ir_node *create_mov_node(ir_node *sched_point, dbg_info *dbg, ir_node *block, long value) {
112 ir_graph *irg = current_ir_graph;
115 mov = new_rd_arm_Mov_i(dbg, irg, block, mode_Iu, value);
116 arch_set_irn_register(arch_env, mov, &arm_gp_regs[REG_R12]);
117 sched_add_before(sched_point, mov);
122 * Creates a Mvn node.
124 static ir_node *create_mvn_node(ir_node *sched_point, dbg_info *dbg, ir_node *block, long value) {
125 ir_graph *irg = current_ir_graph;
128 mvn = new_rd_arm_Mvn_i(dbg, irg, block, mode_Iu, value);
129 arch_set_irn_register(arch_env, mvn, &arm_gp_regs[REG_R12]);
130 sched_add_before(sched_point, mvn);
135 * Creates a possible DAG for an constant and schedule it before
136 * the node sched_point.
137 * The Dag deliveres it's result in register R12.
139 static ir_node *create_const_graph_value(ir_node *sched_point, unsigned int value) {
141 ir_node *block, *result;
145 arm_gen_vals_from_word(value, &v);
146 arm_gen_vals_from_word(~value, &vn);
148 dbg = get_irn_dbg_info(sched_point);
149 block = get_nodes_block(sched_point);
151 if (vn.ops < v.ops) {
153 result = create_mvn_node(sched_point, dbg, block, arm_encode_imm_w_shift(vn.shifts[0], vn.values[0]));
155 for (cnt = 1; cnt < vn.ops; ++cnt) {
156 long value = arm_encode_imm_w_shift(vn.shifts[cnt], vn.values[cnt]);
157 ir_node *bic_i_node = new_rd_arm_Bic_i(dbg, current_ir_graph, block, result, mode_Iu, value);
158 arch_set_irn_register(arch_env, bic_i_node, &arm_gp_regs[REG_R12]);
159 sched_add_before(sched_point, bic_i_node);
165 result = create_mov_node(sched_point, dbg, block, arm_encode_imm_w_shift(v.shifts[0], v.values[0]));
167 for (cnt = 1; cnt < v.ops; ++cnt) {
168 long value = arm_encode_imm_w_shift(v.shifts[cnt], v.values[cnt]);
169 ir_node *orr_i_node = new_rd_arm_Or_i(dbg, current_ir_graph, block, result, mode_Iu, value);
170 arch_set_irn_register(arch_env, orr_i_node, &arm_gp_regs[REG_R12]);
171 sched_add_before(sched_point, orr_i_node);
180 * Returns non.zero if the given offset can be directly encoded into an ARM instruction.
182 static int allowed_arm_immediate(int offset, arm_vals *result) {
183 arm_gen_vals_from_word(offset, result);
184 return result->ops <= 1;
188 * Fix an IncSP node if the offset gets too big
190 static void peephole_be_IncSP(ir_node *node) {
193 int offset, cnt, align, sign = 1;
196 /* first optimize incsp->incsp combinations */
197 be_peephole_IncSP_IncSP(node);
199 offset = be_get_IncSP_offset(node);
200 /* can be transformed into Add OR Sub */
205 if (allowed_arm_immediate(offset, &v))
208 be_set_IncSP_offset(node, (int)arm_encode_imm_w_shift(v.shifts[0], v.values[0]) * sign);
210 irg = current_ir_graph;
211 block = get_nodes_block(node);
212 align = be_get_IncSP_align(node);
213 for (cnt = 1; cnt < v.ops; ++cnt) {
214 int value = (int)arm_encode_imm_w_shift(v.shifts[cnt], v.values[cnt]);
215 ir_node *next = be_new_IncSP(&arm_gp_regs[REG_SP], irg, block, node, value * sign, align);
216 sched_add_after(node, next);
222 * creates the address by Adds
224 static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v)
226 ir_graph *irg = current_ir_graph;
227 dbg_info *dbg = get_irn_dbg_info(node);
228 ir_node *block = get_nodes_block(node);
232 ptr = new_rd_arm_Add_i(dbg, irg, block, frame, mode_Iu, arm_encode_imm_w_shift(v->shifts[0], v->values[0]));
233 arch_set_irn_register(arch_env, ptr, &arm_gp_regs[REG_R12]);
234 sched_add_before(node, ptr);
236 for (cnt = 1; cnt < v->ops; ++cnt) {
237 long value = arm_encode_imm_w_shift(v->shifts[cnt], v->values[cnt]);
238 ir_node *next = new_rd_arm_Add_i(dbg, irg, block, ptr, mode_Iu, value);
239 arch_set_irn_register(arch_env, next, &arm_gp_regs[REG_R12]);
240 sched_add_before(node, next);
247 * creates the address by Subs
249 static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v)
251 ir_graph *irg = current_ir_graph;
252 dbg_info *dbg = get_irn_dbg_info(node);
253 ir_node *block = get_nodes_block(node);
257 ptr = new_rd_arm_Sub_i(dbg, irg, block, frame, mode_Iu, arm_encode_imm_w_shift(v->shifts[0], v->values[0]));
258 arch_set_irn_register(arch_env, ptr, &arm_gp_regs[REG_R12]);
259 sched_add_before(node, ptr);
261 for (cnt = 1; cnt < v->ops; ++cnt) {
262 long value = arm_encode_imm_w_shift(v->shifts[cnt], v->values[cnt]);
263 ir_node *next = new_rd_arm_Sub_i(dbg, irg, block, ptr, mode_Iu, value);
264 arch_set_irn_register(arch_env, next, &arm_gp_regs[REG_R12]);
265 sched_add_before(node, next);
272 * Fix an be_Spill node if the offset gets too big
274 static void peephole_be_Spill(ir_node *node) {
275 ir_entity *ent = be_get_frame_entity(node);
276 int use_add = 1, offset = get_entity_offset(ent);
277 ir_node *block, *ptr, *frame, *value, *store;
283 if (allowed_arm_immediate(offset, &v))
290 frame = be_get_Spill_frame(node);
292 ptr = gen_ptr_add(node, frame, &v);
294 ptr = gen_ptr_sub(node, frame, &v);
297 value = be_get_Spill_val(node);
298 mode = get_irn_mode(value);
299 irg = current_ir_graph;
300 dbg = get_irn_dbg_info(node);
301 block = get_nodes_block(node);
303 if (mode_is_float(mode)) {
304 if (USE_FPA(cg->isa)) {
305 /* transform into fpaStf */
306 store = new_rd_arm_fpaStf(dbg, irg, block, ptr, value, get_irg_no_mem(irg), mode);
307 sched_add_before(node, store);
309 panic("peephole_be_Spill: spill not supported for this mode");
311 } else if (mode_is_dataM(mode)) {
312 /* transform into Store */;
313 store = new_rd_arm_Store(dbg, irg, block, ptr, value, get_irg_no_mem(irg));
314 sched_add_before(node, store);
316 panic("peephole_be_Spill: spill not supported for this mode");
319 be_peephole_before_exchange(node, store);
321 exchange(node, store);
322 be_peephole_after_exchange(store);
326 * Fix an be_Reload node if the offset gets too big
328 static void peephole_be_Reload(ir_node *node) {
329 ir_entity *ent = be_get_frame_entity(node);
330 int use_add = 1, offset = get_entity_offset(ent);
331 ir_node *block, *ptr, *frame, *load, *mem, *proj;
336 const arch_register_t *reg;
338 if (allowed_arm_immediate(offset, &v))
345 frame = be_get_Reload_frame(node);
347 ptr = gen_ptr_add(node, frame, &v);
349 ptr = gen_ptr_sub(node, frame, &v);
352 reg = arch_get_irn_register(arch_env, node);
353 mem = be_get_Reload_mem(node);
354 mode = get_irn_mode(node);
355 irg = current_ir_graph;
356 dbg = get_irn_dbg_info(node);
357 block = get_nodes_block(node);
359 if (mode_is_float(mode)) {
360 if (USE_FPA(cg->isa)) {
361 /* transform into fpaLdf */
362 load = new_rd_arm_fpaLdf(dbg, irg, block, ptr, mem, mode);
363 sched_add_before(node, load);
364 proj = new_rd_Proj(dbg, irg, block, load, mode, pn_arm_fpaLdf_res);
365 arch_set_irn_register(arch_env, proj, reg);
367 panic("peephole_be_Spill: spill not supported for this mode");
369 } else if (mode_is_dataM(mode)) {
370 /* transform into Store */;
371 load = new_rd_arm_Load(dbg, irg, block, ptr, mem);
372 sched_add_before(node, load);
373 proj = new_rd_Proj(dbg, irg, block, load, mode_Iu, pn_arm_Load_res);
374 arch_set_irn_register(arch_env, proj, reg);
376 panic("peephole_be_Spill: spill not supported for this mode");
379 be_peephole_before_exchange(node, proj);
381 exchange(node, proj);
382 be_peephole_after_exchange(proj);
386 * Register a peephole optimization function.
388 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) {
389 assert(op->ops.generic == NULL);
390 op->ops.generic = (op_func)func;
393 /* Perform peephole-optimizations. */
394 void arm_peephole_optimization(arm_code_gen_t *new_cg)
397 arch_env = cg->arch_env;
399 /* register peephole optimizations */
400 clear_irp_opcodes_generic_func();
401 register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
402 register_peephole_optimisation(op_be_Spill, peephole_be_Spill);
403 register_peephole_optimisation(op_be_Reload, peephole_be_Reload);
405 be_peephole_opt(cg->birg);