added support for Shl, Shr, Shrs and Mul
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
1 /**
2  * This file implements the mapping of 64Bit intrinsic functions to
3  * code or library calls.
4  * @author Michael Beck
5  * $Id$
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "irgmod.h"
13 #include "irop.h"
14 #include "irnode_t.h"
15 #include "ircons.h"
16 #include "irprog_t.h"
17 #include "lower_intrinsics.h"
18 #include "lower_dw.h"
19 #include "mangle.h"
20 #include "array.h"
21
22 #include "ia32_new_nodes.h"
23
24 /** The array of all intrinsics that must be mapped. */
25 static i_record *intrinsics;
26
27 /** An array to cache all entities */
28 static entity *i_ents[iro_MaxOpcode];
29
30 /*
31  * Maps all intrinsic calls that the backend support
32  * and map all instructions the backend did not support
33  * to runtime calls.
34  */
35 void ia32_handle_intrinsics(void) {
36         if (intrinsics && ARR_LEN(intrinsics) > 0)
37                 lower_intrinsics(intrinsics, ARR_LEN(intrinsics));
38 }
39
40 #define BINOP_Left_Low   0
41 #define BINOP_Left_High  1
42 #define BINOP_Right_Low  2
43 #define BINOP_Right_High 3
44
45 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
46         ir_node *res, *in[2];
47
48         in[0] = l_res;
49         in[1] = h_res;
50         res = new_r_Tuple(irg, block, 2, in);
51
52         turn_into_tuple(call, pn_Call_max);
53         set_Tuple_pred(call, pn_Call_M_regular,        get_irg_no_mem(irg));
54         set_Tuple_pred(call, pn_Call_X_except,         get_irg_bad(irg));
55         set_Tuple_pred(call, pn_Call_T_result,         res);
56         set_Tuple_pred(call, pn_Call_M_except,         get_irg_bad(irg));
57         set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
58 }
59
60 /**
61  * Map an Add (a_l, a_h, b_l, b_h)
62  */
63 static int map_Add(ir_node *call, void *ctx) {
64         ir_graph *irg        = current_ir_graph;
65         dbg_info *dbg        = get_irn_dbg_info(call);
66         ir_node  *block      = get_nodes_block(call);
67         ir_node  **params    = get_Call_param_arr(call);
68         ir_type  *method     = get_Call_type(call);
69         ir_node  *a_l        = params[BINOP_Left_Low];
70         ir_node  *a_h        = params[BINOP_Left_High];
71         ir_node  *b_l        = params[BINOP_Right_Low];
72         ir_node  *b_h        = params[BINOP_Right_High];
73         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
74         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
75         ir_node  *l_res, *h_res;
76
77         /* l_res = a_l + b_l */
78         l_res = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, l_res_mode);
79
80         /* h_res = a_h + b_h + carry */
81         h_res = new_rd_ia32_l_AddC(dbg, irg, block, a_h, b_h, h_res_mode);
82
83         resolve_call(call, l_res, h_res, irg, block);
84         return 1;
85 }
86
87 /**
88  * Map a Sub (a_l, a_h, b_l, b_h)
89  */
90 static int map_Sub(ir_node *call, void *ctx) {
91         ir_graph *irg        = current_ir_graph;
92         dbg_info *dbg        = get_irn_dbg_info(call);
93         ir_node  *block      = get_nodes_block(call);
94         ir_node  **params    = get_Call_param_arr(call);
95         ir_type  *method     = get_Call_type(call);
96         ir_node  *a_l        = params[BINOP_Left_Low];
97         ir_node  *a_h        = params[BINOP_Left_High];
98         ir_node  *b_l        = params[BINOP_Right_Low];
99         ir_node  *b_h        = params[BINOP_Right_High];
100         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
101         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
102         ir_node  *l_res, *h_res;
103
104         /* l_res = a_l - b_l */
105         l_res = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, l_res_mode);
106
107         /* h_res = a_h - b_h - carry */
108         h_res = new_rd_ia32_l_SubC(dbg, irg, block, a_h, b_h, h_res_mode);
109
110         resolve_call(call, l_res, h_res, irg, block);
111
112         return 1;
113 }
114
115 /**
116  * Map a Shl (a_l, a_h, count)
117  */
118 static int map_Shl(ir_node *call, void *ctx) {
119         ir_graph *irg        = current_ir_graph;
120         dbg_info *dbg        = get_irn_dbg_info(call);
121         ir_node  *block      = get_nodes_block(call);
122         ir_node  **params    = get_Call_param_arr(call);
123         ir_type  *method     = get_Call_type(call);
124         ir_node  *a_l        = params[BINOP_Left_Low];
125         ir_node  *a_h        = params[BINOP_Left_High];
126         ir_node  *cnt        = params[BINOP_Right_Low];
127         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
128         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
129         ir_node  *l_res, *h_res;
130
131         /* h_res = SHLD a_h, a_l, cnt */
132         l_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_res_mode);
133
134         /* l_res = SHL a_l, cnt */
135         h_res = new_rd_ia32_l_Shl(dbg, irg, block, a_l, cnt, h_res_mode);
136
137         resolve_call(call, l_res, h_res, irg, block);
138
139         return 1;
140 }
141
142 /**
143  * Map a Shr (a_l, a_h, count)
144  */
145 static int map_Shr(ir_node *call, void *ctx) {
146         ir_graph *irg        = current_ir_graph;
147         dbg_info *dbg        = get_irn_dbg_info(call);
148         ir_node  *block      = get_nodes_block(call);
149         ir_node  **params    = get_Call_param_arr(call);
150         ir_type  *method     = get_Call_type(call);
151         ir_node  *a_l        = params[BINOP_Left_Low];
152         ir_node  *a_h        = params[BINOP_Left_High];
153         ir_node  *cnt        = params[BINOP_Right_Low];
154         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
155         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
156         ir_node  *l_res, *h_res;
157
158         /* l_res = SHRD a_l, a_h, cnt */
159         l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_res_mode);
160
161         /* h_res = SHR a_h, cnt */
162         h_res = new_rd_ia32_l_Shr(dbg, irg, block, a_h, cnt, h_res_mode);
163
164         resolve_call(call, l_res, h_res, irg, block);
165
166         return 1;
167 }
168
169 /**
170  * Map a Shrs (a_l, a_h, count)
171  */
172 static int map_Shrs(ir_node *call, void *ctx) {
173         ir_graph *irg        = current_ir_graph;
174         dbg_info *dbg        = get_irn_dbg_info(call);
175         ir_node  *block      = get_nodes_block(call);
176         ir_node  **params    = get_Call_param_arr(call);
177         ir_type  *method     = get_Call_type(call);
178         ir_node  *a_l        = params[BINOP_Left_Low];
179         ir_node  *a_h        = params[BINOP_Left_High];
180         ir_node  *cnt        = params[BINOP_Right_Low];
181         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
182         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
183         ir_node  *l_res, *h_res;
184
185         /* l_res = SHRD a_l, a_h, cnt */
186         l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_res_mode);
187
188         /* h_res = SAR a_h, cnt */
189         h_res = new_rd_ia32_l_Shrs(dbg, irg, block, a_h, cnt, h_res_mode);
190
191         resolve_call(call, l_res, h_res, irg, block);
192
193         return 1;
194 }
195
196 /**
197  * Map a Mul (a_l, a_h, b_l, b_h)
198  */
199 static int map_Mul(ir_node *call, void *ctx) {
200         ir_graph *irg        = current_ir_graph;
201         dbg_info *dbg        = get_irn_dbg_info(call);
202         ir_node  *block      = get_nodes_block(call);
203         ir_node  **params    = get_Call_param_arr(call);
204         ir_type  *method     = get_Call_type(call);
205         ir_node  *a_l        = params[BINOP_Left_Low];
206         ir_node  *a_h        = params[BINOP_Left_High];
207         ir_node  *b_l        = params[BINOP_Right_Low];
208         ir_node  *b_h        = params[BINOP_Right_High];
209         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
210         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
211         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
212
213         /*
214                 EDX:EAX = a_l * b_l
215                 l_res   = EAX
216
217                 t1 = b_l * a_h
218                 t2 = t1 + EDX
219                 t3 = a_l * b_h
220                 h_res = t2 + t3
221         */
222         mul   = new_rd_ia32_l_MulS(dbg, irg, block, a_l, b_l);
223         pEDX  = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_MulS_EDX);
224         l_res = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_MulS_EAX);
225
226         mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_h, b_l, h_res_mode);
227         add   = new_rd_ia32_l_Add(dbg, irg, block, mul, pEDX, h_res_mode);
228         mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_h, h_res_mode);
229         h_res = new_rd_ia32_l_Add(dbg, irg, block, add, mul, h_res_mode);
230
231         resolve_call(call, l_res, h_res, irg, block);
232
233         return 1;
234 }
235
236 /* Ia32 implementation of intrinsic mapping. */
237 entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
238                                   const ir_mode *imode, const ir_mode *omode,
239                                   void *context)
240 {
241         i_record      elt;
242         entity        **ent = NULL;
243         i_mapper_func mapper;
244
245         if (! intrinsics)
246                 intrinsics = NEW_ARR_F(i_record, 0);
247
248         switch (get_op_code(op)) {
249         case iro_Add:
250                 ent    = &i_ents[iro_Add];
251                 mapper = map_Add;
252                 break;
253         case iro_Sub:
254                 ent    = &i_ents[iro_Sub];
255                 mapper = map_Sub;
256                 break;
257         case iro_Shl:
258                 ent    = &i_ents[iro_Shl];
259                 mapper = map_Shl;
260                 break;
261         case iro_Shr:
262                 ent    = &i_ents[iro_Shr];
263                 mapper = map_Shr;
264                 break;
265         case iro_Shrs:
266                 ent    = &i_ents[iro_Shrs];
267                 mapper = map_Shrs;
268                 break;
269         case iro_Mul:
270                 ent    = &i_ents[iro_Mul];
271                 mapper = map_Mul;
272                 break;
273         default:
274                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
275                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
276         }
277
278         if (ent && ! *ent) {
279 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
280
281                 ident *id = mangle(IDENT("L"), get_op_ident(op));
282                 *ent = new_entity(get_glob_type(), id, method);
283         }
284
285         elt.i_call.kind     = INTRINSIC_CALL;
286         elt.i_call.i_ent    = *ent;
287         elt.i_call.i_mapper = mapper;
288         elt.i_call.ctx      = context;
289         elt.i_call.link     = NULL;
290
291         ARR_APP1(i_record, intrinsics, elt);
292         return *ent;
293 }