2 * This file implements the mapping of 64Bit intrinsic functions to
3 * code or library calls.
17 #include "lower_intrinsics.h"
22 #include "ia32_new_nodes.h"
24 /** The array of all intrinsics that must be mapped. */
25 static i_record *intrinsics;
27 /** An array to cache all entities */
28 static entity *i_ents[iro_MaxOpcode];
31 * Maps all intrinsic calls that the backend support
32 * and map all instructions the backend did not support
35 void ia32_handle_intrinsics(void) {
36 if (intrinsics && ARR_LEN(intrinsics) > 0)
37 lower_intrinsics(intrinsics, ARR_LEN(intrinsics));
40 #define BINOP_Left_Low 0
41 #define BINOP_Left_High 1
42 #define BINOP_Right_Low 2
43 #define BINOP_Right_High 3
45 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
50 res = new_r_Tuple(irg, block, 2, in);
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));
61 * Map an Add (a_l, a_h, b_l, b_h)
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;
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);
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);
83 resolve_call(call, l_res, h_res, irg, block);
88 * Map a Sub (a_l, a_h, b_l, b_h)
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;
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);
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);
110 resolve_call(call, l_res, h_res, irg, block);
116 * Map a Shl (a_l, a_h, count)
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;
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);
134 /* l_res = SHL a_l, cnt */
135 h_res = new_rd_ia32_l_Shl(dbg, irg, block, a_l, cnt, h_res_mode);
137 resolve_call(call, l_res, h_res, irg, block);
143 * Map a Shr (a_l, a_h, count)
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;
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);
161 /* h_res = SHR a_h, cnt */
162 h_res = new_rd_ia32_l_Shr(dbg, irg, block, a_h, cnt, h_res_mode);
164 resolve_call(call, l_res, h_res, irg, block);
170 * Map a Shrs (a_l, a_h, count)
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;
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);
188 /* h_res = SAR a_h, cnt */
189 h_res = new_rd_ia32_l_Shrs(dbg, irg, block, a_h, cnt, h_res_mode);
191 resolve_call(call, l_res, h_res, irg, block);
197 * Map a Mul (a_l, a_h, b_l, b_h)
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;
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);
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);
231 resolve_call(call, l_res, h_res, irg, block);
237 * Map a Minus (a_l, a_h)
239 static int map_Minus(ir_node *call, void *ctx) {
240 ir_graph *irg = current_ir_graph;
241 dbg_info *dbg = get_irn_dbg_info(call);
242 ir_node *block = get_nodes_block(call);
243 ir_node **params = get_Call_param_arr(call);
244 ir_type *method = get_Call_type(call);
245 ir_node *a_l = params[BINOP_Left_Low];
246 ir_node *a_h = params[BINOP_Left_High];
247 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
248 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
249 ir_node *l_res, *h_res, *cnst;
251 /* l_res = 0 - a_l */
252 l_res = new_rd_ia32_l_Minus(dbg, irg, block, a_l, l_res_mode);
254 /* h_res = 0 - a_h - carry */
256 /* too bad: we need 0 in a register here */
257 cnst = new_Const_long(h_res_mode, 0);
258 h_res = new_rd_ia32_l_SubC(dbg, irg, block, cnst, a_h, h_res_mode);
260 resolve_call(call, l_res, h_res, irg, block);
266 * Map a Abs (a_l, a_h)
268 static int map_Abs(ir_node *call, void *ctx) {
269 ir_graph *irg = current_ir_graph;
270 dbg_info *dbg = get_irn_dbg_info(call);
271 ir_node *block = get_nodes_block(call);
272 ir_node **params = get_Call_param_arr(call);
273 ir_type *method = get_Call_type(call);
274 ir_node *a_l = params[BINOP_Left_Low];
275 ir_node *a_h = params[BINOP_Left_High];
276 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
277 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
278 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
281 Code inspired by gcc output :) (although gcc doubles the
282 operation for t1 as t2 and uses t1 for operations with low part
283 and t2 for operations with high part which is actually unnecessary
284 because t1 and t2 represent the same value)
290 h_res = t3 - t1 - carry
294 sign = new_rd_ia32_l_Shrs(dbg, irg, block, a_h, new_Const_long(h_res_mode, 31), h_res_mode);
295 sub_l = new_rd_ia32_l_Eor(dbg, irg, block, a_l, sign, l_res_mode);
296 sub_h = new_rd_ia32_l_Eor(dbg, irg, block, a_h, sign, h_res_mode);
297 l_res = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign, l_res_mode);
298 h_res = new_rd_ia32_l_SubC(dbg, irg, block, sub_h, sign, l_res_mode);
300 resolve_call(call, l_res, h_res, irg, block);
305 /* Ia32 implementation of intrinsic mapping. */
306 entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
307 const ir_mode *imode, const ir_mode *omode,
312 i_mapper_func mapper;
315 intrinsics = NEW_ARR_F(i_record, 0);
317 switch (get_op_code(op)) {
319 ent = &i_ents[iro_Add];
323 ent = &i_ents[iro_Sub];
327 ent = &i_ents[iro_Shl];
331 ent = &i_ents[iro_Shr];
335 ent = &i_ents[iro_Shrs];
339 ent = &i_ents[iro_Mul];
343 ent = &i_ents[iro_Minus];
347 ent = &i_ents[iro_Abs];
351 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
352 return def_create_intrinsic_fkt(method, op, imode, omode, context);
356 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
358 ident *id = mangle(IDENT("L"), get_op_ident(op));
359 *ent = new_entity(get_glob_type(), id, method);
362 elt.i_call.kind = INTRINSIC_CALL;
363 elt.i_call.i_ent = *ent;
364 elt.i_call.i_mapper = mapper;
365 elt.i_call.ctx = context;
366 elt.i_call.link = NULL;
368 ARR_APP1(i_record, intrinsics, elt);