convert bitfield initializer tarvals before using them
[libfirm] / ir / lower / lower_intrinsics.c
1 /*
2  * Copyright (C) 1995-2008 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   lowering of Calls of intrinsic functions
23  * @author  Michael Beck
24  * @version $Id$
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "lowering.h"
32 #include "irop_t.h"
33 #include "irprog_t.h"
34 #include "irnode_t.h"
35 #include "irprog_t.h"
36 #include "irgwalk.h"
37 #include "ircons.h"
38 #include "irgmod.h"
39 #include "irgopt.h"
40 #include "trouts.h"
41 #include "irvrfy.h"
42 #include "pmap.h"
43 #include "xmalloc.h"
44 #include "array_t.h"
45 #include "iropt_dbg.h"
46
47 /** Walker environment. */
48 typedef struct _walker_env {
49         pmap     *c_map;              /**< The intrinsic call map. */
50         unsigned nr_of_intrinsics;    /**< statistics */
51         i_instr_record **i_map;       /**< The intrinsic instruction map. */
52 } walker_env_t;
53
54 /**
55  * walker: call all mapper functions
56  */
57 static void call_mapper(ir_node *node, void *env) {
58         walker_env_t *wenv = env;
59         ir_op *op = get_irn_op(node);
60
61         if (op == op_Call) {
62                 ir_node *symconst;
63                 pmap_entry *p;
64                 const i_call_record *r;
65                 ir_entity *ent;
66
67                 symconst = get_Call_ptr(node);
68                 if (! is_Global(symconst))
69                         return;
70
71                 ent = get_Global_entity(symconst);
72                 p   = pmap_find(wenv->c_map, ent);
73
74                 if (p) {
75                         r = p->value;
76                         wenv->nr_of_intrinsics += r->i_mapper(node, r->ctx) ? 1 : 0;
77                 }
78         } else {
79                 if (op->code < (unsigned) ARR_LEN(wenv->i_map)) {
80                         const i_instr_record *r = wenv->i_map[op->code];
81                         /* run all possible mapper */
82                         while (r) {
83                                 if (r->i_mapper(node, r->ctx)) {
84                                         ++wenv->nr_of_intrinsics;
85                                         break;
86                                 }
87                                 r = r->link;
88                         }
89                 }
90         }
91 }  /* call_mapper */
92
93 /* Go through all graphs and map calls to intrinsic functions. */
94 unsigned lower_intrinsics(i_record *list, int length, int part_block_used) {
95         int            i, n_ops = get_irp_n_opcodes();
96         ir_graph       *irg;
97         pmap           *c_map = pmap_create_ex(length);
98         i_instr_record **i_map;
99         unsigned       nr_of_intrinsics = 0;
100         walker_env_t   wenv;
101
102         /* we use the ir_op generic pointers here */
103         NEW_ARR_A(const i_instr_record *, i_map, n_ops);
104         memset((void *)i_map, 0, sizeof(*i_map) * n_ops);
105
106         /* fill a map for faster search */
107         for (i = length - 1; i >= 0; --i) {
108                 if (list[i].i_call.kind == INTRINSIC_CALL) {
109                         pmap_insert(c_map, list[i].i_call.i_ent, (void *)&list[i].i_call);
110                 } else {
111                         ir_op *op = list[i].i_instr.op;
112                         assert(op->code < (unsigned) ARR_LEN(i_map));
113
114                         list[i].i_instr.link = i_map[op->code];
115                         i_map[op->code] = &list[i].i_instr;
116                 }
117         }
118
119         wenv.c_map = c_map;
120         wenv.i_map = i_map;
121
122         for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
123                 irg = get_irp_irg(i);
124
125                 if (part_block_used)
126                         collect_phiprojs(irg);
127
128                 wenv.nr_of_intrinsics = 0;
129                 irg_walk_graph(irg, NULL, call_mapper, &wenv);
130
131                 if (wenv.nr_of_intrinsics > 0) {
132                         /* Changes detected: we might have added/removed nodes. */
133                         set_irg_outs_inconsistent(irg);
134                         set_irg_callee_info_state(irg, irg_callee_info_inconsistent);
135
136                         /* Exception control flow might have changed / new block might have added. */
137                         set_irg_doms_inconsistent(irg);
138                         set_irg_extblk_inconsistent(irg);
139                         set_irg_loopinfo_inconsistent(irg);
140
141                         /* Calls might be removed/added. */
142                         set_trouts_inconsistent();
143
144                         /* verify here */
145                         irg_verify(irg, VRFY_NORMAL);
146
147                         /* Optimize it, tuple might be created. */
148                         optimize_graph_df(irg);
149
150                         nr_of_intrinsics += wenv.nr_of_intrinsics;
151                 }
152         }
153         pmap_destroy(c_map);
154
155         return nr_of_intrinsics;
156 }  /* lower_intrinsics */
157
158 /**
159  * Helper function, replace the call by the given node.
160  *
161  * @param irn      the result node
162  * @param call     the call to replace
163  * @param mem      the new mem result
164  * @param reg_jmp  new regular control flow, if NULL, a Jmp will be used
165  * @param exc_jmp  new exception control flow, if reg_jmp == NULL, a Bad will be used
166  */
167 static void replace_call(ir_node *irn, ir_node *call, ir_node *mem, ir_node *reg_jmp, ir_node *exc_jmp) {
168         ir_node *block = get_nodes_block(call);
169
170         if (reg_jmp == NULL) {
171
172                 /* Beware: do we need here a protection against CSE? Better we do it. */
173                 int old_cse = get_opt_cse();
174                 set_opt_cse(0);
175                 reg_jmp = new_r_Jmp(current_ir_graph, block);
176                 set_opt_cse(old_cse);
177                 exc_jmp = new_Bad();
178         }
179         irn = new_r_Tuple(current_ir_graph, block, 1, &irn);
180
181         turn_into_tuple(call, pn_Call_max);
182         set_Tuple_pred(call, pn_Call_M_regular, mem);
183         set_Tuple_pred(call, pn_Call_X_regular, reg_jmp);
184         set_Tuple_pred(call, pn_Call_X_except, exc_jmp);
185         set_Tuple_pred(call, pn_Call_T_result, irn);
186         set_Tuple_pred(call, pn_Call_M_except, mem);
187         set_Tuple_pred(call, pn_Call_P_value_res_base, new_Bad());
188 }  /* replace_call */
189
190 /* A mapper for the integer abs. */
191 int i_mapper_abs(ir_node *call, void *ctx) {
192         ir_node *mem   = get_Call_mem(call);
193         ir_node *block = get_nodes_block(call);
194         ir_node *op    = get_Call_param(call, 0);
195         ir_node *irn;
196         dbg_info *dbg  = get_irn_dbg_info(call);
197         (void) ctx;
198
199         irn = new_rd_Abs(dbg, current_ir_graph, block, op, get_irn_mode(op));
200         DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_ABS);
201         replace_call(irn, call, mem, NULL, NULL);
202         return 1;
203 }  /* i_mapper_abs */
204
205 /* A mapper for the alloca() function. */
206 int i_mapper_alloca(ir_node *call, void *ctx) {
207         ir_node *mem   = get_Call_mem(call);
208         ir_node *block = get_nodes_block(call);
209         ir_node *op    = get_Call_param(call, 0);
210         ir_node *irn, *exc, *no_exc;
211         dbg_info *dbg  = get_irn_dbg_info(call);
212         (void) ctx;
213
214         if (mode_is_signed(get_irn_mode(op))) {
215                 op = new_rd_Conv(dbg, current_ir_graph, block, op, mode_Iu);
216         }
217
218         irn    = new_rd_Alloc(dbg, current_ir_graph, block, mem, op, firm_unknown_type, stack_alloc);
219         mem    = new_rd_Proj(dbg, current_ir_graph, block, irn, mode_M, pn_Alloc_M);
220         no_exc = new_rd_Proj(dbg, current_ir_graph, block, irn, mode_X, pn_Alloc_X_regular);
221         exc    = new_rd_Proj(dbg, current_ir_graph, block, irn, mode_X, pn_Alloc_X_except);
222         irn    = new_rd_Proj(dbg, current_ir_graph, block, irn, get_modeP_data(), pn_Alloc_res);
223
224         DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_ALLOCA);
225         replace_call(irn, call, mem, no_exc, exc);
226         return 1;
227 }  /* i_mapper_alloca */
228
229 /* A mapper for the floating point sqrt. */
230 int i_mapper_sqrt(ir_node *call, void *ctx) {
231         ir_node *mem;
232         tarval *tv;
233         ir_node *op = get_Call_param(call, 0);
234         (void) ctx;
235
236         if (!is_Const(op))
237                 return 0;
238
239         tv = get_Const_tarval(op);
240         if (! tarval_is_null(tv) && !tarval_is_one(tv))
241                 return 0;
242
243         mem = get_Call_mem(call);
244
245         /* sqrt(0) = 0, sqrt(1) = 1 */
246         DBG_OPT_ALGSIM0(call, op, FS_OPT_RTS_SQRT);
247         replace_call(op, call, mem, NULL, NULL);
248         return 1;
249 }  /* i_mapper_sqrt */
250
251 /* A mapper for the floating point cbrt. */
252 int i_mapper_cbrt(ir_node *call, void *ctx) {
253         ir_node *mem;
254         tarval *tv;
255         ir_node *op = get_Call_param(call, 0);
256         (void) ctx;
257
258         if (!is_Const(op))
259                 return 0;
260
261         tv = get_Const_tarval(op);
262         if (! tarval_is_null(tv) && !tarval_is_one(tv) && !tarval_is_minus_one(tv))
263                 return 0;
264
265         mem = get_Call_mem(call);
266
267         /* cbrt(0) = 0, cbrt(1) = 1, cbrt(-1) = -1 */
268         DBG_OPT_ALGSIM0(call, op, FS_OPT_RTS_CBRT);
269         replace_call(op, call, mem, NULL, NULL);
270         return 1;
271 }  /* i_mapper_cbrt */
272
273 /* A mapper for the floating point pow. */
274 int i_mapper_pow(ir_node *call, void *ctx) {
275         dbg_info *dbg;
276         ir_node *mem;
277         ir_node *left  = get_Call_param(call, 0);
278         ir_node *right = get_Call_param(call, 1);
279         ir_node *block = get_nodes_block(call);
280         ir_node *irn, *reg_jmp = NULL, *exc_jmp = NULL;
281         (void) ctx;
282
283         if (is_Const(left) && is_Const_one(left)) {
284                 /* pow (1.0, x) = 1.0 */
285                 irn = left;
286         } else if (is_Const(right)) {
287                 tarval *tv = get_Const_tarval(right);
288                 if (tarval_is_null(tv)) {
289                         /* pow(x, 0.0) = 1.0 */
290                         ir_mode *mode = get_tarval_mode(tv);
291                         irn = new_r_Const(current_ir_graph, block, mode, get_mode_one(mode));
292                 } else if (tarval_is_one(tv)) {
293                         /* pow(x, 1.0) = x */
294                         irn = left;
295                 } else if (tarval_is_minus_one(tv)) {
296                         /* pow(x, -1.0) = 1/x */
297                         irn = NULL;
298                 } else
299                         return 0;
300         } else {
301                 return 0;
302         }
303
304         mem = get_Call_mem(call);
305         dbg = get_irn_dbg_info(call);
306
307         if (irn == NULL) {
308                 ir_mode *mode = get_irn_mode(left);
309                 ir_node *quot;
310
311                 irn  = new_r_Const(current_ir_graph, block, mode, get_mode_one(mode));
312                 quot = new_rd_Quot(dbg, current_ir_graph, block, mem, irn, left, mode, op_pin_state_pinned);
313                 mem  = new_r_Proj(current_ir_graph, block, quot, mode_M, pn_Quot_M);
314                 irn  = new_r_Proj(current_ir_graph, block, quot, mode, pn_Quot_res);
315                 reg_jmp = new_r_Proj(current_ir_graph, block, quot, mode_X, pn_Quot_X_regular);
316                 exc_jmp = new_r_Proj(current_ir_graph, block, quot, mode_X, pn_Quot_X_except);
317         }
318         DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_POW);
319         replace_call(irn, call, mem, reg_jmp, exc_jmp);
320         return 1;
321 }  /* i_mapper_pow */
322
323 /* A mapper for the floating point exp. */
324 int i_mapper_exp(ir_node *call, void *ctx) {
325         ir_node *val  = get_Call_param(call, 0);
326         (void) ctx;
327
328         if (is_Const(val) && is_Const_null(val)) {
329                 /* exp(0.0) = 1.0 */
330                 ir_node *block = get_nodes_block(call);
331                 ir_mode *mode  = get_irn_mode(val);
332                 ir_node *irn   = new_r_Const(current_ir_graph, block, mode, get_mode_one(mode));
333                 ir_node *mem   = get_Call_mem(call);
334                 DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_EXP);
335                 replace_call(irn, call, mem, NULL, NULL);
336                 return 1;
337         }
338         return 0;
339 }  /* i_mapper_exp */
340
341 /**
342  * A mapper for mapping f(0.0) to 0.0.
343  */
344 static int i_mapper_zero_to_zero(ir_node *call, void *ctx, int reason) {
345         ir_node *val  = get_Call_param(call, 0);
346         (void) ctx;
347
348         if (is_Const(val) && is_Const_null(val)) {
349                 /* f(0.0) = 0.0 */
350                 ir_node *mem = get_Call_mem(call);
351                 DBG_OPT_ALGSIM0(call, val, reason);
352                 replace_call(val, call, mem, NULL, NULL);
353                 return 1;
354         }
355         return 0;
356 }  /* i_mapper_zero_to_zero */
357
358 /**
359  * A mapper for mapping f(1.0) to 0.0.
360  */
361 static int i_mapper_one_to_zero(ir_node *call, void *ctx, int reason) {
362         ir_node *val  = get_Call_param(call, 0);
363         (void) ctx;
364
365         if (is_Const(val) && is_Const_one(val)) {
366                 /* acos(1.0) = 0.0 */
367                 ir_node *block = get_nodes_block(call);
368                 ir_mode *mode  = get_irn_mode(val);
369                 ir_node *irn   = new_r_Const(current_ir_graph, block, mode, get_mode_null(mode));
370                 ir_node *mem   = get_Call_mem(call);
371                 DBG_OPT_ALGSIM0(call, irn, reason);
372                 replace_call(irn, call, mem, NULL, NULL);
373                 return 1;
374         }
375         return 0;
376 }  /* i_mapper_one_to_zero */
377
378 /**
379  * A mapper for mapping a functions with the following characteristics:
380  * f(-x)  = f(x).
381  * f(0.0) = 1.0
382  */
383 static int i_mapper_symmetric_zero_to_one(ir_node *call, void *ctx, int reason) {
384         ir_node *val  = get_Call_param(call, 0);
385         (void) ctx;
386
387         if (is_strictConv(val)) {
388                 ir_node *op = get_Conv_op(val);
389                 if (is_Minus(op)) {
390                         /* f(-x) = f(x) with strictConv */
391                         ir_node *block = get_nodes_block(call);
392                         ir_mode *mode  = get_irn_mode(val);
393                         dbg_info *dbg  = get_irn_dbg_info(val);
394
395                         op = get_Minus_op(op);
396                         val = new_rd_Conv(dbg, current_ir_graph, block, op, mode);
397                         if (is_Conv(val)) {
398                                 /* still a Conv ? */
399                                 set_Conv_strict(val, 1);
400                         }
401                         DBG_OPT_ALGSIM2(call, op, call, FS_OPT_RTS_SYMMETRIC);
402                         set_Call_param(call, 0, val);
403                 }
404         } else if (is_Minus(val)) {
405                 /* f(-x) = f(x) */
406                 val = get_Minus_op(val);
407                 DBG_OPT_ALGSIM2(call, val, call, FS_OPT_RTS_SYMMETRIC);
408                 set_Call_param(call, 0, val);
409         }
410
411         if (is_Const(val) && is_Const_null(val)) {
412                 /* f(0.0) = 1.0 */
413                 ir_node *block = get_nodes_block(call);
414                 ir_mode *mode  = get_irn_mode(val);
415                 ir_node *irn   = new_r_Const(current_ir_graph, block, mode, get_mode_one(mode));
416                 ir_node *mem   = get_Call_mem(call);
417                 DBG_OPT_ALGSIM0(call, irn, reason);
418                 replace_call(irn, call, mem, NULL, NULL);
419                 return 1;
420         }
421         return 0;
422 }  /* i_mapper_symmetric_zero_to_one */
423
424 /* A mapper for the floating point log. */
425 int i_mapper_log(ir_node *call, void *ctx) {
426         /* log(1.0) = 0.0 */
427         return i_mapper_one_to_zero(call, ctx, FS_OPT_RTS_LOG);
428 }  /* i_mapper_log */
429
430 /* A mapper for the floating point sin. */
431 int i_mapper_sin(ir_node *call, void *ctx) {
432         /* sin(0.0) = 0.0 */
433         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_SIN);
434 }  /* i_mapper_sin */
435
436 /* A mapper for the floating point cos. */
437 int i_mapper_cos(ir_node *call, void *ctx) {
438         /* cos(0.0) = 1.0, cos(-x) = x */
439         return i_mapper_symmetric_zero_to_one(call, ctx, FS_OPT_RTS_COS);
440 }  /* i_mapper_cos */
441
442 /* A mapper for the floating point tan. */
443 int i_mapper_tan(ir_node *call, void *ctx) {
444         /* tan(0.0) = 0.0 */
445         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_TAN);
446 }  /* i_mapper_tan */
447
448 /* A mapper for the floating point asin. */
449 int i_mapper_asin(ir_node *call, void *ctx) {
450         /* asin(0.0) = 0.0 */
451         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_ASIN);
452 }  /* i_mapper_asin */
453
454 /* A mapper for the floating point acos. */
455 int i_mapper_acos(ir_node *call, void *ctx) {
456         /* acos(1.0) = 0.0 */
457         return i_mapper_one_to_zero(call, ctx, FS_OPT_RTS_ACOS);
458 }  /* i_mapper_acos */
459
460 /* A mapper for the floating point atan. */
461 int i_mapper_atan(ir_node *call, void *ctx) {
462         /* atan(0.0) = 0.0 */
463         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_ATAN);
464 }  /* i_mapper_atan */
465
466 /* A mapper for the floating point sinh. */
467 int i_mapper_sinh(ir_node *call, void *ctx) {
468         /* sinh(0.0) = 0.0 */
469         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_SINH);
470 }  /* i_mapper_sinh */
471
472 /* A mapper for the floating point cosh. */
473 int i_mapper_cosh(ir_node *call, void *ctx) {
474         /* cosh(0.0) = 1.0, cosh(-x) = x */
475         return i_mapper_symmetric_zero_to_one(call, ctx, FS_OPT_RTS_COSH);
476 }  /* i_mapper_cosh */
477
478 /* A mapper for the floating point tanh. */
479 int i_mapper_tanh(ir_node *call, void *ctx) {
480         /* tanh(0.0) = 0.0 */
481         return i_mapper_zero_to_zero(call, ctx, FS_OPT_RTS_TANH);
482 }  /* i_mapper_tanh */
483
484 /**
485  * Return the const entity that is accessed through the pointer ptr or
486  * NULL if there is no entity (or the entity is not constant).
487  *
488  * @param ptr  the pointer
489  */
490 static ir_entity *get_const_entity(ir_node *ptr) {
491         /* FIXME: this cannot handle constant strings inside struct initializers yet */
492         if (is_Global(ptr)) {
493                 ir_entity *ent = get_Global_entity(ptr);
494
495                 if (get_entity_variability(ent) == variability_constant) {
496                         /* a constant entity */
497                         return ent;
498                 }
499         }
500         return NULL;
501 }  /* get_const_entity */
502
503 /**
504  * Calculate the value of strlen if possible.
505  *
506  * @param ent     the entity
507  * @param res_tp  the result type
508  *
509  * @return a Const node containing the strlen() result or NULL
510  *         if the evaluation fails
511  */
512 static ir_node *eval_strlen(ir_entity *ent, ir_type *res_tp) {
513         ir_type *tp = get_entity_type(ent);
514         ir_mode *mode;
515         int     i, n, len = -1;
516
517         if (! is_Array_type(tp))
518                 return NULL;
519         tp = get_array_element_type(tp);
520         if (! is_Primitive_type(tp))
521                 return NULL;
522         mode = get_type_mode(tp);
523
524         /* FIXME: This is too restrict, as the type char might be more the 8bits */
525         if (!mode_is_int(mode) || get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
526                 return NULL;
527
528         n = get_compound_ent_n_values(ent);
529         for (i = 0; i < n; ++i) {
530                 ir_node *irn = get_compound_ent_value(ent, i);
531
532                 if (! is_Const(irn))
533                         return NULL;
534
535                 if (is_Const_null(irn)) {
536                         /* found the length */
537                         len = i;
538                         break;
539                 }
540         }
541         if (len >= 0) {
542                 tarval *tv = new_tarval_from_long(len, get_type_mode(res_tp));
543                 return new_Const_type(tv, res_tp);
544         }
545         return NULL;
546 }  /* eval_strlen */
547
548 /* A mapper for strlen */
549 int i_mapper_strlen(ir_node *call, void *ctx) {
550         ir_node *s     = get_Call_param(call, 0);
551         ir_entity *ent = get_const_entity(s);
552
553         (void) ctx;
554
555         /* FIXME: this cannot handle constant strings inside struct initializers yet */
556         if (ent != NULL) {
557                 /* a constant entity */
558                 ir_type *tp = get_Call_type(call);
559                 ir_node *irn;
560
561                 tp  = get_method_res_type(tp, 0);
562                 irn = eval_strlen(ent, tp);
563
564                 if (irn) {
565                         ir_node *mem = get_Call_mem(call);
566                         DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_STRLEN);
567                         replace_call(irn, call, mem, NULL, NULL);
568                         return 1;
569                 }
570         }
571         return 0;
572 }  /* i_mapper_strlen */
573
574 /**
575  * Calculate the value of strlen if possible.
576  *
577  * @param left    the left entity
578  * @param right   the right entity
579  * @param res_tp  the result type
580  *
581  * @return a Const node containing the strcmp() result or NULL
582  *         if the evaluation fails
583  */
584 static ir_node *eval_strcmp(ir_entity *left, ir_entity *right, ir_type *res_tp) {
585         ir_type *tp;
586         ir_mode *mode;
587         int     i, n, n_r, res;
588
589         tp = get_entity_type(left);
590         if (! is_Array_type(tp))
591                 return NULL;
592         tp = get_array_element_type(tp);
593         if (! is_Primitive_type(tp))
594                 return NULL;
595         mode = get_type_mode(tp);
596
597         /* FIXME: This is too restrict, as the type char might be more the 8bits */
598         if (!mode_is_int(mode) || get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
599                 return NULL;
600
601         tp = get_entity_type(right);
602         if (! is_Array_type(tp))
603                 return NULL;
604         tp = get_array_element_type(tp);
605         if (! is_Primitive_type(tp))
606                 return NULL;
607         mode = get_type_mode(tp);
608
609         /* FIXME: This is too restrict, as the type char might be more the 8bits */
610         if (!mode_is_int(mode) || get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
611                 return NULL;
612
613         n   = get_compound_ent_n_values(left);
614         n_r = get_compound_ent_n_values(right);
615         if (n_r < n)
616                 n = n_r;
617         for (i = 0; i < n; ++i) {
618                 ir_node *irn;
619                 long v_l, v_r;
620                 tarval *tv;
621
622                 irn = get_compound_ent_value(left, i);
623                 if (! is_Const(irn))
624                         return NULL;
625                 tv = get_Const_tarval(irn);
626                 v_l = get_tarval_long(tv);
627
628                 irn = get_compound_ent_value(right, i);
629                 if (! is_Const(irn))
630                         return NULL;
631                 tv = get_Const_tarval(irn);
632                 v_r = get_tarval_long(tv);
633
634                 if (v_l < v_r) {
635                         res = -1;
636                         break;
637                 }
638                 if (v_l > v_r) {
639                         res = +1;
640                         break;
641                 }
642
643                 if (v_l == 0) {
644                         res = 0;
645                         break;
646                 }
647         }
648         if (i < n) {
649                 /* we found an end */
650                 tarval *tv = new_tarval_from_long(res, get_type_mode(res_tp));
651                 return new_Const_type(tv, res_tp);
652         }
653         return NULL;
654 }  /* eval_strcmp */
655
656 /**
657  * Checks if an entity represents the empty string.
658  *
659  * @param ent     the entity
660  *
661  * @return non-zero if ent represents the empty string
662  */
663 static int is_empty_string(ir_entity *ent) {
664         ir_type *tp = get_entity_type(ent);
665         ir_mode *mode;
666         int     n;
667         ir_node *irn;
668
669         if (! is_Array_type(tp))
670                 return 0;
671         tp = get_array_element_type(tp);
672         if (! is_Primitive_type(tp))
673                 return 0;
674         mode = get_type_mode(tp);
675
676         /* FIXME: This is too restrict, as the type char might be more the 8bits */
677         if (!mode_is_int(mode) || get_mode_size_bits(mode) != get_mode_size_bits(mode_Bs))
678                 return 0;
679
680         n = get_compound_ent_n_values(ent);
681         if (n < 1)
682                 return 0;
683         irn = get_compound_ent_value(ent, 0);
684
685         return is_Const(irn) && is_Const_null(irn);
686 }  /* is_empty_string */
687
688 /* A mapper for strcmp */
689 int i_mapper_strcmp(ir_node *call, void *ctx) {
690         ir_node   *left    = get_Call_param(call, 0);
691         ir_node   *right   = get_Call_param(call, 1);
692         ir_node   *irn     = NULL;
693         ir_node   *exc     = NULL;
694         ir_node   *reg     = NULL;
695         ir_type   *call_tp = get_Call_type(call);
696         ir_type   *res_tp  = get_method_res_type(call_tp, 0);
697         ir_entity *ent_l, *ent_r;
698         ir_type   *char_tp;
699         ir_node   *v;
700
701         (void) ctx;
702
703         /* do some type checks first */
704         if (! is_Primitive_type(res_tp))
705                 return 0;
706         char_tp = get_method_param_type(call_tp, 0);
707         if (char_tp != get_method_param_type(call_tp, 1))
708                 return 0;
709         if (! is_Pointer_type(char_tp))
710                 return 0;
711         char_tp = get_pointer_points_to_type(char_tp);
712
713         if (left == right) {
714                 /* a strcmp(s, s) ==> 0 */
715                 ir_node *mem   = get_Call_mem(call);
716                 ir_mode *mode  = get_type_mode(res_tp);
717                 ir_node *block = get_nodes_block(call);
718
719                 irn = new_r_Const(current_ir_graph, block, mode, get_mode_null(mode));
720                 DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_STRCMP);
721                 replace_call(irn, call, mem, NULL, NULL);
722                 return 1;
723         }
724         ent_l = get_const_entity(left);
725         ent_r = get_const_entity(right);
726
727         if (ent_l != NULL && ent_r != NULL) {
728                 /* both entities are const, try to evaluate */
729                 irn = eval_strcmp(ent_l, ent_r, res_tp);
730         } else if (ent_l != NULL) {
731                 if (is_empty_string(ent_l)) {
732                         /* s strcmp("", s) ==> -(*s)*/
733                         v = right;
734                         goto replace_by_call;
735                 }
736         } else if (ent_r != NULL) {
737                 if (is_empty_string(ent_r)) {
738                         /* s strcmp(s, "") ==> (*s) */
739                         ir_node  *mem, *block;
740                         dbg_info *dbg;
741                         ir_mode  *mode;
742
743                         v = left;
744 replace_by_call:
745                         mem   = get_Call_mem(call);
746                         block = get_nodes_block(call);
747                         dbg   = get_irn_dbg_info(call);
748                         mode  = get_type_mode(char_tp);
749
750                         /* replace the strcmp by (*x) */
751                         irn = new_rd_Load(dbg, current_ir_graph, block, mem, v, mode);
752                         mem = new_r_Proj(current_ir_graph, block, irn, mode_M, pn_Load_M);
753                         exc = new_r_Proj(current_ir_graph, block, irn, mode_X, pn_Load_X_except);
754                         reg = new_r_Proj(current_ir_graph, block, irn, mode_X, pn_Load_X_regular);
755                         irn = new_r_Proj(current_ir_graph, block, irn, mode, pn_Load_res);
756
757                         /* conv to the result mode */
758                         mode = get_type_mode(res_tp);
759                         irn  = new_rd_Conv(dbg, current_ir_graph, block, irn, mode);
760
761                         if (v == right) {
762                                 /* negate in the ("", s) case */
763                                 irn = new_rd_Minus(dbg, current_ir_graph, block, irn, mode);
764                         }
765                 }
766         }
767
768         if (irn != NULL) {
769                 ir_node *mem = get_Call_mem(call);
770                 DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_STRCMP);
771                 replace_call(irn, call, mem, reg, exc);
772                 return 1;
773         }
774
775         return 0;
776 }  /* i_mapper_strcmp */
777
778 /* A mapper for strncmp */
779 int i_mapper_strncmp(ir_node *call, void *ctx) {
780         ir_node *left  = get_Call_param(call, 0);
781         ir_node *right = get_Call_param(call, 1);
782         ir_node *len   = get_Call_param(call, 2);
783         ir_node *irn;
784         (void) ctx;
785
786         if (left == right || (is_Const(len) && is_Const_null(len))) {
787                 /* a strncmp(s, s, len) ==> 0 OR
788                    a strncmp(a, b, 0) ==> 0 */
789                 ir_node   *mem     = get_Call_mem(call);
790                 ir_node   *adr     = get_Call_ptr(call);
791                 ir_entity *ent     = get_SymConst_entity(adr);
792                 ir_type   *call_tp = get_entity_type(ent);
793                 ir_type   *res_tp  = get_method_res_type(call_tp, 0);
794                 ir_mode   *mode    = get_type_mode(res_tp);
795                 ir_node   *block   = get_nodes_block(call);
796
797                 irn = new_r_Const(current_ir_graph, block, mode, get_mode_null(mode));
798                 DBG_OPT_ALGSIM0(call, irn, FS_OPT_RTS_STRNCMP);
799                 replace_call(irn, call, mem, NULL, NULL);
800                 return 1;
801         }
802         return 0;
803 }  /* i_mapper_strncmp */
804
805 /* A mapper for memcpy */
806 int i_mapper_memcpy(ir_node *call, void *ctx) {
807         ir_node *len = get_Call_param(call, 2);
808         (void) ctx;
809
810         if (is_Const(len) && is_Const_null(len)) {
811                 /* a memcpy(d, s, 0) ==> d */
812                 ir_node *mem = get_Call_mem(call);
813                 ir_node *dst = get_Call_param(call, 0);
814
815                 DBG_OPT_ALGSIM0(call, dst, FS_OPT_RTS_MEMCPY);
816                 replace_call(dst, call, mem, NULL, NULL);
817                 return 1;
818         }
819         return 0;
820 }  /* i_mapper_memcpy */
821
822 /* A mapper for memset */
823 int i_mapper_memset(ir_node *call, void *ctx) {
824         ir_node *len = get_Call_param(call, 2);
825         (void) ctx;
826
827         if (is_Const(len) && is_Const_null(len)) {
828                 /* a memset(d, C, 0) ==> d */
829                 ir_node *mem = get_Call_mem(call);
830                 ir_node *dst = get_Call_param(call, 0);
831
832                 DBG_OPT_ALGSIM0(call, dst, FS_OPT_RTS_MEMSET);
833                 replace_call(dst, call, mem, NULL, NULL);
834                 return 1;
835         }
836         return 0;
837 }  /* i_mapper_memset */
838
839 /**
840  * Returns the result mode of a node.
841  */
842 static ir_mode *get_irn_res_mode(ir_node *node) {
843         switch (get_irn_opcode(node)) {
844         case iro_Load:   return get_Load_mode(node);
845         case iro_Quot:   return get_Quot_resmode(node);
846         case iro_Div:    return get_Div_resmode(node);
847         case iro_Mod:    return get_Mod_resmode(node);
848         case iro_DivMod: return get_DivMod_resmode(node);
849         default: return NULL;
850         }
851 }  /* get_irn_res_mode */
852
853 #define LMAX(a, b) ((a) > (b) ? (a) : (b))
854
855 /* A mapper for mapping unsupported instructions to runtime calls. */
856 int i_mapper_RuntimeCall(ir_node *node, runtime_rt *rt) {
857         int i, j, arity, first, n_param, n_res;
858         long n_proj;
859         ir_type *mtp;
860         ir_node *mem, *bl, *call, *addr, *res_proj;
861         ir_node **in;
862         ir_graph *irg;
863         symconst_symbol sym;
864         ir_mode *mode = get_irn_mode(node);
865
866         if (mode != rt->mode)
867                 return 0;
868         /* check if the result modes match */
869         if (mode == mode_T && rt->res_mode != NULL) {
870                 mode = get_irn_res_mode(node);
871                 if (mode != rt->res_mode)
872                         return 0;
873         }
874
875         arity = get_irn_arity(node);
876         if (arity <= 0)
877                 return 0;
878
879         mtp     = get_entity_type(rt->ent);
880         n_param = get_method_n_params(mtp);
881         irg     = current_ir_graph;
882
883         mem = get_irn_n(node, 0);
884         if (get_irn_mode(mem) != mode_M) {
885                 mem = new_r_NoMem(irg);
886                 first = 0;
887         } else
888                 first = 1;
889
890         /* check if the modes of the predecessors match the parameter modes */
891         if (arity - first != n_param)
892                 return 0;
893
894         for (i = first, j = 0; i < arity; ++i, ++j) {
895                 ir_type *param_tp = get_method_param_type(mtp, j);
896                 ir_node *pred = get_irn_n(node, i);
897
898                 if (get_type_mode(param_tp) != get_irn_mode(pred))
899                         return 0;
900         }
901
902         n_res = get_method_n_ress(mtp);
903
904         /* step 0: calculate the number of needed Proj's */
905         n_proj = 0;
906         n_proj = LMAX(n_proj, rt->mem_proj_nr + 1);
907         n_proj = LMAX(n_proj, rt->regular_proj_nr + 1);
908         n_proj = LMAX(n_proj, rt->exc_proj_nr + 1);
909         n_proj = LMAX(n_proj, rt->exc_mem_proj_nr + 1);
910         n_proj = LMAX(n_proj, rt->res_proj_nr + 1);
911
912         if (n_proj > 0) {
913                 if (rt->mode != mode_T) /* must be mode_T */
914                         return 0;
915         } else {
916                 if (n_res > 0)
917                         /* must match */
918                         if (get_type_mode(get_method_res_type(mtp, 0)) != rt->mode)
919                                 return 0;
920         }
921
922         /* ok, when we are here, the number of predecessors match as well as the parameter modes */
923         bl = get_nodes_block(node);
924
925         in = NULL;
926         if (n_param > 0) {
927                 NEW_ARR_A(ir_node *, in, n_param);
928                 for (i = 0; i < n_param; ++i)
929                         in[i] = get_irn_n(node, first + i);
930         }
931
932         /* step 1: create the call */
933         sym.entity_p = rt->ent;
934         addr = new_r_SymConst(irg, bl, mode_P_code, sym, symconst_addr_ent);
935         call = new_rd_Call(get_irn_dbg_info(node), irg, bl, mem, addr, n_param, in, mtp);
936         set_irn_pinned(call, get_irn_pinned(node));
937
938         if (n_res > 0)
939                 res_proj = new_r_Proj(irg, bl, call, mode_T, pn_Call_T_result);
940         else
941                 res_proj = NULL;
942
943         if (n_proj > 0) {
944                 n_proj += n_res - 1;
945
946                 /* we are ready */
947                 turn_into_tuple(node, n_proj);
948
949                 for (i = 0; i < n_proj; ++i)
950                         set_Tuple_pred(node, i, new_r_Bad(irg));
951                 if (rt->mem_proj_nr >= 0)
952                         set_Tuple_pred(node, rt->mem_proj_nr, new_r_Proj(irg, bl, call, mode_M, pn_Call_M_regular));
953                 if (!is_NoMem(mem)) {
954                         /* Exceptions can only be handled with real memory */
955                         if (rt->regular_proj_nr >= 0)
956                                 set_Tuple_pred(node, rt->regular_proj_nr, new_r_Proj(irg, bl, call, mode_X, pn_Call_X_regular));
957                         if (rt->exc_proj_nr >= 0)
958                                 set_Tuple_pred(node, rt->exc_proj_nr, new_r_Proj(irg, bl, call, mode_X, pn_Call_X_except));
959                         if (rt->exc_mem_proj_nr >= 0)
960                                 set_Tuple_pred(node, rt->mem_proj_nr, new_r_Proj(irg, bl, call, mode_M, pn_Call_M_except));
961                 }
962
963                 if (rt->res_proj_nr >= 0)
964                         for (i = 0; i < n_res; ++i)
965                                 set_Tuple_pred(node, rt->res_proj_nr + i,
966                                 new_r_Proj(irg, bl, res_proj, get_type_mode(get_method_res_type(mtp, i)), i));
967                         return 1;
968         } else {
969                 /* only one return value supported */
970                 if (n_res > 0) {
971                         ir_mode *mode = get_type_mode(get_method_res_type(mtp, 0));
972
973                         res_proj = new_r_Proj(irg, bl, call, mode_T, pn_Call_T_result);
974                         res_proj = new_r_Proj(irg, bl, res_proj, mode, 0);
975
976                         exchange(node, res_proj);
977                         return 1;
978                 }
979         }
980         /* should not happen */
981         return 0;
982 }  /* i_mapper_RuntimeCall */