Swap the esp and value inputs of ia32_Push (so esp is before val). This is more consi...
[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
278                 if (cg->opt & IA32_OPT_PUSHARGS)
279                         ia32_create_Pushs(node);
280         }
281 }
282
283 /**
284  * Peephole optimisation for ia32_Const's
285  */
286 static ir_node *peephole_ia32_Const(ir_node *node)
287 {
288         const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
289         const arch_register_t       *reg;
290         ir_graph                    *irg = current_ir_graph;
291         ir_node                     *block;
292         dbg_info                    *dbgi;
293         ir_node                     *produceval;
294         ir_node                     *xor;
295         ir_node                     *noreg;
296
297         /* try to transform a mov 0, reg to xor reg reg */
298         if(attr->offset != 0 || attr->symconst != NULL)
299                 return NULL;
300         /* xor destroys the flags, so no-one must be using them */
301         if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
302                 return NULL;
303
304         reg = arch_get_irn_register(arch_env, node);
305         assert(be_peephole_get_reg_value(reg) == NULL);
306
307         /* create xor(produceval, produceval) */
308         block      = get_nodes_block(node);
309         dbgi       = get_irn_dbg_info(node);
310         produceval = new_rd_ia32_ProduceVal(dbgi, irg, block);
311         arch_set_irn_register(arch_env, produceval, reg);
312
313         noreg = ia32_new_NoReg_gp(cg);
314         xor   = new_rd_ia32_Xor(dbgi, irg, block, noreg, noreg, new_NoMem(),
315                                 produceval, produceval);
316         arch_set_irn_register(arch_env, xor, reg);
317
318         sched_add_before(node, produceval);
319         sched_add_before(node, xor);
320         exchange(node, xor);
321         sched_remove(node);
322
323         return xor;
324 }
325
326 /**
327  * Register a peephole optimisation function.
328  */
329 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) {
330         assert(op->ops.generic == NULL);
331         op->ops.generic = (void*) func;
332 }
333
334 /* Perform peephole-optimizations. */
335 void ia32_peephole_optimization(ir_graph *irg, ia32_code_gen_t *new_cg)
336 {
337         cg       = new_cg;
338         arch_env = cg->arch_env;
339
340         /* register peephole optimisations */
341         clear_irp_opcodes_generic_func();
342         register_peephole_optimisation(op_ia32_Const, peephole_ia32_Const);
343
344         be_peephole_opt(cg->birg);
345         irg_walk_graph(irg, ia32_peephole_optimize_node, NULL, NULL);
346 }
347
348 /**
349  * Removes node from schedule if it is not used anymore. If irn is a mode_T node
350  * all it's Projs are removed as well.
351  * @param irn  The irn to be removed from schedule
352  */
353 static INLINE void try_kill(ir_node *node)
354 {
355         if(get_irn_mode(node) == mode_T) {
356                 const ir_edge_t *edge, *next;
357                 foreach_out_edge_safe(node, edge, next) {
358                         ir_node *proj = get_edge_src_irn(edge);
359                         try_kill(proj);
360                 }
361         }
362
363         if(get_irn_n_edges(node) != 0)
364                 return;
365
366         if (sched_is_scheduled(node)) {
367                 sched_remove(node);
368         }
369
370         be_kill_node(node);
371 }
372
373 static void optimize_conv_store(ir_node *node)
374 {
375         ir_node *pred;
376         ir_mode *conv_mode;
377         ir_mode *store_mode;
378
379         if(!is_ia32_Store(node) && !is_ia32_Store8Bit(node))
380                 return;
381
382         pred = get_irn_n(node, 2);
383         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
384                 return;
385
386         /* the store only stores the lower bits, so we only need the conv
387          * it it shrinks the mode */
388         conv_mode  = get_ia32_ls_mode(pred);
389         store_mode = get_ia32_ls_mode(node);
390         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(store_mode))
391                 return;
392
393         set_irn_n(node, 2, get_irn_n(pred, 2));
394         if(get_irn_n_edges(pred) == 0) {
395                 be_kill_node(pred);
396         }
397 }
398
399 static void optimize_load_conv(ir_node *node)
400 {
401         ir_node *pred, *predpred;
402         ir_mode *load_mode;
403         ir_mode *conv_mode;
404
405         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
406                 return;
407
408         pred = get_irn_n(node, 2);
409         if(!is_Proj(pred))
410                 return;
411
412         predpred = get_Proj_pred(pred);
413         if(!is_ia32_Load(predpred))
414                 return;
415
416         /* the load is sign extending the upper bits, so we only need the conv
417          * if it shrinks the mode */
418         load_mode = get_ia32_ls_mode(predpred);
419         conv_mode = get_ia32_ls_mode(node);
420         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(load_mode))
421                 return;
422
423         if(get_mode_sign(conv_mode) != get_mode_sign(load_mode)) {
424                 /* change the load if it has only 1 user */
425                 if(get_irn_n_edges(pred) == 1) {
426                         ir_mode *newmode;
427                         if(get_mode_sign(conv_mode)) {
428                                 newmode = find_signed_mode(load_mode);
429                         } else {
430                                 newmode = find_unsigned_mode(load_mode);
431                         }
432                         assert(newmode != NULL);
433                         set_ia32_ls_mode(predpred, newmode);
434                 } else {
435                         /* otherwise we have to keep the conv */
436                         return;
437                 }
438         }
439
440         /* kill the conv */
441         exchange(node, pred);
442 }
443
444 static void optimize_conv_conv(ir_node *node)
445 {
446         ir_node *pred_proj, *pred, *result_conv;
447         ir_mode *pred_mode, *conv_mode;
448
449         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
450                 return;
451
452         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
453         pred_proj = get_irn_n(node, n_ia32_Conv_I2I_val);
454         if(is_Proj(pred_proj))
455                 pred = get_Proj_pred(pred_proj);
456         else
457                 pred = pred_proj;
458
459         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
460                 return;
461
462         /* we know that after a conv, the upper bits are sign extended
463          * so we only need the 2nd conv if it shrinks the mode */
464         conv_mode = get_ia32_ls_mode(node);
465         pred_mode = get_ia32_ls_mode(pred);
466         /* if 2nd conv is smaller then first conv, then we can always take the 2nd
467          * conv */
468         if(get_mode_size_bits(conv_mode) <= get_mode_size_bits(pred_mode)) {
469                 if(get_irn_n_edges(pred_proj) == 1) {
470                         result_conv = pred_proj;
471                         set_ia32_ls_mode(pred, conv_mode);
472
473                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
474                         if (get_mode_size_bits(conv_mode) == 8) {
475                                 set_irn_op(pred, op_ia32_Conv_I2I8Bit);
476                                 set_ia32_in_req_all(pred, get_ia32_in_req_all(node));
477                         }
478                 } else {
479                         /* TODO: construct syncs/stuff here but we'll probably end up with
480                          * 2 statements anyway */
481                         if(get_irn_mode(pred) == mode_T) {
482                                 return;
483                         }
484
485                         result_conv = exact_copy(pred);
486                         set_ia32_ls_mode(result_conv, conv_mode);
487
488                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
489                         if (get_mode_size_bits(conv_mode) == 8) {
490                                 set_irn_op(result_conv, op_ia32_Conv_I2I8Bit);
491                                 set_ia32_in_req_all(result_conv, get_ia32_in_req_all(node));
492                         }
493                 }
494         } else {
495                 /* if both convs have the same sign, then we can take the smaller one */
496                 if(get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
497                         result_conv = pred_proj;
498                 } else {
499                         /* no optimisation possible if smaller conv is sign-extend */
500                         if(mode_is_signed(pred_mode)) {
501                                 return;
502                         }
503                         /* we can take the smaller conv if it is unsigned */
504                         result_conv = pred_proj;
505                 }
506         }
507
508         /* kill the conv */
509         exchange(node, result_conv);
510
511         if(get_irn_n_edges(pred) == 0) {
512                 be_kill_node(pred);
513         }
514         optimize_conv_conv(result_conv);
515 }
516
517 static void optimize_node(ir_node *node, void *env)
518 {
519         (void) env;
520
521         optimize_load_conv(node);
522         optimize_conv_store(node);
523         optimize_conv_conv(node);
524 }
525
526 /**
527  * Performs conv and address mode optimization.
528  */
529 void ia32_optimize_graph(ia32_code_gen_t *cg)
530 {
531         irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg);
532
533         if (cg->dump)
534                 be_dump(cg->irg, "-opt", dump_ir_block_graph_sched);
535 }
536
537 void ia32_init_optimize(void)
538 {
539         FIRM_DBG_REGISTER(dbg, "firm.be.ia32.optimize");
540 }