ia32_intrinsics.c 16.5 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

6
/**
Christian Würdig's avatar
Christian Würdig committed
7
8
9
10
 * @file
 * @brief       This file implements the mapping of 64Bit intrinsic
 *              functions to code or library calls.
 * @author      Michael Beck
11
 */
12
#include "iredges.h"
13
#include "irgmod.h"
14
15
16
17
#include "irop.h"
#include "irnode_t.h"
#include "ircons.h"
#include "irprog_t.h"
18
#include "iroptimize.h"
19
#include "lower_dw.h"
20
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
21
#include "error.h"
22
#include "util.h"
23

24
#include "ia32_new_nodes.h"
25
26
#include "bearch_ia32_t.h"
#include "gen_ia32_regalloc_if.h"
Matthias Braun's avatar
Matthias Braun committed
27
#include "begnuas.h"
28

29
30
31
/** The array of all intrinsics that must be mapped. */
static i_record *intrinsics;

32
/** An array to cache all entities. */
33
static ir_entity *i_ents[iro_last + 1];
34

35
/*
36
37
38
39
 * Maps all intrinsic calls that the backend support
 * and map all instructions the backend did not support
 * to runtime calls.
 */
40
41
void ia32_handle_intrinsics(void)
{
Michael Beck's avatar
Michael Beck committed
42
43
44
	if (intrinsics && ARR_LEN(intrinsics) > 0) {
		lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
	}
45
46
47
48
49
50
51
}

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

52
53
54
/**
 * Reroute edges from the pn_Call_T_result proj of a call.
 *
55
56
57
 * @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
58
 */
59
static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
60
{
61
	foreach_out_edge_safe(resproj, edge) {
62
63
64
65
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

		if (pn == 0) {
Matthias Braun's avatar
Matthias Braun committed
66
			edges_reroute(proj, l_res);
67
		} else if (pn == 1 && h_res != NULL) {
Matthias Braun's avatar
Matthias Braun committed
68
			edges_reroute(proj, h_res);
69
70
71
72
73
74
		} else {
			panic("Unsupported Result-Proj from Call found");
		}
	}
}

75
76
/**
 * Replace a call be a tuple of l_res, h_res.
77
78
79
80
81
82
 *
 * @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)
83
 */
84
85
static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
{
86
	ir_node *jmp, *res, *in[2];
Christoph Mallon's avatar
Christoph Mallon committed
87
	ir_node *nomem = get_irg_no_mem(irg);
88
	int     old_cse;
89

90
91
	if (edges_activated(irg)) {
		/* use rerouting to prevent some warning in the backend */
92
		foreach_out_edge_safe(call, edge) {
93
			ir_node *proj = get_edge_src_irn(edge);
94
			pn_Call pn    = (pn_Call)get_Proj_proj(proj);
95
96
97
98
99
100
101
102
103
104
105

			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);
106
				jmp = new_r_Jmp(block);
107
				set_opt_cse(old_cse);
Matthias Braun's avatar
Matthias Braun committed
108
				edges_reroute(proj, jmp);
109
110
111
112
				break;

			case pn_Call_X_except:
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
113
				edges_reroute(proj, new_r_Bad(irg, mode_X));
114
				break;
115
			case pn_Call_M:
116
				/* should not happen here */
Matthias Braun's avatar
Matthias Braun committed
117
				edges_reroute(proj, nomem);
118
119
				break;
			case pn_Call_T_result:
Matthias Braun's avatar
Matthias Braun committed
120
				reroute_result(proj, l_res, h_res);
121
122
123
124
125
126
127
128
129
130
131
132
133
134
				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;
135
			res = new_r_Tuple(block, 2, in);
136
137
138
139
140
141
142
143
144
145
146
		}

		/*
		 * 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);
147
		jmp = new_r_Jmp(block);
148
149
		set_opt_cse(old_cse);

150
151
152
153
154
155
156
		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);
157
	}
158
159
160
161
162
}

/**
 * Map an Add (a_l, a_h, b_l, b_h)
 */
163
164
static int map_Add(ir_node *call, void *ctx)
{
165
166
167
168
169
170
171
172
173
174
175
176
177
	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
178
	(void) ctx;
179
180
181

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

183
	add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
184
	flags    = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
185
	add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
186

187
	l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
188
	h_res = add_high;
189

190
	resolve_call(call, l_res, h_res, current_ir_graph, block);
191
192
193
194
195
196
	return 1;
}

/**
 * Map a Sub (a_l, a_h, b_l, b_h)
 */
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
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
212
	(void) ctx;
213
214

	/* l_res = a_l - b_l */
215
	/* h_res = a_h - b_h - carry */
216

217
	sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
218
	flags    = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
219
	sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
220

221
	l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
222
	h_res = sub_high;
223

224
	resolve_call(call, l_res, h_res, current_ir_graph, block);
225
226
227
	return 1;
}

228
229
230
/**
 * Checks where node high is a sign extension of low.
 */
231
232
233
static int is_sign_extend(ir_node *low, ir_node *high)
{
	if (is_Shrs(high)) {
Matthias Braun's avatar
Matthias Braun committed
234
235
236
		ir_node   *high_l;
		ir_node   *high_r;
		ir_tarval *shift_count;
237
238
239
240
241
242
243
244
245
246
247
248
249

		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
250
251
		ir_tarval *tl = get_Const_tarval(low);
		ir_tarval *th = get_Const_tarval(high);
252
253
254
255
256
257
258
259
260
261
262
263

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

264
265
266
/**
 * Map a Mul (a_l, a_h, b_l, b_h)
 */
267
268
static int map_Mul(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
269
270
271
272
273
274
275
276
277
	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));
278
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
279
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
280
	(void) ctx;
281
282
283
284
285
286
287
288
289
290

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

292
	/* handle the often used case of 32x32=64 mul */
293
	if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
294
		mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
295
296
		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);
297
298
299
	} else {
		/* note that zero extension is handled hare efficiently */
		mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
300
301
		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);
302
303
304
305
306
307
308

		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);
309
	}
310
	resolve_call(call, l_res, h_res, current_ir_graph, block);
311
312
313
314

	return 1;
}

315
316
317
/**
 * Map a Minus (a_l, a_h)
 */
318
319
static int map_Minus(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
320
321
322
323
324
325
326
	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));
327
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
328
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
329
	(void) ctx;
330

331
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
332
333
	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);
334

335
	resolve_call(call, l_res, h_res, current_ir_graph, block);
336
337
338
339

	return 1;
}

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

342
/**
343
 * Maps a Div. Change into a library call.
344
 */
Matthias Braun's avatar
Matthias Braun committed
345
346
static int map_Div(ir_node *call, void *ctx)
{
347
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
Michael Beck's avatar
Michael Beck committed
348
	ir_type   *method    = get_Call_type(call);
349
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
350
351
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
352
	ir_graph  *irg = get_irn_irg(call);
353
	symconst_symbol sym;
354

355
	if (mode_is_signed(h_mode)) {
356
357
358
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
359
360
361
			/* create library entity */
			ident *id = ID("__divdi3");
			ent = env->divdi3 = create_compilerlib_entity(id, method);
362
363
		}
	} else {
364
		/* 64bit unsigned Division */
365
366
367
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
368
369
			ident *id = ID("__udivdi3");
			ent = env->udivdi3 = create_compilerlib_entity(id, method);
370
		}
371
	}
Matthias Braun's avatar
Matthias Braun committed
372

373
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
374
375
376
377
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

378
379
380
	return 1;
}

381
382
383
/**
 * Maps a Mod. Change into a library call
 */
384
385
static int map_Mod(ir_node *call, void *ctx)
{
386
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
387
	ir_type   *method    = get_Call_type(call);
388
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
389
390
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
391
	ir_graph  *irg = get_irn_irg(call);
392
393
	symconst_symbol sym;

394
	if (mode_is_signed(h_mode)) {
395
396
397
398
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
399
400
			ident *id = ID("__moddi3");
			ent = env->moddi3 = create_compilerlib_entity(id, method);
401
402
403
404
405
406
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
407
408
			ident *id = ID("__umoddi3");
			ent = env->umoddi3 = create_compilerlib_entity(id, method);
409
410
		}
	}
Matthias Braun's avatar
Matthias Braun committed
411

412
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
413
414
415
416
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

417
	return 1;
418
419
420
}

/**
421
 * Maps a Conv.
422
 */
423
424
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
425
426
427
428
429
430
431
432
	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;
433
434

	if (n == 1) {
435
436
		ir_node *float_to_ll;

437
438
439
440
441
442
443
		/* 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");

444
445
446
447
		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);

448
449
450
			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,
451
452
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
453
			/* Convert from float to unsigned 64bit. */
454
			ir_tarval *flt_tv   = new_tarval_from_str("9223372036854775808", 19, ia32_mode_E);
Matthias Braun's avatar
Matthias Braun committed
455
456
457
458
459
			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];
460
461
462
463

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

464
			a_f   = new_rd_Conv(dbg, upper_blk, a_f, ia32_mode_E);
465
466
			cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
			cond  = new_rd_Cond(dbg, upper_blk, cmp);
467
468
			in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
			in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
469
			blk   = new_r_Block(irg, 1, &in[1]);
470
			in[1] = new_r_Jmp(blk);
471
472
473
474

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
475
476
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
477

478
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
479
480

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

483
			flt_phi = new_r_Phi(lower_blk, 2, in, ia32_mode_E);
484

485
			/* fix Phi links for next part_block() */
486
487
488
489
			if (is_Phi(int_phi))
				add_Block_phi(lower_blk, int_phi);
			if (is_Phi(flt_phi))
				add_Block_phi(lower_blk, flt_phi);
490
491
492

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

493
			l_res = new_r_Proj(float_to_ll, l_res_mode,
494
							   pn_ia32_l_FloattoLL_res_low);
495
			h_res = new_r_Proj(float_to_ll, h_res_mode,
496
497
							   pn_ia32_l_FloattoLL_res_high);

498
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
499
500
501
502

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

503
504
			for (proj = (ir_node*)get_irn_link(call); proj != NULL;
			     proj = (ir_node*)get_irn_link(proj)) {
505
				set_nodes_block(proj, lower_blk);
506
			}
507
508
			block = lower_blk;
		}
509
510
		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
511
512
513
	} else if (n == 2) {
		ir_node *ll_to_float;

514
515
516
517
518
		/* 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
519
520
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
521

522
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
523
524

		/* lower the call */
525
526
527
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
528
529
530
531
532
	}

	return 1;
}

533
/* Ia32 implementation of intrinsic mapping. */
534
535
536
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
537
538
{
	i_record      elt;
539
	ir_entity     **ent = NULL;
540
541
542
543
544
545
546
547
548
549
550
551
552
553
	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;
554
555
556
557
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
558
559
560
561
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
562
563
564
565
566
567
568
569
570
571
572
573
	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;
574
	default:
Christian Würdig's avatar
Christian Würdig committed
575
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
576
577
578
579
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

	if (ent && ! *ent) {
Christoph Mallon's avatar
Christoph Mallon committed
580
		ident *id = id_mangle(ID("L"), get_op_ident(op));
581
		*ent = new_entity(get_glob_type(), id, method);
582
		set_entity_visibility(*ent, ir_visibility_private);
583
584
585
586
587
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
588
	elt.i_call.ctx      = context;
589
590
591
	elt.i_call.link     = NULL;

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