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