ia32_intrinsics.c 28.1 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 "lowering.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
70
71
72
73
74
/**
 * Reroute edges from the pn_Call_T_result proj of a call.
 *
 * @param proj   the pn_Call_T_result Proj
 * @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
 */
75
76
static void reroute_result(ir_node *proj, ir_node *l_res, ir_node *h_res, ir_graph *irg)
{
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
	const ir_edge_t *edge, *next;

	foreach_out_edge_safe(proj, edge, next) {
		ir_node *proj = get_edge_src_irn(edge);
		long    pn    = get_Proj_proj(proj);

		if (pn == 0) {
			edges_reroute(proj, l_res, irg);
		} else if (pn == 1 && h_res != NULL) {
			edges_reroute(proj, h_res, irg);
		} 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
106
	ir_node *bad   = get_irg_bad(irg);
	ir_node *nomem = get_irg_no_mem(irg);
107
	int     old_cse;
108

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

			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);
127
				jmp = new_r_Jmp(block);
128
129
130
131
132
133
134
135
				set_opt_cse(old_cse);
				edges_reroute(proj, jmp, irg);
				break;

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

		turn_into_tuple(call, pn_Call_max);
		/*
		 * 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);
169
		jmp = new_r_Jmp(block);
170
171
		set_opt_cse(old_cse);

172
		set_Tuple_pred(call, pn_Call_M,                nomem);
173
174
175
176
		set_Tuple_pred(call, pn_Call_X_regular,        jmp);
		set_Tuple_pred(call, pn_Call_X_except,         bad);
		set_Tuple_pred(call, pn_Call_T_result,         res);
	}
177
178
179
180
181
}

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

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

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

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

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

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

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

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

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

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

247
248
249
/**
 * Map a Shl (a_l, a_h, count)
 */
250
251
static int map_Shl(ir_node *call, void *ctx)
{
252
253
254
255
256
257
258
259
260
	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);
	ir_node  *a_l     = params[BINOP_Left_Low];
	ir_node  *a_h     = params[BINOP_Left_High];
	ir_node  *cnt     = params[BINOP_Right_Low];
	ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
261
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
262
263
	ir_mode  *c_mode;
	ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
Matthias Braun's avatar
Matthias Braun committed
264
	(void) ctx;
265

Michael Beck's avatar
Michael Beck committed
266
267
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
Matthias Braun's avatar
Matthias Braun committed
268
		ir_tarval *tv = get_Const_tarval(cnt);
Michael Beck's avatar
Michael Beck committed
269

270
271
		if (tarval_cmp(tv, new_tarval_from_long(32, l_mode))
				& (ir_relation_greater_equal)) {
Michael Beck's avatar
Michael Beck committed
272
273
			/* simplest case: shift only the lower bits. Note that there is no
			   need to reduce the constant here, this is done by the hardware.  */
274
275
			ir_node *conv = new_rd_Conv(dbg, block, a_l, h_mode);
			h_res = new_rd_Shl(dbg, block, conv, cnt, h_mode);
276
			l_res = new_rd_Const(dbg, irg, get_mode_null(l_mode));
Michael Beck's avatar
Michael Beck committed
277

278
279
		} else {
			/* h_res = SHLD a_h, a_l, cnt */
280
			h_res = new_bd_ia32_l_ShlD(dbg, block, a_h, a_l, cnt, h_mode);
281
282

			/* l_res = SHL a_l, cnt */
283
			l_res = new_bd_ia32_l_ShlDep(dbg, block, a_l, cnt, h_res, l_mode);
Michael Beck's avatar
Michael Beck committed
284
		}
285
286
287

		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
288
289
290
291
292
	}

	part_block(call);
	upper = get_nodes_block(call);

293
	/* h_res = SHLD a_h, a_l, cnt */
294
	h1 = new_bd_ia32_l_ShlD(dbg, upper, a_h, a_l, cnt, h_mode);
295
296

	/* l_res = SHL a_l, cnt */
297
	l1 = new_bd_ia32_l_ShlDep(dbg, upper, a_l, cnt, h1, l_mode);
Michael Beck's avatar
Michael Beck committed
298
299

	c_mode = get_irn_mode(cnt);
300
	irn    = new_r_Const_long(irg, c_mode, 32);
301
	irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
302
	irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)), ir_relation_equal);
303
	cond   = new_rd_Cond(dbg, upper, irn);
Michael Beck's avatar
Michael Beck committed
304

305
306
	in[0]  = new_r_Proj(cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(cond, mode_X, pn_Cond_false);
Michael Beck's avatar
Michael Beck committed
307
308
309

	/* the block for cnt >= 32 */
	n_block = new_rd_Block(dbg, irg, 1, &in[1]);
310
	h2      = new_rd_Conv(dbg, n_block, l1, h_mode);
311
	l2      = new_r_Const(irg, get_mode_null(l_mode));
312
	in[1]   = new_r_Jmp(n_block);
Michael Beck's avatar
Michael Beck committed
313
314
315
316
317

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
318
	l_res = new_r_Phi(block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
319
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
320
321
322

	in[0] = h1;
	in[1] = h2;
323
	h_res = new_r_Phi(block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
324
325
	set_Phi_next(l_res, h_res);
	set_Phi_next(h_res, NULL);
Michael Beck's avatar
Michael Beck committed
326
327
328

	/* move it down */
	set_nodes_block(call, block);
329
330
	for (irn = (ir_node*)get_irn_link(call); irn != NULL;
	     irn = (ir_node*)get_irn_link(irn)) {
Michael Beck's avatar
Michael Beck committed
331
		set_nodes_block(irn, block);
332
	}
333
334
335
336
337
338
339
340

	resolve_call(call, l_res, h_res, irg, block);
	return 1;
}

/**
 * Map a Shr (a_l, a_h, count)
 */
341
342
static int map_Shr(ir_node *call, void *ctx)
{
343
344
345
346
347
348
349
350
351
	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);
	ir_node  *a_l     = params[BINOP_Left_Low];
	ir_node  *a_h     = params[BINOP_Left_High];
	ir_node  *cnt     = params[BINOP_Right_Low];
	ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
352
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
353
354
	ir_mode  *c_mode;
	ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
Matthias Braun's avatar
Matthias Braun committed
355
	(void) ctx;
356

Michael Beck's avatar
Michael Beck committed
357
358
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
Matthias Braun's avatar
Matthias Braun committed
359
		ir_tarval *tv = get_Const_tarval(cnt);
Michael Beck's avatar
Michael Beck committed
360

361
		if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (ir_relation_greater_equal)) {
Michael Beck's avatar
Michael Beck committed
362
363
			/* simplest case: shift only the higher bits. Note that there is no
			   need to reduce the constant here, this is done by the hardware.  */
364
			ir_node *conv = new_rd_Conv(dbg, block, a_h, l_mode);
365
			h_res = new_rd_Const(dbg, irg, get_mode_null(h_mode));
366
			l_res = new_rd_Shr(dbg, block, conv, cnt, l_mode);
367
368
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
369
			l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
370

371
			/* h_res = SHR a_h, cnt */
372
			h_res = new_bd_ia32_l_ShrDep(dbg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
373
		}
374
375
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
376
377
378
379
380
	}

	part_block(call);
	upper = get_nodes_block(call);

381
	/* l_res = SHRD a_h:a_l, cnt */
382
	l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
383

384
	/* h_res = SHR a_h, cnt */
385
	h1 = new_bd_ia32_l_ShrDep(dbg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
386
387

	c_mode = get_irn_mode(cnt);
388
	irn    = new_r_Const_long(irg, c_mode, 32);
389
	irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
390
	irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)), ir_relation_equal);
391
	cond   = new_rd_Cond(dbg, upper, irn);
Michael Beck's avatar
Michael Beck committed
392

393
394
	in[0]  = new_r_Proj(cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(cond, mode_X, pn_Cond_false);
Michael Beck's avatar
Michael Beck committed
395
396
397

	/* the block for cnt >= 32 */
	n_block = new_rd_Block(dbg, irg, 1, &in[1]);
398
	l2      = new_rd_Conv(dbg, n_block, h1, l_mode);
399
	h2      = new_r_Const(irg, get_mode_null(h_mode));
400
	in[1]   = new_r_Jmp(n_block);
Michael Beck's avatar
Michael Beck committed
401
402
403
404
405

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
406
	l_res = new_r_Phi(block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
407
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
408
409
410

	in[0] = h1;
	in[1] = h2;
411
	h_res = new_r_Phi(block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
412
413
	set_Phi_next(l_res, h_res);
	set_Phi_next(h_res, NULL);
Michael Beck's avatar
Michael Beck committed
414
415
416

	/* move it down */
	set_nodes_block(call, block);
417
418
	for (irn = (ir_node*)get_irn_link(call); irn != NULL;
	     irn = (ir_node*)get_irn_link(irn)) {
Michael Beck's avatar
Michael Beck committed
419
		set_nodes_block(irn, block);
420
	}
421
422
423
424
425
426
427
428

	resolve_call(call, l_res, h_res, irg, block);
	return 1;
}

/**
 * Map a Shrs (a_l, a_h, count)
 */
429
430
static int map_Shrs(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
431
432
433
434
435
436
437
438
439
	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);
	ir_node  *a_l     = params[BINOP_Left_Low];
	ir_node  *a_h     = params[BINOP_Left_High];
	ir_node  *cnt     = params[BINOP_Right_Low];
	ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
440
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
441
442
	ir_mode  *c_mode;
	ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
Matthias Braun's avatar
Matthias Braun committed
443
	(void) ctx;
444

Michael Beck's avatar
Michael Beck committed
445
446
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
Matthias Braun's avatar
Matthias Braun committed
447
		ir_tarval *tv = get_Const_tarval(cnt);
Michael Beck's avatar
Michael Beck committed
448

449
		if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (ir_relation_greater_equal)) {
Michael Beck's avatar
Michael Beck committed
450
451
			/* simplest case: shift only the higher bits. Note that there is no
			   need to reduce the constant here, this is done by the hardware.  */
452
			ir_node *conv    = new_rd_Conv(dbg, block, a_h, l_mode);
453
			ir_mode *c_mode  = get_irn_mode(cnt);
Michael Beck's avatar
Michael Beck committed
454

455
456
			h_res = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
			l_res = new_rd_Shrs(dbg, block, conv, cnt, l_mode);
457
458
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
459
			l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
460

461
			/* h_res = SAR a_h, cnt */
462
			h_res = new_bd_ia32_l_SarDep(dbg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
463
		}
464
465
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
466
467
468
469
470
	}

	part_block(call);
	upper = get_nodes_block(call);

471
	/* l_res = SHRD a_h:a_l, cnt */
472
	l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
473
474

	/* h_res = SAR a_h, cnt */
475
	h1 = new_bd_ia32_l_SarDep(dbg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
476
477

	c_mode = get_irn_mode(cnt);
478
	irn    = new_r_Const_long(irg, c_mode, 32);
479
	irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
480
	irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)), ir_relation_equal);
481
	cond   = new_rd_Cond(dbg, upper, irn);
Michael Beck's avatar
Michael Beck committed
482

483
484
	in[0]  = new_r_Proj(cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(cond, mode_X, pn_Cond_false);
Michael Beck's avatar
Michael Beck committed
485
486
487

	/* the block for cnt >= 32 */
	n_block = new_rd_Block(dbg, irg, 1, &in[1]);
488
489
490
	l2      = new_rd_Conv(dbg, n_block, h1, l_mode);
	h2      = new_rd_Shrs(dbg, n_block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
	in[1]   = new_r_Jmp(n_block);
Michael Beck's avatar
Michael Beck committed
491
492
493
494
495

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
496
	l_res = new_r_Phi(block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
497
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
498
499
500

	in[0] = h1;
	in[1] = h2;
501
	h_res = new_r_Phi(block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
502
503
	set_Phi_next(l_res, h_res);
	set_Phi_next(h_res, NULL);
Michael Beck's avatar
Michael Beck committed
504
505
506

	/* move it down */
	set_nodes_block(call, block);
507
508
	for (irn = (ir_node*)get_irn_link(call); irn != NULL;
	     irn = (ir_node*)get_irn_link(irn)) {
Michael Beck's avatar
Michael Beck committed
509
		set_nodes_block(irn, block);
510
	}
511
512
513
514
515

	resolve_call(call, l_res, h_res, irg, block);
	return 1;
}

516
517
518
/**
 * Checks where node high is a sign extension of low.
 */
519
520
521
static int is_sign_extend(ir_node *low, ir_node *high)
{
	if (is_Shrs(high)) {
Matthias Braun's avatar
Matthias Braun committed
522
523
524
		ir_node   *high_l;
		ir_node   *high_r;
		ir_tarval *shift_count;
525
526
527
528
529
530
531
532
533
534
535
536
537

		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
538
539
		ir_tarval *tl = get_Const_tarval(low);
		ir_tarval *th = get_Const_tarval(high);
540
541
542
543
544
545
546
547
548
549
550
551

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

552
553
554
/**
 * Map a Mul (a_l, a_h, b_l, b_h)
 */
555
556
static int map_Mul(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
557
558
559
560
561
562
563
564
565
	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));
566
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
567
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
568
	(void) ctx;
569
570
571
572
573
574
575
576
577
578

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

580
	/* handle the often used case of 32x32=64 mul */
581
	if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
582
		mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
583
584
		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);
585
586
587
	} else {
		/* note that zero extension is handled hare efficiently */
		mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
588
589
		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);
590
591
592
593
594
595
596

		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);
597
	}
598
	resolve_call(call, l_res, h_res, current_ir_graph, block);
599
600
601
602

	return 1;
}

603
604
605
/**
 * Map a Minus (a_l, a_h)
 */
606
607
static int map_Minus(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
608
609
610
611
612
613
614
	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));
615
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
616
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
617
	(void) ctx;
618

619
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
620
621
	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);
622

623
	resolve_call(call, l_res, h_res, current_ir_graph, block);
624
625
626
627

	return 1;
}

628
#if 0
629
630
631
/**
 * Map a Abs (a_l, a_h)
 */
632
633
static int map_Abs(ir_node *call, void *ctx)
{
634
635
636
637
638
639
640
641
642
643
	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;
644
	ir_node  *sign_l;
645
646
	ir_node  *l_sub;
	ir_node  *flags;
Matthias Braun's avatar
Matthias Braun committed
647
	(void) ctx;
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662

	/*
		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
663
	/* TODO: give a hint to the backend somehow to not create a cltd here... */
664
	sign   = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
665
666
667
	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);
668

669
	l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
670
671
	l_res  = new_r_Proj(l_sub, l_mode,     pn_ia32_res);
	flags  = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
672
	h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
673

674
	resolve_call(call, l_res, h_res, current_ir_graph, block);
675
676
677

	return 1;
}
678
#endif
679

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

Matthias Braun's avatar
Matthias Braun committed
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
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);
	set_entity_visibility(entity, ir_visibility_local);
	set_entity_ld_ident(entity, id);
	return entity;
}

703
/**
704
 * Maps a Div. Change into a library call.
705
 */
Matthias Braun's avatar
Matthias Braun committed
706
707
static int map_Div(ir_node *call, void *ctx)
{
708
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
Michael Beck's avatar
Michael Beck committed
709
	ir_type   *method    = get_Call_type(call);
710
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
711
712
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
713
	ir_graph  *irg = get_irn_irg(call);
714
	symconst_symbol sym;
715

716
	if (mode_is_signed(h_mode)) {
717
718
719
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
Matthias Braun's avatar
Matthias Braun committed
720
			ent = env->divdi3 = create_compiler_lib_entity("divdi3", method);
721
722
		}
	} else {
723
		/* 64bit unsigned Division */
724
725
726
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
727
			ent = env->udivdi3 = create_compiler_lib_entity("udivdi3", method);
728
		}
729
	}
Matthias Braun's avatar
Matthias Braun committed
730

731
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
732
733
734
735
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

736
737
738
	return 1;
}

739
740
741
/**
 * Maps a Mod. Change into a library call
 */
742
743
static int map_Mod(ir_node *call, void *ctx)
{
744
	ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
745
	ir_type   *method    = get_Call_type(call);
746
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
747
748
	ir_node   *ptr;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
749
	ir_graph  *irg = get_irn_irg(call);
750
751
	symconst_symbol sym;

752
	if (mode_is_signed(h_mode)) {
753
754
755
756
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
757
			ent = env->moddi3 = create_compiler_lib_entity("moddi3", method);
758
759
760
761
762
763
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
Matthias Braun's avatar
Matthias Braun committed
764
			ent = env->umoddi3 = create_compiler_lib_entity("umoddi3", method);
765
766
		}
	}
Matthias Braun's avatar
Matthias Braun committed
767

768
	ptr = get_Call_ptr(call);
Matthias Braun's avatar
Matthias Braun committed
769
770
771
772
	sym.entity_p = ent;
	ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
	set_Call_ptr(call, ptr);

773
	return 1;
774
775
776
}

/**
777
 * Maps a Conv.
778
 */
779
780
static int map_Conv(ir_node *call, void *ctx)
{
Matthias Braun's avatar
Matthias Braun committed
781
782
783
784
785
786
787
788
	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;
789
790

	if (n == 1) {
791
792
		ir_node *float_to_ll;

793
794
795
796
797
798
799
		/* 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");

800
801
802
803
		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);

804
805
806
			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,
807
808
809
							   pn_ia32_l_FloattoLL_res_high);
		} else {
			/* convert from float to signed 64bit */
Matthias Braun's avatar
Matthias Braun committed
810
811
812
813
814
815
816
			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];
817
818
819
820

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

821
822
			cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
			cond  = new_rd_Cond(dbg, upper_blk, cmp);
823
824
			in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
			in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
825
			blk   = new_r_Block(irg, 1, &in[1]);
826
			in[1] = new_r_Jmp(blk);
827
828
829
830

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
831
832
			in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
			in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
833

834
			int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
835
836

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

839
			flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
840

841
			/* fix Phi links for next part_block() */
842
843
844
			set_Block_phis(lower_blk, int_phi);
			set_Phi_next(int_phi, flt_phi);
			set_Phi_next(flt_phi, NULL);
845
846
847

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

848
			l_res = new_r_Proj(float_to_ll, l_res_mode,
849
							   pn_ia32_l_FloattoLL_res_low);
850
			h_res = new_r_Proj(float_to_ll, h_res_mode,
851
852
							   pn_ia32_l_FloattoLL_res_high);

853
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
854
855
856
857

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

858
859
			for (proj = (ir_node*)get_irn_link(call); proj != NULL;
			     proj = (ir_node*)get_irn_link(proj)) {
860
				set_nodes_block(proj, lower_blk);
861
			}
862
863
			block = lower_blk;
		}
864
865
		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
866
867
868
	} else if (n == 2) {
		ir_node *ll_to_float;

869
870
871
872
873
		/* 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
874
875
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
876

877
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
878
879

		/* lower the call */
880
881
882
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
883
884
885
886
887
	}

	return 1;
}

888
/* Ia32 implementation of intrinsic mapping. */
889
890
891
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
892
893
{
	i_record      elt;
894
	ir_entity     **ent = NULL;
895
896
897
898
899
900
901
902
903
904
905
906
907
908
	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;
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
	case iro_Shl:
		ent    = &i_ents[iro_Shl];
		mapper = map_Shl;
		break;
	case iro_Shr:
		ent    = &i_ents[iro_Shr];
		mapper = map_Shr;
		break;
	case iro_Shrs:
		ent    = &i_ents[iro_Shrs];
		mapper = map_Shrs;
		break;
	case iro_Mul:
		ent    = &i_ents[iro_Mul];
		mapper = map_Mul;
		break;
925
926
927
928
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
929
930
931
932
933
934
935
936
937
938
939
940
	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;
941
	default:
Christian Würdig's avatar
Christian Würdig committed
942
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
943
944
945
946
947
948
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

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

949
		ident *id = id_mangle(IDENT("L"), get_op_ident(op));
950
		*ent = new_entity(get_glob_type(), id, method);
951
		set_entity_visibility(*ent, ir_visibility_private);
952
953
954
955
956
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
957
	elt.i_call.ctx      = context;
958
959
960
	elt.i_call.link     = NULL;

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