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
#include "util.h"
39

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

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

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

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

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

68
69
70
/**
 * Reroute edges from the pn_Call_T_result proj of a call.
 *
71
72
73
 * @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
74
 */
75
static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
76
{
77
	foreach_out_edge_safe(resproj, edge) {
78
79
80
81
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

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

91
92
/**
 * Replace a call be a tuple of l_res, h_res.
93
94
95
96
97
98
 *
 * @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)
99
 */
100
101
static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
{
102
	ir_node *jmp, *res, *in[2];
Christoph Mallon's avatar
Christoph Mallon committed
103
	ir_node *nomem = get_irg_no_mem(irg);
104
	int     old_cse;
105

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

			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);
122
				jmp = new_r_Jmp(block);
123
				set_opt_cse(old_cse);
Matthias Braun's avatar
Matthias Braun committed
124
				edges_reroute(proj, jmp);
125
126
127
128
				break;

			case pn_Call_X_except:
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
129
				edges_reroute(proj, new_r_Bad(irg, mode_X));
130
				break;
131
			case pn_Call_M:
132
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
133
				edges_reroute(proj, nomem);
134
135
				break;
			case pn_Call_T_result:
Matthias Braun's avatar
Matthias Braun committed
136
				reroute_result(proj, l_res, h_res);
137
138
139
140
141
142
143
144
145
146
147
148
149
150
				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;
151
			res = new_r_Tuple(block, 2, in);
152
153
154
155
156
157
158
159
160
161
162
		}

		/*
		 * 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);
163
		jmp = new_r_Jmp(block);
164
165
		set_opt_cse(old_cse);

166
167
168
169
170
171
172
		ir_node *const in[] = {
			[pn_Call_M]         = nomem,
			[pn_Call_T_result]  = res,
			[pn_Call_X_regular] = jmp,
			[pn_Call_X_except]  = new_r_Bad(irg, mode_X),
		};
		turn_into_tuple(call, ARRAY_SIZE(in), in);
173
	}
174
175
176
177
178
}

/**
 * Map an Add (a_l, a_h, b_l, b_h)
 */
179
180
static int map_Add(ir_node *call, void *ctx)
{
181
182
183
184
185
186
187
188
189
190
191
192
193
	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
194
	(void) ctx;
195
196
197

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

199
	add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
200
	flags    = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
201
	add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
202

203
	l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
204
	h_res = add_high;
205

206
	resolve_call(call, l_res, h_res, current_ir_graph, block);
207
208
209
210
211
212
	return 1;
}

/**
 * Map a Sub (a_l, a_h, b_l, b_h)
 */
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
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
228
	(void) ctx;
229
230

	/* l_res = a_l - b_l */
231
	/* h_res = a_h - b_h - carry */
232

233
	sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
234
	flags    = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
235
	sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
236

237
	l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
238
	h_res = sub_high;
239

240
	resolve_call(call, l_res, h_res, current_ir_graph, block);
241
242
243
	return 1;
}

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

		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
266
267
		ir_tarval *tl = get_Const_tarval(low);
		ir_tarval *th = get_Const_tarval(high);
268
269
270
271
272
273
274
275
276
277
278
279

		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;
}

280
281
282
/**
 * Map a Mul (a_l, a_h, b_l, b_h)
 */
283
284
static int map_Mul(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
285
286
287
288
289
290
291
292
293
	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));
294
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
295
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
296
	(void) ctx;
297
298
299
300
301
302
303
304
305
306

	/*
		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
307

308
	/* handle the often used case of 32x32=64 mul */
309
	if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
310
		mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
311
312
		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);
313
314
315
	} else {
		/* note that zero extension is handled hare efficiently */
		mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
316
317
		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);
318
319
320
321
322
323
324

		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);
325
	}
326
	resolve_call(call, l_res, h_res, current_ir_graph, block);
327
328
329
330

	return 1;
}

331
332
333
/**
 * Map a Minus (a_l, a_h)
 */
334
335
static int map_Minus(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
336
337
338
339
340
341
342
	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));
343
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
344
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
345
	(void) ctx;
346

347
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
348
349
	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);
350

351
	resolve_call(call, l_res, h_res, current_ir_graph, block);
352
353
354
355

	return 1;
}

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

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

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

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

394
395
396
	return 1;
}

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

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

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

433
	return 1;
434
435
436
}

/**
437
 * Maps a Conv.
438
 */
439
440
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
441
442
443
444
445
446
447
448
	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;
449
450

	if (n == 1) {
451
452
		ir_node *float_to_ll;

453
454
455
456
457
458
459
		/* 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");

460
461
462
463
		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);

464
465
466
			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,
467
468
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
469
			/* Convert from float to unsigned 64bit. */
470
			ir_tarval *flt_tv   = new_tarval_from_str("9223372036854775808", 19, ia32_mode_E);
Matthias Braun's avatar
Matthias Braun committed
471
472
473
474
475
			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];
476
477
478
479

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

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

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
491
492
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
493

494
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
495
496

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

499
			flt_phi = new_r_Phi(lower_blk, 2, in, ia32_mode_E);
500

501
			/* fix Phi links for next part_block() */
502
503
504
505
			if (is_Phi(int_phi))
				add_Block_phi(lower_blk, int_phi);
			if (is_Phi(flt_phi))
				add_Block_phi(lower_blk, flt_phi);
506
507
508

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

509
			l_res = new_r_Proj(float_to_ll, l_res_mode,
510
							   pn_ia32_l_FloattoLL_res_low);
511
			h_res = new_r_Proj(float_to_ll, h_res_mode,
512
513
							   pn_ia32_l_FloattoLL_res_high);

514
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
515
516
517
518

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

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

530
531
532
533
534
		/* 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
535
536
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
537

538
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
539
540

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

	return 1;
}

549
/* Ia32 implementation of intrinsic mapping. */
550
551
552
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
553
554
{
	i_record      elt;
555
	ir_entity     **ent = NULL;
556
557
558
559
560
561
562
563
564
565
566
567
568
569
	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;
570
571
572
573
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
574
575
576
577
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
578
579
580
581
582
583
584
585
586
587
588
589
	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;
590
	default:
Christian Würdig's avatar
Christian Würdig committed
591
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
592
593
594
595
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

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

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
604
	elt.i_call.ctx      = context;
605
606
607
	elt.i_call.link     = NULL;

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