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