- fix a conceptual bug in peephole, we need a callback before and after
[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 #include "irprintf.h"
42 #include "error.h"
43
44 #include "../be_t.h"
45 #include "../beabi.h"
46 #include "../benode_t.h"
47 #include "../besched_t.h"
48 #include "../bepeephole.h"
49
50 #include "ia32_new_nodes.h"
51 #include "ia32_optimize.h"
52 #include "bearch_ia32_t.h"
53 #include "gen_ia32_regalloc_if.h"
54 #include "ia32_transform.h"
55 #include "ia32_dbg_stat.h"
56 #include "ia32_util.h"
57
58 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
59
60 static const arch_env_t *arch_env;
61 static ia32_code_gen_t  *cg;
62
63 static void peephole_IncSP_IncSP(ir_node *node);
64
65 #if 0
66 static void peephole_ia32_Store_IncSP_to_push(ir_node *node)
67 {
68         ir_node  *base  = get_irn_n(node, n_ia32_Store_base);
69         ir_node  *index = get_irn_n(node, n_ia32_Store_index);
70         ir_node  *mem   = get_irn_n(node, n_ia32_Store_mem);
71         ir_node  *incsp = base;
72         ir_node  *val;
73         ir_node  *noreg;
74         ir_graph *irg;
75         ir_node  *block;
76         dbg_info *dbgi;
77         ir_mode  *mode;
78         ir_node  *push;
79         ir_node  *proj;
80         int       offset;
81         int       node_offset;
82
83         /* nomem inidicates the store doesn't alias with anything else */
84         if(!is_NoMem(mem))
85                 return;
86
87         /* find an IncSP in front of us, we might have to skip barriers for this */
88         while(is_Proj(incsp)) {
89                 ir_node *proj_pred = get_Proj_pred(incsp);
90                 if(!be_is_Barrier(proj_pred))
91                         return;
92                 incsp = get_irn_n(proj_pred, get_Proj_proj(incsp));
93         }
94         if(!be_is_IncSP(incsp))
95                 return;
96
97         peephole_IncSP_IncSP(incsp);
98
99         /* must be in the same block */
100         if(get_nodes_block(incsp) != get_nodes_block(node))
101                 return;
102
103         if(!is_ia32_NoReg_GP(index) || get_ia32_am_sc(node) != NULL) {
104                 panic("Invalid storeAM found (%+F)", node);
105         }
106
107         /* we should be the store to the end of the stackspace */
108         offset      = be_get_IncSP_offset(incsp);
109         mode        = get_ia32_ls_mode(node);
110         node_offset = get_ia32_am_offs_int(node);
111         if(node_offset != offset - get_mode_size_bytes(mode))
112                 return;
113
114         /* we can use a push instead of the store */
115         irg   = current_ir_graph;
116         block = get_nodes_block(node);
117         dbgi  = get_irn_dbg_info(node);
118         noreg = ia32_new_NoReg_gp(cg);
119         base  = be_get_IncSP_pred(incsp);
120         val   = get_irn_n(node, n_ia32_Store_val);
121         push  = new_rd_ia32_Push(dbgi, irg, block, noreg, noreg, mem, base, val);
122
123         proj  = new_r_Proj(irg, block, push, mode_M, pn_ia32_Push_M);
124
125         be_set_IncSP_offset(incsp, offset - get_mode_size_bytes(mode));
126
127         sched_add_before(node, push);
128         sched_remove(node);
129
130         be_peephole_before_exchange(node, proj);
131         exchange(node, proj);
132         be_peephole_after_exchange(proj);
133 }
134
135 static void peephole_ia32_Store(ir_node *node)
136 {
137         peephole_ia32_Store_IncSP_to_push(node);
138 }
139 #endif
140
141 // only optimize up to 48 stores behind IncSPs
142 #define MAXPUSH_OPTIMIZE        48
143
144 /**
145  * Tries to create pushs from IncSP,Store combinations
146  */
147 static void peephole_IncSP_Store_to_push(ir_node *irn)
148 {
149         int i;
150         int offset;
151         ir_node *node;
152         ir_node *stores[MAXPUSH_OPTIMIZE];
153         ir_node *block = get_nodes_block(irn);
154         ir_graph *irg = cg->irg;
155         ir_node *curr_sp;
156         ir_mode *spmode = get_irn_mode(irn);
157
158         memset(stores, 0, sizeof(stores));
159
160         assert(be_is_IncSP(irn));
161
162         offset = be_get_IncSP_offset(irn);
163         if(offset < 4)
164                 return;
165
166         /*
167          * We first walk the schedule after the IncSP node as long as we find
168          * suitable stores that could be transformed to a push.
169          * We save them into the stores array which is sorted by the frame offset/4
170          * attached to the node
171          */
172         for(node = sched_next(irn); !sched_is_end(node); node = sched_next(node)) {
173                 ir_node *mem;
174                 int offset;
175                 int storeslot;
176
177                 // it has to be a store
178                 if(!is_ia32_Store(node))
179                         break;
180
181                 // it has to use our sp value
182                 if(get_irn_n(node, n_ia32_base) != irn)
183                         continue;
184                 // store has to be attached to NoMem
185                 mem = get_irn_n(node, n_ia32_mem);
186                 if(!is_NoMem(mem)) {
187                         continue;
188                 }
189
190                 /* unfortunately we can't support the full AMs possible for push at the
191                  * moment. TODO: fix this */
192                 if(get_ia32_am_scale(node) > 0 || !is_ia32_NoReg_GP(get_irn_n(node, n_ia32_index)))
193                         break;
194
195                 offset = get_ia32_am_offs_int(node);
196
197                 storeslot = offset / 4;
198                 if(storeslot >= MAXPUSH_OPTIMIZE)
199                         continue;
200
201                 // storing into the same slot twice is bad (and shouldn't happen...)
202                 if(stores[storeslot] != NULL)
203                         break;
204
205                 // storing at half-slots is bad
206                 if(offset % 4 != 0)
207                         break;
208
209                 stores[storeslot] = node;
210         }
211
212         curr_sp = be_get_IncSP_pred(irn);
213
214         // walk the stores in inverse order and create pushs for them
215         i = (offset / 4) - 1;
216         if(i >= MAXPUSH_OPTIMIZE) {
217                 i = MAXPUSH_OPTIMIZE - 1;
218         }
219
220         for( ; i >= 0; --i) {
221                 const arch_register_t *spreg;
222                 ir_node *push;
223                 ir_node *val, *mem, *mem_proj;
224                 ir_node *store = stores[i];
225                 ir_node *noreg = ia32_new_NoReg_gp(cg);
226
227                 if(store == NULL || is_Bad(store))
228                         break;
229
230                 val = get_irn_n(store, n_ia32_unary_op);
231                 mem = get_irn_n(store, n_ia32_mem);
232                 spreg = arch_get_irn_register(cg->arch_env, curr_sp);
233
234                 push = new_rd_ia32_Push(get_irn_dbg_info(store), irg, block, noreg, noreg, mem, curr_sp, val);
235
236                 sched_add_before(irn, push);
237
238                 // create stackpointer proj
239                 curr_sp = new_r_Proj(irg, block, push, spmode, pn_ia32_Push_stack);
240                 arch_set_irn_register(cg->arch_env, curr_sp, spreg);
241
242                 // create memory proj
243                 mem_proj = new_r_Proj(irg, block, push, mode_M, pn_ia32_Push_M);
244
245                 // use the memproj now
246                 exchange(store, mem_proj);
247
248                 // we can remove the store now
249                 sched_remove(store);
250
251                 offset -= 4;
252         }
253
254         be_set_IncSP_offset(irn, offset);
255         be_set_IncSP_pred(irn, curr_sp);
256 }
257
258 /**
259  * Tries to optimize two following IncSP.
260  */
261 static void peephole_IncSP_IncSP(ir_node *node)
262 {
263         int      pred_offs;
264         int      curr_offs;
265         int      offs;
266         ir_node *pred = be_get_IncSP_pred(node);
267         ir_node *predpred;
268
269         if(!be_is_IncSP(pred))
270                 return;
271
272         if(get_irn_n_edges(pred) > 1)
273                 return;
274
275         pred_offs = be_get_IncSP_offset(pred);
276         curr_offs = be_get_IncSP_offset(node);
277
278         if(pred_offs == BE_STACK_FRAME_SIZE_EXPAND) {
279                 if(curr_offs != BE_STACK_FRAME_SIZE_SHRINK) {
280                         return;
281                 }
282                 offs = 0;
283         } else if(pred_offs == BE_STACK_FRAME_SIZE_SHRINK) {
284                 if(curr_offs != BE_STACK_FRAME_SIZE_EXPAND) {
285                         return;
286                 }
287                 offs = 0;
288         } else if(curr_offs == BE_STACK_FRAME_SIZE_EXPAND
289                         || curr_offs == BE_STACK_FRAME_SIZE_SHRINK) {
290                 return;
291         } else {
292                 offs = curr_offs + pred_offs;
293         }
294
295         /* add pred offset to ours and remove pred IncSP */
296         be_set_IncSP_offset(node, offs);
297
298         predpred = be_get_IncSP_pred(pred);
299         be_peephole_before_exchange(pred, predpred);
300
301         /* rewire dependency edges */
302         edges_reroute_kind(pred, predpred, EDGE_KIND_DEP, current_ir_graph);
303         be_set_IncSP_pred(node, predpred);
304         sched_remove(pred);
305         be_kill_node(pred);
306
307         be_peephole_after_exchange(predpred);
308 }
309
310 static const arch_register_t *get_free_gp_reg(void)
311 {
312         int i;
313
314         for(i = 0; i < N_ia32_gp_REGS; ++i) {
315                 const arch_register_t *reg = &ia32_gp_regs[i];
316                 if(arch_register_type_is(reg, ignore))
317                         continue;
318
319                 if(be_peephole_get_value(CLASS_ia32_gp, i) == NULL)
320                         return &ia32_gp_regs[i];
321         }
322
323         return NULL;
324 }
325
326 static void peephole_be_IncSP(ir_node *node)
327 {
328         const arch_register_t *esp = &ia32_gp_regs[REG_ESP];
329         const arch_register_t *reg;
330         ir_graph              *irg;
331         dbg_info              *dbgi;
332         ir_node               *block;
333         ir_node               *keep;
334         ir_node               *val;
335         ir_node               *pop;
336         ir_node               *noreg;
337         ir_node               *stack;
338         int                    offset;
339
340         /* first optimize incsp->incsp combinations */
341         peephole_IncSP_IncSP(node);
342
343         /* transform IncSP->Store combinations to Push where possible */
344         peephole_IncSP_Store_to_push(node);
345
346         /* replace IncSP -4 by Pop freereg when possible */
347         offset = be_get_IncSP_offset(node);
348         if(offset != -4)
349                 return;
350
351         if(arch_get_irn_register(arch_env, node) != esp)
352                 return;
353
354         reg = get_free_gp_reg();
355         if(reg == NULL)
356                 return;
357
358         irg   = current_ir_graph;
359         dbgi  = get_irn_dbg_info(node);
360         block = get_nodes_block(node);
361         noreg = ia32_new_NoReg_gp(cg);
362         stack = be_get_IncSP_pred(node);
363         pop   = new_rd_ia32_Pop(dbgi, irg, block, noreg, noreg, new_NoMem(), stack);
364
365         stack = new_r_Proj(irg, block, pop, mode_Iu, pn_ia32_Pop_stack);
366         arch_set_irn_register(arch_env, stack, esp);
367         val   = new_r_Proj(irg, block, pop, mode_Iu, pn_ia32_Pop_res);
368         arch_set_irn_register(arch_env, val, reg);
369
370         sched_add_before(node, pop);
371
372         keep  = sched_next(node);
373         if(!be_is_Keep(keep)) {
374                 ir_node *in[1];
375                 in[0] = val;
376                 keep = be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, in);
377                 sched_add_before(node, keep);
378         } else {
379                 be_Keep_add_node(keep, &ia32_reg_classes[CLASS_ia32_gp], val);
380         }
381
382         be_peephole_before_exchange(node, stack);
383         sched_remove(node);
384         exchange(node, stack);
385         be_peephole_after_exchange(stack);
386 }
387
388 /**
389  * Peephole optimisation for ia32_Const's
390  */
391 static void peephole_ia32_Const(ir_node *node)
392 {
393         const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
394         const arch_register_t       *reg;
395         ir_graph                    *irg = current_ir_graph;
396         ir_node                     *block;
397         dbg_info                    *dbgi;
398         ir_node                     *produceval;
399         ir_node                     *xor;
400         ir_node                     *noreg;
401
402         /* try to transform a mov 0, reg to xor reg reg */
403         if(attr->offset != 0 || attr->symconst != NULL)
404                 return;
405         /* xor destroys the flags, so no-one must be using them */
406         if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
407                 return;
408
409         reg = arch_get_irn_register(arch_env, node);
410         assert(be_peephole_get_reg_value(reg) == NULL);
411
412         /* create xor(produceval, produceval) */
413         block      = get_nodes_block(node);
414         dbgi       = get_irn_dbg_info(node);
415         produceval = new_rd_ia32_ProduceVal(dbgi, irg, block);
416         arch_set_irn_register(arch_env, produceval, reg);
417
418         noreg = ia32_new_NoReg_gp(cg);
419         xor   = new_rd_ia32_Xor(dbgi, irg, block, noreg, noreg, new_NoMem(),
420                                 produceval, produceval);
421         arch_set_irn_register(arch_env, xor, reg);
422
423         sched_add_before(node, produceval);
424         sched_add_before(node, xor);
425
426         be_peephole_before_exchange(node, xor);
427         exchange(node, xor);
428         sched_remove(node);
429         be_peephole_after_exchange(xor);
430 }
431
432 static INLINE int is_noreg(ia32_code_gen_t *cg, const ir_node *node)
433 {
434         return node == cg->noreg_gp;
435 }
436
437 static ir_node *create_immediate_from_int(ia32_code_gen_t *cg, int val)
438 {
439         ir_graph *irg         = current_ir_graph;
440         ir_node  *start_block = get_irg_start_block(irg);
441         ir_node  *immediate   = new_rd_ia32_Immediate(NULL, irg, start_block, NULL,
442                                                       0, val);
443         arch_set_irn_register(cg->arch_env, immediate, &ia32_gp_regs[REG_GP_NOREG]);
444
445         return immediate;
446 }
447
448 static ir_node *create_immediate_from_am(ia32_code_gen_t *cg,
449                                          const ir_node *node)
450 {
451         ir_graph  *irg     = get_irn_irg(node);
452         ir_node   *block   = get_nodes_block(node);
453         int        offset  = get_ia32_am_offs_int(node);
454         int        sc_sign = is_ia32_am_sc_sign(node);
455         ir_entity *entity  = get_ia32_am_sc(node);
456         ir_node   *res;
457
458         res = new_rd_ia32_Immediate(NULL, irg, block, entity, sc_sign, offset);
459         arch_set_irn_register(cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]);
460         return res;
461 }
462
463 static int is_am_one(const ir_node *node)
464 {
465         int        offset  = get_ia32_am_offs_int(node);
466         ir_entity *entity  = get_ia32_am_sc(node);
467
468         return offset == 1 && entity == NULL;
469 }
470
471 static int is_am_minus_one(const ir_node *node)
472 {
473         int        offset  = get_ia32_am_offs_int(node);
474         ir_entity *entity  = get_ia32_am_sc(node);
475
476         return offset == -1 && entity == NULL;
477 }
478
479 /**
480  * Transforms a LEA into an Add or SHL if possible.
481  */
482 static void peephole_ia32_Lea(ir_node *node)
483 {
484         const arch_env_t      *arch_env = cg->arch_env;
485         ir_graph              *irg      = current_ir_graph;
486         ir_node               *base;
487         ir_node               *index;
488         const arch_register_t *base_reg;
489         const arch_register_t *index_reg;
490         const arch_register_t *out_reg;
491         int                    scale;
492         int                    has_immediates;
493         ir_node               *op1;
494         ir_node               *op2;
495         dbg_info              *dbgi;
496         ir_node               *block;
497         ir_node               *res;
498         ir_node               *noreg;
499         ir_node               *nomem;
500
501         assert(is_ia32_Lea(node));
502
503         /* we can only do this if are allowed to globber the flags */
504         if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
505                 return;
506
507         base  = get_irn_n(node, n_ia32_Lea_base);
508         index = get_irn_n(node, n_ia32_Lea_index);
509
510         if(is_noreg(cg, base)) {
511                 base     = NULL;
512                 base_reg = NULL;
513         } else {
514                 base_reg = arch_get_irn_register(arch_env, base);
515         }
516         if(is_noreg(cg, index)) {
517                 index     = NULL;
518                 index_reg = NULL;
519         } else {
520                 index_reg = arch_get_irn_register(arch_env, index);
521         }
522
523         if(base == NULL && index == NULL) {
524                 /* we shouldn't construct these in the first place... */
525 #ifdef DEBUG_libfirm
526                 ir_fprintf(stderr, "Optimisation warning: found immediate only lea\n");
527 #endif
528                 return;
529         }
530
531         out_reg = arch_get_irn_register(arch_env, node);
532         scale   = get_ia32_am_scale(node);
533         assert(!is_ia32_need_stackent(node) || get_ia32_frame_ent(node) != NULL);
534         /* check if we have immediates values (frame entities should already be
535          * expressed in the offsets) */
536         if(get_ia32_am_offs_int(node) != 0 || get_ia32_am_sc(node) != NULL) {
537                 has_immediates = 1;
538         } else {
539                 has_immediates = 0;
540         }
541
542         /* we can transform leas where the out register is the same as either the
543          * base or index register back to an Add or Shl */
544         if(out_reg == base_reg) {
545                 if(index == NULL) {
546 #ifdef DEBUG_libfirm
547                         if(!has_immediates) {
548                                 ir_fprintf(stderr, "Optimisation warning: found lea which is "
549                                            "just a copy\n");
550                         }
551 #endif
552                         op1 = base;
553                         goto make_add_immediate;
554                 }
555                 if(scale == 0 && !has_immediates) {
556                         op1 = base;
557                         op2 = index;
558                         goto make_add;
559                 }
560                 /* can't create an add */
561                 return;
562         } else if(out_reg == index_reg) {
563                 if(base == NULL) {
564                         if(has_immediates && scale == 0) {
565                                 op1 = index;
566                                 goto make_add_immediate;
567                         } else if(!has_immediates && scale > 0) {
568                                 op1 = index;
569                                 op2 = create_immediate_from_int(cg, scale);
570                                 goto make_shl;
571                         } else if(!has_immediates) {
572 #ifdef DEBUG_libfirm
573                                 ir_fprintf(stderr, "Optimisation warning: found lea which is "
574                                            "just a copy\n");
575 #endif
576                         }
577                 } else if(scale == 0 && !has_immediates) {
578                         op1 = index;
579                         op2 = base;
580                         goto make_add;
581                 }
582                 /* can't create an add */
583                 return;
584         } else {
585                 /* can't create an add */
586                 return;
587         }
588
589 make_add_immediate:
590         if(cg->isa->opt & IA32_OPT_INCDEC) {
591                 if(is_am_one(node)) {
592                         dbgi  = get_irn_dbg_info(node);
593                         block = get_nodes_block(node);
594                         res   = new_rd_ia32_Inc(dbgi, irg, block, op1);
595                         arch_set_irn_register(arch_env, res, out_reg);
596                         goto exchange;
597                 }
598                 if(is_am_minus_one(node)) {
599                         dbgi  = get_irn_dbg_info(node);
600                         block = get_nodes_block(node);
601                         res   = new_rd_ia32_Dec(dbgi, irg, block, op1);
602                         arch_set_irn_register(arch_env, res, out_reg);
603                         goto exchange;
604                 }
605         }
606         op2 = create_immediate_from_am(cg, node);
607
608 make_add:
609         dbgi  = get_irn_dbg_info(node);
610         block = get_nodes_block(node);
611         noreg = ia32_new_NoReg_gp(cg);
612         nomem = new_NoMem();
613         res   = new_rd_ia32_Add(dbgi, irg, block, noreg, noreg, nomem, op1, op2);
614         arch_set_irn_register(arch_env, res, out_reg);
615         set_ia32_commutative(res);
616         goto exchange;
617
618 make_shl:
619         dbgi  = get_irn_dbg_info(node);
620         block = get_nodes_block(node);
621         noreg = ia32_new_NoReg_gp(cg);
622         nomem = new_NoMem();
623         res   = new_rd_ia32_Shl(dbgi, irg, block, op1, op2);
624         arch_set_irn_register(arch_env, res, out_reg);
625         goto exchange;
626
627 exchange:
628         SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, node));
629
630         /* add new ADD/SHL to schedule */
631         DBG_OPT_LEA2ADD(node, res);
632
633         /* exchange the Add and the LEA */
634         be_peephole_before_exchange(node, res);
635         sched_add_before(node, res);
636         sched_remove(node);
637         exchange(node, res);
638         be_peephole_after_exchange(res);
639 }
640
641 /**
642  * Register a peephole optimisation function.
643  */
644 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) {
645         assert(op->ops.generic == NULL);
646         op->ops.generic = (void*) func;
647 }
648
649 /* Perform peephole-optimizations. */
650 void ia32_peephole_optimization(ia32_code_gen_t *new_cg)
651 {
652         cg       = new_cg;
653         arch_env = cg->arch_env;
654
655         /* register peephole optimisations */
656         clear_irp_opcodes_generic_func();
657         register_peephole_optimisation(op_ia32_Const, peephole_ia32_Const);
658         //register_peephole_optimisation(op_ia32_Store, peephole_ia32_Store);
659         register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
660         register_peephole_optimisation(op_ia32_Lea, peephole_ia32_Lea);
661
662         be_peephole_opt(cg->birg);
663 }
664
665 /**
666  * Removes node from schedule if it is not used anymore. If irn is a mode_T node
667  * all it's Projs are removed as well.
668  * @param irn  The irn to be removed from schedule
669  */
670 static INLINE void try_kill(ir_node *node)
671 {
672         if(get_irn_mode(node) == mode_T) {
673                 const ir_edge_t *edge, *next;
674                 foreach_out_edge_safe(node, edge, next) {
675                         ir_node *proj = get_edge_src_irn(edge);
676                         try_kill(proj);
677                 }
678         }
679
680         if(get_irn_n_edges(node) != 0)
681                 return;
682
683         if (sched_is_scheduled(node)) {
684                 sched_remove(node);
685         }
686
687         be_kill_node(node);
688 }
689
690 static void optimize_conv_store(ir_node *node)
691 {
692         ir_node *pred;
693         ir_node *pred_proj;
694         ir_mode *conv_mode;
695         ir_mode *store_mode;
696
697         if(!is_ia32_Store(node) && !is_ia32_Store8Bit(node))
698                 return;
699
700         assert(n_ia32_Store_val == n_ia32_Store8Bit_val);
701         pred_proj = get_irn_n(node, n_ia32_Store_val);
702         if(is_Proj(pred_proj)) {
703                 pred = get_Proj_pred(pred_proj);
704         } else {
705                 pred = pred_proj;
706         }
707         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
708                 return;
709         if(get_ia32_op_type(pred) != ia32_Normal)
710                 return;
711
712         /* the store only stores the lower bits, so we only need the conv
713          * it it shrinks the mode */
714         conv_mode  = get_ia32_ls_mode(pred);
715         store_mode = get_ia32_ls_mode(node);
716         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(store_mode))
717                 return;
718
719         set_irn_n(node, n_ia32_Store_val, get_irn_n(pred, n_ia32_Conv_I2I_val));
720         if(get_irn_n_edges(pred_proj) == 0) {
721                 be_kill_node(pred_proj);
722                 if(pred != pred_proj)
723                         be_kill_node(pred);
724         }
725 }
726
727 static void optimize_load_conv(ir_node *node)
728 {
729         ir_node *pred, *predpred;
730         ir_mode *load_mode;
731         ir_mode *conv_mode;
732
733         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
734                 return;
735
736         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
737         pred = get_irn_n(node, n_ia32_Conv_I2I_val);
738         if(!is_Proj(pred))
739                 return;
740
741         predpred = get_Proj_pred(pred);
742         if(!is_ia32_Load(predpred))
743                 return;
744
745         /* the load is sign extending the upper bits, so we only need the conv
746          * if it shrinks the mode */
747         load_mode = get_ia32_ls_mode(predpred);
748         conv_mode = get_ia32_ls_mode(node);
749         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(load_mode))
750                 return;
751
752         if(get_mode_sign(conv_mode) != get_mode_sign(load_mode)) {
753                 /* change the load if it has only 1 user */
754                 if(get_irn_n_edges(pred) == 1) {
755                         ir_mode *newmode;
756                         if(get_mode_sign(conv_mode)) {
757                                 newmode = find_signed_mode(load_mode);
758                         } else {
759                                 newmode = find_unsigned_mode(load_mode);
760                         }
761                         assert(newmode != NULL);
762                         set_ia32_ls_mode(predpred, newmode);
763                 } else {
764                         /* otherwise we have to keep the conv */
765                         return;
766                 }
767         }
768
769         /* kill the conv */
770         exchange(node, pred);
771 }
772
773 static void optimize_conv_conv(ir_node *node)
774 {
775         ir_node *pred_proj, *pred, *result_conv;
776         ir_mode *pred_mode, *conv_mode;
777         int      conv_mode_bits;
778         int      pred_mode_bits;
779
780         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
781                 return;
782
783         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
784         pred_proj = get_irn_n(node, n_ia32_Conv_I2I_val);
785         if(is_Proj(pred_proj))
786                 pred = get_Proj_pred(pred_proj);
787         else
788                 pred = pred_proj;
789
790         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
791                 return;
792
793         /* we know that after a conv, the upper bits are sign extended
794          * so we only need the 2nd conv if it shrinks the mode */
795         conv_mode      = get_ia32_ls_mode(node);
796         conv_mode_bits = get_mode_size_bits(conv_mode);
797         pred_mode      = get_ia32_ls_mode(pred);
798         pred_mode_bits = get_mode_size_bits(pred_mode);
799
800         if(conv_mode_bits == pred_mode_bits
801                         && get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
802                 result_conv = pred_proj;
803         } else if(conv_mode_bits <= pred_mode_bits) {
804                 /* if 2nd conv is smaller then first conv, then we can always take the
805                  * 2nd conv */
806                 if(get_irn_n_edges(pred_proj) == 1) {
807                         result_conv = pred_proj;
808                         set_ia32_ls_mode(pred, conv_mode);
809
810                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
811                         if (get_mode_size_bits(conv_mode) == 8) {
812                                 set_irn_op(pred, op_ia32_Conv_I2I8Bit);
813                                 set_ia32_in_req_all(pred, get_ia32_in_req_all(node));
814                         }
815                 } else {
816                         /* we don't want to end up with 2 loads, so we better do nothing */
817                         if(get_irn_mode(pred) == mode_T) {
818                                 return;
819                         }
820
821                         result_conv = exact_copy(pred);
822                         set_ia32_ls_mode(result_conv, conv_mode);
823
824                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
825                         if (get_mode_size_bits(conv_mode) == 8) {
826                                 set_irn_op(result_conv, op_ia32_Conv_I2I8Bit);
827                                 set_ia32_in_req_all(result_conv, get_ia32_in_req_all(node));
828                         }
829                 }
830         } else {
831                 /* if both convs have the same sign, then we can take the smaller one */
832                 if(get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
833                         result_conv = pred_proj;
834                 } else {
835                         /* no optimisation possible if smaller conv is sign-extend */
836                         if(mode_is_signed(pred_mode)) {
837                                 return;
838                         }
839                         /* we can take the smaller conv if it is unsigned */
840                         result_conv = pred_proj;
841                 }
842         }
843
844         /* kill the conv */
845         exchange(node, result_conv);
846
847         if(get_irn_n_edges(pred_proj) == 0) {
848                 be_kill_node(pred_proj);
849                 if(pred != pred_proj)
850                         be_kill_node(pred);
851         }
852         optimize_conv_conv(result_conv);
853 }
854
855 static void optimize_node(ir_node *node, void *env)
856 {
857         (void) env;
858
859         optimize_load_conv(node);
860         optimize_conv_store(node);
861         optimize_conv_conv(node);
862 }
863
864 /**
865  * Performs conv and address mode optimization.
866  */
867 void ia32_optimize_graph(ia32_code_gen_t *cg)
868 {
869         irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg);
870
871         if (cg->dump)
872                 be_dump(cg->irg, "-opt", dump_ir_block_graph_sched);
873 }
874
875 void ia32_init_optimize(void)
876 {
877         FIRM_DBG_REGISTER(dbg, "firm.be.ia32.optimize");
878 }