added mips backend from the backend praktikum
[libfirm] / ir / be / mips / mips_transform.c
1 /* The codegenrator (transform FIRM into mips FIRM */
2 /* $Id$ */
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7
8 #include <limits.h>
9
10 #include "irnode_t.h"
11 #include "irgraph_t.h"
12 #include "irmode_t.h"
13 #include "irgmod.h"
14 #include "iredges.h"
15 #include "irvrfy.h"
16 #include "ircons.h"
17 #include "dbginfo.h"
18 #include "iropt_t.h"
19 #include "debug.h"
20
21 #include "../benode_t.h"
22 #include "../beabi.h"
23 #include "../besched.h"
24 #include "../besched_t.h"
25 #include "bearch_mips_t.h"
26
27 #include "mips_nodes_attr.h"
28 #include "../arch/archop.h"     /* we need this for Min and Max nodes */
29 #include "mips_transform.h"
30 #include "mips_new_nodes.h"
31 #include "mips_map_regs.h"
32 #include "mips_util.h"
33 #include "mips_emitter.h"
34
35 #include "gen_mips_regalloc_if.h"
36
37 /****************************************************************************************************
38  *                  _        _                        __                           _   _
39  *                 | |      | |                      / _|                         | | (_)
40  *  _ __   ___   __| | ___  | |_ _ __ __ _ _ __  ___| |_ ___  _ __ _ __ ___   __ _| |_ _  ___  _ __
41  * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __|  _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
42  * | | | | (_) | (_| |  __/ | |_| | | (_| | | | \__ \ || (_) | |  | | | | | | (_| | |_| | (_) | | | |
43  * |_| |_|\___/ \__,_|\___|  \__|_|  \__,_|_| |_|___/_| \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
44  *
45  ****************************************************************************************************/
46
47 #define MIPS_GENBINFUNC(mips_nodetype)                                                                                                                  \
48         static ir_node* mips_gen_##mips_nodetype(mips_transform_env_t *env, ir_node *op1, ir_node *op2) {\
49                 ASSERT_NO_FLOAT(env->mode);                                                                                                                             \
50                 /*assert(get_irn_mode(op1) == get_irn_mode(op2));*/                                                                             \
51                 /*assert(get_irn_mode(op1) == env->mode);*/                                                                                             \
52                 assert(get_mode_size_bits(env->mode) == 32);                                                                                    \
53                 return new_rd_mips_##mips_nodetype(env->dbg, env->irg, env->block, op1, op2, env->mode);\
54         }
55
56 MIPS_GENBINFUNC(add);
57 MIPS_GENBINFUNC(sub);
58 MIPS_GENBINFUNC(div);
59 MIPS_GENBINFUNC(and);
60 MIPS_GENBINFUNC(or);
61 MIPS_GENBINFUNC(xor);
62 MIPS_GENBINFUNC(sl);
63 MIPS_GENBINFUNC(sr);
64 MIPS_GENBINFUNC(sra);
65
66 #define MIPS_GENUNFUNC(mips_nodetype)                                                                                                                   \
67         static ir_node *mips_gen_##mips_nodetype(mips_transform_env_t *env, ir_node *op) {                      \
68                 ASSERT_NO_FLOAT(env->mode);                                                                                                                             \
69                 assert(get_irn_mode(op) == env->mode);                                                                                                  \
70                 assert(get_mode_size_bits(env->mode) == 32);                                                                                    \
71                 return new_rd_mips_##mips_nodetype(env->dbg, env->irg, env->block, op, env->mode);              \
72         }
73
74 MIPS_GENUNFUNC(not);
75
76 static ir_node* mips_get_reg_node(mips_transform_env_t *env, const arch_register_t *reg) {
77         return be_abi_get_callee_save_irn(env->cg->birg->abi, reg);
78 }
79
80 static ir_node* gen_zero_node(mips_transform_env_t *env, dbg_info *ebg, ir_graph *irg, ir_node *block)
81 {
82         ir_node *zero = be_abi_get_callee_save_irn(env->cg->birg->abi, &mips_general_purpose_regs[REG_ZERO]);
83         // TODO make zero nodes work
84         //ir_node *unknown = new_rd_mips_zero(dbg, irg, block, mode);
85
86         return zero;
87 }
88
89 static ir_node* gen_node_for_Const(mips_transform_env_t *env, dbg_info *dbg, ir_graph *irg, ir_node *block, ir_node *constant)
90 {
91         tarval* tv = get_Const_tarval(constant);
92         ir_node *lui;
93         ir_node *lli;
94         mips_attr_t *attr;
95         ir_mode* mode = get_irn_mode(constant);
96         unsigned long val, lower, upper;
97
98         val = get_tarval_long(tv);
99         if(val == 0)
100                 return gen_zero_node(env, dbg, irg, block);
101
102         lower = val & 0xffff;
103         upper = (val >> 16) & 0xffff;
104         if(upper == 0) {
105                 ir_node *zero = gen_zero_node(env, dbg, irg, block);
106                 ir_node *lli = new_rd_mips_lli(dbg, irg, block, zero, mode);
107                 attr = get_mips_attr(lli);
108                 attr->tv = new_tarval_from_long(val, mode);
109
110                 return lli;
111         }
112
113         lui = new_rd_mips_lui(dbg, irg, block, mode);
114         attr = get_mips_attr(lui);
115         attr->tv = new_tarval_from_long(val, mode);
116
117         if(lower == 0)
118                 return lui;
119
120         lli = new_rd_mips_lli(dbg, irg, block, lui, mode);
121         attr = get_mips_attr(lli);
122         attr->tv = new_tarval_from_long(val, mode);
123
124         return lli;
125 }
126
127 static ir_node* exchange_node_for_Const(mips_transform_env_t *env, ir_node* pred, int n) {
128         ir_node *node = env->irn;
129         dbg_info *dbg = get_irn_dbg_info(pred);
130         ir_graph *irg = get_irn_irg(node);
131         ir_mode* mode = get_irn_mode(pred);
132         ir_node *block;
133
134         if(get_irn_opcode(node) == iro_Phi) {
135                 ir_node *phipred = get_nodes_block(node);
136                 block = get_Block_cfgpred_block(phipred, n);
137         } else {
138                 block = get_nodes_block(node);
139         }
140
141         return gen_node_for_Const(env, dbg, irg, block, pred);
142 }
143
144 static ir_node* gen_node_for_SymConst(mips_transform_env_t *env, ir_node* pred, int n) {
145         ir_node *result;
146         symconst_kind kind;
147         mips_attr_t *attr;
148         ir_node *node = env->irn;
149         dbg_info *dbg = get_irn_dbg_info(pred);
150         ir_graph *irg = get_irn_irg(node);
151         ir_mode* mode = get_irn_mode(pred);
152         ir_node *block;
153
154         if (is_Phi(node)) {
155                 ir_node *phipred = get_nodes_block(node);
156                 block = get_Block_cfgpred_block(phipred, n);
157         } else {
158                 block = get_nodes_block(node);
159         }
160
161         kind = get_SymConst_kind(pred);
162         if(kind == symconst_addr_ent) {
163                 result = new_rd_mips_la(dbg, irg, block, mode);
164                 attr = get_mips_attr(result);
165                 attr->symconst_id = get_entity_ld_ident(get_SymConst_entity(pred));
166                 return result;
167         } else if(kind == symconst_addr_name) {
168                 result = new_rd_mips_la(dbg, irg, block, mode);
169                 attr = get_mips_attr(result);
170                 attr->symconst_id = get_SymConst_name(pred);
171                 return result;
172         }
173
174         // TODO
175         assert(0);
176         return NULL;
177 }
178
179 /**
180  * Generates a mips node for a firm Load node
181  */
182 static ir_node *gen_node_for_Load(mips_transform_env_t *env) {
183         ir_node *node = env->irn;
184         ir_node *result = NULL;
185         ir_mode *mode;
186         ir_node *load_ptr;
187         mips_attr_t *attr;
188
189         ASSERT_NO_FLOAT(get_irn_mode(node));
190
191         mode = get_Load_mode(node);
192         assert(mode->vector_elem == 1);
193         assert(mode->sort == irms_int_number || mode->sort == irms_reference);
194
195         load_ptr = get_Load_ptr(node);
196         assert(get_mode_sort(mode) == irms_reference || get_mode_sort(mode) == irms_int_number);
197         result = new_rd_mips_load_r(env->dbg, env->irg, env->block,
198                         get_Load_mem(node), load_ptr, get_irn_mode(node));
199
200         attr = get_mips_attr(result);
201         attr->tv = new_tarval_from_long(0, mode_Iu);
202         attr->modes.load_store_mode = mode;
203
204         return result;
205 }
206
207 /**
208  * Generates a mips node for a firm Store node
209  */
210 static ir_node *gen_node_for_Store(mips_transform_env_t *env) {
211         ir_node *node = env->irn;
212         ir_node *result = NULL;
213         ir_mode *mode;
214         mips_attr_t *attr;
215         ir_node *store_ptr;
216
217         ASSERT_NO_FLOAT(env->mode);
218
219         store_ptr = get_Store_ptr(node);
220         mode = get_irn_mode(store_ptr);
221         assert(mode->vector_elem == 1);
222         assert(mode->sort == irms_int_number || mode->sort == irms_reference);
223
224         if(get_irn_opcode(store_ptr) == iro_SymConst) {
225                 result = new_rd_mips_store_i(env->dbg, env->irg, env->block, get_Store_mem(node),
226                         get_Store_ptr(node), get_Store_value(node), env->mode);
227         } else {
228                 result = new_rd_mips_store_r(env->dbg, env->irg, env->block, get_Store_mem(node),
229                         get_Store_ptr(node), get_Store_value(node), env->mode);
230         }
231         attr = get_mips_attr(result);
232         attr->tv = new_tarval_from_long(0, mode_Iu);
233         attr->modes.load_store_mode = mode;
234
235         return result;
236 }
237
238 static ir_node *gen_node_for_div_Proj(mips_transform_env_t *env) {
239         ir_node *proj = env->irn;
240         ir_node *new_proj;
241         ir_node *pred = get_irn_n(proj, 0);
242         mips_attr_t *attr;
243         long n;
244
245         n = get_Proj_proj(proj);
246
247         // set the div mode to the DivMod node
248         attr = get_mips_attr(pred);
249         assert(attr->modes.original_mode == NULL || attr->modes.original_mode == env->mode);
250         attr->modes.original_mode = env->mode;
251
252         // we have to construct a new proj here, to avoid circular refs that
253         // happen when we reuse the old one
254         new_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, mode_ANY, 1, &pred);
255         set_Proj_proj(new_proj, n);
256
257         if(n == pn_DivMod_res_div) {
258                 return new_rd_mips_mflo(env->dbg, env->irg, env->block, new_proj, env->mode);
259         } else if(n == pn_DivMod_res_mod) {
260                 return new_rd_mips_mfhi(env->dbg, env->irg, env->block, new_proj, env->mode);
261         }
262
263         return proj;
264 }
265
266 static ir_node *make_jmp_or_fallthrough(mips_transform_env_t *env)
267 {
268         const ir_edge_t *edge;
269         ir_node *node = env->irn;
270         ir_node *next_block;
271         int our_block_sched_nr = mips_get_block_sched_nr(get_nodes_block(node));
272
273         edge = get_irn_out_edge_first(node);
274         next_block = get_edge_src_irn(edge);
275
276         if(mips_get_sched_block(env->cg, our_block_sched_nr + 1) == next_block) {
277                 return new_rd_mips_fallthrough(env->dbg, env->irg, env->block, mode_X);
278         }
279
280         return new_rd_mips_b(env->dbg, env->irg, env->block, mode_X);
281 }
282
283 static ir_node *gen_node_for_Cond_Proj(mips_transform_env_t *env, ir_node* node, int true_false)
284 {
285         // we can't use get_Cond_selector here because the selector is already
286         // replaced by a mips_ compare node
287         ir_node *proj = get_Cond_selector(node);
288         ir_node *original_cmp = get_irn_n(proj, 0);
289         ir_node *result = NULL;
290         ir_node *cmp;
291         ir_node *condjmp;
292         ir_node *op1, *op2;
293         dbg_info *dbg = env->dbg;
294         ir_graph *irg = env->irg;
295         ir_node *block = env->block;
296         long n;
297
298         n = get_Proj_proj(proj);
299         assert(n < 8 && "Only ordered comps supported");
300
301         assert(get_irn_opcode(original_cmp) == iro_Cmp);
302         op1 = get_Cmp_left(original_cmp);
303         op2 = get_Cmp_right(original_cmp);
304
305         switch(n) {
306         case pn_Cmp_False:
307                 if(true_false)
308                         return NULL;
309
310                 return make_jmp_or_fallthrough(env);
311
312         case pn_Cmp_Eq:
313                 if(!true_false)
314                         return make_jmp_or_fallthrough(env);
315
316                 condjmp = new_rd_mips_beq(dbg, irg, block, op1, op2, mode_T);
317                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
318
319         case pn_Cmp_Lt:
320                 if(!true_false)
321                         return make_jmp_or_fallthrough(env);
322
323                 cmp = new_rd_mips_slt(dbg, irg, block, op1, op2, get_irn_mode(op1));
324                 condjmp = new_rd_mips_bgtz(dbg, irg, block, cmp, mode_T);
325                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
326
327         case pn_Cmp_Le:
328                 if(!true_false)
329                         return make_jmp_or_fallthrough(env);
330
331                 cmp = new_rd_mips_slt(dbg, irg, block, op2, op1, get_irn_mode(op1));
332                 condjmp = new_rd_mips_blez(dbg, irg, block, cmp, mode_T);
333                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
334
335         case pn_Cmp_Gt:
336                 if(!true_false)
337                         return make_jmp_or_fallthrough(env);
338
339                 cmp = new_rd_mips_slt(dbg, irg, block, op2, op1, get_irn_mode(op1));
340                 condjmp = new_rd_mips_bgtz(dbg, irg, block, cmp, mode_T);
341                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
342
343         case pn_Cmp_Ge:
344                 if(!true_false)
345                         return make_jmp_or_fallthrough(env);
346
347                 cmp = new_rd_mips_slt(dbg, irg, block, op1, op2, get_irn_mode(op1));
348                 condjmp = new_rd_mips_blez(dbg, irg, block, cmp, mode_T);
349                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
350
351         case pn_Cmp_Lg:
352                 if(!true_false)
353                         return make_jmp_or_fallthrough(env);
354
355                 condjmp = new_rd_mips_bne(dbg, irg, block, op1, op2, mode_T);
356                 return new_rd_Proj(dbg, irg, block, condjmp, mode_X, 1);
357
358         case pn_Cmp_Leg:
359                 if(!true_false)
360                         return NULL;
361
362                 return make_jmp_or_fallthrough(env);
363
364         default:
365                 assert(0);
366         }
367
368         return NULL;
369 }
370
371 static ir_node *gen_node_for_Proj(mips_transform_env_t *env)
372 {
373         ir_node *proj = env->irn;
374         long n;
375         ir_node *predecessor = get_Proj_pred(proj);
376
377         // all DivMods, Div, Mod should be replaced by now
378         assert(get_irn_opcode(predecessor) != iro_DivMod);
379         assert(get_irn_opcode(predecessor) != iro_Div);
380         assert(get_irn_opcode(predecessor) != iro_Mod);
381
382         if(is_mips_div(predecessor))
383                 return gen_node_for_div_Proj(env);
384
385         if(get_irn_opcode(predecessor) == iro_Cond) {
386                 ir_node *selector = get_Cond_selector(predecessor);
387                 ir_mode *mode = get_irn_mode(selector);
388                 n = get_Proj_proj(proj);
389
390                 if(get_mode_sort(mode) == irms_internal_boolean) {
391                         assert(n == pn_Cond_true || n == pn_Cond_false);
392                         return gen_node_for_Cond_Proj(env, predecessor, n == pn_Cond_true);
393                 }
394         }
395
396         return proj;
397 }
398
399 static ir_node *gen_node_for_Cond(mips_transform_env_t *env)
400 {
401         ir_node *selector = get_Cond_selector(env->irn);
402         ir_mode *selector_mode = get_irn_mode(selector);
403         ir_node *node = env->irn;
404         dbg_info *dbg = env->dbg;
405         ir_graph *irg = env->irg;
406         ir_node *block = env->block;
407         ir_node *sub, *sltu, *minval_const, *max_const, *switchjmp;
408         ir_node *defaultproj, *defaultproj_succ;
409         ir_node *beq, *sl;
410         long pn, minval, maxval, defaultprojn;
411         const ir_edge_t *edge;
412         ir_node *zero, *two_const, *add, *la, *load, *proj;
413         ir_mode *unsigned_mode;
414         mips_attr_t *attr;
415
416         // mode_b conds are handled by gen_node_for_Proj
417         if(get_mode_sort(selector_mode) != irms_int_number)
418                 return env->irn;
419
420         assert(get_mode_size_bits(selector_mode) == 32);
421
422         defaultprojn = get_Cond_defaultProj(node);
423
424         // go over all projs to find min-&maxval of the switch
425         minval = INT_MAX;
426         maxval = INT_MIN;
427         foreach_out_edge(node, edge) {
428                 ir_node* proj = get_edge_src_irn(edge);
429                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
430
431                 pn = get_Proj_proj(proj);
432                 if(pn == defaultprojn) {
433                         defaultproj = proj;
434                         continue;
435                 }
436
437                 if(pn < minval)
438                         minval = pn;
439                 if(pn > maxval)
440                         maxval = pn;
441         }
442         assert(defaultproj != NULL);
443
444         // subtract minval from the switch value
445
446         if(minval != 0) {
447                 minval_const = new_rd_Const(dbg, irg, block, selector_mode, new_tarval_from_long(minval, selector_mode));
448                 minval_const = gen_node_for_Const(env, dbg, irg, block, minval_const);
449                 sub = new_rd_mips_sub(dbg, irg, block, selector, minval_const, selector_mode);
450         } else {
451                 sub = selector;
452         }
453
454         // compare if we're above maxval-minval or below zero.
455         // we can do this with 1 compare because we use unsigned mode
456         unsigned_mode = new_ir_mode(get_mode_name(selector_mode),
457                         get_mode_sort(selector_mode), get_mode_size_bits(selector_mode),
458                         0, get_mode_arithmetic(selector_mode), get_mode_modulo_shift(selector_mode));
459
460         max_const = new_rd_Const(dbg, irg, block, unsigned_mode, new_tarval_from_long(maxval - minval + 1, unsigned_mode));
461         max_const = gen_node_for_Const(env, dbg, irg, block, max_const);
462         sltu = new_rd_mips_slt(dbg, irg, block, sub, max_const, unsigned_mode);
463
464         zero = gen_zero_node(env, dbg, irg, block);
465         beq = new_rd_mips_beq(dbg, irg, block, sltu, zero, mode_T);
466
467         // attach defaultproj to beq now
468         set_irn_n(defaultproj, 0, beq);
469         set_Proj_proj(defaultproj, 1);
470
471         two_const = new_rd_Const(dbg, irg, block, unsigned_mode, new_tarval_from_long(2, unsigned_mode));
472         two_const = gen_node_for_Const(env, dbg, irg, block, two_const);
473         sl = new_rd_mips_sl(dbg, irg, block, sub, two_const, unsigned_mode);
474
475         la = new_rd_mips_la(dbg, irg, block, mode_Iu);
476         add = new_rd_mips_add(dbg, irg, block, sl, la, mode_Iu);
477         load = new_rd_mips_load_r(dbg, irg, block, new_rd_NoMem(irg), add, mode_T);
478         attr = get_mips_attr(load);
479         attr->modes.load_store_mode = mode_Iu;
480         attr->tv = new_tarval_from_long(0, mode_Iu);
481
482         proj = new_rd_Proj(dbg, irg, block, load, mode_Iu, pn_Load_res);
483
484         switchjmp = new_rd_mips_SwitchJump(dbg, irg, block, proj, mode_T);
485         attr = get_mips_attr(switchjmp);
486         attr->switch_default_pn = defaultprojn;
487
488         edge = get_irn_out_edge_first(defaultproj);
489         defaultproj_succ = get_edge_src_irn(edge);
490         attr->symconst_id = new_id_from_str(mips_get_block_label(defaultproj_succ));
491
492         attr = get_mips_attr(la);
493         attr->symconst_id = new_id_from_str(mips_get_jumptbl_label(switchjmp));
494
495         return switchjmp;
496 }
497
498 static ir_node *create_conv_store_load(mips_transform_env_t *env, ir_mode* srcmode, ir_mode* dstmode) {
499         ir_node *nomem, *store, *mem_proj, *value_proj, *load;
500         entity *mem_entity;
501         ir_node *node = env->irn;
502         ir_node *pred = get_Conv_op(node);
503         ir_node *sp;
504         // TODO HACK make this global...
505         ident* id;
506         ir_type *i32type;
507         ir_type *ptr_i32type;
508         mips_attr_t* attr;
509
510         id = new_id_from_str("__conv0");
511         i32type = new_type_primitive(new_id_from_str("ptr32"), mode_Iu);
512         ptr_i32type = new_d_type_pointer(id, i32type, mode_P, env->dbg);
513         mem_entity = new_d_entity(get_irg_frame_type(env->irg), id, ptr_i32type, env->dbg);
514
515         sp = mips_get_reg_node(env, &mips_general_purpose_regs[REG_SP]);
516         nomem = new_ir_node(env->dbg, env->irg, env->block, op_NoMem, mode_M, 0, NULL);
517
518         store = new_rd_mips_store_r(env->dbg, env->irg, env->block, nomem, sp, pred, mode_T);
519         attr = get_mips_attr(store);
520         attr->tv = new_tarval_from_long(0, mode_Iu);
521         attr->modes.load_store_mode = srcmode;
522         attr->stack_entity = mem_entity;
523
524         mem_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, mode_M, 1, &store);
525         set_Proj_proj(mem_proj, pn_Store_M);
526
527         load = new_rd_mips_load_r(env->dbg, env->irg, env->block, mem_proj, sp, mode_T);
528         attr = get_mips_attr(load);
529         attr->tv = new_tarval_from_long(0, mode_Iu);
530         attr->modes.load_store_mode = dstmode;
531         attr->stack_entity = mem_entity;
532
533         value_proj = new_ir_node(env->dbg, env->irg, env->block, op_Proj, env->mode, 1, &load);
534         set_Proj_proj(value_proj, pn_Load_res);
535
536         return value_proj;
537 }
538
539 static ir_node *create_conv_and(mips_transform_env_t *env, long immediate) {
540         ir_node *node = env->irn;
541         ir_node *pred;
542         ir_node *result;
543         mips_attr_t *attr;
544
545         pred = get_Conv_op(node);
546         result = new_rd_mips_andi(env->dbg, env->irg, env->block, pred, node->mode);
547         attr = get_mips_attr(result);
548         attr->tv = new_tarval_from_long(immediate, mode_Iu);
549
550         return result;
551 }
552
553 static ir_node *gen_node_for_Conv(mips_transform_env_t *env) {
554         ir_node *node = env->irn;
555         ir_node *pred;
556         ir_mode *srcmode;
557         ir_mode *destmode;
558         int dst_size, src_size;
559
560         pred = get_Conv_op(node);
561         srcmode = get_irn_mode(pred);
562         destmode = get_irn_mode(node);
563
564         dst_size = get_mode_size_bits(destmode);
565         src_size = get_mode_size_bits(srcmode);
566
567         if(srcmode->size >= destmode->size) {
568                 assert(srcmode->size > destmode->size || srcmode->sign != destmode->sign);
569                 return new_rd_mips_reinterpret_conv(env->dbg, env->irg, env->block, pred, node->mode);
570         }
571         if(srcmode->sign) {
572                 if(srcmode->size == 8) {
573                         return create_conv_store_load(env, mode_Bs, mode_Bs);
574                 } else if(srcmode->size == 16) {
575                         return create_conv_store_load(env, mode_Hs, mode_Hs);
576                 }
577         } else {
578                 if(src_size == 8) {
579                         return create_conv_and(env, 0xff);
580                 } else if(src_size == 16) {
581                         return create_conv_and(env, 0xffff);
582                 }
583         }
584
585         assert(0);
586         return NULL;
587 }
588
589 static ir_node *gen_node_mips_div(mips_transform_env_t *env, ir_node* op1, ir_node* op2, long p_div, long p_mod,
590                                                                   long p_m, long p_x)
591 {
592         ir_node *node = env->irn;
593         ir_node *div;
594         const ir_edge_t *edge;
595
596         div = new_rd_mips_div(env->dbg, env->irg, env->block, op1, op2, mode_T);
597
598         // Adjust div projs
599         foreach_out_edge(node, edge) {
600                 ir_node *proj = get_edge_src_irn(edge);
601                 long n = get_Proj_proj(proj);
602                 assert(is_Proj(proj) && "non-Proj from Mod node");
603                 if (n == p_div) {
604                         set_Proj_proj(proj, pn_DivMod_res_div);
605                 } else if (n == p_mod) {
606                         set_Proj_proj(proj, pn_DivMod_res_mod);
607                 } else if(n == p_m) {
608                         set_Proj_proj(proj, pn_DivMod_M);
609                 } else if(n == p_x) {
610                         set_Proj_proj(proj, pn_DivMod_X_except);
611                 } else {
612                         assert(!"invalid proj");
613                 }
614         }
615
616         return div;
617 }
618
619 static ir_node *gen_node_for_DivMod(mips_transform_env_t *env) {
620         ir_node *node = env->irn;
621
622         return gen_node_mips_div(env, get_DivMod_left(node), get_DivMod_right(node), pn_DivMod_res_div,
623                                                          pn_DivMod_res_mod, pn_DivMod_M, pn_DivMod_X_except);
624 }
625
626 static ir_node *gen_node_for_Div(mips_transform_env_t *env) {
627         ir_node *node = env->irn;
628
629         return gen_node_mips_div(env, get_Div_left(node), get_Div_right(node), pn_Div_res, -1,
630                                                          pn_Div_M, pn_Div_X_except);
631 }
632
633 static ir_node *gen_node_for_Mod(mips_transform_env_t *env) {
634         ir_node *node = env->irn;
635
636         return gen_node_mips_div(env, get_Mod_left(node), get_Mod_right(node), -1, pn_Mod_res,
637                                                          pn_Mod_M, pn_Mod_X_except);
638 }
639
640 static ir_node *gen_node_for_Mul(mips_transform_env_t *env) {
641         ir_node *node = env->irn;
642         ir_node *mul;
643         ir_node *mflo;
644         ir_node *op1, *op2;
645
646         op1 = get_Mul_left(node);
647         op2 = get_Mul_right(node);
648
649         assert(get_mode_size_bits(env->mode) == 32);
650         assert(get_mode_size_bits(get_irn_mode(op1)) == get_mode_size_bits(env->mode));
651         assert(get_mode_size_bits(get_irn_mode(op2)) == get_mode_size_bits(env->mode));
652
653         mul = new_rd_mips_mult(env->dbg, env->irg, env->block, get_Mul_left(node), get_Mul_right(node), env->mode);
654         mflo = new_rd_mips_mflo(env->dbg, env->irg, env->block, mul, env->mode);
655
656         return mflo;
657 }
658
659 static ir_node *gen_node_for_IJmp(mips_transform_env_t *env) {
660         ir_node *node = env->irn;
661
662         return new_rd_mips_j(env->dbg, env->irg, env->block, get_IJmp_target(node), node->mode);
663 }
664
665 static ir_node *gen_node_for_Jmp(mips_transform_env_t *env) {
666         return make_jmp_or_fallthrough(env);
667 }
668
669 static ir_node *gen_node_for_Abs(mips_transform_env_t *env) {
670         ir_node *node = env->irn;
671         ir_node *sra, *add, *xor;
672         mips_attr_t *attr;
673
674         // TODO for other bit sizes...
675         assert(get_mode_size_bits(env->mode) == 32);
676         sra = new_rd_mips_srai(env->dbg, env->irg, env->block, get_Abs_op(node), node->mode);
677         attr = get_mips_attr(sra);
678         attr->tv = new_tarval_from_long(31, mode_Iu);
679         add = new_rd_mips_add(env->dbg, env->irg, env->block, get_Abs_op(node), sra, node->mode);
680         xor = new_rd_mips_xor(env->dbg, env->irg, env->block, sra, add, node->mode);
681
682         return xor;
683 }
684
685 static ir_node *gen_node_for_Rot(mips_transform_env_t *env) {
686         ir_node *node = env->irn;
687         ir_node *subu, *srlv, *sllv, *or;
688
689         subu = new_rd_mips_subuzero(env->dbg, env->irg, env->block, get_Rot_right(node), env->mode);
690         srlv = new_rd_mips_srlv(env->dbg, env->irg, env->block, get_Rot_left(node), subu, env->mode);
691         sllv = new_rd_mips_sllv(env->dbg, env->irg, env->block, get_Rot_left(node), get_Rot_right(node), env->mode);
692         or = new_rd_mips_or(env->dbg, env->irg, env->block, sllv, srlv, env->mode);
693
694         return or;
695 }
696
697 static ir_node *gen_node_for_Unknown(mips_transform_env_t *env)
698 {
699         return gen_zero_node(env, env->dbg, env->irg, env->block);
700 }
701
702 /*
703  * lower a copyB into standard Firm assembler :-)
704  */
705 ir_node *gen_code_for_CopyB(ir_node *block, ir_node *node) {
706         ir_node *cnt, *sub;
707         ir_node *dst = get_CopyB_dst(node);
708         ir_node *src = get_CopyB_src(node);
709         ir_type *type = get_CopyB_type(node);
710         ir_node *mem = get_CopyB_mem(node);
711         ir_node *mm[4];
712         ir_node *result = NULL;
713         int size = get_type_size_bytes(type);
714         dbg_info *dbg = get_irn_dbg_info(node);
715         ir_graph *irg = get_irn_irg(block);
716         mips_attr_t *attr;
717         int i, n;
718
719         if (size > 16) {
720                 ir_node     *phi, *projT, *projF, *cmp, *proj, *cond, *jmp, *in[2];
721                 ir_node     *new_bl, *src_phi, *dst_phi, *mem_phi, *add;
722                 ir_mode     *p_mode = get_irn_mode(src);
723                 ir_node     *ld[4];
724
725                 /* build the control loop */
726                 in[0] = in[1] = new_r_Unknown(irg, mode_X);
727
728                 new_bl = new_r_Block(irg, 2, in);
729
730                 in[0] = cnt = new_Const_long(mode_Is, (size >> 4));
731         in[1] = new_r_Unknown(irg, mode_Is);
732                 phi   = new_r_Phi(irg, new_bl, 2, in, mode_Is);
733
734                 sub = new_rd_Sub(dbg, irg, new_bl, phi, new_Const_long(mode_Is, -1), mode_Is);
735                 set_Phi_pred(phi, 1, sub);
736
737                 cmp = new_rd_Cmp(dbg, irg, new_bl, sub, new_Const_long(mode_Is, 0));
738                 proj = new_r_Proj(irg, new_bl, cmp, mode_b, pn_Cmp_Lg);
739                 cond = new_rd_Cond(dbg, irg, new_bl, proj);
740
741                 projT = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_true);
742                 projF = new_r_Proj(irg, new_bl, cond, mode_X, pn_Cond_false);
743
744                 jmp = get_Block_cfgpred(block, 0);
745                 set_Block_cfgpred(block, 0, projF);
746
747                 set_Block_cfgpred(new_bl, 0, jmp);
748                 set_Block_cfgpred(new_bl, 1, projT);
749
750                 size &= 0xF;
751
752                 /* build the copy */
753                 in[0]   = src;
754         in[1]   = new_r_Unknown(irg, p_mode);
755                 src_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
756
757                 in[0]   = dst;
758                 dst_phi = new_r_Phi(irg, new_bl, 2, in, p_mode);
759
760                 add = new_rd_Add(dbg, irg, new_bl, src_phi, new_Const_long(mode_Is, 16), p_mode);
761                 set_Phi_pred(src_phi, 1, add);
762                 add = new_rd_Add(dbg, irg, new_bl, dst_phi, new_Const_long(mode_Is, 16), p_mode);
763                 set_Phi_pred(dst_phi, 1, add);
764
765                 in[0]   = mem;
766         in[1]   = new_r_Unknown(irg, mode_M);
767                 mem_phi = new_r_Phi(irg, new_bl, 2, in, mode_M);
768
769                 src = src_phi;
770                 dst = dst_phi;
771
772                 /* create 4 parallel loads */
773                 for (i = 0; i < 4; ++i) {
774                         ir_node *load;
775
776                         load = new_rd_mips_load_r(dbg, irg, new_bl, mem_phi, src, mode_T);
777                         attr = get_mips_attr(load);
778                         attr->modes.load_store_mode = mode_Iu;
779                         attr->tv = new_tarval_from_long(i * 4, mode_Iu);
780
781                         ld[i] = new_rd_Proj(dbg, irg, new_bl, load, mode_Iu, pn_Load_res);
782                 }
783
784                 /* create 4 parallel stores */
785                 for (i = 0; i < 4; ++i) {
786                         ir_node *store;
787
788                         store = new_rd_mips_store_r(dbg, irg, new_bl, mem_phi, dst, ld[i], mode_T);
789                         attr = get_mips_attr(store);
790                         attr->modes.load_store_mode = mode_Iu;
791                         attr->tv = new_tarval_from_long(i * 4, mode_Iu);
792
793                         mm[i] = new_rd_Proj(dbg, irg, new_bl, store, mode_M, pn_Store_M);
794                 }
795                 mem = new_r_Sync(irg, new_bl, 4, mm);
796                 result = mem;
797                 set_Phi_pred(mem_phi, 1, mem);
798         }
799
800         // output store/loads manually
801         n = 0;
802         for(i = size; i > 0; ) {
803                 ir_mode *mode;
804                 ir_node *load, *store, *projv;
805                 int offset = size - i;
806                 if(i >= 4) {
807                         mode = mode_Iu;
808                         i -= 4;
809                 } else if(i >= 2) {
810                         mode = mode_Hu;
811                         i -= 2;
812                 } else {
813                         mode = mode_Bu;
814                         i -= 1;
815                 }
816
817                 load = new_rd_mips_load_r(dbg, irg, block, mem, src, mode_T);
818                 attr = get_mips_attr(load);
819                 attr->modes.load_store_mode = mode;
820                 attr->tv = new_tarval_from_long(offset, mode_Iu);
821
822                 projv = new_rd_Proj(dbg, irg, block, load, mode, pn_Load_res);
823
824                 store = new_rd_mips_store_r(dbg, irg, block, mem, dst, projv, mode_T);
825                 attr = get_mips_attr(store);
826                 attr->modes.load_store_mode = mode;
827                 attr->tv = new_tarval_from_long(offset, mode_Iu);
828
829                 mm[n] = new_rd_Proj(dbg, irg, block, store, mode_M, pn_Store_M);
830                 n++;
831         }
832
833         if(n > 0) {
834                 result = new_r_Sync(irg, block, n, mm);
835         } else if(n == 1) {
836                 result = mm[0];
837         }
838
839         return result;
840 }
841
842 static void mips_fix_CopyB_Proj(mips_transform_env_t* env) {
843         ir_node *node = env->irn;
844         long n = get_Proj_proj(node);
845
846         if(n == pn_CopyB_M_except) {
847                 assert(0);
848         } else if(n == pn_CopyB_M_regular) {
849                 set_Proj_proj(node, pn_Store_M);
850         } else if(n == pn_CopyB_M_except) {
851                 set_Proj_proj(node, pn_Store_X_except);
852         }
853 }
854
855 static void mips_transform_Spill(mips_transform_env_t* env) {
856         ir_node *node = env->irn;
857         ir_node *sched_point = NULL;
858         ir_node *store, *proj;
859         ir_node *nomem = new_rd_NoMem(env->irg);
860         ir_node *ptr   = get_irn_n(node, 0);
861         ir_node *val   = get_irn_n(node, 1);
862         entity  *ent   = be_get_frame_entity(node);
863         mips_attr_t *attr;
864
865         if(sched_is_scheduled(node)) {
866                 sched_point = sched_prev(node);
867         }
868
869         store = new_rd_mips_store_r(env->dbg, env->irg, env->block, nomem, ptr, val, mode_T);
870         attr = get_mips_attr(store);
871         attr->stack_entity = ent;
872         attr->modes.load_store_mode = get_irn_mode(val);
873
874         proj = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
875
876         if (sched_point) {
877                 sched_add_after(sched_point, store);
878                 sched_add_after(store, proj);
879
880                 sched_remove(node);
881         }
882
883         exchange(node, proj);
884 }
885
886 static void mips_transform_Reload(mips_transform_env_t* env) {
887         ir_node *node = env->irn;
888         ir_node *sched_point = NULL;
889         ir_node *load, *proj;
890         ir_node *nomem = new_rd_NoMem(env->irg);
891         ir_node *ptr   = get_irn_n(node, 0);
892         ir_node *mem   = get_irn_n(node, 1);
893         ir_mode *mode  = get_irn_mode(node);
894         entity  *ent   = be_get_frame_entity(node);
895         const arch_register_t* reg;
896         mips_attr_t *attr;
897
898         if(sched_is_scheduled(node)) {
899                 sched_point = sched_prev(node);
900         }
901
902         load = new_rd_mips_load_r(env->dbg, env->irg, env->block, mem, ptr, mode_T);
903         attr = get_mips_attr(load);
904         attr->stack_entity = ent;
905         attr->modes.load_store_mode = mode;
906
907         proj = new_rd_Proj(env->dbg, env->irg, env->block, load, mode, pn_Load_res);
908
909         if (sched_point) {
910                 sched_add_after(sched_point, load);
911                 sched_add_after(load, proj);
912
913                 sched_remove(node);
914         }
915
916         /* copy the register from the old node to the new Load */
917         reg = arch_get_irn_register(env->cg->arch_env, node);
918         arch_set_irn_register(env->cg->arch_env, proj, reg);
919
920         exchange(node, proj);
921 }
922
923 static ir_node *gen_node_for_StackParam(mips_transform_env_t *env)
924 {
925         ir_node *node = env->irn;
926         ir_node *sp = get_irn_n(node, 0);
927         ir_node *load;
928         ir_node *nomem = new_rd_NoMem(env->irg);
929         ir_node *proj;
930         mips_attr_t *attr;
931
932         load = new_rd_mips_load_r(env->dbg, env->irg, env->block, nomem, sp, mode_T);
933         attr = get_mips_attr(load);
934         attr->stack_entity = be_get_frame_entity(node);
935         attr->modes.load_store_mode = env->mode;
936
937         proj = new_rd_Proj(env->dbg, env->irg, env->block, load, env->mode, pn_Load_res);
938
939         return proj;
940 }
941
942 static ir_node *gen_node_for_AddSP(mips_transform_env_t *env)
943 {
944         ir_node *node = env->irn;
945         ir_node *op1, *op2;
946         ir_node *add;
947         const arch_register_t *reg;
948
949         op1 = get_irn_n(node, 0);
950         op2 = get_irn_n(node, 1);
951
952         add = new_rd_mips_add(env->dbg, env->irg, env->block, op1, op2, mode_Iu);
953
954         /* copy the register requirements from the old node to the new node */
955         reg = arch_get_irn_register(env->cg->arch_env, node);
956         arch_set_irn_register(env->cg->arch_env, add, reg);
957
958         return add;
959 }
960
961 /*********************************************************
962  *                  _             _      _
963  *                 (_)           | |    (_)
964  *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
965  * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
966  * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
967  * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
968  *
969  *********************************************************/
970
971
972 /**
973  * Transforms the given firm node (and maybe some other related nodes)
974  * into one or more assembler nodes.
975  *
976  * @param node    the firm node
977  * @param env     the debug module
978  */
979 void mips_transform_node(ir_node *node, void *env) {
980         mips_code_gen_t *cgenv = (mips_code_gen_t *)env;
981         opcode  code               = get_irn_opcode(node);
982         ir_node *asm_node          = node;
983         mips_transform_env_t tenv;
984
985         if (is_Block(node))
986                 return;
987
988         tenv.block    = get_nodes_block(node);
989         tenv.dbg      = get_irn_dbg_info(node);
990         tenv.irg      = current_ir_graph;
991         tenv.irn      = node;
992         tenv.mod      = cgenv->mod;
993         tenv.mode     = get_irn_mode(node);
994         tenv.cg           = cgenv;
995
996 #define UNOP(firm_opcode, mips_nodetype)        case iro_##firm_opcode: asm_node = mips_gen_##mips_nodetype(&tenv, get_##firm_opcode##_op(node)); break
997 #define BINOP(firm_opcode, mips_nodetype)       case iro_##firm_opcode: asm_node = mips_gen_##mips_nodetype(&tenv, get_##firm_opcode##_left(node), get_##firm_opcode##_right(node)); break
998 #define IGN(a)         case iro_##a: break
999 #define BAD(a)         case iro_##a: goto bad
1000
1001         DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
1002
1003         switch (code) {
1004                 BINOP(Add, add);
1005                 BINOP(Sub, sub);
1006                 BINOP(And, and);
1007                 BINOP(Or, or);
1008                 BINOP(Eor, xor);
1009                 UNOP(Not, not);
1010                 BINOP(Shl, sl);
1011                 BINOP(Shr, sr);
1012                 BINOP(Shrs, sra);
1013
1014         case iro_Abs:
1015                 asm_node = gen_node_for_Abs(&tenv);
1016                 break;
1017
1018         case iro_Rot:
1019                 asm_node = gen_node_for_Rot(&tenv);
1020                 break;
1021
1022         case iro_Div:
1023                 asm_node = gen_node_for_Div(&tenv);
1024                 break;
1025
1026         case iro_Mod:
1027                 asm_node = gen_node_for_Mod(&tenv);
1028                 break;
1029
1030         case iro_Load:
1031                 asm_node = gen_node_for_Load(&tenv);
1032                 break;
1033
1034         case iro_Store:
1035                 asm_node = gen_node_for_Store(&tenv);
1036                 break;
1037
1038         case iro_Proj:
1039                 asm_node = gen_node_for_Proj(&tenv);
1040                 break;
1041
1042         case iro_Conv:
1043                 asm_node = gen_node_for_Conv(&tenv);
1044                 break;
1045
1046         case iro_DivMod:
1047                 asm_node = gen_node_for_DivMod(&tenv);
1048                 break;
1049
1050         case iro_Mul:
1051                 asm_node = gen_node_for_Mul(&tenv);
1052                 break;
1053
1054         case iro_Jmp:
1055                 asm_node = gen_node_for_Jmp(&tenv);
1056                 break;
1057
1058         case iro_IJmp:
1059                 asm_node = gen_node_for_IJmp(&tenv);
1060                 break;
1061
1062         case iro_Unknown:
1063                 asm_node = gen_node_for_Unknown(&tenv);
1064                 break;
1065
1066         case iro_Cond:
1067                 asm_node = gen_node_for_Cond(&tenv);
1068                 break;
1069
1070                 /* TODO: implement these nodes */
1071                 BAD(Mux);
1072
1073                 /* You probably don't need to handle the following nodes */
1074
1075                 // call is handled in the emit phase
1076                 IGN(Call);
1077                 // Cmp is handled together with Cond
1078                 IGN(Cmp);
1079                 IGN(Alloc);
1080
1081                 IGN(Block);
1082                 IGN(Start);
1083                 IGN(End);
1084                 IGN(NoMem);
1085                 IGN(Phi);
1086                 IGN(Break);
1087                 IGN(Sync);
1088
1089                 IGN(Const);
1090                 IGN(SymConst);
1091
1092                 BAD(Raise);
1093                 BAD(Sel);
1094                 BAD(InstOf);
1095                 BAD(Cast);
1096                 BAD(Free);
1097                 BAD(Tuple);
1098                 BAD(Id);
1099                 BAD(Bad);
1100                 BAD(Confirm);
1101                 BAD(Filter);
1102                 BAD(CallBegin);
1103                 BAD(EndReg);
1104                 BAD(EndExcept);
1105
1106                 default:
1107                         if(be_is_StackParam(node)) {
1108                                 asm_node = gen_node_for_StackParam(&tenv);
1109                         } else if(be_is_AddSP(node)) {
1110                                 asm_node = gen_node_for_AddSP(&tenv);
1111                         }
1112                         break;
1113
1114 bad:
1115                 fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
1116                 assert(0);
1117         }
1118
1119         if (asm_node != node) {
1120                 exchange(node, asm_node);
1121                 DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
1122         } else {
1123                 DB((tenv.mod, LEVEL_1, "ignored\n"));
1124         }
1125 }
1126
1127 void mips_pre_transform_node(ir_node *node, void *env) {
1128         mips_code_gen_t *cgenv = (mips_code_gen_t *)env;
1129         int i;
1130
1131         mips_transform_env_t tenv;
1132
1133         if (is_Block(node))
1134                 return;
1135
1136         tenv.block    = get_nodes_block(node);
1137         tenv.dbg      = get_irn_dbg_info(node);
1138         tenv.irg      = current_ir_graph;
1139         tenv.irn      = node;
1140         tenv.mod      = cgenv->mod;
1141         tenv.mode     = get_irn_mode(node);
1142         tenv.cg           = cgenv;
1143
1144         if(is_Proj(node)) {
1145                 ir_node* pred = get_Proj_pred(node);
1146
1147                 if(get_irn_opcode(pred) == iro_CopyB) {
1148                         mips_fix_CopyB_Proj(&tenv);
1149                 }
1150         }
1151
1152         for(i = 0; i < get_irn_arity(node); ++i) {
1153                 ir_node* pred = get_irn_n(node, i);
1154
1155                 if (is_Const(pred)) {
1156                         ir_node* constnode = exchange_node_for_Const(&tenv, pred, i);
1157                         set_irn_n(node, i, constnode);
1158                 } else if (get_irn_op(pred) == op_SymConst) {
1159                         ir_node* constnode = gen_node_for_SymConst(&tenv, pred, i);
1160                         set_irn_n(node, i, constnode);
1161                 }
1162         }
1163 }
1164
1165 /**
1166  * Calls the transform functions for Spill and Reload.
1167  */
1168 void mips_after_ra_walker(ir_node *node, void *env) {
1169         mips_code_gen_t *cg = env;
1170         mips_transform_env_t tenv;
1171
1172         if (is_Block(node))
1173                 return;
1174
1175         tenv.block = get_nodes_block(node);
1176         tenv.dbg   = get_irn_dbg_info(node);
1177         tenv.irg   = current_ir_graph;
1178         tenv.irn   = node;
1179         tenv.mod   = cg->mod;
1180         tenv.mode  = get_irn_mode(node);
1181         tenv.cg    = cg;
1182
1183         /* be_is_StackParam(node) || */
1184         if (be_is_Reload(node)) {
1185                 mips_transform_Reload(&tenv);
1186         } else if (be_is_Spill(node)) {
1187                 mips_transform_Spill(&tenv);
1188         }
1189 }