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