amd64: Added Load and FrameAddr transformation. And fixed some corruption bugs w...
[libfirm] / ir / be / mips / mips_transform.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   The codegenrator (transform FIRM into mips FIRM
23  * @author  Matthias Braun, Mehdi
24  * @version $Id$
25  */
26 #include "config.h"
27
28 #include <limits.h>
29
30 #include "irnode_t.h"
31 #include "irgraph_t.h"
32 #include "irmode_t.h"
33 #include "irgmod.h"
34 #include "iredges.h"
35 #include "irvrfy.h"
36 #include "ircons.h"
37 #include "irprintf.h"
38 #include "irop.h"
39 #include "iropt_t.h"
40 #include "debug.h"
41 #include "error.h"
42
43 #include "../benode.h"
44 #include "../beabi.h"
45 #include "../besched.h"
46 #include "../besched.h"
47 #include "../beirg.h"
48 #include "../betranshlp.h"
49 #include "bearch_mips_t.h"
50
51 #include "mips_nodes_attr.h"
52 #include "mips_transform.h"
53 #include "mips_new_nodes.h"
54 #include "mips_map_regs.h"
55 #include "mips_util.h"
56 #include "mips_emitter.h"
57
58 #include "gen_mips_regalloc_if.h"
59
60 /****************************************************************************************************
61  *                  _        _                        __                           _   _
62  *                 | |      | |                      / _|                         | | (_)
63  *  _ __   ___   __| | ___  | |_ _ __ __ _ _ __  ___| |_ ___  _ __ _ __ ___   __ _| |_ _  ___  _ __
64  * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __|  _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
65  * | | | | (_) | (_| |  __/ | |_| | | (_| | | | \__ \ || (_) | |  | | | | | | (_| | |_| | (_) | | | |
66  * |_| |_|\___/ \__,_|\___|  \__|_|  \__,_|_| |_|___/_| \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
67  *
68  ****************************************************************************************************/
69
70 typedef ir_node *construct_binop_func(dbg_info *db, ir_node *block,
71                 ir_node *left, ir_node *right);
72
73 static inline int mode_needs_gp_reg(ir_mode *mode)
74 {
75         return mode_is_int(mode) || mode_is_reference(mode);
76 }
77
78 ir_node *mips_create_Immediate(long val)
79 {
80         ir_graph *irg   = current_ir_graph;
81         ir_node  *block = get_irg_start_block(irg);
82         ir_node  *res;
83
84         assert(val >=  -32768 && val <= 32767);
85         res      = new_bd_mips_Immediate(NULL, block, MIPS_IMM_CONST, NULL, val);
86         arch_set_irn_register(res, &mips_gp_regs[REG_GP_NOREG]);
87
88         return res;
89 }
90
91 ir_node* mips_create_zero(void)
92 {
93         ir_graph *irg   = current_ir_graph;
94         ir_node  *block = get_irg_start_block(irg);
95         ir_node  *zero  = new_bd_mips_zero(NULL, block);
96
97         arch_set_irn_register(zero, &mips_gp_regs[REG_GP_NOREG]);
98
99         return zero;
100 }
101
102 static ir_node *try_create_Immediate(ir_node *node)
103 {
104         tarval   *tv;
105         long      val;
106         ir_mode  *mode;
107
108         if (!is_Const(node))
109                 return NULL;
110
111         mode = get_irn_mode(node);
112         if (!mode_needs_gp_reg(mode))
113                 return NULL;
114
115         tv = get_Const_tarval(node);
116         if (tarval_is_long(tv)) {
117                 val = get_tarval_long(tv);
118         } else {
119                 ir_fprintf(stderr, "Optimisation Warning: tarval %+F is not a long?\n",
120                            node);
121                 return NULL;
122         }
123
124         if (val < -32768 || val > 32767)
125                 return NULL;
126
127         return mips_create_Immediate(val);
128 }
129
130 static void create_binop_operands(ir_node **new_left, ir_node **new_right,
131                                   ir_node *left, ir_node *right,
132                                   int is_commutative)
133 {
134         *new_right = try_create_Immediate(right);
135         if (*new_right != NULL) {
136                 *new_left = be_transform_node(left);
137                 return;
138         }
139         if (is_commutative) {
140                 *new_right = try_create_Immediate(left);
141                 if (*new_right != NULL) {
142                         *new_left = be_transform_node(right);
143                         return;
144                 }
145         }
146
147         *new_left  = be_transform_node(left);
148         *new_right = be_transform_node(right);
149 }
150
151 static ir_node *gen_binop(ir_node *node, ir_node *left, ir_node *right,
152                           construct_binop_func func, int supports_immediate)
153 {
154         dbg_info *dbgi  = get_irn_dbg_info(node);
155         ir_node  *block = be_transform_node(get_nodes_block(node));
156         ir_node  *res;
157         ir_node  *new_left, *new_right;
158
159         assert(mode_needs_gp_reg(get_irn_mode(node)));
160
161         if (supports_immediate) {
162                 int is_commutative = is_op_commutative(get_irn_op(node));
163                 create_binop_operands(&new_left, &new_right, left, right,
164                                       is_commutative);
165         } else {
166                 new_left  = be_transform_node(left);
167                 new_right = be_transform_node(right);
168         }
169
170         res = func(dbgi, block, new_left, new_right);
171
172         return res;
173 }
174
175 static ir_node *gen_Add(ir_node *node)
176 {
177         /* TODO: match add(symconst, const) */
178         return gen_binop(node, get_Add_left(node), get_Add_right(node),
179                          new_bd_mips_addu, 1);
180 }
181
182 static ir_node *gen_Sub(ir_node *node)
183 {
184         return gen_binop(node, get_Sub_left(node), get_Sub_right(node),
185                          new_bd_mips_addu, 0);
186 }
187
188 static ir_node *gen_And(ir_node *node)
189 {
190         return gen_binop(node, get_Add_left(node), get_Add_right(node),
191                          new_bd_mips_and, 1);
192 }
193
194 static ir_node *gen_Or(ir_node *node)
195 {
196         return gen_binop(node, get_Add_left(node), get_Add_right(node),
197                          new_bd_mips_or, 1);
198 }
199
200 static ir_node *gen_Eor(ir_node *node)
201 {
202         return gen_binop(node, get_Add_left(node), get_Add_right(node),
203                          new_bd_mips_xor, 1);
204 }
205
206 static ir_node *gen_Shl(ir_node *node)
207 {
208         return gen_binop(node, get_Add_left(node), get_Add_right(node),
209                          new_bd_mips_sll, 1);
210 }
211
212 static ir_node *gen_Shr(ir_node *node)
213 {
214         return gen_binop(node, get_Add_left(node), get_Add_right(node),
215                          new_bd_mips_srl, 1);
216 }
217
218 static ir_node *gen_Shrs(ir_node *node)
219 {
220         return gen_binop(node, get_Add_left(node), get_Add_right(node),
221                          new_bd_mips_sra, 1);
222 }
223
224 static ir_node *gen_Not(ir_node *node)
225 {
226         dbg_info *dbgi  = get_irn_dbg_info(node);
227         ir_node  *block = be_transform_node(get_nodes_block(node));
228         ir_node  *op    = get_Not_op(node);
229         ir_node  *new_op;
230         ir_node  *res;
231         ir_node  *one;
232
233         /* we can transform not->or to nor */
234         if (is_Or(op)) {
235                 return gen_binop(op, get_Or_left(op), get_Or_right(op),
236                                  new_bd_mips_nor, 1);
237         }
238
239         /* construct (op < 1) */
240         one    = mips_create_Immediate(1);
241         new_op = be_transform_node(op);
242         res    = new_bd_mips_sltu(dbgi, block, new_op, one);
243
244         return res;
245 }
246
247 static ir_node *gen_Minus(ir_node *node)
248 {
249         dbg_info *dbgi   = get_irn_dbg_info(node);
250         ir_node  *block  = be_transform_node(get_nodes_block(node));
251         ir_node  *op     = get_Minus_op(node);
252         ir_node  *new_op = be_transform_node(op);
253         ir_node  *res;
254         ir_node  *zero;
255
256         /* construct (0 - op) */
257         zero = mips_create_zero();
258         res  = new_bd_mips_subu(dbgi, block, zero, new_op);
259
260         return res;
261 }
262
263 static ir_node *gen_Abs(ir_node *node)
264 {
265         dbg_info *dbgi   = get_irn_dbg_info(node);
266         ir_node  *block  = be_transform_node(get_nodes_block(node));
267         ir_node  *op     = get_Abs_op(node);
268         ir_node  *new_op = be_transform_node(op);
269         ir_node  *sra_const, *sra, *add, *xor;
270
271         /* TODO: support other bit sizes... */
272         assert(get_mode_size_bits(get_irn_mode(node)) == 32);
273         sra_const = mips_create_Immediate(31);
274         sra       = new_bd_mips_sra( dbgi, block, new_op, sra_const);
275         add       = new_bd_mips_addu(dbgi, block, new_op, sra);
276         xor       = new_bd_mips_xor( dbgi, block, sra, add);
277
278         return xor;
279 }
280
281 static ir_node* gen_Const(ir_node *node)
282 {
283         dbg_info *dbgi  = get_irn_dbg_info(node);
284         ir_node  *block = be_transform_node(get_nodes_block(node));
285         tarval   *tv    = get_Const_tarval(node);
286         ir_node  *upper_node;
287         ir_node  *lower_node;
288         ir_node  *or_const;
289         unsigned long val, lower, upper;
290
291         if (tarval_is_long(tv)) {
292                 val = get_tarval_long(tv);
293         } else {
294                 panic("Can't get value of tarval %+F", node);
295         }
296
297         val = get_tarval_long(tv);
298
299         lower = val & 0xffff;
300         upper = (val >> 16) & 0xffff;
301         if (upper == 0) {
302                 upper_node = mips_create_zero();
303         } else {
304                 upper_node = new_bd_mips_lui(dbgi, block, MIPS_IMM_CONST, NULL, upper);
305         }
306
307         if (lower == 0)
308                 return upper_node;
309
310         or_const   = mips_create_Immediate(lower);
311         lower_node = new_bd_mips_or(dbgi, block, upper_node, or_const);
312
313         return lower_node;
314 }
315
316 static ir_node* gen_SymConst(ir_node *node)
317 {
318         dbg_info *dbgi  = get_irn_dbg_info(node);
319         ir_node  *block = be_transform_node(get_nodes_block(node));
320         ir_entity *entity;
321         ir_node *lui, *or_const, *or;
322
323         if (get_SymConst_kind(node) != symconst_addr_ent) {
324                 panic("Only address entity symconsts supported in mips backend");
325         }
326
327         entity = get_SymConst_entity(node);
328
329         lui      = new_bd_mips_lui(dbgi, block, MIPS_IMM_SYMCONST_HI, entity, 0);
330         or_const = new_bd_mips_Immediate(dbgi, block, MIPS_IMM_SYMCONST_LO, entity, 0);
331         or       = new_bd_mips_or(dbgi, block, lui, or_const);
332
333         arch_set_irn_register(or_const, &mips_gp_regs[REG_GP_NOREG]);
334
335         return or;
336 }
337
338 typedef ir_node* (*gen_load_func)(dbg_info *dbg, ir_node *block, ir_node *ptr,
339                 ir_node *mem, ir_entity *entity, long offset);
340
341 /**
342  * Generates a mips node for a firm Load node
343  */
344 static ir_node *gen_Load(ir_node *node)
345 {
346         dbg_info *dbgi    = get_irn_dbg_info(node);
347         ir_node  *block   = be_transform_node(get_nodes_block(node));
348         ir_node  *mem     = get_Load_mem(node);
349         ir_node  *new_mem = be_transform_node(mem);
350         ir_node  *ptr     = get_Load_ptr(node);
351         ir_node  *new_ptr = be_transform_node(ptr);
352         ir_mode  *mode    = get_Load_mode(node);
353         int       sign    = get_mode_sign(mode);
354         ir_node  *res;
355         gen_load_func func;
356
357         ASSERT_NO_FLOAT(mode);
358         assert(mode_needs_gp_reg(mode));
359
360         /* TODO: make use of offset in ptrs */
361
362         switch (get_mode_size_bits(mode)) {
363         case 32:
364                 func = new_bd_mips_lw;
365                 break;
366         case 16:
367                 func = sign ? new_bd_mips_lh : new_bd_mips_lhu;
368                 break;
369         case 8:
370                 func = sign ? new_bd_mips_lb : new_bd_mips_lbu;
371                 break;
372         default:
373                 panic("mips backend only support 32, 16, 8 bit loads");
374         }
375
376         res = func(dbgi, block, new_ptr, new_mem, NULL, 0);
377         set_irn_pinned(res, get_irn_pinned(node));
378
379         return res;
380 }
381
382 typedef ir_node* (*gen_store_func)(dbg_info *dbg, ir_node *block, ir_node *ptr,
383                 ir_node *val, ir_node *mem, ir_entity *ent, long offset);
384
385 /**
386  * Generates a mips node for a firm Store node
387  */
388 static ir_node *gen_Store(ir_node *node)
389 {
390         dbg_info    *dbgi    = get_irn_dbg_info(node);
391         ir_node     *block   = be_transform_node(get_nodes_block(node));
392         ir_node     *mem     = get_Store_mem(node);
393         ir_node     *new_mem = be_transform_node(mem);
394         ir_node     *ptr     = get_Store_ptr(node);
395         ir_node     *new_ptr = be_transform_node(ptr);
396         ir_node     *val     = get_Store_value(node);
397         ir_node     *new_val = be_transform_node(val);
398         ir_mode     *mode    = get_irn_mode(val);
399         gen_store_func func;
400         ir_node     *res;
401
402         assert(mode_needs_gp_reg(mode));
403
404         switch (get_mode_size_bits(mode)) {
405         case 32:
406                 func = new_bd_mips_sw;
407                 break;
408         case 16:
409                 func = new_bd_mips_sh;
410                 break;
411         case 8:
412                 func = new_bd_mips_sb;
413                 break;
414         default:
415                 panic("store only supported for 32, 16, 8 bit values in mips backend");
416         }
417
418         res = func(dbgi, block, new_ptr, new_val, new_mem, NULL, 0);
419         set_irn_pinned(res, get_irn_pinned(node));
420
421         return res;
422 }
423
424 static ir_node *gen_Proj_DivMod(ir_node *node)
425 {
426         dbg_info *dbgi    = get_irn_dbg_info(node);
427         ir_node  *block   = be_transform_node(get_nodes_block(node));
428         ir_node  *divmod  = get_Proj_pred(node);
429         ir_node  *new_div = be_transform_node(divmod);
430         long      pn      = get_Proj_proj(node);
431         ir_node  *proj;
432
433         assert(is_mips_div(new_div) || is_mips_divu(new_div));
434
435         switch (get_irn_opcode(divmod)) {
436         case iro_Div:
437                 switch (pn) {
438                 case pn_Div_M:
439                         return new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_M);
440                 case pn_Div_res:
441                         proj = new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_lohi);
442                         return new_bd_mips_mflo(dbgi, block, proj);
443                 default:
444                         break;
445                 }
446         case iro_Mod:
447                 switch (pn) {
448                 case pn_Mod_M:
449                         return new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_M);
450                 case pn_Mod_res:
451                         proj = new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_lohi);
452                         return new_bd_mips_mfhi(dbgi, block, proj);
453                 default:
454                         break;
455                 }
456
457         case iro_DivMod:
458                 switch (pn) {
459                 case pn_Div_M:
460                         return new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_M);
461                 case pn_DivMod_res_div:
462                         proj = new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_lohi);
463                         return new_bd_mips_mflo(dbgi, block, proj);
464                 case pn_DivMod_res_mod:
465                         proj = new_rd_Proj(dbgi, new_div, mode_M, pn_mips_div_lohi);
466                         return new_bd_mips_mfhi(dbgi, block, proj);
467                 default:
468                         break;
469                 }
470         default:
471                 break;
472         }
473
474         panic("invalid proj attached to %+F", divmod);
475 }
476
477 static ir_node *gen_Proj_Start(ir_node *node)
478 {
479         dbg_info *dbgi  = get_irn_dbg_info(node);
480         ir_node  *block = be_transform_node(get_nodes_block(node));
481         long      pn    = get_Proj_proj(node);
482         ir_graph *irg;
483
484         if (pn == pn_Start_X_initial_exec) {
485                 /* we exchange the projx with a jump */
486                 ir_node *jump = new_rd_Jmp(dbgi, block);
487                 return jump;
488         }
489         irg = get_irn_irg(node);
490         if (node == get_irg_anchor(irg, anchor_tls)) {
491                 /* TODO... */
492                 return be_duplicate_node(node);
493         }
494         return be_duplicate_node(node);
495 }
496
497 static ir_node *gen_Proj(ir_node *node)
498 {
499         dbg_info *dbgi = get_irn_dbg_info(node);
500         ir_node  *pred = get_Proj_pred(node);
501
502         switch (get_irn_opcode(pred)) {
503         case iro_Load:
504                 break;
505         case iro_Store:
506                 break;
507         case iro_Div:
508         case iro_Mod:
509         case iro_DivMod:
510                 return gen_Proj_DivMod(node);
511
512         case iro_Start:
513                 return gen_Proj_Start(node);
514
515         default:
516                 assert(get_irn_mode(node) != mode_T);
517                 if (mode_needs_gp_reg(get_irn_mode(node))) {
518                         ir_node *new_pred = be_transform_node(pred);
519                         long     pn       = get_Proj_proj(node);
520
521                         return new_rd_Proj(dbgi, new_pred, mode_Iu, pn);
522                 }
523                 break;
524         }
525
526         return be_duplicate_node(node);
527 }
528
529 static ir_node *gen_Phi(ir_node *node)
530 {
531         dbg_info *dbgi  = get_irn_dbg_info(node);
532         ir_node  *block = be_transform_node(get_nodes_block(node));
533         ir_graph *irg   = get_Block_irg(block);
534         ir_mode  *mode  = get_irn_mode(node);
535         ir_node  *phi;
536
537         if (mode_needs_gp_reg(mode)) {
538                 assert(get_mode_size_bits(mode) <= 32);
539                 mode = mode_Iu;
540         }
541
542         /* phi nodes allow loops, so we use the old arguments for now
543          * and fix this later */
544         phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node),
545                           get_irn_in(node) + 1);
546         copy_node_attr(irg, node, phi);
547         be_duplicate_deps(node, phi);
548
549         be_enqueue_preds(node);
550
551         return phi;
552 }
553
554 #if 0
555 static ir_node *gen_node_for_SwitchCond(mips_transform_env_t *env)
556 {
557         ir_node *selector = get_Cond_selector(env->irn);
558         ir_mode *selector_mode = get_irn_mode(selector);
559         ir_node *node = env->irn;
560         dbg_info *dbg = env->dbg;
561         ir_graph *irg = env->irg;
562         ir_node *block = env->block;
563         ir_node *sub, *sltu, *minval_const, *max_const, *switchjmp;
564         ir_node *defaultproj, *defaultproj_succ;
565         ir_node *beq, *sl;
566         long pn, minval, maxval, defaultprojn;
567         const ir_edge_t *edge;
568         ir_node *zero, *two_const, *add, *la, *load, *proj;
569         ir_mode *unsigned_mode;
570         mips_attr_t *attr;
571
572         // mode_b conds are handled by gen_node_for_Proj
573         if (get_mode_sort(selector_mode) != irms_int_number)
574                 return env->irn;
575
576         assert(get_mode_size_bits(selector_mode) == 32);
577
578         defaultproj = NULL;
579         defaultprojn = get_Cond_default_proj(node);
580
581         // go over all projs to find min-&maxval of the switch
582         minval = INT_MAX;
583         maxval = INT_MIN;
584         foreach_out_edge(node, edge) {
585                 ir_node* proj = get_edge_src_irn(edge);
586                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
587
588                 pn = get_Proj_proj(proj);
589                 if (pn == defaultprojn) {
590                         defaultproj = proj;
591                         continue;
592                 }
593
594                 if (pn < minval)
595                         minval = pn;
596                 if (pn > maxval)
597                         maxval = pn;
598         }
599         assert(defaultproj != NULL);
600
601         // subtract minval from the switch value
602
603         if (minval != 0) {
604                 minval_const = new_rd_Const(dbg, irg, selector_mode, new_tarval_from_long(minval, selector_mode));
605                 minval_const = gen_node_for_Const(env, dbg, irg, block, minval_const);
606                 sub = new_bd_mips_sub(dbg, block, selector, minval_const);
607         } else {
608                 sub = selector;
609         }
610
611         // compare if we're above maxval-minval or below zero.
612         // we can do this with 1 compare because we use unsigned mode
613         unsigned_mode = new_ir_mode(get_mode_name(selector_mode),
614                         get_mode_sort(selector_mode), get_mode_size_bits(selector_mode),
615                         0, get_mode_arithmetic(selector_mode), get_mode_modulo_shift(selector_mode));
616
617         max_const = new_rd_Const(dbg, irg, unsigned_mode, new_tarval_from_long(maxval - minval + 1, unsigned_mode));
618         max_const = gen_node_for_Const(env, dbg, irg, block, max_const);
619         sltu = new_bd_mips_slt(dbg, block, sub, max_const);
620
621         zero = gen_zero_node(env, dbg, irg, block);
622         beq = new_bd_mips_beq(dbg, block, sltu, zero, mode_T);
623
624         // attach defaultproj to beq now
625         set_irn_n(defaultproj, 0, beq);
626         set_Proj_proj(defaultproj, 1);
627
628         two_const = new_rd_Const(dbg, irg, block, unsigned_mode, new_tarval_from_long(2, unsigned_mode));
629         two_const = gen_node_for_Const(env, dbg, irg, block, two_const);
630         sl = new_bd_mips_sl(dbg, block, sub, two_const);
631
632         la   = new_bd_mips_la(    dbg, block);
633         add  = new_bd_mips_addu(  dbg, block, sl, la);
634         load = new_bd_mips_load_r(dbg, block, new_NoMem(), add, mode_T);
635         attr = get_mips_attr(load);
636         attr->modes.load_store_mode = mode_Iu;
637         attr->tv = new_tarval_from_long(0, mode_Iu);
638
639         proj = new_rd_Proj(dbg, load, mode_Iu, pn_Load_res);
640
641         switchjmp = new_bd_mips_SwitchJump(dbg, block, proj, mode_T);
642         attr = get_mips_attr(switchjmp);
643         attr->switch_default_pn = defaultprojn;
644
645         edge = get_irn_out_edge_first(defaultproj);
646         defaultproj_succ = get_edge_src_irn(edge);
647         attr->symconst_id = new_id_from_str(mips_get_block_label(defaultproj_succ));
648
649         attr = get_mips_attr(la);
650         attr->symconst_id = new_id_from_str(mips_get_jumptbl_label(switchjmp));
651
652         return switchjmp;
653 }
654 #endif
655
656 static ir_node *gen_Cond(ir_node *node)
657 {
658         dbg_info *dbgi      = get_irn_dbg_info(node);
659         ir_node  *block     = get_nodes_block(node);
660         ir_node  *sel_proj  = get_Cond_selector(node);
661         ir_node  *cmp       = get_Proj_pred(sel_proj);
662         ir_node  *left      = get_Cmp_left(cmp);
663         ir_node  *new_left  = be_transform_node(left);
664         ir_node  *right     = get_Cmp_right(cmp);
665         ir_node  *new_right = be_transform_node(right);
666         long      pnc       = get_Proj_proj(sel_proj);
667         ir_node  *res;
668         ir_node  *slt;
669         ir_node  *zero;
670
671         /* TODO: use blez & co. when possible */
672
673         switch (pnc) {
674         case pn_Cmp_False:
675         case pn_Cmp_True:
676         case pn_Cmp_Leg:
677                 panic("mips backend can't handle unoptimized constant Cond");
678
679         case pn_Cmp_Eq:
680                 res = new_bd_mips_beq(dbgi, block, new_left, new_right);
681                 break;
682
683         case pn_Cmp_Lt:
684                 zero = mips_create_zero();
685                 slt  = new_bd_mips_slt(dbgi, block, new_left, new_right);
686                 res  = new_bd_mips_bne(dbgi, block, slt, zero);
687                 break;
688
689         case pn_Cmp_Le:
690                 zero = mips_create_zero();
691                 slt  = new_bd_mips_slt(dbgi, block, new_right, new_left);
692                 res  = new_bd_mips_beq(dbgi, block, slt, zero);
693                 break;
694
695         case pn_Cmp_Gt:
696                 zero = mips_create_zero();
697                 slt  = new_bd_mips_slt(dbgi, block, new_right, new_left);
698                 res  = new_bd_mips_bne(dbgi, block, slt, zero);
699                 break;
700
701         case pn_Cmp_Ge:
702                 zero = mips_create_zero();
703                 slt  = new_bd_mips_slt(dbgi, block, new_right, new_left);
704                 res  = new_bd_mips_bne(dbgi, block, slt, zero);
705                 break;
706
707         case pn_Cmp_Lg:
708                 res = new_bd_mips_bne(dbgi, block, new_left, new_right);
709                 break;
710
711         default:
712                 panic("mips backend doesn't handle unordered compares yet");
713         }
714
715         return res;
716 }
717
718 static ir_node *gen_Conv(ir_node *node)
719 {
720         dbg_info *dbgi     = get_irn_dbg_info(node);
721         ir_node  *block    = be_transform_node(get_nodes_block(node));
722         ir_node  *op       = get_Conv_op(node);
723         ir_node  *new_op   = be_transform_node(op);
724         ir_mode  *src_mode = get_irn_mode(op);
725         ir_mode  *dst_mode = get_irn_mode(node);
726         int       src_size = get_mode_size_bits(src_mode);
727         int       dst_size = get_mode_size_bits(dst_mode);
728         ir_node  *res;
729
730         assert(mode_needs_gp_reg(src_mode));
731         assert(mode_needs_gp_reg(dst_mode));
732
733         /* we only need to do something on upconvs */
734         if (src_size >= dst_size) {
735                 /* unnecessary conv */
736                 return new_op;
737         }
738
739         if (mode_is_signed(src_mode)) {
740                 if (src_size == 8) {
741                         res = new_bd_mips_seb(dbgi, block, new_op);
742                 } else if (src_size == 16) {
743                         res = new_bd_mips_seh(dbgi, block, new_op);
744                 } else {
745                         panic("invalid conv %+F", node);
746                 }
747         } else {
748                 ir_node *and_const;
749
750                 if (src_size == 8) {
751                         and_const = mips_create_Immediate(0xff);
752                 } else if (src_size == 16) {
753                         and_const = mips_create_Immediate(0xffff);
754                 } else {
755                         panic("invalid conv %+F", node);
756                 }
757                 res = new_bd_mips_and(dbgi, block, new_op, and_const);
758         }
759
760         return res;
761 }
762
763 static ir_node *create_div(ir_node *node, ir_node *left, ir_node *right,
764                            ir_mode *mode)
765 {
766         dbg_info *dbgi      = get_irn_dbg_info(node);
767         ir_node  *block     = be_transform_node(get_nodes_block(node));
768         ir_node  *new_left  = be_transform_node(left);
769         ir_node  *new_right = be_transform_node(right);
770         ir_node  *res;
771
772         if (mode_is_signed(mode)) {
773                 res = new_bd_mips_div(dbgi, block, new_left, new_right);
774         } else {
775                 res = new_bd_mips_divu(dbgi, block, new_left, new_right);
776         }
777
778         set_irn_pinned(res, get_irn_pinned(node));
779
780         return res;
781 }
782
783 static ir_node *gen_DivMod(ir_node *node)
784 {
785         return create_div(node, get_DivMod_left(node), get_DivMod_right(node),
786                           get_DivMod_resmode(node));
787 }
788
789 static ir_node *gen_Div(ir_node *node)
790 {
791         return create_div(node, get_Div_left(node), get_Div_right(node),
792                           get_Div_resmode(node));
793 }
794
795 static ir_node *gen_Mod(ir_node *node)
796 {
797         return create_div(node, get_Mod_left(node), get_Mod_right(node),
798                           get_Mod_resmode(node));
799 }
800
801 #if 0
802 static ir_node *gen_node_for_Mul(mips_transform_env_t *env)
803 {
804         ir_node *node = env->irn;
805         ir_node *mul;
806         ir_node *mflo;
807         ir_node *op1, *op2;
808         ir_mode *mode = get_irn_mode(node);
809
810         op1 = get_Mul_left(node);
811         op2 = get_Mul_right(node);
812
813         assert(get_mode_size_bits(env->mode) == 32);
814         assert(get_mode_size_bits(get_irn_mode(op1)) == get_mode_size_bits(env->mode));
815         assert(get_mode_size_bits(get_irn_mode(op2)) == get_mode_size_bits(env->mode));
816
817         if (mode_is_signed(mode)) {
818                 mul = new_bd_mips_mult(env->dbg, env->block, get_Mul_left(node), get_Mul_right(node));
819         } else {
820                 mul = new_bd_mips_multu(env->dbg, env->block, get_Mul_left(node), get_Mul_right(node));
821         }
822         mflo = new_bd_mips_mflo(env->dbg, env->block, mul);
823
824         return mflo;
825 }
826
827 static ir_node *gen_node_for_IJmp(mips_transform_env_t *env)
828 {
829         ir_node  *node   = env->irn;
830         dbg_info *dbg    = get_irn_dbg_info(node);
831         ir_node  *block  = get_nodes_block(node);
832         ir_node  *target = get_IJmp_target(node);
833
834         return new_bd_mips_jr(dbg, block, target);
835 }
836
837 static ir_node *gen_node_for_Rot(mips_transform_env_t *env)
838 {
839         ir_node *node = env->irn;
840         ir_node *subu, *srlv, *sllv, *or;
841
842         subu = new_bd_mips_subuzero(env->dbg, env->block, get_Rot_right(node));
843         srlv = new_bd_mips_srlv(env->dbg, env->block, get_Rot_left(node), subu);
844         sllv = new_bd_mips_sllv(env->dbg, env->block, get_Rot_left(node), get_Rot_right(node));
845         or   = new_bd_mips_or(env->dbg, env->block, sllv, srlv);
846
847         return or;
848 }
849 #endif
850
851 static ir_node *gen_Unknown(ir_node *node)
852 {
853         (void) node;
854         assert(mode_needs_gp_reg(get_irn_mode(node)));
855         return mips_create_zero();
856 }
857
858 #if 0
859 /*
860  * lower a copyB into standard Firm assembler :-)
861  */
862 ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node)
863 {
864         ir_node *cnt, *sub;
865         ir_node *dst = get_CopyB_dst(node);
866         ir_node *src = get_CopyB_src(node);
867         ir_type *type = get_CopyB_type(node);
868         ir_node *mem = get_CopyB_mem(node);
869         ir_node *mm[4];
870         ir_node *result = NULL;
871         int size = get_type_size_bytes(type);
872         dbg_info *dbg = get_irn_dbg_info(node);
873         ir_graph *irg = get_irn_irg(block);
874         mips_attr_t *attr;
875         int i, n;
876
877         if (size > 16) {
878                 ir_node     *phi, *projT, *projF, *cmp, *proj, *cond, *jmp, *in[2];
879                 ir_node     *new_bl, *src_phi, *dst_phi, *mem_phi, *add;
880                 ir_mode     *p_mode = get_irn_mode(src);
881                 ir_node     *ld[4];
882
883                 /* build the control loop */
884                 in[0] = in[1] = new_r_Unknown(irg, mode_X);
885
886                 new_bl = new_r_Block(irg, 2, in);
887
888                 in[0] = cnt = new_Const_long(mode_Is, (size >> 4));
889         in[1] = new_r_Unknown(irg, mode_Is);
890                 phi   = new_r_Phi(irg, new_bl, 2, in, mode_Is);
891
892                 sub = new_rd_Sub(dbg, irg, new_bl, phi, new_Const_long(mode_Is, -1), mode_Is);
893                 set_Phi_pred(phi, 1, sub);
894
895                 cmp = new_rd_Cmp(dbg, irg, new_bl, sub, new_Const_long(mode_Is, 0));
896                 proj = new_r_Proj(irg, new_bl, cmp, mode_b, pn_Cmp_Lg);
897                 cond = new_rd_Cond(dbg, irg, new_bl, proj);
898
899                 projT = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_true);
900                 projF = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_false);
901
902                 jmp = get_Block_cfgpred(block, 0);
903                 set_Block_cfgpred(block, 0, projF);
904
905                 set_Block_cfgpred(new_bl, 0, jmp);
906                 set_Block_cfgpred(new_bl, 1, projT);
907
908                 size &= 0xF;
909
910                 /* build the copy */
911                 in[0]   = src;
912         in[1]   = new_r_Unknown(irg, p_mode);
913                 src_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
914
915                 in[0]   = dst;
916                 dst_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
917
918                 add = new_rd_Add(dbg, irg, new_bl, src_phi, new_Const_long(mode_Is, 16), p_mode);
919                 set_Phi_pred(src_phi, 1, add);
920                 add = new_rd_Add(dbg, irg, new_bl, dst_phi, new_Const_long(mode_Is, 16), p_mode);
921                 set_Phi_pred(dst_phi, 1, add);
922
923                 in[0]   = mem;
924         in[1]   = new_r_Unknown(irg, mode_M);
925                 mem_phi = new_r_Phi(irg, new_bl, 2, in, mode_M);
926
927                 src = src_phi;
928                 dst = dst_phi;
929
930                 /* create 4 parallel loads */
931                 for (i = 0; i < 4; ++i) {
932                         ir_node *load;
933
934                         load = new_bd_mips_load_r(dbg, new_bl, mem_phi, src, mode_T);
935                         attr = get_mips_attr(load);
936                         attr->modes.load_store_mode = mode_Iu;
937                         attr->tv = new_tarval_from_long(i * 4, mode_Iu);
938
939                         ld[i] = new_rd_Proj(dbg, irg, load, mode_Iu, pn_Load_res);
940                 }
941
942                 /* create 4 parallel stores */
943                 for (i = 0; i < 4; ++i) {
944                         ir_node *store;
945
946                         store = new_bd_mips_store_r(dbg, new_bl, mem_phi, dst, ld[i], mode_T);
947                         attr = get_mips_attr(store);
948                         attr->modes.load_store_mode = mode_Iu;
949                         attr->tv = new_tarval_from_long(i * 4, mode_Iu);
950
951                         mm[i] = new_rd_Proj(dbg, irg, store, mode_M, pn_Store_M);
952                 }
953                 mem = new_r_Sync(irg, new_bl, 4, mm);
954                 result = mem;
955                 set_Phi_pred(mem_phi, 1, mem);
956         }
957
958         // output store/loads manually
959         n = 0;
960         for (i = size; i > 0; ) {
961                 ir_mode *mode;
962                 ir_node *load, *store, *projv;
963                 int offset = size - i;
964                 if (i >= 4) {
965                         mode = mode_Iu;
966                         i -= 4;
967                 } else if (i >= 2) {
968                         mode = mode_Hu;
969                         i -= 2;
970                 } else {
971                         mode = mode_Bu;
972                         i -= 1;
973                 }
974
975                 load = new_bd_mips_load_r(dbg, block, mem, src, mode_T);
976                 attr = get_mips_attr(load);
977                 attr->modes.load_store_mode = mode;
978                 attr->tv = new_tarval_from_long(offset, mode_Iu);
979
980                 projv = new_rd_Proj(dbg, irg, load, mode, pn_Load_res);
981
982                 store = new_bd_mips_store_r(dbg, block, mem, dst, projv, mode_T);
983                 attr = get_mips_attr(store);
984                 attr->modes.load_store_mode = mode;
985                 attr->tv = new_tarval_from_long(offset, mode_Iu);
986
987                 mm[n] = new_rd_Proj(dbg, irg, store, mode_M, pn_Store_M);
988                 n++;
989         }
990
991         if (n > 0) {
992                 result = new_r_Sync(irg, block, n, mm);
993         } else if (n == 1) {
994                 result = mm[0];
995         }
996
997         return result;
998 }
999
1000 static void mips_fix_CopyB_Proj(mips_transform_env_t* env)
1001 {
1002         ir_node *node = env->irn;
1003         long n = get_Proj_proj(node);
1004
1005         if (n == pn_CopyB_M_except) {
1006                 panic("Unsupported Proj from CopyB");
1007         } else if (n == pn_CopyB_M_regular) {
1008                 set_Proj_proj(node, pn_Store_M);
1009         } else if (n == pn_CopyB_M_except) {
1010                 set_Proj_proj(node, pn_Store_X_except);
1011         }
1012 }
1013 #endif
1014
1015 static void mips_transform_Spill(mips_transform_env_t* env)
1016 {
1017         ir_node   *node = env->irn;
1018         ir_node   *sched_point = NULL;
1019         ir_node   *store;
1020         ir_node   *nomem = new_NoMem();
1021         ir_node   *ptr   = get_irn_n(node, 0);
1022         ir_node   *val   = get_irn_n(node, 1);
1023         ir_entity *ent   = be_get_frame_entity(node);
1024
1025         if (sched_is_scheduled(node)) {
1026                 sched_point = sched_prev(node);
1027         }
1028
1029         store = new_bd_mips_sw(env->dbg, env->block, ptr, val, nomem, ent, 0);
1030
1031         if (sched_point) {
1032                 sched_add_after(sched_point, store);
1033                 sched_remove(node);
1034         }
1035
1036         exchange(node, store);
1037 }
1038
1039 static void mips_transform_Reload(mips_transform_env_t* env)
1040 {
1041         ir_node   *node = env->irn;
1042         ir_node   *sched_point = NULL;
1043         ir_node   *load, *proj;
1044         ir_node   *ptr   = get_irn_n(node, 0);
1045         ir_node   *mem   = get_irn_n(node, 1);
1046         ir_entity *ent   = be_get_frame_entity(node);
1047         const arch_register_t* reg;
1048
1049         if (sched_is_scheduled(node)) {
1050                 sched_point = sched_prev(node);
1051         }
1052
1053         load = new_bd_mips_lw(env->dbg, env->block, ptr, mem, ent, 0);
1054
1055         proj = new_rd_Proj(env->dbg, load, mode_Iu, pn_mips_lw_res);
1056
1057         if (sched_point) {
1058                 sched_add_after(sched_point, load);
1059
1060                 sched_remove(node);
1061         }
1062
1063         /* copy the register from the old node to the new Load */
1064         reg = arch_get_irn_register(node);
1065         arch_set_irn_register(proj, reg);
1066
1067         exchange(node, proj);
1068 }
1069
1070 #if 0
1071 static ir_node *gen_AddSP(ir_node *node)
1072 {
1073         ir_node *node = env->irn;
1074         ir_node *op1, *op2;
1075         ir_node *add;
1076         const arch_register_t *reg;
1077
1078         op1 = get_irn_n(node, 0);
1079         op2 = get_irn_n(node, 1);
1080
1081         add = new_bd_mips_addu(env->dbg, env->block, op1, op2);
1082
1083         /* copy the register requirements from the old node to the new node */
1084         reg = arch_get_irn_register(node);
1085         arch_set_irn_register(add, reg);
1086
1087         return add;
1088 }
1089 #endif
1090
1091 /*********************************************************
1092  *                  _             _      _
1093  *                 (_)           | |    (_)
1094  *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
1095  * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
1096  * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
1097  * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
1098  *
1099  *********************************************************/
1100
1101 typedef ir_node *(*mips_transform_func) (ir_node *node);
1102
1103 static void register_transformer(ir_op *op, mips_transform_func func)
1104 {
1105         assert(op->ops.generic == NULL);
1106         op->ops.generic = (op_func) func;
1107 }
1108
1109 static void register_transformers(void)
1110 {
1111         clear_irp_opcodes_generic_func();
1112
1113         register_transformer(op_Add, gen_Add);
1114         register_transformer(op_Sub, gen_Sub);
1115         register_transformer(op_And, gen_And);
1116         register_transformer(op_Or,  gen_Or);
1117         register_transformer(op_Eor, gen_Eor);
1118         register_transformer(op_Shl, gen_Shl);
1119         register_transformer(op_Shr, gen_Shr);
1120         register_transformer(op_Shrs, gen_Shrs);
1121         register_transformer(op_Not, gen_Not);
1122         register_transformer(op_Minus, gen_Minus);
1123         register_transformer(op_Div, gen_Div);
1124         register_transformer(op_Mod, gen_Mod);
1125         register_transformer(op_DivMod, gen_DivMod);
1126         register_transformer(op_Abs, gen_Abs);
1127         register_transformer(op_Load, gen_Load);
1128         register_transformer(op_Store, gen_Store);
1129         register_transformer(op_Cond, gen_Cond);
1130         register_transformer(op_Conv, gen_Conv);
1131         register_transformer(op_Const, gen_Const);
1132         register_transformer(op_SymConst, gen_SymConst);
1133         register_transformer(op_Unknown, gen_Unknown);
1134         register_transformer(op_Proj, gen_Proj);
1135         register_transformer(op_Phi, gen_Phi);
1136 }
1137
1138 void mips_transform_graph(mips_code_gen_t *cg)
1139 {
1140         register_transformers();
1141         be_transform_graph(cg->irg, NULL);
1142 }
1143
1144 /**
1145  * Calls the transform functions for Spill and Reload.
1146  */
1147 void mips_after_ra_walker(ir_node *node, void *env)
1148 {
1149         mips_code_gen_t *cg = env;
1150         mips_transform_env_t tenv;
1151
1152         if (is_Block(node))
1153                 return;
1154
1155         tenv.block = get_nodes_block(node);
1156         tenv.dbg   = get_irn_dbg_info(node);
1157         tenv.irg   = current_ir_graph;
1158         tenv.irn   = node;
1159         tenv.mode  = get_irn_mode(node);
1160         tenv.cg    = cg;
1161
1162         if (be_is_Reload(node)) {
1163                 mips_transform_Reload(&tenv);
1164         } else if (be_is_Spill(node)) {
1165                 mips_transform_Spill(&tenv);
1166         }
1167 }