ia32_intrinsics.c 19.4 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 "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

Matthias Braun's avatar
Matthias Braun committed
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
static ir_entity *create_compiler_lib_entity(const char *name, ir_type *type)
{
	ir_type   *glob   = get_glob_type();
	ident     *id     = new_id_from_str(name);
	ir_entity *entity;

	/* Hack: we need to know the type of runtime library we use. Strictly
	   speaking it's not the same as the object-file-format. But in practice
	   the following should be enough */
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
			|| be_gas_object_file_format == OBJECT_FILE_FORMAT_COFF) {
		id = id_mangle3("___", id, "");
	} else {
		id = id_mangle3("__", id, "");
	}
	entity = new_entity(glob, id, type);
427
	set_entity_visibility(entity, ir_visibility_external);
Matthias Braun's avatar
Matthias Braun committed
428
429
430
431
	set_entity_ld_ident(entity, id);
	return entity;
}

432
/**
433
 * Maps a Div. Change into a library call.
434
 */
Matthias Braun's avatar
Matthias Braun committed
435
436
static int map_Div(ir_node *call, void *ctx)
{
437
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
Michael Beck's avatar
Michael Beck committed
438
	ir_type   *method    = get_Call_type(call);
439
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
440
441
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
442
	ir_graph  *irg = get_irn_irg(call);
443
	symconst_symbol sym;
444

445
	if (mode_is_signed(h_mode)) {
446
447
448
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
Matthias Braun's avatar
Matthias Braun committed
449
			ent = env->divdi3 = create_compiler_lib_entity("divdi3", method);
450
451
		}
	} else {
452
		/* 64bit unsigned Division */
453
454
455
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
456
			ent = env->udivdi3 = create_compiler_lib_entity("udivdi3", method);
457
		}
458
	}
Matthias Braun's avatar
Matthias Braun committed
459

460
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
461
462
463
464
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

465
466
467
	return 1;
}

468
469
470
/**
 * Maps a Mod. Change into a library call
 */
471
472
static int map_Mod(ir_node *call, void *ctx)
{
473
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
474
	ir_type   *method    = get_Call_type(call);
475
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
476
477
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
478
	ir_graph  *irg = get_irn_irg(call);
479
480
	symconst_symbol sym;

481
	if (mode_is_signed(h_mode)) {
482
483
484
485
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
486
			ent = env->moddi3 = create_compiler_lib_entity("moddi3", method);
487
488
489
490
491
492
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
493
			ent = env->umoddi3 = create_compiler_lib_entity("umoddi3", method);
494
495
		}
	}
Matthias Braun's avatar
Matthias Braun committed
496

497
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
498
499
500
501
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

502
	return 1;
503
504
505
}

/**
506
 * Maps a Conv.
507
 */
508
509
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
510
511
512
513
514
515
516
517
	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;
518
519

	if (n == 1) {
520
521
		ir_node *float_to_ll;

522
523
524
525
526
527
528
		/* 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");

529
530
531
532
		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);

533
534
535
			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,
536
537
538
							   pn_ia32_l_FloattoLL_res_high);
		} else {
			/* convert from float to signed 64bit */
Matthias Braun's avatar
Matthias Braun committed
539
540
541
542
543
544
545
			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];
546
547
548
549

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

550
551
			cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
			cond  = new_rd_Cond(dbg, upper_blk, cmp);
552
553
			in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
			in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
554
			blk   = new_r_Block(irg, 1, &in[1]);
555
			in[1] = new_r_Jmp(blk);
556
557
558
559

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
560
561
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
562

563
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
564
565

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

568
			flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
569

570
			/* fix Phi links for next part_block() */
571
572
573
			set_Block_phis(lower_blk, int_phi);
			set_Phi_next(int_phi, flt_phi);
			set_Phi_next(flt_phi, NULL);
574
575
576

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

577
			l_res = new_r_Proj(float_to_ll, l_res_mode,
578
							   pn_ia32_l_FloattoLL_res_low);
579
			h_res = new_r_Proj(float_to_ll, h_res_mode,
580
581
							   pn_ia32_l_FloattoLL_res_high);

582
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
583
584
585
586

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

587
588
			for (proj = (ir_node*)get_irn_link(call); proj != NULL;
			     proj = (ir_node*)get_irn_link(proj)) {
589
				set_nodes_block(proj, lower_blk);
590
			}
591
592
			block = lower_blk;
		}
593
594
		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
595
596
597
	} else if (n == 2) {
		ir_node *ll_to_float;

598
599
600
601
602
		/* 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
603
604
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
605

606
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
607
608

		/* lower the call */
609
610
611
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
612
613
614
615
616
	}

	return 1;
}

617
/* Ia32 implementation of intrinsic mapping. */
618
619
620
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
621
622
{
	i_record      elt;
623
	ir_entity     **ent = NULL;
624
625
626
627
628
629
630
631
632
633
634
635
636
637
	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;
638
639
640
641
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
642
643
644
645
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
646
647
648
649
650
651
652
653
654
655
656
657
	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;
658
	default:
Christian Würdig's avatar
Christian Würdig committed
659
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
660
661
662
663
664
665
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

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

666
		ident *id = id_mangle(IDENT("L"), get_op_ident(op));
667
		*ent = new_entity(get_glob_type(), id, method);
668
		set_entity_visibility(*ent, ir_visibility_private);
669
670
671
672
673
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
674
	elt.i_call.ctx      = context;
675
676
677
	elt.i_call.link     = NULL;

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