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
25
 * @file
 * @brief       This file implements the mapping of 64Bit intrinsic
 *              functions to code or library calls.
 * @author      Michael Beck
 * @version     $Id$
26
 */
27
28
#include "config.h"

29
#include "iredges.h"
30
#include "irgmod.h"
31
32
33
34
#include "irop.h"
#include "irnode_t.h"
#include "ircons.h"
#include "irprog_t.h"
35
#include "iroptimize.h"
36
#include "lower_dw.h"
37
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
38
#include "error.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
78
	const ir_edge_t *edge, *next;

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

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

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

108
109
110
111
112
113
	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);
114
			pn_Call pn    = (pn_Call)get_Proj_proj(proj);
115
116
117
118
119
120
121
122
123
124
125

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return 1;
}

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

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

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

	return 1;
}

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

	/*
		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
393
	/* TODO: give a hint to the backend somehow to not create a cltd here... */
394
	sign   = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
395
396
397
	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);
398

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

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

	return 1;
}
408
#endif
409

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

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

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

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

448
449
450
	return 1;
}

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

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

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

487
	return 1;
488
489
490
}

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

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

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

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

518
519
520
			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,
521
522
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
523
			/* Convert from float to unsigned 64bit. */
Matthias Braun's avatar
Matthias Braun committed
524
525
526
527
528
529
530
			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];
531
532
533
534

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

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

			set_irn_in(lower_blk, 2, in);

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

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

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

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

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

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

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

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

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

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

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

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

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

	return 1;
}

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

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

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

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

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