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