ia32_intrinsics.c 18.8 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
	foreach_out_edge_safe(resproj, edge) {
77
78
79
80
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

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

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

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

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

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

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

165
		turn_into_tuple(call, pn_Call_max+1);
Matthias Braun's avatar
Matthias Braun committed
166
167
168
169
		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);
170
	}
171
172
173
174
175
}

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

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

196
	add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
197
	flags    = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
198
	add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
199

200
	l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
201
	h_res = add_high;
202

203
	resolve_call(call, l_res, h_res, current_ir_graph, block);
204
205
206
207
208
209
	return 1;
}

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

	/* l_res = a_l - b_l */
228
	/* h_res = a_h - b_h - carry */
229

230
	sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
231
	flags    = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
232
	sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
233

234
	l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
235
	h_res = sub_high;
236

237
	resolve_call(call, l_res, h_res, current_ir_graph, block);
238
239
240
	return 1;
}

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

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

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

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

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

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

		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);
322
	}
323
	resolve_call(call, l_res, h_res, current_ir_graph, block);
324
325
326
327

	return 1;
}

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

344
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
345
346
	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);
347

348
	resolve_call(call, l_res, h_res, current_ir_graph, block);
349
350
351
352

	return 1;
}

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

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

394
	l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
395
396
	l_res  = new_r_Proj(l_sub, l_mode,     pn_ia32_res);
	flags  = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
397
	h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
398

399
	resolve_call(call, l_res, h_res, current_ir_graph, block);
400
401
402

	return 1;
}
403
#endif
404

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

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

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

438
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
439
440
441
442
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

443
444
445
	return 1;
}

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

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

477
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
478
479
480
481
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

482
	return 1;
483
484
485
}

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

	if (n == 1) {
500
501
		ir_node *float_to_ll;

502
503
504
505
506
507
508
		/* 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");

509
510
511
512
		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);

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

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

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

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
540
541
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
542

543
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
544
545

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

548
			flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
549

550
			/* fix Phi links for next part_block() */
551
552
553
			set_Block_phis(lower_blk, int_phi);
			set_Phi_next(int_phi, flt_phi);
			set_Phi_next(flt_phi, NULL);
554
555
556

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

557
			l_res = new_r_Proj(float_to_ll, l_res_mode,
558
							   pn_ia32_l_FloattoLL_res_low);
559
			h_res = new_r_Proj(float_to_ll, h_res_mode,
560
561
							   pn_ia32_l_FloattoLL_res_high);

562
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
563
564
565
566

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

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

578
579
580
581
582
		/* 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
583
584
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
585

586
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
587
588

		/* lower the call */
589
590
591
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
592
593
594
595
596
	}

	return 1;
}

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

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

646
		ident *id = id_mangle(IDENT("L"), get_op_ident(op));
647
		*ent = new_entity(get_glob_type(), id, method);
648
		set_entity_visibility(*ent, ir_visibility_private);
649
650
651
652
653
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
654
	elt.i_call.ctx      = context;
655
656
657
	elt.i_call.link     = NULL;

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