ia32_intrinsics.c 17.1 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

20
/**
Christian Würdig's avatar
Christian Würdig committed
21
22
23
24
 * @file
 * @brief       This file implements the mapping of 64Bit intrinsic
 *              functions to code or library calls.
 * @author      Michael Beck
25
 */
26
27
#include "config.h"

28
#include "iredges.h"
29
#include "irgmod.h"
30
31
32
33
#include "irop.h"
#include "irnode_t.h"
#include "ircons.h"
#include "irprog_t.h"
34
#include "iroptimize.h"
35
#include "lower_dw.h"
36
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
37
#include "error.h"
38

39
#include "ia32_new_nodes.h"
40
41
#include "bearch_ia32_t.h"
#include "gen_ia32_regalloc_if.h"
Matthias Braun's avatar
Matthias Braun committed
42
#include "begnuas.h"
43

44
45
46
/** The array of all intrinsics that must be mapped. */
static i_record *intrinsics;

47
/** An array to cache all entities. */
48
static ir_entity *i_ents[iro_Last + 1];
49

50
/*
51
52
53
54
 * Maps all intrinsic calls that the backend support
 * and map all instructions the backend did not support
 * to runtime calls.
 */
55
56
void ia32_handle_intrinsics(void)
{
Michael Beck's avatar
Michael Beck committed
57
58
59
	if (intrinsics && ARR_LEN(intrinsics) > 0) {
		lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
	}
60
61
62
63
64
65
66
}

#define BINOP_Left_Low   0
#define BINOP_Left_High  1
#define BINOP_Right_Low  2
#define BINOP_Right_High 3

67
68
69
/**
 * Reroute edges from the pn_Call_T_result proj of a call.
 *
70
71
72
 * @param resproj  the pn_Call_T_result Proj
 * @param l_res    the lower 32 bit result
 * @param h_res    the upper 32 bit result or NULL
73
 */
74
static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
75
{
76
	foreach_out_edge_safe(resproj, edge) {
77
78
79
80
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

		if (pn == 0) {
Matthias Braun's avatar
Matthias Braun committed
81
			edges_reroute(proj, l_res);
82
		} else if (pn == 1 && h_res != NULL) {
Matthias Braun's avatar
Matthias Braun committed
83
			edges_reroute(proj, h_res);
84
85
86
87
88
89
		} else {
			panic("Unsupported Result-Proj from Call found");
		}
	}
}

90
91
/**
 * Replace a call be a tuple of l_res, h_res.
92
93
94
95
96
97
 *
 * @param call   the call node to replace
 * @param l_res  the lower 32 bit result
 * @param h_res  the upper 32 bit result or NULL
 * @param irg    the graph to replace on
 * @param block  the block to replace on (always the call block)
98
 */
99
100
static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
{
101
	ir_node *jmp, *res, *in[2];
Christoph Mallon's avatar
Christoph Mallon committed
102
	ir_node *nomem = get_irg_no_mem(irg);
103
	int     old_cse;
104

105
106
	if (edges_activated(irg)) {
		/* use rerouting to prevent some warning in the backend */
107
		foreach_out_edge_safe(call, edge) {
108
			ir_node *proj = get_edge_src_irn(edge);
109
			pn_Call pn    = (pn_Call)get_Proj_proj(proj);
110
111
112
113
114
115
116
117
118
119
120

			switch (pn) {
			case pn_Call_X_regular:
				/* Beware:
				 * We do not check here if this call really has exception and regular Proj's.
				 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
				 * (in movgen.c from 186.crafty for example).
				 * So be sure the newly created Jmp cannot CSE.
				 */
				old_cse = get_opt_cse();
				set_opt_cse(0);
121
				jmp = new_r_Jmp(block);
122
				set_opt_cse(old_cse);
Matthias Braun's avatar
Matthias Braun committed
123
				edges_reroute(proj, jmp);
124
125
126
127
				break;

			case pn_Call_X_except:
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
128
				edges_reroute(proj, new_r_Bad(irg, mode_X));
129
				break;
130
			case pn_Call_M:
131
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
132
				edges_reroute(proj, nomem);
133
134
				break;
			case pn_Call_T_result:
Matthias Braun's avatar
Matthias Braun committed
135
				reroute_result(proj, l_res, h_res);
136
137
138
139
140
141
142
143
144
145
146
147
148
149
				break;
			default:
				panic("Wrong Proj from Call");
			}
			kill_node(proj);
		}
		kill_node(call);
	} else {
		/* no edges, build Tuple */
		if (h_res == NULL)
			res = l_res;
		else {
			in[0] = l_res;
			in[1] = h_res;
150
			res = new_r_Tuple(block, 2, in);
151
152
153
154
155
156
157
158
159
160
161
		}

		/*
		 * Beware:
		 * We do not check here if this call really has exception and regular Proj's.
		 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
		 * (in movgen.c from 186.crafty for example).
		 * So be sure the newly created Jmp cannot CSE.
		 */
		old_cse = get_opt_cse();
		set_opt_cse(0);
162
		jmp = new_r_Jmp(block);
163
164
		set_opt_cse(old_cse);

165
		turn_into_tuple(call, pn_Call_max+1);
Matthias Braun's avatar
Matthias Braun committed
166
167
168
169
		set_Tuple_pred(call, pn_Call_M,         nomem);
		set_Tuple_pred(call, pn_Call_X_regular, jmp);
		set_Tuple_pred(call, pn_Call_X_except,  new_r_Bad(irg, mode_X));
		set_Tuple_pred(call, pn_Call_T_result,  res);
170
	}
171
172
173
174
175
}

/**
 * Map an Add (a_l, a_h, b_l, b_h)
 */
176
177
static int map_Add(ir_node *call, void *ctx)
{
178
179
180
181
182
183
184
185
186
187
188
189
190
	dbg_info *dbg        = get_irn_dbg_info(call);
	ir_node  *block      = get_nodes_block(call);
	ir_node  **params    = get_Call_param_arr(call);
	ir_type  *method     = get_Call_type(call);
	ir_node  *a_l        = params[BINOP_Left_Low];
	ir_node  *a_h        = params[BINOP_Left_High];
	ir_node  *b_l        = params[BINOP_Right_Low];
	ir_node  *b_h        = params[BINOP_Right_High];
	ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
	ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
	ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
	ir_node  *add_low, *add_high, *flags;
	ir_node  *l_res, *h_res;
Matthias Braun's avatar
Matthias Braun committed
191
	(void) ctx;
192
193
194

	/* l_res = a_l + b_l */
	/* h_res = a_h + b_h + carry */
195

196
	add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
197
	flags    = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
198
	add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
199

200
	l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
201
	h_res = add_high;
202

203
	resolve_call(call, l_res, h_res, current_ir_graph, block);
204
205
206
207
208
209
	return 1;
}

/**
 * Map a Sub (a_l, a_h, b_l, b_h)
 */
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
static int map_Sub(ir_node *call, void *ctx)
{
	dbg_info *dbg        = get_irn_dbg_info(call);
	ir_node  *block      = get_nodes_block(call);
	ir_node  **params    = get_Call_param_arr(call);
	ir_type  *method     = get_Call_type(call);
	ir_node  *a_l        = params[BINOP_Left_Low];
	ir_node  *a_h        = params[BINOP_Left_High];
	ir_node  *b_l        = params[BINOP_Right_Low];
	ir_node  *b_h        = params[BINOP_Right_High];
	ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
	ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
	ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
	ir_node  *sub_low, *sub_high, *flags;
	ir_node  *l_res, *h_res;
Matthias Braun's avatar
Matthias Braun committed
225
	(void) ctx;
226
227

	/* l_res = a_l - b_l */
228
	/* h_res = a_h - b_h - carry */
229

230
	sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
231
	flags    = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
232
	sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
233

234
	l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
235
	h_res = sub_high;
236

237
	resolve_call(call, l_res, h_res, current_ir_graph, block);
238
239
240
	return 1;
}

241
242
243
/**
 * Checks where node high is a sign extension of low.
 */
244
245
246
static int is_sign_extend(ir_node *low, ir_node *high)
{
	if (is_Shrs(high)) {
Matthias Braun's avatar
Matthias Braun committed
247
248
249
		ir_node   *high_l;
		ir_node   *high_r;
		ir_tarval *shift_count;
250
251
252
253
254
255
256
257
258
259
260
261
262

		high_r = get_Shrs_right(high);
		if (!is_Const(high_r)) return 0;

		shift_count = get_Const_tarval(high_r);
		if (!tarval_is_long(shift_count))       return 0;
		if (get_tarval_long(shift_count) != 31) return 0;

		high_l = get_Shrs_left(high);

		if (is_Conv(low)    && get_Conv_op(low)    == high_l) return 1;
		if (is_Conv(high_l) && get_Conv_op(high_l) == low)    return 1;
	} else if (is_Const(low) && is_Const(high)) {
Matthias Braun's avatar
Matthias Braun committed
263
264
		ir_tarval *tl = get_Const_tarval(low);
		ir_tarval *th = get_Const_tarval(high);
265
266
267
268
269
270
271
272
273
274
275
276

		if (tarval_is_long(th) && tarval_is_long(tl)) {
			long l = get_tarval_long(tl);
			long h = get_tarval_long(th);

			return (h == 0  && l >= 0) || (h == -1 && l <  0);
		}
	}

	return 0;
}

277
278
279
/**
 * Map a Mul (a_l, a_h, b_l, b_h)
 */
280
281
static int map_Mul(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
282
283
284
285
286
287
288
289
290
	dbg_info *dbg     = get_irn_dbg_info(call);
	ir_node  *block   = get_nodes_block(call);
	ir_node  **params = get_Call_param_arr(call);
	ir_type  *method  = get_Call_type(call);
	ir_node  *a_l     = params[BINOP_Left_Low];
	ir_node  *a_h     = params[BINOP_Left_High];
	ir_node  *b_l     = params[BINOP_Right_Low];
	ir_node  *b_h     = params[BINOP_Right_High];
	ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
291
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
292
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
293
	(void) ctx;
294
295
296
297
298
299
300
301
302
303

	/*
		EDX:EAX = a_l * b_l
		l_res   = EAX

		t1 = b_l * a_h
		t2 = t1 + EDX
		t3 = a_l * b_h
		h_res = t2 + t3
	*/
Michael Beck's avatar
Michael Beck committed
304

305
	/* handle the often used case of 32x32=64 mul */
306
	if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
307
		mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
308
309
		h_res = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_IMul_res_high);
		l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_IMul_res_low);
310
311
312
	} else {
		/* note that zero extension is handled hare efficiently */
		mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
313
314
		pEDX  = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_Mul_res_high);
		l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_Mul_res_low);
315
316
317
318
319
320
321

		b_l   = new_rd_Conv(dbg, block, b_l, h_mode);
		mul   = new_rd_Mul( dbg, block, a_h, b_l, h_mode);
		add   = new_rd_Add( dbg, block, mul, pEDX, h_mode);
		a_l   = new_rd_Conv(dbg, block, a_l, h_mode);
		mul   = new_rd_Mul( dbg, block, a_l, b_h, h_mode);
		h_res = new_rd_Add( dbg, block, add, mul, h_mode);
322
	}
323
	resolve_call(call, l_res, h_res, current_ir_graph, block);
324
325
326
327

	return 1;
}

328
329
330
/**
 * Map a Minus (a_l, a_h)
 */
331
332
static int map_Minus(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
333
334
335
336
337
338
339
	dbg_info *dbg     = get_irn_dbg_info(call);
	ir_node  *block   = get_nodes_block(call);
	ir_node  **params = get_Call_param_arr(call);
	ir_type  *method  = get_Call_type(call);
	ir_node  *a_l     = params[BINOP_Left_Low];
	ir_node  *a_h     = params[BINOP_Left_High];
	ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
340
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
341
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
342
	(void) ctx;
343

344
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
345
346
	l_res = new_r_Proj(res, l_mode, pn_ia32_Minus64Bit_low_res);
	h_res = new_r_Proj(res, h_mode, pn_ia32_Minus64Bit_high_res);
347

348
	resolve_call(call, l_res, h_res, current_ir_graph, block);
349
350
351
352

	return 1;
}

353
#define ID(x) new_id_from_chars(x, sizeof(x)-1)
Christian Würdig's avatar
Christian Würdig committed
354

355
/**
356
 * Maps a Div. Change into a library call.
357
 */
Matthias Braun's avatar
Matthias Braun committed
358
359
static int map_Div(ir_node *call, void *ctx)
{
360
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
Michael Beck's avatar
Michael Beck committed
361
	ir_type   *method    = get_Call_type(call);
362
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
363
364
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
365
	ir_graph  *irg = get_irn_irg(call);
366
	symconst_symbol sym;
367

368
	if (mode_is_signed(h_mode)) {
369
370
371
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
372
373
374
			/* create library entity */
			ident *id = ID("__divdi3");
			ent = env->divdi3 = create_compilerlib_entity(id, method);
375
376
		}
	} else {
377
		/* 64bit unsigned Division */
378
379
380
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
381
382
			ident *id = ID("__udivdi3");
			ent = env->udivdi3 = create_compilerlib_entity(id, method);
383
		}
384
	}
Matthias Braun's avatar
Matthias Braun committed
385

386
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
387
388
389
390
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

391
392
393
	return 1;
}

394
395
396
/**
 * Maps a Mod. Change into a library call
 */
397
398
static int map_Mod(ir_node *call, void *ctx)
{
399
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
400
	ir_type   *method    = get_Call_type(call);
401
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
402
403
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
404
	ir_graph  *irg = get_irn_irg(call);
405
406
	symconst_symbol sym;

407
	if (mode_is_signed(h_mode)) {
408
409
410
411
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
412
413
			ident *id = ID("__moddi3");
			ent = env->moddi3 = create_compilerlib_entity(id, method);
414
415
416
417
418
419
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
420
421
			ident *id = ID("__umoddi3");
			ent = env->umoddi3 = create_compilerlib_entity(id, method);
422
423
		}
	}
Matthias Braun's avatar
Matthias Braun committed
424

425
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
426
427
428
429
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

430
	return 1;
431
432
433
}

/**
434
 * Maps a Conv.
435
 */
436
437
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
438
439
440
441
442
443
444
445
	ir_graph  *irg     = current_ir_graph;
	dbg_info  *dbg     = get_irn_dbg_info(call);
	ir_node   *block   = get_nodes_block(call);
	ir_node   **params = get_Call_param_arr(call);
	ir_type   *method  = get_Call_type(call);
	int       n        = get_Call_n_params(call);
	ir_node   *l_res, *h_res;
	(void) ctx;
446
447

	if (n == 1) {
448
449
		ir_node *float_to_ll;

450
451
452
453
454
455
456
		/* We have a Conv float -> long long here */
		ir_node *a_f        = params[0];
		ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
		ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));

		assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");

457
458
459
460
		if (mode_is_signed(h_res_mode)) {
			/* convert from float to signed 64bit */
			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);

461
462
463
			l_res = new_r_Proj(float_to_ll, l_res_mode,
			                   pn_ia32_l_FloattoLL_res_low);
			h_res = new_r_Proj(float_to_ll, h_res_mode,
464
465
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
466
			/* Convert from float to unsigned 64bit. */
467
			ir_tarval *flt_tv   = new_tarval_from_str("9223372036854775808", 19, ia32_mode_E);
Matthias Braun's avatar
Matthias Braun committed
468
469
470
471
472
			ir_node   *flt_corr = new_r_Const(irg, flt_tv);
			ir_node   *lower_blk = block;
			ir_node   *upper_blk;
			ir_node   *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
			ir_node   *in[2];
473
474
475
476

			part_block(call);
			upper_blk = get_nodes_block(call);

477
			a_f   = new_rd_Conv(dbg, upper_blk, a_f, ia32_mode_E);
478
479
			cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
			cond  = new_rd_Cond(dbg, upper_blk, cmp);
480
481
			in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
			in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
482
			blk   = new_r_Block(irg, 1, &in[1]);
483
			in[1] = new_r_Jmp(blk);
484
485
486
487

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
488
489
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
490

491
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
492
493

			in[0] = a_f;
494
			in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, ia32_mode_E);
495

496
			flt_phi = new_r_Phi(lower_blk, 2, in, ia32_mode_E);
497

498
			/* fix Phi links for next part_block() */
499
500
501
502
			if (is_Phi(int_phi))
				add_Block_phi(lower_blk, int_phi);
			if (is_Phi(flt_phi))
				add_Block_phi(lower_blk, flt_phi);
503
504
505

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

506
			l_res = new_r_Proj(float_to_ll, l_res_mode,
507
							   pn_ia32_l_FloattoLL_res_low);
508
			h_res = new_r_Proj(float_to_ll, h_res_mode,
509
510
							   pn_ia32_l_FloattoLL_res_high);

511
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
512
513
514
515

			/* move the call and its Proj's to the lower block */
			set_nodes_block(call, lower_blk);

516
517
			for (proj = (ir_node*)get_irn_link(call); proj != NULL;
			     proj = (ir_node*)get_irn_link(proj)) {
518
				set_nodes_block(proj, lower_blk);
519
			}
520
521
			block = lower_blk;
		}
522
523
		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
524
525
526
	} else if (n == 2) {
		ir_node *ll_to_float;

527
528
529
530
531
		/* We have a Conv long long -> float here */
		ir_node *a_l       = params[BINOP_Left_Low];
		ir_node *a_h       = params[BINOP_Left_High];
		ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));

Matthias Braun's avatar
Matthias Braun committed
532
533
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
534

535
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
536
537

		/* lower the call */
538
539
540
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
541
542
543
544
545
	}

	return 1;
}

546
/* Ia32 implementation of intrinsic mapping. */
547
548
549
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
550
551
{
	i_record      elt;
552
	ir_entity     **ent = NULL;
553
554
555
556
557
558
559
560
561
562
563
564
565
566
	i_mapper_func mapper;

	if (! intrinsics)
		intrinsics = NEW_ARR_F(i_record, 0);

	switch (get_op_code(op)) {
	case iro_Add:
		ent    = &i_ents[iro_Add];
		mapper = map_Add;
		break;
	case iro_Sub:
		ent    = &i_ents[iro_Sub];
		mapper = map_Sub;
		break;
567
568
569
570
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
571
572
573
574
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
575
576
577
578
579
580
581
582
583
584
585
586
	case iro_Div:
		ent    = &i_ents[iro_Div];
		mapper = map_Div;
		break;
	case iro_Mod:
		ent    = &i_ents[iro_Mod];
		mapper = map_Mod;
		break;
	case iro_Conv:
		ent    = &i_ents[iro_Conv];
		mapper = map_Conv;
		break;
587
	default:
Christian Würdig's avatar
Christian Würdig committed
588
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
589
590
591
592
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

	if (ent && ! *ent) {
Christoph Mallon's avatar
Christoph Mallon committed
593
		ident *id = id_mangle(ID("L"), get_op_ident(op));
594
		*ent = new_entity(get_glob_type(), id, method);
595
		set_entity_visibility(*ent, ir_visibility_private);
596
597
598
599
600
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
601
	elt.i_call.ctx      = context;
602
603
604
	elt.i_call.link     = NULL;

	ARR_APP1(i_record, intrinsics, elt);
Sebastian Hack's avatar
Sebastian Hack committed
605
	return *ent;
606
}