added
[libfirm] / ir / lower / lower_intrinsics.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/lower/lower_intrinsics.c
4  * Purpose:     lowering of Calls of intrinsic functions
5  * Author:      Michael Beck
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 1998-2005 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #ifdef HAVE_ALLOCA_H
17 #include <alloca.h>
18 #endif
19 #ifdef HAVE_MALLOC_H
20 #include <malloc.h>
21 #endif
22
23 #include "irprog_t.h"
24 #include "irnode_t.h"
25 #include "irgwalk.h"
26 #include "ircons.h"
27 #include "irgmod.h"
28 #include "lower_intrinsics.h"
29 #include "pmap.h"
30
31 typedef struct _walker_env {
32   pmap     *map;              /**< the intrinsic map. */
33   unsigned nr_of_intrinsics;  /**< statistics */
34 } walker_env_t;
35
36 /**
37  * walker: do the call mapping
38  */
39 static void call_mapper(ir_node *call, void *env) {
40   walker_env_t *wenv = env;
41   ir_node *symconst;
42   pmap_entry *p;
43   const i_record *r;
44   entity *ent;
45
46   if (get_irn_op(call) != op_Call)
47     return;
48
49   symconst = get_Call_ptr(call);
50   if (get_irn_op(symconst) != op_SymConst ||
51       get_SymConst_kind(symconst) != symconst_addr_ent)
52     return;
53
54   ent = get_SymConst_entity(symconst);
55   p   = pmap_find(wenv->map, ent);
56
57   if (p) {
58     r = p->value;
59     wenv->nr_of_intrinsics += r->i_mapper(call, r->ctx) ? 1 : 0;
60   }
61 }
62
63 /* Go through all graphs and map calls to intrinsic functions. */
64 unsigned lower_intrinsic_calls(const i_record *list, int length) {
65   int          i;
66   ir_graph     *irg;
67   pmap         *map = pmap_create_ex(length);
68   walker_env_t wenv;
69   unsigned     nr_of_intrinsics = 0;
70
71   /* fill a map for faster search */
72   for (i = length - 1; i >= 0; --i)
73     pmap_insert(map, list[i].i_ent, (void *)&list[i]);
74
75   wenv.map = map;
76
77   for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
78     irg = get_irp_irg(i);
79
80     wenv.nr_of_intrinsics = 0;
81     irg_walk_graph(irg, NULL, call_mapper, map);
82
83     if (wenv.nr_of_intrinsics) {
84       /* changes detected */
85       set_irg_outs_inconsistent(irg);
86       set_irg_callee_info_state(irg, irg_callee_info_inconsistent);
87
88       /* exception control flow might have changed */
89       set_irg_dom_inconsistent(irg);
90       set_irg_loopinfo_inconsistent(irg);
91
92       nr_of_intrinsics += wenv.nr_of_intrinsics;
93     }
94   }
95   pmap_destroy(map);
96
97   return nr_of_intrinsics;
98 }
99
100 /* A mapper for the integer abs. */
101 int i_mapper_Abs(ir_node *call, void *ctx) {
102   ir_node *mem   = get_Call_mem(call);
103   ir_node *block = get_nodes_block(call);
104   ir_node *op    = get_Call_param(call, 0);
105   ir_node *irn;
106   dbg_info *dbg  = get_irn_dbg_info(call);
107
108   irn = new_rd_Abs(dbg, current_ir_graph, block, op, get_irn_mode(op));
109   irn = new_Tuple(1, &irn);
110
111   turn_into_tuple(call, pn_Call_max);
112   set_Tuple_pred(call, pn_Call_M_regular, mem);
113   set_Tuple_pred(call, pn_Call_X_except, new_Bad());
114   set_Tuple_pred(call, pn_Call_T_result, irn);
115   set_Tuple_pred(call, pn_Call_M_except, mem);
116   set_Tuple_pred(call, pn_Call_P_value_res_base, new_Bad());
117
118   return 1;
119 }
120
121 /* A mapper for the alloca() function. */
122 int i_mapper_Alloca(ir_node *call, void *ctx) {
123   ir_node *mem   = get_Call_mem(call);
124   ir_node *block = get_nodes_block(call);
125   ir_node *op    = get_Call_param(call, 0);
126   ir_node *irn, *exc;
127   dbg_info *dbg  = get_irn_dbg_info(call);
128
129   irn = new_rd_Alloc(dbg, current_ir_graph, block, mem, op, firm_unknown_type, stack_alloc);
130   mem = new_Proj(irn, mode_M, pn_Alloc_M);
131   exc = new_Proj(irn, mode_X, pn_Alloc_X_except);
132   irn = new_Proj(irn, get_modeP_data(), pn_Alloc_res);
133   irn = new_Tuple(1, &irn);
134
135   turn_into_tuple(call, pn_Call_max);
136   set_Tuple_pred(call, pn_Call_M_regular, mem);
137   set_Tuple_pred(call, pn_Call_X_except, exc);
138   set_Tuple_pred(call, pn_Call_T_result, irn);
139   set_Tuple_pred(call, pn_Call_M_except, mem);
140   set_Tuple_pred(call, pn_Call_P_value_res_base, new_Bad());
141
142   return 1;
143 }