Improved start sets for blocks with one pred.
[libfirm] / ir / be / ia32 / bearch_ia32.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifdef _WIN32
6 #include <malloc.h>
7 #else
8 #include <alloca.h>
9 #endif
10
11 #include "pseudo_irg.h"
12 #include "irgwalk.h"
13 #include "irprog.h"
14 #include "irprintf.h"
15 #include "iredges_t.h"
16 #include "ircons.h"
17 #include "irgmod.h"
18
19 #include "bitset.h"
20 #include "debug.h"
21
22 #include "../beabi.h"                 /* the general register allocator interface */
23 #include "../benode_t.h"
24 #include "../belower.h"
25 #include "../besched_t.h"
26 #include "bearch_ia32_t.h"
27
28 #include "ia32_new_nodes.h"           /* ia32 nodes interface */
29 #include "gen_ia32_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
30 #include "ia32_gen_decls.h"           /* interface declaration emitter */
31 #include "ia32_transform.h"
32 #include "ia32_emitter.h"
33 #include "ia32_map_regs.h"
34 #include "ia32_optimize.h"
35
36 #define DEBUG_MODULE "firm.be.ia32.isa"
37
38 /* TODO: ugly */
39 static set *cur_reg_set = NULL;
40
41 #undef is_Start
42 #define is_Start(irn) (get_irn_opcode(irn) == iro_Start)
43
44 extern ir_node *be_new_NoReg(ir_graph *irg);
45
46 /**************************************************
47  *                         _ _              _  __
48  *                        | | |            (_)/ _|
49  *  _ __ ___  __ _    __ _| | | ___   ___   _| |_
50  * | '__/ _ \/ _` |  / _` | | |/ _ \ / __| | |  _|
51  * | | |  __/ (_| | | (_| | | | (_) | (__  | | |
52  * |_|  \___|\__, |  \__,_|_|_|\___/ \___| |_|_|
53  *            __/ |
54  *           |___/
55  **************************************************/
56
57 static ir_node *my_skip_proj(const ir_node *n) {
58         while (is_Proj(n))
59                 n = get_Proj_pred(n);
60         return (ir_node *)n;
61 }
62
63 static int is_Call_Proj(const ir_node *n) {
64         if (is_Proj(n)                               &&
65                 is_Proj(get_Proj_pred(n))                &&
66                 get_irn_mode(get_Proj_pred(n)) == mode_T &&
67                 is_ia32_Call(get_Proj_pred(get_Proj_pred(n))))
68         {
69                 return 1;
70         }
71
72         return 0;
73 }
74
75 static int is_Start_Proj(const ir_node *n) {
76         if (is_Proj(n)                               &&
77                 is_Proj(get_Proj_pred(n))                &&
78                 get_irn_mode(get_Proj_pred(n)) == mode_T &&
79                 is_Start(get_Proj_pred(get_Proj_pred(n))))
80         {
81                 return 1;
82         }
83
84         return 0;
85 }
86
87 static int is_P_frame_base_Proj(const ir_node *n) {
88         if (is_Proj(n)                                    &&
89                 is_Start(get_Proj_pred(n)) &&
90                 get_Proj_proj(n) == pn_Start_P_frame_base)
91         {
92                 return 1;
93         }
94
95         return 0;
96 }
97
98 static int is_used_by_Keep(const ir_node *n) {
99         return be_is_Keep(get_edge_src_irn(get_irn_out_edge_first(n)));
100 }
101
102 /**
103  * Return register requirements for an ia32 node.
104  * If the node returns a tuple (mode_T) then the proj's
105  * will be asked for this information.
106  */
107 static const arch_register_req_t *ia32_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
108         const ia32_register_req_t *irn_req;
109         long                       node_pos = pos == -1 ? 0 : pos;
110         ir_mode                   *mode     = get_irn_mode(irn);
111         firm_dbg_module_t         *mod      = firm_dbg_register(DEBUG_MODULE);
112         const ia32_irn_ops_t      *ops      = self;
113
114         if (mode == mode_T || mode == mode_M) {
115                 DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn));
116                 return NULL;
117         }
118
119         DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn));
120
121
122         if (is_Call_Proj(irn) && is_used_by_Keep(irn)) {
123                 if (pos >= 0) {
124                         req = NULL;
125                 }
126                 else {
127                         irn_req = ia32_projnum_reg_req_map[get_Proj_proj(irn)];
128                         memcpy(req, &(irn_req->req), sizeof(*req));
129                 }
130
131                 return req;
132         }
133         else if (is_Start_Proj(irn)) {
134                 irn_req = ops->cg->reg_param_req[get_Proj_proj(irn)];
135                 assert(irn_req && "missing requirement for regparam");
136                 memcpy(req, &(irn_req->req), sizeof(*req));
137                 return req;
138                 //return NULL;
139         }
140         else if (is_Proj(irn)) {
141                 if (pos == -1) {
142                         node_pos = ia32_translate_proj_pos(irn);
143                 }
144                 else {
145                         node_pos = pos;
146                 }
147
148                 irn = my_skip_proj(irn);
149
150                 DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos));
151         }
152
153         if (is_ia32_irn(irn)) {
154                 if (pos >= 0) {
155                         irn_req = get_ia32_in_req(irn, pos);
156                 }
157                 else {
158                         irn_req = get_ia32_out_req(irn, node_pos);
159                 }
160
161                 DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos));
162
163                 memcpy(req, &(irn_req->req), sizeof(*req));
164
165                 if (arch_register_req_is(&(irn_req->req), should_be_same)) {
166                         assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI");
167                         req->other_same = get_irn_n(irn, irn_req->same_pos);
168                 }
169
170                 if (arch_register_req_is(&(irn_req->req), should_be_different)) {
171                         assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI");
172                         req->other_different = get_irn_n(irn, irn_req->different_pos);
173                 }
174         }
175         else {
176                 /* treat Phi like Const with default requirements */
177                 if (is_Phi(irn)) {
178                         DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn));
179                         if (mode_is_float(mode))
180                                 memcpy(req, &(ia32_default_req_ia32_fp.req), sizeof(*req));
181                         else if (mode_is_int(mode) || mode_is_reference(mode))
182                                 memcpy(req, &(ia32_default_req_ia32_gp.req), sizeof(*req));
183                         else if (mode == mode_T || mode == mode_M) {
184                                 DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn));
185                                 return NULL;
186                         }
187                         else
188                                 assert(0 && "unsupported Phi-Mode");
189                 }
190                 else if (is_Start(irn)) {
191                         DB((mod, LEVEL_1, "returning reqs none for ProjX -> Start (%+F )\n", irn));
192                         switch (node_pos) {
193                                 case pn_Start_X_initial_exec:
194                                 case pn_Start_P_value_arg_base:
195                                 case pn_Start_P_globals:
196                                 case pn_Start_P_frame_base:
197                                         memcpy(req, &(ia32_default_req_none.req), sizeof(*req));
198                                         break;
199                                 case pn_Start_T_args:
200                                         assert(0 && "ProjT(pn_Start_T_args) should not be asked");
201                         }
202                 }
203                 else if (get_irn_op(irn) == op_Return && pos > 0) {
204                         DB((mod, LEVEL_1, "returning reqs EAX for %+F\n", irn));
205                         memcpy(req, &(ia32_default_req_ia32_gp_eax.req), sizeof(*req));
206                 }
207                 else {
208                         DB((mod, LEVEL_1, "returning NULL for %+F (not ia32)\n", irn));
209                         req = NULL;
210                 }
211         }
212
213         return req;
214 }
215
216 static void ia32_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) {
217         int pos = 0;
218
219         if (is_Proj(irn)) {
220                 pos = ia32_translate_proj_pos(irn);
221                 irn = my_skip_proj(irn);
222         }
223
224         if (is_ia32_irn(irn)) {
225                 const arch_register_t **slots;
226
227                 slots      = get_ia32_slots(irn);
228                 slots[pos] = reg;
229         }
230         else {
231                 ia32_set_firm_reg(irn, reg, cur_reg_set);
232         }
233 }
234
235 static const arch_register_t *ia32_get_irn_reg(const void *self, const ir_node *irn) {
236         int pos = 0;
237         const arch_register_t *reg = NULL;
238
239         if (is_Proj(irn)) {
240                 pos = ia32_translate_proj_pos(irn);
241                 irn = my_skip_proj(irn);
242         }
243
244         if (is_ia32_irn(irn)) {
245                 const arch_register_t **slots;
246                 slots = get_ia32_slots(irn);
247                 reg   = slots[pos];
248         }
249         else {
250                 reg = ia32_get_firm_reg(irn, cur_reg_set);
251         }
252
253         return reg;
254 }
255
256 static arch_irn_class_t ia32_classify(const void *self, const ir_node *irn) {
257         irn = my_skip_proj(irn);
258         if (is_cfop(irn))
259                 return arch_irn_class_branch;
260         else if (is_ia32_Call(irn))
261                 return arch_irn_class_call;
262         else if (is_ia32_irn(irn))
263                 return arch_irn_class_normal;
264         else
265                 return 0;
266 }
267
268 static arch_irn_flags_t ia32_get_flags(const void *self, const ir_node *irn) {
269         irn = my_skip_proj(irn);
270         if (is_ia32_irn(irn))
271                 return get_ia32_flags(irn);
272         else {
273                 return 0;
274         }
275 }
276
277 /* fill register allocator interface */
278
279 static const arch_irn_ops_if_t ia32_irn_ops_if = {
280         ia32_get_irn_reg_req,
281         ia32_set_irn_reg,
282         ia32_get_irn_reg,
283         ia32_classify,
284         ia32_get_flags
285 };
286
287 ia32_irn_ops_t ia32_irn_ops = {
288         &ia32_irn_ops_if,
289         NULL
290 };
291
292
293
294 /**************************************************
295  *                _                         _  __
296  *               | |                       (_)/ _|
297  *   ___ ___   __| | ___  __ _  ___ _ __    _| |_
298  *  / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \  | |  _|
299  * | (_| (_) | (_| |  __/ (_| |  __/ | | | | | |
300  *  \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
301  *                        __/ |
302  *                       |___/
303  **************************************************/
304
305 /**
306  * Transforms the standard firm graph into
307  * an ia32 firm graph
308  */
309 static void ia32_prepare_graph(void *self) {
310         ia32_code_gen_t *cg = self;
311
312         if (! is_pseudo_ir_graph(cg->irg)) {
313                 irg_walk_blkwise_graph(cg->irg, ia32_place_consts, ia32_transform_node, cg);
314         }
315 }
316
317
318
319 /**
320  * Stack reservation and StackParam lowering.
321  */
322 static void ia32_finish_irg(ir_graph *irg, ia32_code_gen_t *cg) {
323 #if 0
324         firm_dbg_module_t *mod       = cg->mod;
325         ir_node           *frame     = get_irg_frame(irg);
326         ir_node           *end_block = get_irg_end_block(irg);
327         ir_node          **returns, **in, **new_in;
328         ir_node           *stack_reserve, *sched_point;
329         ir_node           *stack_free, *new_ret, *return_block;
330         int                stack_size = 0, i, n_arg;
331         arch_register_t   *stack_reg;
332         tarval            *stack_size_tv;
333         dbg_info          *frame_dbg;
334
335         /* Determine stack register */
336         if (cg->has_alloca) {
337                 stack_reg = &ia32_gp_regs[REG_EBP];
338         }
339         else {
340                 stack_reg = &ia32_gp_regs[REG_ESP];
341         }
342
343         /* If frame is used, then we need to reserve some stackspace. */
344         if (get_irn_n_edges(frame) > 0) {
345                 /* The initial stack reservation. */
346                 stack_size    = get_type_size_bytes(get_irg_frame_type(irg));
347                 frame_dbg     = get_irn_dbg_info(frame);
348                 stack_reserve = new_rd_ia32_Sub_i(frame_dbg, irg, get_nodes_block(frame), new_NoMem(), mode_Is);
349                 stack_size_tv = new_tarval_from_long(stack_size, mode_Is);
350                 set_ia32_Immop_tarval(stack_reserve, stack_size_tv);
351
352                 assert(stack_size && "bOrken stack layout");
353
354                 /* reroute all edges from frame pointer to corrected frame pointer */
355                 edges_reroute(frame, stack_reserve, irg);
356                 set_irn_n(stack_reserve, 0, frame);
357
358                 /* schedule frame pointer */
359                 if (! sched_is_scheduled(frame)) {
360                         sched_add_after(get_irg_start(irg), frame);
361                 }
362
363                 /* set register */
364                 arch_set_irn_register(cg->arch_env, frame, stack_reg);
365                 arch_set_irn_register(cg->arch_env, stack_reserve, stack_reg);
366
367                 /* insert into schedule */
368                 sched_add_after(frame, stack_reserve);
369
370                 /* Free stack for each Return node */
371                 returns = get_Block_cfgpred_arr(end_block);
372                 for (i = 0; i < get_Block_n_cfgpreds(end_block); i++) {
373                         assert(get_irn_opcode(returns[i]) == iro_Return && "cfgpred of endblock is not a return");
374
375                         return_block = get_nodes_block(returns[i]);
376
377                         /* free the stack */
378                         stack_free = new_rd_ia32_Add_i(frame_dbg, irg, return_block, stack_reserve, mode_Is);
379                         set_ia32_Immop_tarval(stack_free, stack_size_tv);
380                         arch_set_irn_register(cg->arch_env, stack_free, stack_reg);
381
382                         DBG((mod, LEVEL_1, "examining %+F, %+F created, block %+F", returns[i], stack_free, return_block));
383
384                         /* get the old Return arguments */
385                         n_arg  = get_Return_n_ress(returns[i]);
386                         in     = get_Return_res_arr(returns[i]);
387                         new_in = alloca((n_arg + 2) * sizeof(new_in[0]));
388
389                         /* copy the old to the new in's */
390                         memcpy(new_in, in, n_arg * sizeof(in[0]));
391                         new_in[n_arg++] = stack_free;
392                         new_in[n_arg++] = get_Return_mem(returns[i]);
393
394                         /* create the new return node */
395                         new_ret = new_rd_ia32_Return(get_irn_dbg_info(returns[i]), irg, return_block, n_arg, new_in);
396
397                         /* In case the return node is the only node in the block, */
398                         /* it is not scheduled, so we need this work-around.      */
399                         if (! sched_is_scheduled(returns[i])) {
400                                 sched_point = return_block;
401                         }
402                         else {
403                                 sched_point = sched_prev(returns[i]);
404                                 sched_remove(returns[i]);
405                         }
406
407                         /* exchange the old return with the new one */
408                         exchange(returns[i], new_ret);
409
410                         DB((mod, LEVEL_1, " ... replaced with %+F\n", new_ret));
411
412                         /* remove the old one from schedule and add the new nodes properly */
413                         sched_add_after(sched_point, new_ret);
414                         sched_add_after(sched_point, stack_free);
415                 }
416         }
417 #endif
418 }
419
420
421
422 /**
423  * Dummy functions for hooks we don't need but which must be filled.
424  */
425 static void ia32_before_sched(void *self) {
426         ia32_code_gen_t *cg = self;
427
428         lower_nodes_before_sched(cg->irg, cg->arch_env);
429 }
430
431 static void ia32_before_ra(void *self) {
432 }
433
434
435 /**
436  * Creates a Store for a Spill
437  */
438 static ir_node *ia32_lower_spill(void *self, ir_node *spill) {
439         ia32_code_gen_t *cg    = self;
440         dbg_info        *dbg   = get_irn_dbg_info(spill);
441         ir_node         *block = get_nodes_block(spill);
442         ir_node         *ptr   = get_irg_frame(cg->irg);
443         ir_node         *val   = be_get_Spill_context(spill);
444         ir_node         *mem   = new_rd_NoMem(cg->irg);
445         ir_node         *noreg = be_new_NoReg(cg->irg);
446         ir_mode         *mode  = get_irn_mode(spill);
447         ir_node         *res;
448         entity          *ent   = be_get_spill_entity(spill);
449         unsigned         offs  = get_entity_offset_bytes(ent);
450         char             buf[64];
451
452         DB((cg->mod, LEVEL_1, "lower_spill: got offset %d for %+F\n", offs, ent));
453
454         res = new_rd_ia32_Store(dbg, cg->irg, block, ptr, noreg, val, mem, mode);
455         snprintf(buf, sizeof(buf), "%d", offs);
456         add_ia32_am_offs(res, buf);
457
458         return res;
459 }
460
461 /**
462  * Create a Load for a Spill
463  */
464 static ir_node *ia32_lower_reload(void *self, ir_node *reload) {
465         ia32_code_gen_t *cg    = self;
466         dbg_info        *dbg   = get_irn_dbg_info(reload);
467         ir_node         *block = get_nodes_block(reload);
468         ir_node         *ptr   = get_irg_frame(cg->irg);
469         ir_mode         *mode  = get_irn_mode(reload);
470         ir_node         *pred  = get_irn_n(reload, 0);
471         ir_node         *noreg = be_new_NoReg(cg->irg);
472         char             buf[64];
473         char            *ofs;
474         ir_node         *res;
475
476         if (be_is_Spill(pred)) {
477                 entity   *ent  = be_get_spill_entity(pred);
478                 unsigned  offs = get_entity_offset_bytes(ent);
479                 DB((cg->mod, LEVEL_1, "lower_reload: got offset %d for %+F\n", offs, ent));
480
481                 snprintf(buf, sizeof(buf), "%d", offs);
482         }
483         else if (is_ia32_Store(pred)) {
484                 ofs = get_ia32_am_offs(pred);
485                 strncpy(buf, ofs, sizeof(buf));
486                 free(ofs);
487         }
488         else {
489                 assert(0 && "unsupported Reload predecessor");
490         }
491
492         res = new_rd_ia32_Load(dbg, cg->irg, block, ptr, noreg, pred, mode);
493         add_ia32_am_offs(res, buf);
494
495         return res;
496 }
497
498 /**
499  * Emits the code, closes the output file and frees
500  * the code generator interface.
501  */
502 static void ia32_codegen(void *self) {
503         ia32_code_gen_t *cg = self;
504         ir_graph       *irg = cg->irg;
505         FILE           *out = cg->out;
506
507         if (cg->emit_decls) {
508                 ia32_gen_decls(cg->out);
509                 cg->emit_decls = 0;
510         }
511
512         ia32_finish_irg(irg, cg);
513         //dump_ir_block_graph_sched(irg, "-finished");
514         ia32_gen_routine(out, irg, cg);
515
516         cur_reg_set = NULL;
517
518         pmap_destroy(cg->tv_ent);
519         pmap_destroy(cg->types);
520
521         /* de-allocate code generator */
522         del_set(cg->reg_set);
523         free(self);
524 }
525
526 static void *ia32_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env);
527
528 static const arch_code_generator_if_t ia32_code_gen_if = {
529         ia32_cg_init,
530         ia32_prepare_graph,
531         ia32_before_sched,   /* before scheduling hook */
532         ia32_before_ra,      /* before register allocation hook */
533         ia32_lower_spill,
534         ia32_lower_reload,
535         ia32_codegen         /* emit && done */
536 };
537
538 /**
539  * Initializes the code generator.
540  */
541 static void *ia32_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env) {
542         ia32_isa_t      *isa = (ia32_isa_t *)arch_env->isa;
543         ia32_code_gen_t *cg  = xmalloc(sizeof(*cg));
544
545         cg->impl       = &ia32_code_gen_if;
546         cg->irg        = irg;
547         cg->reg_set    = new_set(ia32_cmp_irn_reg_assoc, 1024);
548         cg->mod        = firm_dbg_register("firm.be.ia32.cg");
549         cg->out        = F;
550         cg->arch_env   = arch_env;
551         cg->types      = pmap_create();
552         cg->tv_ent     = pmap_create();
553
554         isa->num_codegens++;
555
556         if (isa->num_codegens > 1)
557                 cg->emit_decls = 0;
558         else
559                 cg->emit_decls = 1;
560
561         cur_reg_set = cg->reg_set;
562
563         ia32_irn_ops.cg = cg;
564
565         return (arch_code_generator_t *)cg;
566 }
567
568
569
570 /*****************************************************************
571  *  ____             _                  _   _____  _____
572  * |  _ \           | |                | | |_   _|/ ____|  /\
573  * | |_) | __ _  ___| | _____ _ __   __| |   | | | (___   /  \
574  * |  _ < / _` |/ __| |/ / _ \ '_ \ / _` |   | |  \___ \ / /\ \
575  * | |_) | (_| | (__|   <  __/ | | | (_| |  _| |_ ____) / ____ \
576  * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/    \_\
577  *
578  *****************************************************************/
579
580 static ia32_isa_t ia32_isa = {
581         &ia32_isa_if,
582         &ia32_gp_regs[REG_ESP],
583         &ia32_gp_regs[REG_EBP],
584         -1,
585         0,
586         NULL
587 };
588
589 /**
590  * Initializes the backend ISA.
591  */
592 static void *ia32_init(void) {
593         static int inited = 0;
594         ia32_isa_t *isa   = &ia32_isa;
595
596         if(inited)
597                 return NULL;
598
599         inited = 1;
600
601         isa->reg_projnum_map = new_set(ia32_cmp_reg_projnum_assoc, 1024);
602
603         ia32_register_init(isa);
604         ia32_create_opcodes();
605
606         return isa;
607 }
608
609
610
611 /**
612  * Closes the output file and frees the ISA structure.
613  */
614 static void ia32_done(void *self) {
615         free(self);
616 }
617
618
619
620 static int ia32_get_n_reg_class(const void *self) {
621         return N_CLASSES;
622 }
623
624 static const arch_register_class_t *ia32_get_reg_class(const void *self, int i) {
625         assert(i >= 0 && i < N_CLASSES && "Invalid ia32 register class requested.");
626         return &ia32_reg_classes[i];
627 }
628
629 /**
630  * Get the register class which shall be used to store a value of a given mode.
631  * @param self The this pointer.
632  * @param mode The mode in question.
633  * @return A register class which can hold values of the given mode.
634  */
635 const arch_register_class_t *ia32_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
636         if (mode_is_float(mode))
637                 return &ia32_reg_classes[CLASS_ia32_fp];
638         else
639                 return &ia32_reg_classes[CLASS_ia32_gp];
640 }
641
642 /**
643  * Get the ABI restrictions for procedure calls.
644  * @param self        The this pointer.
645  * @param method_type The type of the method (procedure) in question.
646  * @param abi         The abi object to be modified
647  */
648 void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
649         ir_type  *tp;
650         ir_mode  *mode;
651         unsigned  cc        = get_method_calling_convention(method_type);
652         int       n         = get_method_n_params(method_type);
653         int       biggest_n = -1;
654         int       stack_idx = 0;
655         int       i, ignore;
656         ir_mode **modes;
657         const arch_register_t *reg;
658
659         /* set stack parameter passing style */
660         be_abi_call_set_flags(abi, BE_ABI_LEFT_TO_RIGHT);
661
662         /* collect the mode for each type */
663         modes = alloca(n * sizeof(modes[0]));
664
665         for (i = 0; i < n; i++) {
666                 tp       = get_method_param_type(method_type, i);
667                 modes[i] = get_type_mode(tp);
668         }
669
670         /* set register parameters  */
671         if (cc & cc_reg_param) {
672                 /* determine the number of parameters passed via registers */
673                 biggest_n = ia32_get_n_regparam_class(n, modes, &ignore, &ignore);
674
675                 /* loop over all parameters and set the register requirements */
676                 for (i = 0; i <= biggest_n; i++) {
677                         reg = ia32_get_RegParam_reg(n, modes, i, cc);
678                         assert(reg && "kaputt");
679                         be_abi_call_param_reg(abi, i, reg);
680                 }
681
682                 stack_idx = i;
683         }
684
685
686         /* set stack parameters */
687         for (i = stack_idx; i < n; i++) {
688                 be_abi_call_param_stack(abi, i);
689         }
690
691
692         /* set return registers */
693         n = get_method_n_ress(method_type);
694
695         assert(n <= 2 && "more than two results not supported");
696
697         /* In case of 64bit returns, we will have two 32bit values */
698         if (n == 2) {
699                 tp   = get_method_res_type(method_type, 0);
700                 mode = get_type_mode(tp);
701
702                 assert(!mode_is_float(mode) && "two FP results not supported");
703
704                 tp   = get_method_res_type(method_type, 1);
705                 mode = get_type_mode(tp);
706
707                 assert(!mode_is_float(mode) && "two FP results not supported");
708
709                 be_abi_call_res_reg(abi, 0, &ia32_gp_regs[REG_EAX]);
710                 be_abi_call_res_reg(abi, 1, &ia32_gp_regs[REG_EDX]);
711         }
712         else if (n == 1) {
713                 tp   = get_method_res_type(method_type, 0);
714                 mode = get_type_mode(tp);
715
716                 if (mode_is_float(mode)) {
717                         be_abi_call_res_reg(abi, 1, &ia32_fp_regs[REG_XMM0]);
718                 }
719                 else {
720                         be_abi_call_res_reg(abi, 1, &ia32_gp_regs[REG_EAX]);
721                 }
722         }
723 }
724
725
726 static const void *ia32_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
727         return &ia32_irn_ops;
728 }
729
730 const arch_irn_handler_t ia32_irn_handler = {
731         ia32_get_irn_ops
732 };
733
734 const arch_irn_handler_t *ia32_get_irn_handler(const void *self) {
735         return &ia32_irn_handler;
736 }
737
738 long ia32_handle_call_proj(const void *self, ir_node *proj, int is_keep) {
739         ia32_isa_t *isa = (ia32_isa_t *)self;
740         long        pn  = get_Proj_proj(proj);
741
742         if (!is_keep) {
743                 /* It's not a Keep proj, which means, that it is a result proj. */
744                 /* Possible result proj numbers are 0 and 1                     */
745                 /* Set the correct register (depends on the mode) and the       */
746                 /* corresponding proj number                                    */
747                 if (mode_is_float(get_irn_mode(proj))) {
748                         assert(pn == 0 && "only one floating point result supported");
749
750                         /* Get the proj number for the floating point result */
751                         pn = ia32_get_reg_projnum(&ia32_fp_regs[REG_XMM0], isa->reg_projnum_map);
752                 }
753                 else {
754                         /* In case of 64bit return value, the result is */
755                         /* in EDX:EAX and we have two result projs.     */
756                         switch (pn) {
757                                 case 0:
758                                         pn = ia32_get_reg_projnum(&ia32_gp_regs[REG_EAX], isa->reg_projnum_map);
759                                         break;
760                                 case 1:
761                                         pn = ia32_get_reg_projnum(&ia32_gp_regs[REG_EDX], isa->reg_projnum_map);
762                                         break;
763                                 default:
764                                         assert(0 && "only two int results supported");
765                         }
766                 }
767
768                 /* Set the correct proj number */
769                 set_Proj_proj(proj, pn);
770         }
771         else {
772                 /* Set mode to floating point if required */
773                 if (!strcmp(ia32_reg_classes[CLASS_ia32_fp].name,
774                                         ia32_projnum_reg_req_map[pn]->req.cls->name)) {
775                         set_irn_mode(proj, mode_F);
776                 }
777         }
778
779         return pn;
780 }
781
782 int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn) {
783         return is_ia32_irn(irn);
784 }
785
786 /**
787  * Initializes the code generator interface.
788  */
789 static const arch_code_generator_if_t *ia32_get_code_generator_if(void *self) {
790         return &ia32_code_gen_if;
791 }
792
793 list_sched_selector_t ia32_sched_selector;
794
795 /**
796  * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
797  */
798 static const list_sched_selector_t *ia32_get_list_sched_selector(const void *self) {
799         memcpy(&ia32_sched_selector, trivial_selector, sizeof(list_sched_selector_t));
800         ia32_sched_selector.to_appear_in_schedule = ia32_to_appear_in_schedule;
801         return &ia32_sched_selector;
802 }
803
804 #ifdef WITH_LIBCORE
805 static void ia32_register_options(lc_opt_entry_t *ent)
806 {
807 }
808 #endif /* WITH_LIBCORE */
809
810 const arch_isa_if_t ia32_isa_if = {
811 #ifdef WITH_LIBCORE
812         ia32_register_options,
813 #endif
814         ia32_init,
815         ia32_done,
816         ia32_get_n_reg_class,
817         ia32_get_reg_class,
818         ia32_get_reg_class_for_mode,
819         ia32_get_call_abi,
820         ia32_get_irn_handler,
821         ia32_get_code_generator_if,
822         ia32_get_list_sched_selector,
823         ia32_handle_call_proj
824 };