d2962de92e2d411f8a75a8518dbac739cd92650c
[libfirm] / ir / be / ia32 / ia32_optimize.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
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.
10  *
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.
14  *
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
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Implements several optimizations for IA32.
23  * @author      Matthias Braun, Christian Wuerdig
24  * @version     $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "irnode.h"
31 #include "irprog_t.h"
32 #include "ircons.h"
33 #include "irtools.h"
34 #include "firm_types.h"
35 #include "iredges.h"
36 #include "tv.h"
37 #include "irgmod.h"
38 #include "irgwalk.h"
39 #include "height.h"
40 #include "irbitset.h"
41
42 #include "../be_t.h"
43 #include "../beabi.h"
44 #include "../benode_t.h"
45 #include "../besched_t.h"
46 #include "../bepeephole.h"
47
48 #include "ia32_new_nodes.h"
49 #include "bearch_ia32_t.h"
50 #include "gen_ia32_regalloc_if.h"
51 #include "ia32_transform.h"
52 #include "ia32_dbg_stat.h"
53 #include "ia32_util.h"
54
55 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
56
57 static const arch_env_t *arch_env;
58 static ia32_code_gen_t  *cg;
59
60 typedef int is_op_func_t(const ir_node *n);
61 typedef ir_node *load_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *base, ir_node *index, ir_node *mem);
62
63 /**
64  * checks if a node represents the NOREG value
65  */
66 static INLINE int be_is_NoReg(ia32_code_gen_t *cg, const ir_node *irn) {
67         return irn == cg->noreg_gp || irn == cg->noreg_xmm || irn == cg->noreg_vfp;
68 }
69
70 /********************************************************************************************************
71  *  _____                _           _         ____        _   _           _          _   _
72  * |  __ \              | |         | |       / __ \      | | (_)         (_)        | | (_)
73  * | |__) |__  ___ _ __ | |__   ___ | | ___  | |  | |_ __ | |_ _ _ __ ___  _ ______ _| |_ _  ___  _ __
74  * |  ___/ _ \/ _ \ '_ \| '_ \ / _ \| |/ _ \ | |  | | '_ \| __| | '_ ` _ \| |_  / _` | __| |/ _ \| '_ \
75  * | |  |  __/  __/ |_) | | | | (_) | |  __/ | |__| | |_) | |_| | | | | | | |/ / (_| | |_| | (_) | | | |
76  * |_|   \___|\___| .__/|_| |_|\___/|_|\___|  \____/| .__/ \__|_|_| |_| |_|_/___\__,_|\__|_|\___/|_| |_|
77  *                | |                               | |
78  *                |_|                               |_|
79  ********************************************************************************************************/
80
81 /**
82  * NOTE: THESE PEEPHOLE OPTIMIZATIONS MUST BE CALLED AFTER SCHEDULING AND REGISTER ALLOCATION.
83  */
84
85 // only optimize up to 48 stores behind IncSPs
86 #define MAXPUSH_OPTIMIZE        48
87
88 /**
89  * Tries to create pushs from IncSP,Store combinations
90  */
91 static void ia32_create_Pushs(ir_node *irn)
92 {
93         int i;
94         int offset;
95         ir_node *node;
96         ir_node *stores[MAXPUSH_OPTIMIZE];
97         ir_node *block = get_nodes_block(irn);
98         ir_graph *irg = cg->irg;
99         ir_node *curr_sp;
100         ir_mode *spmode = get_irn_mode(irn);
101
102         memset(stores, 0, sizeof(stores));
103
104         assert(be_is_IncSP(irn));
105
106         offset = be_get_IncSP_offset(irn);
107         if(offset < 4)
108                 return;
109
110         /*
111          * We first walk the schedule after the IncSP node as long as we find
112          * suitable stores that could be transformed to a push.
113          * We save them into the stores array which is sorted by the frame offset/4
114          * attached to the node
115          */
116         for(node = sched_next(irn); !sched_is_end(node); node = sched_next(node)) {
117                 ir_node *mem;
118                 int offset;
119                 int storeslot;
120
121                 // it has to be a store
122                 if(!is_ia32_Store(node))
123                         break;
124
125                 // it has to use our sp value
126                 if(get_irn_n(node, n_ia32_base) != irn)
127                         continue;
128                 // store has to be attached to NoMem
129                 mem = get_irn_n(node, n_ia32_mem);
130                 if(!is_NoMem(mem)) {
131                         continue;
132                 }
133
134                 /* unfortunately we can't support the full AMs possible for push at the
135                  * moment. TODO: fix this */
136                 if(get_ia32_am_scale(node) > 0 || !is_ia32_NoReg_GP(get_irn_n(node, n_ia32_index)))
137                         break;
138
139                 offset = get_ia32_am_offs_int(node);
140
141                 storeslot = offset / 4;
142                 if(storeslot >= MAXPUSH_OPTIMIZE)
143                         continue;
144
145                 // storing into the same slot twice is bad (and shouldn't happen...)
146                 if(stores[storeslot] != NULL)
147                         break;
148
149                 // storing at half-slots is bad
150                 if(offset % 4 != 0)
151                         break;
152
153                 stores[storeslot] = node;
154         }
155
156         curr_sp = be_get_IncSP_pred(irn);
157
158         // walk the stores in inverse order and create pushs for them
159         i = (offset / 4) - 1;
160         if(i >= MAXPUSH_OPTIMIZE) {
161                 i = MAXPUSH_OPTIMIZE - 1;
162         }
163
164         for( ; i >= 0; --i) {
165                 const arch_register_t *spreg;
166                 ir_node *push;
167                 ir_node *val, *mem, *mem_proj;
168                 ir_node *store = stores[i];
169                 ir_node *noreg = ia32_new_NoReg_gp(cg);
170
171                 if(store == NULL || is_Bad(store))
172                         break;
173
174                 val = get_irn_n(store, n_ia32_unary_op);
175                 mem = get_irn_n(store, n_ia32_mem);
176                 spreg = arch_get_irn_register(cg->arch_env, curr_sp);
177
178                 push = new_rd_ia32_Push(get_irn_dbg_info(store), irg, block, noreg, noreg, mem, curr_sp, val);
179
180                 set_ia32_am_support(push, ia32_am_Source, ia32_am_unary);
181
182                 sched_add_before(irn, push);
183
184                 // create stackpointer proj
185                 curr_sp = new_r_Proj(irg, block, push, spmode, pn_ia32_Push_stack);
186                 arch_set_irn_register(cg->arch_env, curr_sp, spreg);
187
188                 // create memory proj
189                 mem_proj = new_r_Proj(irg, block, push, mode_M, pn_ia32_Push_M);
190
191                 // use the memproj now
192                 exchange(store, mem_proj);
193
194                 // we can remove the store now
195                 sched_remove(store);
196
197                 offset -= 4;
198         }
199
200         be_set_IncSP_offset(irn, offset);
201
202         // can we remove the IncSP now?
203         if(offset == 0) {
204                 const ir_edge_t *edge, *next;
205
206                 foreach_out_edge_safe(irn, edge, next) {
207                         ir_node *arg = get_edge_src_irn(edge);
208                         int pos = get_edge_src_pos(edge);
209
210                         set_irn_n(arg, pos, curr_sp);
211                 }
212
213                 set_irn_n(irn, 0, new_Bad());
214                 sched_remove(irn);
215         } else {
216                 set_irn_n(irn, 0, curr_sp);
217         }
218 }
219
220 /**
221  * Tries to optimize two following IncSP.
222  */
223 static void ia32_optimize_IncSP(ir_node *node)
224 {
225         int      pred_offs;
226         int      curr_offs;
227         int      offs;
228         ir_node *pred = be_get_IncSP_pred(node);
229         ir_node *predpred;
230
231         if(!be_is_IncSP(pred))
232                 return;
233
234         if(get_irn_n_edges(pred) > 1)
235                 return;
236
237         pred_offs = be_get_IncSP_offset(pred);
238         curr_offs = be_get_IncSP_offset(node);
239
240         if(pred_offs == BE_STACK_FRAME_SIZE_EXPAND) {
241                 if(curr_offs != BE_STACK_FRAME_SIZE_SHRINK) {
242                         return;
243                 }
244                 offs = 0;
245         } else if(pred_offs == BE_STACK_FRAME_SIZE_SHRINK) {
246                 if(curr_offs != BE_STACK_FRAME_SIZE_EXPAND) {
247                         return;
248                 }
249                 offs = 0;
250         } else if(curr_offs == BE_STACK_FRAME_SIZE_EXPAND
251                         || curr_offs == BE_STACK_FRAME_SIZE_SHRINK) {
252                 return;
253         } else {
254                 offs = curr_offs + pred_offs;
255         }
256
257         be_set_IncSP_offset(node, offs);
258
259         /* rewire dependency edges */
260         predpred = be_get_IncSP_pred(pred);
261         edges_reroute_kind(pred, predpred, EDGE_KIND_DEP, current_ir_graph);
262
263         /* Omit the IncSP */
264         be_set_IncSP_pred(node, predpred);
265         sched_remove(pred);
266         be_kill_node(pred);
267 }
268
269 /**
270  * Performs Peephole Optimizations for IncSP nodes.
271  */
272 static void ia32_peephole_optimize_node(ir_node *node, void *env)
273 {
274         (void) env;
275         if (be_is_IncSP(node)) {
276                 ia32_optimize_IncSP(node);
277                 ia32_create_Pushs(node);
278         }
279 }
280
281 /**
282  * Peephole optimisation for ia32_Const's
283  */
284 static ir_node *peephole_ia32_Const(ir_node *node)
285 {
286         const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
287         const arch_register_t       *reg;
288         ir_graph                    *irg = current_ir_graph;
289         ir_node                     *block;
290         dbg_info                    *dbgi;
291         ir_node                     *produceval;
292         ir_node                     *xor;
293         ir_node                     *noreg;
294
295         /* try to transform a mov 0, reg to xor reg reg */
296         if(attr->offset != 0 || attr->symconst != NULL)
297                 return NULL;
298         /* xor destroys the flags, so no-one must be using them */
299         if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
300                 return NULL;
301
302         reg = arch_get_irn_register(arch_env, node);
303         assert(be_peephole_get_reg_value(reg) == NULL);
304
305         /* create xor(produceval, produceval) */
306         block      = get_nodes_block(node);
307         dbgi       = get_irn_dbg_info(node);
308         produceval = new_rd_ia32_ProduceVal(dbgi, irg, block);
309         arch_set_irn_register(arch_env, produceval, reg);
310
311         noreg = ia32_new_NoReg_gp(cg);
312         xor   = new_rd_ia32_Xor(dbgi, irg, block, noreg, noreg, new_NoMem(),
313                                 produceval, produceval);
314         arch_set_irn_register(arch_env, xor, reg);
315
316         sched_add_before(node, produceval);
317         sched_add_before(node, xor);
318         exchange(node, xor);
319         sched_remove(node);
320
321         return xor;
322 }
323
324 /**
325  * Register a peephole optimisation function.
326  */
327 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) {
328         assert(op->ops.generic == NULL);
329         op->ops.generic = (void*) func;
330 }
331
332 /* Perform peephole-optimizations. */
333 void ia32_peephole_optimization(ir_graph *irg, ia32_code_gen_t *new_cg)
334 {
335         cg       = new_cg;
336         arch_env = cg->arch_env;
337
338         /* register peephole optimisations */
339         clear_irp_opcodes_generic_func();
340         register_peephole_optimisation(op_ia32_Const, peephole_ia32_Const);
341
342         be_peephole_opt(cg->birg);
343         irg_walk_graph(irg, ia32_peephole_optimize_node, NULL, NULL);
344 }
345
346 /**
347  * Removes node from schedule if it is not used anymore. If irn is a mode_T node
348  * all it's Projs are removed as well.
349  * @param irn  The irn to be removed from schedule
350  */
351 static INLINE void try_kill(ir_node *node)
352 {
353         if(get_irn_mode(node) == mode_T) {
354                 const ir_edge_t *edge, *next;
355                 foreach_out_edge_safe(node, edge, next) {
356                         ir_node *proj = get_edge_src_irn(edge);
357                         try_kill(proj);
358                 }
359         }
360
361         if(get_irn_n_edges(node) != 0)
362                 return;
363
364         if (sched_is_scheduled(node)) {
365                 sched_remove(node);
366         }
367
368         be_kill_node(node);
369 }
370
371 static void optimize_conv_store(ir_node *node)
372 {
373         ir_node *pred;
374         ir_mode *conv_mode;
375         ir_mode *store_mode;
376
377         if(!is_ia32_Store(node) && !is_ia32_Store8Bit(node))
378                 return;
379
380         pred = get_irn_n(node, 2);
381         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
382                 return;
383
384         /* the store only stores the lower bits, so we only need the conv
385          * it it shrinks the mode */
386         conv_mode  = get_ia32_ls_mode(pred);
387         store_mode = get_ia32_ls_mode(node);
388         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(store_mode))
389                 return;
390
391         set_irn_n(node, 2, get_irn_n(pred, 2));
392         if(get_irn_n_edges(pred) == 0) {
393                 be_kill_node(pred);
394         }
395 }
396
397 static void optimize_load_conv(ir_node *node)
398 {
399         ir_node *pred, *predpred;
400         ir_mode *load_mode;
401         ir_mode *conv_mode;
402
403         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
404                 return;
405
406         pred = get_irn_n(node, 2);
407         if(!is_Proj(pred))
408                 return;
409
410         predpred = get_Proj_pred(pred);
411         if(!is_ia32_Load(predpred))
412                 return;
413
414         /* the load is sign extending the upper bits, so we only need the conv
415          * if it shrinks the mode */
416         load_mode = get_ia32_ls_mode(predpred);
417         conv_mode = get_ia32_ls_mode(node);
418         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(load_mode))
419                 return;
420
421         if(get_mode_sign(conv_mode) != get_mode_sign(load_mode)) {
422                 /* change the load if it has only 1 user */
423                 if(get_irn_n_edges(pred) == 1) {
424                         ir_mode *newmode;
425                         if(get_mode_sign(conv_mode)) {
426                                 newmode = find_signed_mode(load_mode);
427                         } else {
428                                 newmode = find_unsigned_mode(load_mode);
429                         }
430                         assert(newmode != NULL);
431                         set_ia32_ls_mode(predpred, newmode);
432                 } else {
433                         /* otherwise we have to keep the conv */
434                         return;
435                 }
436         }
437
438         /* kill the conv */
439         exchange(node, pred);
440 }
441
442 static void optimize_conv_conv(ir_node *node)
443 {
444         ir_node *pred_proj, *pred, *result_conv;
445         ir_mode *pred_mode, *conv_mode;
446
447         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
448                 return;
449
450         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
451         pred_proj = get_irn_n(node, n_ia32_Conv_I2I_val);
452         if(is_Proj(pred_proj))
453                 pred = get_Proj_pred(pred_proj);
454         else
455                 pred = pred_proj;
456
457         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
458                 return;
459
460         /* we know that after a conv, the upper bits are sign extended
461          * so we only need the 2nd conv if it shrinks the mode */
462         conv_mode = get_ia32_ls_mode(node);
463         pred_mode = get_ia32_ls_mode(pred);
464         /* if 2nd conv is smaller then first conv, then we can always take the 2nd
465          * conv */
466         if(get_mode_size_bits(conv_mode) <= get_mode_size_bits(pred_mode)) {
467                 if(get_irn_n_edges(pred_proj) == 1) {
468                         result_conv = pred_proj;
469                         set_ia32_ls_mode(pred, conv_mode);
470
471                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
472                         if (get_mode_size_bits(conv_mode) == 8) {
473                                 set_irn_op(pred, op_ia32_Conv_I2I8Bit);
474                                 set_ia32_in_req_all(pred, get_ia32_in_req_all(node));
475                         }
476                 } else {
477                         /* we don't want to end up with 2 loads, so we better do nothing */
478                         if(get_irn_mode(pred) == mode_T) {
479                                 return;
480                         }
481
482                         result_conv = exact_copy(pred);
483                         set_ia32_ls_mode(result_conv, conv_mode);
484
485                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
486                         if (get_mode_size_bits(conv_mode) == 8) {
487                                 set_irn_op(result_conv, op_ia32_Conv_I2I8Bit);
488                                 set_ia32_in_req_all(result_conv, get_ia32_in_req_all(node));
489                         }
490                 }
491         } else {
492                 /* if both convs have the same sign, then we can take the smaller one */
493                 if(get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
494                         result_conv = pred_proj;
495                 } else {
496                         /* no optimisation possible if smaller conv is sign-extend */
497                         if(mode_is_signed(pred_mode)) {
498                                 return;
499                         }
500                         /* we can take the smaller conv if it is unsigned */
501                         result_conv = pred_proj;
502                 }
503         }
504
505         /* kill the conv */
506         exchange(node, result_conv);
507
508         if(get_irn_n_edges(pred) == 0) {
509                 be_kill_node(pred);
510         }
511         optimize_conv_conv(result_conv);
512 }
513
514 static void optimize_node(ir_node *node, void *env)
515 {
516         (void) env;
517
518         optimize_load_conv(node);
519         optimize_conv_store(node);
520         optimize_conv_conv(node);
521 }
522
523 /**
524  * Performs conv and address mode optimization.
525  */
526 void ia32_optimize_graph(ia32_code_gen_t *cg)
527 {
528         irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg);
529
530         if (cg->dump)
531                 be_dump(cg->irg, "-opt", dump_ir_block_graph_sched);
532 }
533
534 void ia32_init_optimize(void)
535 {
536         FIRM_DBG_REGISTER(dbg, "firm.be.ia32.optimize");
537 }