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