fixed some bugs in the pop generation, still not all
[libfirm] / ir / be / ia32 / ia32_optimize.c
1 /*
2  * Copyright (C) 1995-2008 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 #include "ia32_architecture.h"
58
59 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
60
61 static const arch_env_t *arch_env;
62 static ia32_code_gen_t  *cg;
63
64 /**
65  * Returns non-zero if the given node produces
66  * a zero flag.
67  *
68  * @param node  the node to check
69  * @param pn    if >= 0, the projection number of the used result
70  */
71 static int produces_zero_flag(ir_node *node, int pn)
72 {
73         ir_node                     *count;
74         const ia32_immediate_attr_t *imm_attr;
75
76         if (!is_ia32_irn(node))
77                 return 0;
78
79         if (pn >= 0) {
80                 if (pn != pn_ia32_res)
81                         return 0;
82         }
83
84         switch (get_ia32_irn_opcode(node)) {
85         case iro_ia32_Add:
86         case iro_ia32_Adc:
87         case iro_ia32_And:
88         case iro_ia32_Or:
89         case iro_ia32_Xor:
90         case iro_ia32_Sub:
91         case iro_ia32_Sbb:
92         case iro_ia32_Neg:
93         case iro_ia32_Inc:
94         case iro_ia32_Dec:
95                 return 1;
96
97         case iro_ia32_ShlD:
98         case iro_ia32_ShrD:
99         case iro_ia32_Shl:
100         case iro_ia32_Shr:
101         case iro_ia32_Sar:
102                 assert(n_ia32_ShlD_count == n_ia32_ShrD_count);
103                 assert(n_ia32_Shl_count == n_ia32_Shr_count
104                                 && n_ia32_Shl_count == n_ia32_Sar_count);
105                 if (is_ia32_ShlD(node) || is_ia32_ShrD(node)) {
106                         count = get_irn_n(node, n_ia32_ShlD_count);
107                 } else {
108                         count = get_irn_n(node, n_ia32_Shl_count);
109                 }
110                 /* when shift count is zero the flags are not affected, so we can only
111                  * do this for constants != 0 */
112                 if (!is_ia32_Immediate(count))
113                         return 0;
114
115                 imm_attr = get_ia32_immediate_attr_const(count);
116                 if (imm_attr->symconst != NULL)
117                         return 0;
118                 if ((imm_attr->offset & 0x1f) == 0)
119                         return 0;
120                 return 1;
121
122         default:
123                 break;
124         }
125         return 0;
126 }
127
128 /**
129  * If the given node has not mode_T, creates a mode_T version (with a result Proj).
130  *
131  * @param node  the node to change
132  *
133  * @return the new mode_T node (if the mode was changed) or node itself
134  */
135 static ir_node *turn_into_mode_t(ir_node *node)
136 {
137         ir_node               *block;
138         ir_node               *res_proj;
139         ir_node               *new_node;
140         const arch_register_t *reg;
141
142         if(get_irn_mode(node) == mode_T)
143                 return node;
144
145         assert(get_irn_mode(node) == mode_Iu);
146
147         new_node = exact_copy(node);
148         set_irn_mode(new_node, mode_T);
149
150         block    = get_nodes_block(new_node);
151         res_proj = new_r_Proj(current_ir_graph, block, new_node, mode_Iu,
152                               pn_ia32_res);
153
154         reg = arch_get_irn_register(arch_env, node);
155         arch_set_irn_register(arch_env, res_proj, reg);
156
157         be_peephole_before_exchange(node, res_proj);
158         sched_add_before(node, new_node);
159         sched_remove(node);
160         exchange(node, res_proj);
161         be_peephole_after_exchange(res_proj);
162
163         return new_node;
164 }
165
166 /**
167  * Peephole optimization for Test instructions.
168  * We can remove the Test, if a zero flags was produced which is still
169  * live.
170  */
171 static void peephole_ia32_Test(ir_node *node)
172 {
173         ir_node         *left  = get_irn_n(node, n_ia32_Test_left);
174         ir_node         *right = get_irn_n(node, n_ia32_Test_right);
175         ir_node         *flags_proj;
176         ir_node         *block;
177         ir_mode         *flags_mode;
178         int              pn    = -1;
179         ir_node         *schedpoint;
180         const ir_edge_t *edge;
181
182         assert(n_ia32_Test_left == n_ia32_Test8Bit_left
183                         && n_ia32_Test_right == n_ia32_Test8Bit_right);
184
185         /* we need a test for 0 */
186         if(left != right)
187                 return;
188
189         block = get_nodes_block(node);
190         if(get_nodes_block(left) != block)
191                 return;
192
193         if(is_Proj(left)) {
194                 pn   = get_Proj_proj(left);
195                 left = get_Proj_pred(left);
196         }
197
198         /* happens rarely, but if it does code will panic' */
199         if (is_ia32_Unknown_GP(left))
200                 return;
201
202         /* walk schedule up and abort when we find left or some other node destroys
203            the flags */
204         schedpoint = sched_prev(node);
205         while(schedpoint != left) {
206                 schedpoint = sched_prev(schedpoint);
207                 if(arch_irn_is(arch_env, schedpoint, modify_flags))
208                         return;
209                 if(schedpoint == block)
210                         panic("couldn't find left");
211         }
212
213         /* make sure only Lg/Eq tests are used */
214         foreach_out_edge(node, edge) {
215                 ir_node *user = get_edge_src_irn(edge);
216                 int      pnc  = get_ia32_condcode(user);
217
218                 if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) {
219                         return;
220                 }
221         }
222
223         if(!produces_zero_flag(left, pn))
224                 return;
225
226         left = turn_into_mode_t(left);
227
228         flags_mode = ia32_reg_classes[CLASS_ia32_flags].mode;
229         flags_proj = new_r_Proj(current_ir_graph, block, left, flags_mode,
230                                 pn_ia32_flags);
231         arch_set_irn_register(arch_env, flags_proj, &ia32_flags_regs[REG_EFLAGS]);
232
233         assert(get_irn_mode(node) != mode_T);
234
235         be_peephole_before_exchange(node, flags_proj);
236         exchange(node, flags_proj);
237         sched_remove(node);
238         be_peephole_after_exchange(flags_proj);
239 }
240
241 /**
242  * AMD Athlon works faster when RET is not destination of
243  * conditional jump or directly preceded by other jump instruction.
244  * Can be avoided by placing a Rep prefix before the return.
245  */
246 static void peephole_ia32_Return(ir_node *node) {
247         ir_node *block, *irn;
248
249         if (!ia32_cg_config.use_pad_return)
250                 return;
251
252         block = get_nodes_block(node);
253
254         if (get_Block_n_cfgpreds(block) == 1) {
255                 ir_node *pred = get_Block_cfgpred(block, 0);
256
257                 if (is_Jmp(pred)) {
258                         /* The block of the return has only one predecessor,
259                            which jumps directly to this block.
260                            This jump will be encoded as a fall through, so we
261                            ignore it here.
262                            However, the predecessor might be empty, so it must be
263                            ensured that empty blocks are gone away ... */
264                         return;
265                 }
266         }
267
268         /* check if this return is the first on the block */
269         sched_foreach_reverse_from(node, irn) {
270                 switch (get_irn_opcode(irn)) {
271                 case beo_Return:
272                         /* the return node itself, ignore */
273                         continue;
274                 case beo_Barrier:
275                         /* ignore the barrier, no code generated */
276                         continue;
277                 case beo_IncSP:
278                         /* arg, IncSP 0 nodes might occur, ignore these */
279                         if (be_get_IncSP_offset(irn) == 0)
280                                 continue;
281                         return;
282                 case iro_Phi:
283                         continue;
284                 default:
285                         return;
286                 }
287         }
288         /* yep, return is the first real instruction in this block */
289 #if 0
290         {
291                 /* add an rep prefix to the return */
292                 ir_node *rep = new_rd_ia32_RepPrefix(get_irn_dbg_info(node), current_ir_graph, block);
293                 keep_alive(rep);
294                 sched_add_before(node, rep);
295         }
296 #else
297         /* ensure, that the 3 byte return is generated */
298         be_Return_set_emit_pop(node, 1);
299 #endif
300 }
301
302 /* only optimize up to 48 stores behind IncSPs */
303 #define MAXPUSH_OPTIMIZE        48
304
305 /**
306  * Tries to create Push's from IncSP, Store combinations.
307  * The Stores are replaced by Push's, the IncSP is modified
308  * (possibly into IncSP 0, but not removed).
309  */
310 static void peephole_IncSP_Store_to_push(ir_node *irn)
311 {
312         int      i, maxslot, inc_ofs;
313         ir_node  *node;
314         ir_node  *stores[MAXPUSH_OPTIMIZE];
315         ir_node  *block;
316         ir_graph *irg;
317         ir_node  *curr_sp;
318         ir_mode  *spmode;
319
320         memset(stores, 0, sizeof(stores));
321
322         assert(be_is_IncSP(irn));
323
324         inc_ofs = be_get_IncSP_offset(irn);
325         if (inc_ofs < 4)
326                 return;
327
328         /*
329          * We first walk the schedule after the IncSP node as long as we find
330          * suitable Stores that could be transformed to a Push.
331          * We save them into the stores array which is sorted by the frame offset/4
332          * attached to the node
333          */
334         maxslot = -1;
335         for (node = sched_next(irn); !sched_is_end(node); node = sched_next(node)) {
336                 ir_node *mem;
337                 int offset;
338                 int storeslot;
339
340                 /* it has to be a Store */
341                 if (!is_ia32_Store(node))
342                         break;
343
344                 /* it has to use our sp value */
345                 if (get_irn_n(node, n_ia32_base) != irn)
346                         continue;
347                 /* Store has to be attached to NoMem */
348                 mem = get_irn_n(node, n_ia32_mem);
349                 if (!is_NoMem(mem))
350                         continue;
351
352                 /* unfortunately we can't support the full AMs possible for push at the
353                  * moment. TODO: fix this */
354                 if (get_ia32_am_scale(node) > 0 || !is_ia32_NoReg_GP(get_irn_n(node, n_ia32_index)))
355                         break;
356
357                 offset = get_ia32_am_offs_int(node);
358                 /* we should NEVER access uninitialized stack BELOW the current SP */
359                 assert(offset >= 0);
360
361                 offset = inc_ofs - 4 - offset;
362
363                 /* storing at half-slots is bad */
364                 if ((offset & 3) != 0)
365                         break;
366
367                 if (offset < 0 || offset >= MAXPUSH_OPTIMIZE * 4)
368                         continue;
369                 storeslot = offset >> 2;
370
371                 /* storing into the same slot twice is bad (and shouldn't happen...) */
372                 if (stores[storeslot] != NULL)
373                         break;
374
375                 stores[storeslot] = node;
376                 if (storeslot > maxslot)
377                         maxslot = storeslot;
378         }
379
380         curr_sp = be_get_IncSP_pred(irn);
381
382         /* walk through the Stores and create Pushs for them */
383         block  = get_nodes_block(irn);
384         spmode = get_irn_mode(irn);
385         irg    = cg->irg;
386         for (i = 0; i <= maxslot; ++i) {
387                 const arch_register_t *spreg;
388                 ir_node *push;
389                 ir_node *val, *mem, *mem_proj;
390                 ir_node *store = stores[i];
391                 ir_node *noreg = ia32_new_NoReg_gp(cg);
392
393                 if (store == NULL)
394                         break;
395
396                 val = get_irn_n(store, n_ia32_unary_op);
397                 mem = get_irn_n(store, n_ia32_mem);
398                 spreg = arch_get_irn_register(cg->arch_env, curr_sp);
399
400                 push = new_rd_ia32_Push(get_irn_dbg_info(store), irg, block, noreg, noreg, mem, val, curr_sp);
401
402                 sched_add_before(irn, push);
403
404                 /* create stackpointer Proj */
405                 curr_sp = new_r_Proj(irg, block, push, spmode, pn_ia32_Push_stack);
406                 arch_set_irn_register(cg->arch_env, curr_sp, spreg);
407
408                 /* create memory Proj */
409                 mem_proj = new_r_Proj(irg, block, push, mode_M, pn_ia32_Push_M);
410
411                 /* use the memproj now */
412                 exchange(store, mem_proj);
413
414                 /* we can remove the Store now */
415                 sched_remove(store);
416
417                 inc_ofs -= 4;
418         }
419
420         be_set_IncSP_offset(irn, inc_ofs);
421         be_set_IncSP_pred(irn, curr_sp);
422 }
423
424 /**
425  * Tries to create Pops from Load, IncSP combinations.
426  * The Loads are replaced by Pops, the IncSP is modified
427  * (possibly into IncSP 0, but not removed).
428  */
429 static void peephole_Load_IncSP_to_pop(ir_node *irn)
430 {
431         const arch_register_t *esp = &ia32_gp_regs[REG_ESP];
432         int      i, maxslot, inc_ofs, ofs;
433         ir_node  *node, *pred_sp, *block;
434         ir_node  *loads[MAXPUSH_OPTIMIZE];
435         ir_graph *irg;
436         unsigned regmask = 0;
437         unsigned copymask = ~0;
438
439         memset(loads, 0, sizeof(loads));
440         assert(be_is_IncSP(irn));
441
442         inc_ofs = -be_get_IncSP_offset(irn);
443         if (inc_ofs < 4)
444                 return;
445
446         /*
447          * We first walk the schedule before the IncSP node as long as we find
448          * suitable Loads that could be transformed to a Pop.
449          * We save them into the stores array which is sorted by the frame offset/4
450          * attached to the node
451          */
452         maxslot = -1;
453         pred_sp = be_get_IncSP_pred(irn);
454         for (node = sched_prev(irn); !sched_is_end(node); node = sched_prev(node)) {
455                 ir_node *mem;
456                 int offset;
457                 int loadslot;
458                 const arch_register_t *sreg, *dreg;
459
460                 /* it has to be a Load */
461                 if (!is_ia32_Load(node)) {
462                         if (be_is_Copy(node)) {
463                                 if (get_irn_mode(node) != mode_Iu) {
464                                         /* not a GP copy, ignore */
465                                         continue;
466                                 }
467                                 dreg = arch_get_irn_register(arch_env, node);
468                                 sreg = arch_get_irn_register(arch_env, be_get_Copy_op(node));
469                                 if (regmask & copymask & (1 << sreg->index)) {
470                                         break;
471                                 }
472                                 if (regmask & copymask & (1 << dreg->index)) {
473                                         break;
474                                 }
475                                 /* we CAN skip Copies if neither the destination nor the source
476                                  * is not in our regmask, ie none of our future Pop will overwrite it */
477                                 regmask |= (1 << dreg->index) | (1 << sreg->index);
478                                 copymask &= ~((1 << dreg->index) | (1 << sreg->index));
479                                 continue;
480                         }
481                         break;
482                 }
483
484                 /* we can handle only GP loads */
485                 if (get_ia32_ls_mode(node) != mode_Iu)
486                         continue;
487
488                 /* it has to use our predecessor sp value */
489                 if (get_irn_n(node, n_ia32_base) != pred_sp)
490                         continue;
491                 /* Load has to be attached to Spill-Mem */
492                 mem = skip_Proj(get_irn_n(node, n_ia32_mem));
493                 if (!is_Phi(mem) && !is_ia32_Store(mem) && !is_ia32_Push(mem))
494                         continue;
495
496                 /* should have NO index */
497                 if (get_ia32_am_scale(node) > 0 || !is_ia32_NoReg_GP(get_irn_n(node, n_ia32_index)))
498                         break;
499
500                 offset = get_ia32_am_offs_int(node);
501                 /* we should NEVER access uninitialized stack BELOW the current SP */
502                 assert(offset >= 0);
503
504                 /* storing at half-slots is bad */
505                 if ((offset & 3) != 0)
506                         break;
507
508                 if (offset < 0 || offset >= MAXPUSH_OPTIMIZE * 4)
509                         continue;
510                 /* ignore those outside the possible windows */
511                 if (offset > inc_ofs - 4)
512                         continue;
513                 loadslot = offset >> 2;
514
515                 /* loading from the same slot twice is bad (and shouldn't happen...) */
516                 if (loads[loadslot] != NULL)
517                         break;
518
519                 dreg = arch_get_irn_register(arch_env, node);
520                 if (regmask & (1 << dreg->index)) {
521                         /* this register is already used */
522                         break;
523                 }
524                 regmask |= 1 << dreg->index;
525
526                 loads[loadslot] = node;
527                 if (loadslot > maxslot)
528                         maxslot = loadslot;
529         }
530
531         if (maxslot < 0)
532                 return;
533
534         /* walk through the Loads and create Pops for them */
535         for (i = maxslot; i >= 0; --i) {
536                 ir_node *load = loads[i];
537
538                 if (load == NULL)
539                         break;
540         }
541         ofs = inc_ofs - (maxslot + 1) * 4;
542         inc_ofs = (i+1) * 4;
543
544         /* Should work even WITH this if removed, but crashes SPEC then */
545         if (ofs > 0 || inc_ofs > 0)
546                 return;
547
548         /* create a new IncSP if needed */
549         block = get_nodes_block(irn);
550         irg   = cg->irg;
551         if (inc_ofs > 0) {
552                 pred_sp = be_new_IncSP(esp, irg, block, pred_sp, -inc_ofs, be_get_IncSP_align(irn));
553                 sched_add_before(irn, pred_sp);
554         }
555
556         for (++i; i <= maxslot; ++i) {
557                 ir_node *load = loads[i];
558                 ir_node *mem, *pop;
559                 const ir_edge_t *edge, *tmp;
560                 const arch_register_t *reg;
561
562                 mem = get_irn_n(load, n_ia32_mem);
563                 reg = arch_get_irn_register(arch_env, load);
564
565                 pop = new_rd_ia32_Pop(get_irn_dbg_info(load), irg, block, mem, pred_sp);
566                 arch_set_irn_register(arch_env, pop, reg);
567
568                 /* create stackpointer Proj */
569                 pred_sp = new_r_Proj(irg, block, pop, mode_Iu, pn_ia32_Pop_stack);
570                 arch_set_irn_register(arch_env, pred_sp, esp);
571
572                 sched_add_before(irn, pop);
573
574                 /* rewire now */
575                 foreach_out_edge_safe(load, edge, tmp) {
576                         ir_node *proj = get_edge_src_irn(edge);
577
578                         set_Proj_pred(proj, pop);
579                 }
580
581
582                 /* we can remove the Load now */
583                 sched_remove(load);
584                 kill_node(load);
585         }
586         be_set_IncSP_offset(irn, -ofs);
587         be_set_IncSP_pred(irn, pred_sp);
588
589 }
590
591
592 /**
593  * Find a free GP register if possible, else return NULL.
594  */
595 static const arch_register_t *get_free_gp_reg(void)
596 {
597         int i;
598
599         for(i = 0; i < N_ia32_gp_REGS; ++i) {
600                 const arch_register_t *reg = &ia32_gp_regs[i];
601                 if(arch_register_type_is(reg, ignore))
602                         continue;
603
604                 if(be_peephole_get_value(CLASS_ia32_gp, i) == NULL)
605                         return &ia32_gp_regs[i];
606         }
607
608         return NULL;
609 }
610
611 /**
612  * Creates a Pop instruction before the given schedule point.
613  *
614  * @param dbgi        debug info
615  * @param irg         the graph
616  * @param block       the block
617  * @param stack       the previous stack value
618  * @param schedpoint  the new node is added before this node
619  * @param reg         the register to pop
620  *
621  * @return the new stack value
622  */
623 static ir_node *create_pop(dbg_info *dbgi, ir_graph *irg, ir_node *block,
624                            ir_node *stack, ir_node *schedpoint,
625                            const arch_register_t *reg)
626 {
627         const arch_register_t *esp = &ia32_gp_regs[REG_ESP];
628         ir_node *pop;
629         ir_node *keep;
630         ir_node *val;
631         ir_node *in[1];
632
633         pop   = new_rd_ia32_Pop(dbgi, irg, block, new_NoMem(), stack);
634
635         stack = new_r_Proj(irg, block, pop, mode_Iu, pn_ia32_Pop_stack);
636         arch_set_irn_register(arch_env, stack, esp);
637         val   = new_r_Proj(irg, block, pop, mode_Iu, pn_ia32_Pop_res);
638         arch_set_irn_register(arch_env, val, reg);
639
640         sched_add_before(schedpoint, pop);
641
642         in[0] = val;
643         keep = be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, in);
644         sched_add_before(schedpoint, keep);
645
646         return stack;
647 }
648
649 /**
650  * Creates a Push instruction before the given schedule point.
651  *
652  * @param dbgi        debug info
653  * @param irg         the graph
654  * @param block       the block
655  * @param stack       the previous stack value
656  * @param schedpoint  the new node is added before this node
657  * @param reg         the register to pop
658  *
659  * @return the new stack value
660  */
661 static ir_node *create_push(dbg_info *dbgi, ir_graph *irg, ir_node *block,
662                             ir_node *stack, ir_node *schedpoint,
663                             const arch_register_t *reg)
664 {
665         const arch_register_t *esp = &ia32_gp_regs[REG_ESP];
666         ir_node *noreg, *nomem, *push, *val;
667
668         val  = new_rd_ia32_ProduceVal(NULL, irg, block);
669         arch_set_irn_register(arch_env, val, reg);
670         sched_add_before(schedpoint, val);
671
672         noreg = ia32_new_NoReg_gp(cg);
673         nomem = get_irg_no_mem(irg);
674         push  = new_rd_ia32_Push(dbgi, irg, block, noreg, noreg, nomem, val, stack);
675         sched_add_before(schedpoint, push);
676
677         stack = new_r_Proj(irg, block, push, mode_Iu, pn_ia32_Push_stack);
678         arch_set_irn_register(arch_env, stack, esp);
679
680         return stack;
681 }
682
683 /**
684  * Optimize an IncSp by replacing it with Push/Pop.
685  */
686 static void peephole_be_IncSP(ir_node *node)
687 {
688         const arch_register_t *esp = &ia32_gp_regs[REG_ESP];
689         const arch_register_t *reg;
690         ir_graph              *irg = current_ir_graph;
691         dbg_info              *dbgi;
692         ir_node               *block;
693         ir_node               *stack;
694         int                    offset;
695
696         /* first optimize incsp->incsp combinations */
697         node = be_peephole_IncSP_IncSP(node);
698
699         /* transform IncSP->Store combinations to Push where possible */
700         peephole_IncSP_Store_to_push(node);
701
702         /* transform Load->IncSP combinations to Pop where possible */
703         peephole_Load_IncSP_to_pop(node);
704
705         if (arch_get_irn_register(arch_env, node) != esp)
706                 return;
707
708         /* replace IncSP -4 by Pop freereg when possible */
709         offset = be_get_IncSP_offset(node);
710         if ((offset != -8 || ia32_cg_config.use_add_esp_8) &&
711             (offset != -4 || ia32_cg_config.use_add_esp_4) &&
712             (offset != +4 || ia32_cg_config.use_sub_esp_4) &&
713             (offset != +8 || ia32_cg_config.use_sub_esp_8))
714                 return;
715
716         if (offset < 0) {
717                 /* we need a free register for pop */
718                 reg = get_free_gp_reg();
719                 if (reg == NULL)
720                         return;
721
722                 dbgi  = get_irn_dbg_info(node);
723                 block = get_nodes_block(node);
724                 stack = be_get_IncSP_pred(node);
725
726                 stack = create_pop(dbgi, irg, block, stack, node, reg);
727
728                 if (offset == -8) {
729                         stack = create_pop(dbgi, irg, block, stack, node, reg);
730                 }
731         } else {
732                 dbgi  = get_irn_dbg_info(node);
733                 block = get_nodes_block(node);
734                 stack = be_get_IncSP_pred(node);
735                 reg   = &ia32_gp_regs[REG_EAX];
736
737                 stack = create_push(dbgi, irg, block, stack, node, reg);
738
739                 if (offset == +8) {
740                         stack = create_push(dbgi, irg, block, stack, node, reg);
741                 }
742         }
743
744         be_peephole_before_exchange(node, stack);
745         sched_remove(node);
746         exchange(node, stack);
747         be_peephole_after_exchange(stack);
748 }
749
750 /**
751  * Peephole optimisation for ia32_Const's
752  */
753 static void peephole_ia32_Const(ir_node *node)
754 {
755         const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
756         const arch_register_t       *reg;
757         ir_graph                    *irg = current_ir_graph;
758         ir_node                     *block;
759         dbg_info                    *dbgi;
760         ir_node                     *produceval;
761         ir_node                     *xor;
762         ir_node                     *noreg;
763
764         /* try to transform a mov 0, reg to xor reg reg */
765         if (attr->offset != 0 || attr->symconst != NULL)
766                 return;
767         if (ia32_cg_config.use_mov_0)
768                 return;
769         /* xor destroys the flags, so no-one must be using them */
770         if (be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
771                 return;
772
773         reg = arch_get_irn_register(arch_env, node);
774         assert(be_peephole_get_reg_value(reg) == NULL);
775
776         /* create xor(produceval, produceval) */
777         block      = get_nodes_block(node);
778         dbgi       = get_irn_dbg_info(node);
779         produceval = new_rd_ia32_ProduceVal(dbgi, irg, block);
780         arch_set_irn_register(arch_env, produceval, reg);
781
782         noreg = ia32_new_NoReg_gp(cg);
783         xor   = new_rd_ia32_Xor(dbgi, irg, block, noreg, noreg, new_NoMem(),
784                                 produceval, produceval);
785         arch_set_irn_register(arch_env, xor, reg);
786
787         sched_add_before(node, produceval);
788         sched_add_before(node, xor);
789
790         be_peephole_before_exchange(node, xor);
791         exchange(node, xor);
792         sched_remove(node);
793         be_peephole_after_exchange(xor);
794 }
795
796 static INLINE int is_noreg(ia32_code_gen_t *cg, const ir_node *node)
797 {
798         return node == cg->noreg_gp;
799 }
800
801 static ir_node *create_immediate_from_int(ia32_code_gen_t *cg, int val)
802 {
803         ir_graph *irg         = current_ir_graph;
804         ir_node  *start_block = get_irg_start_block(irg);
805         ir_node  *immediate   = new_rd_ia32_Immediate(NULL, irg, start_block, NULL,
806                                                       0, val);
807         arch_set_irn_register(cg->arch_env, immediate, &ia32_gp_regs[REG_GP_NOREG]);
808
809         return immediate;
810 }
811
812 static ir_node *create_immediate_from_am(ia32_code_gen_t *cg,
813                                          const ir_node *node)
814 {
815         ir_graph  *irg     = get_irn_irg(node);
816         ir_node   *block   = get_nodes_block(node);
817         int        offset  = get_ia32_am_offs_int(node);
818         int        sc_sign = is_ia32_am_sc_sign(node);
819         ir_entity *entity  = get_ia32_am_sc(node);
820         ir_node   *res;
821
822         res = new_rd_ia32_Immediate(NULL, irg, block, entity, sc_sign, offset);
823         arch_set_irn_register(cg->arch_env, res, &ia32_gp_regs[REG_GP_NOREG]);
824         return res;
825 }
826
827 static int is_am_one(const ir_node *node)
828 {
829         int        offset  = get_ia32_am_offs_int(node);
830         ir_entity *entity  = get_ia32_am_sc(node);
831
832         return offset == 1 && entity == NULL;
833 }
834
835 static int is_am_minus_one(const ir_node *node)
836 {
837         int        offset  = get_ia32_am_offs_int(node);
838         ir_entity *entity  = get_ia32_am_sc(node);
839
840         return offset == -1 && entity == NULL;
841 }
842
843 /**
844  * Transforms a LEA into an Add or SHL if possible.
845  */
846 static void peephole_ia32_Lea(ir_node *node)
847 {
848         const arch_env_t      *arch_env = cg->arch_env;
849         ir_graph              *irg      = current_ir_graph;
850         ir_node               *base;
851         ir_node               *index;
852         const arch_register_t *base_reg;
853         const arch_register_t *index_reg;
854         const arch_register_t *out_reg;
855         int                    scale;
856         int                    has_immediates;
857         ir_node               *op1;
858         ir_node               *op2;
859         dbg_info              *dbgi;
860         ir_node               *block;
861         ir_node               *res;
862         ir_node               *noreg;
863         ir_node               *nomem;
864
865         assert(is_ia32_Lea(node));
866
867         /* we can only do this if are allowed to globber the flags */
868         if(be_peephole_get_value(CLASS_ia32_flags, REG_EFLAGS) != NULL)
869                 return;
870
871         base  = get_irn_n(node, n_ia32_Lea_base);
872         index = get_irn_n(node, n_ia32_Lea_index);
873
874         if(is_noreg(cg, base)) {
875                 base     = NULL;
876                 base_reg = NULL;
877         } else {
878                 base_reg = arch_get_irn_register(arch_env, base);
879         }
880         if(is_noreg(cg, index)) {
881                 index     = NULL;
882                 index_reg = NULL;
883         } else {
884                 index_reg = arch_get_irn_register(arch_env, index);
885         }
886
887         if(base == NULL && index == NULL) {
888                 /* we shouldn't construct these in the first place... */
889 #ifdef DEBUG_libfirm
890                 ir_fprintf(stderr, "Optimisation warning: found immediate only lea\n");
891 #endif
892                 return;
893         }
894
895         out_reg = arch_get_irn_register(arch_env, node);
896         scale   = get_ia32_am_scale(node);
897         assert(!is_ia32_need_stackent(node) || get_ia32_frame_ent(node) != NULL);
898         /* check if we have immediates values (frame entities should already be
899          * expressed in the offsets) */
900         if(get_ia32_am_offs_int(node) != 0 || get_ia32_am_sc(node) != NULL) {
901                 has_immediates = 1;
902         } else {
903                 has_immediates = 0;
904         }
905
906         /* we can transform leas where the out register is the same as either the
907          * base or index register back to an Add or Shl */
908         if(out_reg == base_reg) {
909                 if(index == NULL) {
910 #ifdef DEBUG_libfirm
911                         if(!has_immediates) {
912                                 ir_fprintf(stderr, "Optimisation warning: found lea which is "
913                                            "just a copy\n");
914                         }
915 #endif
916                         op1 = base;
917                         goto make_add_immediate;
918                 }
919                 if(scale == 0 && !has_immediates) {
920                         op1 = base;
921                         op2 = index;
922                         goto make_add;
923                 }
924                 /* can't create an add */
925                 return;
926         } else if(out_reg == index_reg) {
927                 if(base == NULL) {
928                         if(has_immediates && scale == 0) {
929                                 op1 = index;
930                                 goto make_add_immediate;
931                         } else if(!has_immediates && scale > 0) {
932                                 op1 = index;
933                                 op2 = create_immediate_from_int(cg, scale);
934                                 goto make_shl;
935                         } else if(!has_immediates) {
936 #ifdef DEBUG_libfirm
937                                 ir_fprintf(stderr, "Optimisation warning: found lea which is "
938                                            "just a copy\n");
939 #endif
940                         }
941                 } else if(scale == 0 && !has_immediates) {
942                         op1 = index;
943                         op2 = base;
944                         goto make_add;
945                 }
946                 /* can't create an add */
947                 return;
948         } else {
949                 /* can't create an add */
950                 return;
951         }
952
953 make_add_immediate:
954         if(ia32_cg_config.use_incdec) {
955                 if(is_am_one(node)) {
956                         dbgi  = get_irn_dbg_info(node);
957                         block = get_nodes_block(node);
958                         res   = new_rd_ia32_Inc(dbgi, irg, block, op1);
959                         arch_set_irn_register(arch_env, res, out_reg);
960                         goto exchange;
961                 }
962                 if(is_am_minus_one(node)) {
963                         dbgi  = get_irn_dbg_info(node);
964                         block = get_nodes_block(node);
965                         res   = new_rd_ia32_Dec(dbgi, irg, block, op1);
966                         arch_set_irn_register(arch_env, res, out_reg);
967                         goto exchange;
968                 }
969         }
970         op2 = create_immediate_from_am(cg, node);
971
972 make_add:
973         dbgi  = get_irn_dbg_info(node);
974         block = get_nodes_block(node);
975         noreg = ia32_new_NoReg_gp(cg);
976         nomem = new_NoMem();
977         res   = new_rd_ia32_Add(dbgi, irg, block, noreg, noreg, nomem, op1, op2);
978         arch_set_irn_register(arch_env, res, out_reg);
979         set_ia32_commutative(res);
980         goto exchange;
981
982 make_shl:
983         dbgi  = get_irn_dbg_info(node);
984         block = get_nodes_block(node);
985         noreg = ia32_new_NoReg_gp(cg);
986         nomem = new_NoMem();
987         res   = new_rd_ia32_Shl(dbgi, irg, block, op1, op2);
988         arch_set_irn_register(arch_env, res, out_reg);
989         goto exchange;
990
991 exchange:
992         SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, node));
993
994         /* add new ADD/SHL to schedule */
995         DBG_OPT_LEA2ADD(node, res);
996
997         /* exchange the Add and the LEA */
998         be_peephole_before_exchange(node, res);
999         sched_add_before(node, res);
1000         sched_remove(node);
1001         exchange(node, res);
1002         be_peephole_after_exchange(res);
1003 }
1004
1005 /**
1006  * Split a Imul mem, imm into a Load mem and Imul reg, imm if possible.
1007  */
1008 static void peephole_ia32_Imul_split(ir_node *imul) {
1009         const ir_node         *right = get_irn_n(imul, n_ia32_IMul_right);
1010         const arch_register_t *reg;
1011         ir_node               *load, *block, *base, *index, *mem, *res, *noreg;
1012         dbg_info              *dbgi;
1013         ir_graph              *irg;
1014
1015         if (! is_ia32_Immediate(right) || get_ia32_op_type(imul) != ia32_AddrModeS) {
1016                 /* no memory, imm form ignore */
1017                 return;
1018         }
1019         /* we need a free register */
1020         reg = get_free_gp_reg();
1021         if (reg == NULL)
1022                 return;
1023
1024         /* fine, we can rebuild it */
1025         dbgi  = get_irn_dbg_info(imul);
1026         block = get_nodes_block(imul);
1027         irg   = current_ir_graph;
1028         base  = get_irn_n(imul, n_ia32_IMul_base);
1029         index = get_irn_n(imul, n_ia32_IMul_index);
1030         mem   = get_irn_n(imul, n_ia32_IMul_mem);
1031         load = new_rd_ia32_Load(dbgi, irg, block, base, index, mem);
1032
1033         /* copy all attributes */
1034         set_irn_pinned(load, get_irn_pinned(imul));
1035         set_ia32_op_type(load, ia32_AddrModeS);
1036         set_ia32_ls_mode(load, get_ia32_ls_mode(imul));
1037
1038         set_ia32_am_scale(load, get_ia32_am_scale(imul));
1039         set_ia32_am_sc(load, get_ia32_am_sc(imul));
1040         set_ia32_am_offs_int(load, get_ia32_am_offs_int(imul));
1041         if (is_ia32_am_sc_sign(imul))
1042                 set_ia32_am_sc_sign(load);
1043         if (is_ia32_use_frame(imul))
1044                 set_ia32_use_frame(load);
1045         set_ia32_frame_ent(load, get_ia32_frame_ent(imul));
1046
1047         sched_add_before(imul, load);
1048
1049         mem = new_rd_Proj(dbgi, irg, block, load, mode_M, pn_ia32_Load_M);
1050         res = new_rd_Proj(dbgi, irg, block, load, mode_Iu, pn_ia32_Load_res);
1051
1052         arch_set_irn_register(arch_env, res, reg);
1053         be_peephole_after_exchange(res);
1054
1055         set_irn_n(imul, n_ia32_IMul_mem, mem);
1056         noreg = get_irn_n(imul, n_ia32_IMul_left);
1057         set_irn_n(imul, n_ia32_IMul_left, res);
1058         set_ia32_op_type(imul, ia32_Normal);
1059 }
1060
1061 /**
1062  * Replace xorps r,r and xorpd r,r by pxor r,r
1063  */
1064 static void peephole_ia32_xZero(ir_node *xor) {
1065         set_irn_op(xor, op_ia32_xPzero);
1066 }
1067
1068 /**
1069  * Register a peephole optimisation function.
1070  */
1071 static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) {
1072         assert(op->ops.generic == NULL);
1073         op->ops.generic = (op_func)func;
1074 }
1075
1076 /* Perform peephole-optimizations. */
1077 void ia32_peephole_optimization(ia32_code_gen_t *new_cg)
1078 {
1079         cg       = new_cg;
1080         arch_env = cg->arch_env;
1081
1082         /* register peephole optimisations */
1083         clear_irp_opcodes_generic_func();
1084         register_peephole_optimisation(op_ia32_Const, peephole_ia32_Const);
1085         register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP);
1086         register_peephole_optimisation(op_ia32_Lea, peephole_ia32_Lea);
1087         register_peephole_optimisation(op_ia32_Test, peephole_ia32_Test);
1088         register_peephole_optimisation(op_ia32_Test8Bit, peephole_ia32_Test);
1089         register_peephole_optimisation(op_be_Return, peephole_ia32_Return);
1090         if (! ia32_cg_config.use_imul_mem_imm32)
1091                 register_peephole_optimisation(op_ia32_IMul, peephole_ia32_Imul_split);
1092         if (ia32_cg_config.use_pxor)
1093                 register_peephole_optimisation(op_ia32_xZero, peephole_ia32_xZero);
1094
1095         be_peephole_opt(cg->birg);
1096 }
1097
1098 /**
1099  * Removes node from schedule if it is not used anymore. If irn is a mode_T node
1100  * all it's Projs are removed as well.
1101  * @param irn  The irn to be removed from schedule
1102  */
1103 static INLINE void try_kill(ir_node *node)
1104 {
1105         if(get_irn_mode(node) == mode_T) {
1106                 const ir_edge_t *edge, *next;
1107                 foreach_out_edge_safe(node, edge, next) {
1108                         ir_node *proj = get_edge_src_irn(edge);
1109                         try_kill(proj);
1110                 }
1111         }
1112
1113         if(get_irn_n_edges(node) != 0)
1114                 return;
1115
1116         if (sched_is_scheduled(node)) {
1117                 sched_remove(node);
1118         }
1119
1120         be_kill_node(node);
1121 }
1122
1123 static void optimize_conv_store(ir_node *node)
1124 {
1125         ir_node *pred;
1126         ir_node *pred_proj;
1127         ir_mode *conv_mode;
1128         ir_mode *store_mode;
1129
1130         if(!is_ia32_Store(node) && !is_ia32_Store8Bit(node))
1131                 return;
1132
1133         assert(n_ia32_Store_val == n_ia32_Store8Bit_val);
1134         pred_proj = get_irn_n(node, n_ia32_Store_val);
1135         if(is_Proj(pred_proj)) {
1136                 pred = get_Proj_pred(pred_proj);
1137         } else {
1138                 pred = pred_proj;
1139         }
1140         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
1141                 return;
1142         if(get_ia32_op_type(pred) != ia32_Normal)
1143                 return;
1144
1145         /* the store only stores the lower bits, so we only need the conv
1146          * it it shrinks the mode */
1147         conv_mode  = get_ia32_ls_mode(pred);
1148         store_mode = get_ia32_ls_mode(node);
1149         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(store_mode))
1150                 return;
1151
1152         set_irn_n(node, n_ia32_Store_val, get_irn_n(pred, n_ia32_Conv_I2I_val));
1153         if(get_irn_n_edges(pred_proj) == 0) {
1154                 be_kill_node(pred_proj);
1155                 if(pred != pred_proj)
1156                         be_kill_node(pred);
1157         }
1158 }
1159
1160 static void optimize_load_conv(ir_node *node)
1161 {
1162         ir_node *pred, *predpred;
1163         ir_mode *load_mode;
1164         ir_mode *conv_mode;
1165
1166         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
1167                 return;
1168
1169         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
1170         pred = get_irn_n(node, n_ia32_Conv_I2I_val);
1171         if(!is_Proj(pred))
1172                 return;
1173
1174         predpred = get_Proj_pred(pred);
1175         if(!is_ia32_Load(predpred))
1176                 return;
1177
1178         /* the load is sign extending the upper bits, so we only need the conv
1179          * if it shrinks the mode */
1180         load_mode = get_ia32_ls_mode(predpred);
1181         conv_mode = get_ia32_ls_mode(node);
1182         if(get_mode_size_bits(conv_mode) < get_mode_size_bits(load_mode))
1183                 return;
1184
1185         if(get_mode_sign(conv_mode) != get_mode_sign(load_mode)) {
1186                 /* change the load if it has only 1 user */
1187                 if(get_irn_n_edges(pred) == 1) {
1188                         ir_mode *newmode;
1189                         if(get_mode_sign(conv_mode)) {
1190                                 newmode = find_signed_mode(load_mode);
1191                         } else {
1192                                 newmode = find_unsigned_mode(load_mode);
1193                         }
1194                         assert(newmode != NULL);
1195                         set_ia32_ls_mode(predpred, newmode);
1196                 } else {
1197                         /* otherwise we have to keep the conv */
1198                         return;
1199                 }
1200         }
1201
1202         /* kill the conv */
1203         exchange(node, pred);
1204 }
1205
1206 static void optimize_conv_conv(ir_node *node)
1207 {
1208         ir_node *pred_proj, *pred, *result_conv;
1209         ir_mode *pred_mode, *conv_mode;
1210         int      conv_mode_bits;
1211         int      pred_mode_bits;
1212
1213         if (!is_ia32_Conv_I2I(node) && !is_ia32_Conv_I2I8Bit(node))
1214                 return;
1215
1216         assert(n_ia32_Conv_I2I_val == n_ia32_Conv_I2I8Bit_val);
1217         pred_proj = get_irn_n(node, n_ia32_Conv_I2I_val);
1218         if(is_Proj(pred_proj))
1219                 pred = get_Proj_pred(pred_proj);
1220         else
1221                 pred = pred_proj;
1222
1223         if(!is_ia32_Conv_I2I(pred) && !is_ia32_Conv_I2I8Bit(pred))
1224                 return;
1225
1226         /* we know that after a conv, the upper bits are sign extended
1227          * so we only need the 2nd conv if it shrinks the mode */
1228         conv_mode      = get_ia32_ls_mode(node);
1229         conv_mode_bits = get_mode_size_bits(conv_mode);
1230         pred_mode      = get_ia32_ls_mode(pred);
1231         pred_mode_bits = get_mode_size_bits(pred_mode);
1232
1233         if(conv_mode_bits == pred_mode_bits
1234                         && get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
1235                 result_conv = pred_proj;
1236         } else if(conv_mode_bits <= pred_mode_bits) {
1237                 /* if 2nd conv is smaller then first conv, then we can always take the
1238                  * 2nd conv */
1239                 if(get_irn_n_edges(pred_proj) == 1) {
1240                         result_conv = pred_proj;
1241                         set_ia32_ls_mode(pred, conv_mode);
1242
1243                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
1244                         if (get_mode_size_bits(conv_mode) == 8) {
1245                                 set_irn_op(pred, op_ia32_Conv_I2I8Bit);
1246                                 set_ia32_in_req_all(pred, get_ia32_in_req_all(node));
1247                         }
1248                 } else {
1249                         /* we don't want to end up with 2 loads, so we better do nothing */
1250                         if(get_irn_mode(pred) == mode_T) {
1251                                 return;
1252                         }
1253
1254                         result_conv = exact_copy(pred);
1255                         set_ia32_ls_mode(result_conv, conv_mode);
1256
1257                         /* Argh:We must change the opcode to 8bit AND copy the register constraints */
1258                         if (get_mode_size_bits(conv_mode) == 8) {
1259                                 set_irn_op(result_conv, op_ia32_Conv_I2I8Bit);
1260                                 set_ia32_in_req_all(result_conv, get_ia32_in_req_all(node));
1261                         }
1262                 }
1263         } else {
1264                 /* if both convs have the same sign, then we can take the smaller one */
1265                 if(get_mode_sign(conv_mode) == get_mode_sign(pred_mode)) {
1266                         result_conv = pred_proj;
1267                 } else {
1268                         /* no optimisation possible if smaller conv is sign-extend */
1269                         if(mode_is_signed(pred_mode)) {
1270                                 return;
1271                         }
1272                         /* we can take the smaller conv if it is unsigned */
1273                         result_conv = pred_proj;
1274                 }
1275         }
1276
1277         /* kill the conv */
1278         exchange(node, result_conv);
1279
1280         if(get_irn_n_edges(pred_proj) == 0) {
1281                 be_kill_node(pred_proj);
1282                 if(pred != pred_proj)
1283                         be_kill_node(pred);
1284         }
1285         optimize_conv_conv(result_conv);
1286 }
1287
1288 static void optimize_node(ir_node *node, void *env)
1289 {
1290         (void) env;
1291
1292         optimize_load_conv(node);
1293         optimize_conv_store(node);
1294         optimize_conv_conv(node);
1295 }
1296
1297 /**
1298  * Performs conv and address mode optimization.
1299  */
1300 void ia32_optimize_graph(ia32_code_gen_t *cg)
1301 {
1302         irg_walk_blkwise_graph(cg->irg, NULL, optimize_node, cg);
1303
1304         if (cg->dump)
1305                 be_dump(cg->irg, "-opt", dump_ir_block_graph_sched);
1306 }
1307
1308 void ia32_init_optimize(void)
1309 {
1310         FIRM_DBG_REGISTER(dbg, "firm.be.ia32.optimize");
1311 }