ia32_intrinsics.c 18.9 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
77
	const ir_edge_t *edge, *next;

78
	foreach_out_edge_safe(resproj, edge, next) {
79
80
81
82
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

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

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

107
108
109
110
111
112
	if (edges_activated(irg)) {
		/* use rerouting to prevent some warning in the backend */
		const ir_edge_t *edge, *next;

		foreach_out_edge_safe(call, edge, next) {
			ir_node *proj = get_edge_src_irn(edge);
113
			pn_Call pn    = (pn_Call)get_Proj_proj(proj);
114
115
116
117
118
119
120
121
122
123
124

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

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

		/*
		 * 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);
166
		jmp = new_r_Jmp(block);
167
168
		set_opt_cse(old_cse);

169
		turn_into_tuple(call, pn_Call_max+1);
Matthias Braun's avatar
Matthias Braun committed
170
171
172
173
		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);
174
	}
175
176
177
178
179
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 1;
}

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

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

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

	return 1;
}

357
#if 0
358
359
360
/**
 * Map a Abs (a_l, a_h)
 */
361
362
static int map_Abs(ir_node *call, void *ctx)
{
363
364
365
366
367
368
369
370
371
372
	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));
	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  *l_res, *h_res, *sign, *sub_l, *sub_h;
373
	ir_node  *sign_l;
374
375
	ir_node  *l_sub;
	ir_node  *flags;
Matthias Braun's avatar
Matthias Braun committed
376
	(void) ctx;
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

	/*
		Code inspired by gcc output :) (although gcc doubles the
		operation for t1 as t2 and uses t1 for operations with low part
		and t2 for operations with high part which is actually unnecessary
		because t1 and t2 represent the same value)

		t1    = SHRS a_h, 31
		t2    = a_l ^ t1
		t3    = a_h ^ t1
		l_res = t2 - t1
		h_res = t3 - t1 - carry

	*/

Matthias Braun's avatar
Matthias Braun committed
392
	/* TODO: give a hint to the backend somehow to not create a cltd here... */
393
	sign   = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
394
395
396
	sign_l = new_rd_Conv(dbg, block, sign, l_mode);
	sub_l  = new_rd_Eor(dbg, block, a_l, sign_l, l_mode);
	sub_h  = new_rd_Eor(dbg, block, a_h, sign,   h_mode);
397

398
	l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
399
400
	l_res  = new_r_Proj(l_sub, l_mode,     pn_ia32_res);
	flags  = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
401
	h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
402

403
	resolve_call(call, l_res, h_res, current_ir_graph, block);
404
405
406

	return 1;
}
407
#endif
408

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

411
/**
412
 * Maps a Div. Change into a library call.
413
 */
Matthias Braun's avatar
Matthias Braun committed
414
415
static int map_Div(ir_node *call, void *ctx)
{
416
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
Michael Beck's avatar
Michael Beck committed
417
	ir_type   *method    = get_Call_type(call);
418
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
419
420
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
421
	ir_graph  *irg = get_irn_irg(call);
422
	symconst_symbol sym;
423

424
	if (mode_is_signed(h_mode)) {
425
426
427
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
428
429
430
			/* create library entity */
			ident *id = ID("__divdi3");
			ent = env->divdi3 = create_compilerlib_entity(id, method);
431
432
		}
	} else {
433
		/* 64bit unsigned Division */
434
435
436
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
437
438
			ident *id = ID("__udivdi3");
			ent = env->udivdi3 = create_compilerlib_entity(id, method);
439
		}
440
	}
Matthias Braun's avatar
Matthias Braun committed
441

442
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
443
444
445
446
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

447
448
449
	return 1;
}

450
451
452
/**
 * Maps a Mod. Change into a library call
 */
453
454
static int map_Mod(ir_node *call, void *ctx)
{
455
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
456
	ir_type   *method    = get_Call_type(call);
457
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
458
459
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
460
	ir_graph  *irg = get_irn_irg(call);
461
462
	symconst_symbol sym;

463
	if (mode_is_signed(h_mode)) {
464
465
466
467
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
468
469
			ident *id = ID("__moddi3");
			ent = env->moddi3 = create_compilerlib_entity(id, method);
470
471
472
473
474
475
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
476
477
			ident *id = ID("__umoddi3");
			ent = env->umoddi3 = create_compilerlib_entity(id, method);
478
479
		}
	}
Matthias Braun's avatar
Matthias Braun committed
480

481
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
482
483
484
485
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

486
	return 1;
487
488
489
}

/**
490
 * Maps a Conv.
491
 */
492
493
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
494
495
496
497
498
499
500
501
	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;
502
503

	if (n == 1) {
504
505
		ir_node *float_to_ll;

506
507
508
509
510
511
512
		/* 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");

513
514
515
516
		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);

517
518
519
			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,
520
521
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
522
			/* Convert from float to unsigned 64bit. */
Matthias Braun's avatar
Matthias Braun committed
523
524
525
526
527
528
529
			ir_mode   *flt_mode = get_irn_mode(a_f);
			ir_tarval *flt_tv   = new_tarval_from_str("9223372036854775808", 19, flt_mode);
			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];
530
531
532
533

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

534
535
			cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
			cond  = new_rd_Cond(dbg, upper_blk, cmp);
536
537
			in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
			in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
538
			blk   = new_r_Block(irg, 1, &in[1]);
539
			in[1] = new_r_Jmp(blk);
540
541
542
543

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
544
545
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
546

547
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
548
549

			in[0] = a_f;
550
			in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
551

552
			flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
553

554
			/* fix Phi links for next part_block() */
555
556
557
			set_Block_phis(lower_blk, int_phi);
			set_Phi_next(int_phi, flt_phi);
			set_Phi_next(flt_phi, NULL);
558
559
560

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

561
			l_res = new_r_Proj(float_to_ll, l_res_mode,
562
							   pn_ia32_l_FloattoLL_res_low);
563
			h_res = new_r_Proj(float_to_ll, h_res_mode,
564
565
							   pn_ia32_l_FloattoLL_res_high);

566
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
567
568
569
570

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

571
572
			for (proj = (ir_node*)get_irn_link(call); proj != NULL;
			     proj = (ir_node*)get_irn_link(proj)) {
573
				set_nodes_block(proj, lower_blk);
574
			}
575
576
			block = lower_blk;
		}
577
578
		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
579
580
581
	} else if (n == 2) {
		ir_node *ll_to_float;

582
583
584
585
586
		/* 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
587
588
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
589

590
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
591
592

		/* lower the call */
593
594
595
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
596
597
598
599
600
	}

	return 1;
}

601
/* Ia32 implementation of intrinsic mapping. */
602
603
604
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
605
606
{
	i_record      elt;
607
	ir_entity     **ent = NULL;
608
609
610
611
612
613
614
615
616
617
618
619
620
621
	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;
622
623
624
625
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
626
627
628
629
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
630
631
632
633
634
635
636
637
638
639
640
641
	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;
642
	default:
Christian Würdig's avatar
Christian Würdig committed
643
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
644
645
646
647
648
649
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

	if (ent && ! *ent) {
#define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)

650
		ident *id = id_mangle(IDENT("L"), get_op_ident(op));
651
		*ent = new_entity(get_glob_type(), id, method);
652
		set_entity_visibility(*ent, ir_visibility_private);
653
654
655
656
657
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
658
	elt.i_call.ctx      = context;
659
660
661
	elt.i_call.link     = NULL;

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