becopyopt: Remove the unnecessary attribute name from struct copy_opt_t.
[libfirm] / ir / be / arm / arm_optimize.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief       Implements several optimizations for ARM.
9  * @author      Michael Beck
10  */
11 #include "config.h"
12
13 #include "irgmod.h"
14 #include "ircons.h"
15 #include "iredges.h"
16 #include "error.h"
17
18 #include "benode.h"
19 #include "bepeephole.h"
20 #include "besched.h"
21
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"
27
28 static unsigned arm_ror(unsigned v, unsigned ror)
29 {
30         return (v << (32 - ror)) | (v >> ror);
31 }
32
33 /*
34  * construct 8bit values and rot amounts for a value.
35  */
36 void arm_gen_vals_from_word(unsigned int value, arm_vals *result)
37 {
38         int initial = 0;
39
40         /* TODO: not optimal yet, as we only "shift" the value and don't take advantage of rotations */
41
42         /* special case: we prefer shift amount 0 */
43         if (value <= 0xFF) {
44                 result->values[0] = value;
45                 result->rors[0]   = 0;
46                 result->ops       = 1;
47                 return;
48         }
49
50         result->ops = 0;
51         do {
52                 while ( (value & 0x3) == 0) {
53                         value  >>= 2;
54                         initial += 2;
55                 }
56
57                 result->values[result->ops] = value & 0xFF;
58                 result->rors[result->ops]   = (32-initial) % 32;
59                 ++result->ops;
60
61                 value  >>= 8;
62                 initial += 8;
63         } while (value != 0);
64 }
65
66 /**
67  * Returns non.zero if the given offset can be directly encoded into an ARM
68  * instruction.
69  */
70 static int allowed_arm_immediate(int offset, arm_vals *result)
71 {
72         arm_gen_vals_from_word(offset, result);
73         return result->ops <= 1;
74 }
75
76 /**
77  * Fix an IncSP node if the offset gets too big
78  */
79 static void peephole_be_IncSP(ir_node *node)
80 {
81         ir_node  *first;
82         ir_node  *last;
83         ir_node  *block;
84         int       offset;
85         int       cnt;
86         int       sign = 1;
87         arm_vals  v;
88
89         /* first optimize incsp->incsp combinations */
90         node = be_peephole_IncSP_IncSP(node);
91
92         offset = be_get_IncSP_offset(node);
93         /* can be transformed into Add OR Sub */
94         if (offset < 0) {
95                 sign = -1;
96                 offset = -offset;
97         }
98         if (allowed_arm_immediate(offset, &v))
99                 return;
100
101         be_set_IncSP_offset(node, sign * arm_ror(v.values[0], v.rors[0]));
102
103         first = node;
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,
108                                              value, 1);
109                 sched_add_after(node, incsp);
110                 node = incsp;
111         }
112
113         /* reattach IncSP users */
114         last = node;
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);
119                 if (user == node)
120                         continue;
121                 set_irn_n(user, pos, last);
122         }
123 }
124
125 /**
126  * creates the address by Adds
127  */
128 static ir_node *gen_ptr_add(ir_node *node, ir_node *frame, arm_vals *v)
129 {
130         dbg_info *dbgi  = get_irn_dbg_info(node);
131         ir_node  *block = get_nodes_block(node);
132         int     cnt;
133         ir_node *ptr;
134
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);
138
139         for (cnt = 1; cnt < v->ops; ++cnt) {
140                 ir_node *next = new_bd_arm_Add_imm(dbgi, block, ptr, v->values[cnt],
141                                                    v->rors[cnt]);
142                 arch_set_irn_register(next, &arm_registers[REG_R12]);
143                 sched_add_before(node, next);
144                 ptr = next;
145         }
146         return ptr;
147 }
148
149 /**
150 * creates the address by Subs
151 */
152 static ir_node *gen_ptr_sub(ir_node *node, ir_node *frame, arm_vals *v)
153 {
154         dbg_info *dbgi  = get_irn_dbg_info(node);
155         ir_node  *block = get_nodes_block(node);
156         int     cnt;
157         ir_node *ptr;
158
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);
162
163         for (cnt = 1; cnt < v->ops; ++cnt) {
164                 ir_node *next = new_bd_arm_Sub_imm(dbgi, block, ptr, v->values[cnt],
165                                                    v->rors[cnt]);
166                 arch_set_irn_register(next, &arm_registers[REG_R12]);
167                 sched_add_before(node, next);
168                 ptr = next;
169         }
170         return ptr;
171 }
172
173 /** fix frame addresses which are too big */
174 static void peephole_arm_FrameAddr(ir_node *node)
175 {
176         arm_SymConst_attr_t *attr   = get_arm_SymConst_attr(node);
177         int                  offset = attr->fp_offset;
178         arm_vals             v;
179         ir_node             *base;
180         ir_node             *ptr;
181
182         if (allowed_arm_immediate(offset, &v))
183                 return;
184
185         base = get_irn_n(node, n_arm_FrameAddr_base);
186         /* TODO: suboptimal */
187         ptr = gen_ptr_add(node, base, &v);
188
189         attr->fp_offset = 0;
190         set_irn_n(node, n_arm_FrameAddr_base, ptr);
191 }
192
193 /**
194  * Fix stackpointer relative stores if the offset gets too big
195  */
196 static void peephole_arm_Str_Ldr(ir_node *node)
197 {
198         arm_load_store_attr_t *attr    = get_arm_load_store_attr(node);
199         int                    offset  = attr->offset;
200         int                    use_add = 1;
201         ir_node               *ptr;
202         arm_vals              v;
203
204         if (allowed_arm_immediate(offset, &v))
205                 return;
206
207         /* we should only have too big offsets for frame entities */
208         if (!attr->is_frame_entity) {
209                 fprintf(stderr,
210                         "POSSIBLE ARM BACKEND PROBLEM: offset in Store too big\n");
211         }
212         if (offset < 0) {
213                 use_add = 0;
214                 offset = -offset;
215         }
216
217         if (is_arm_Str(node)) {
218                 ptr = get_irn_n(node, n_arm_Str_ptr);
219         } else {
220                 assert(is_arm_Ldr(node));
221                 ptr = get_irn_n(node, n_arm_Ldr_ptr);
222         }
223
224         if (use_add) {
225                 ptr = gen_ptr_add(node, ptr, &v);
226         } else {
227                 ptr = gen_ptr_sub(node, ptr, &v);
228         }
229
230         /* TODO: sub-optimal, the last offset could probably be left inside the
231            store */
232         if (is_arm_Str(node)) {
233                 set_irn_n(node, n_arm_Str_ptr, ptr);
234         } else {
235                 assert(is_arm_Ldr(node));
236                 set_irn_n(node, n_arm_Ldr_ptr, ptr);
237         }
238         attr->offset = 0;
239 }
240
241 /**
242  * Register a peephole optimization function.
243  */
244 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
245 {
246         assert(op->ops.generic == NULL);
247         op->ops.generic = (op_func)func;
248 }
249
250 /* Perform peephole-optimizations. */
251 void arm_peephole_optimization(ir_graph *irg)
252 {
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);
259
260         be_peephole_opt(irg);
261 }