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

			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
136
				set_opt_cse(old_cse);
				edges_reroute(proj, jmp, irg);
				break;

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

		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);
170
		jmp = new_r_Jmp(block);
171
172
		set_opt_cse(old_cse);

173
		set_Tuple_pred(call, pn_Call_M,                nomem);
174
175
176
177
178
		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);
		set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
	}
179
180
181
182
183
}

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

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

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

208
	l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
209
	h_res = add_high;
210

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

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

	/* l_res = a_l - b_l */
236
	/* h_res = a_h - b_h - carry */
237

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

242
	l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
243
	h_res = sub_high;
244

245
	resolve_call(call, l_res, h_res, current_ir_graph, block);
246
247
248
	return 1;
}

249
250
251
/**
 * Map a Shl (a_l, a_h, count)
 */
252
253
static int map_Shl(ir_node *call, void *ctx)
{
254
255
256
257
258
259
260
261
262
	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));
263
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
264
265
	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
266
	(void) ctx;
267

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

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

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

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

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

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

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

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

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

307
308
	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
309
310
311

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

	set_irn_in(block, 2, in);

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

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

	/* move it down */
	set_nodes_block(call, block);
	for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
		set_nodes_block(irn, block);
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
362
363

		if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
			/* 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
390
	irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
	irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)));
391
	irn    = new_r_Proj(irn, mode_b, pn_Cmp_Eq);
392
	cond   = new_rd_Cond(dbg, upper, irn);
Michael Beck's avatar
Michael Beck committed
393

394
395
	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
396
397
398

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

	set_irn_in(block, 2, in);

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

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

	/* move it down */
	set_nodes_block(call, block);
	for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
		set_nodes_block(irn, block);
420
421
422
423
424
425
426
427

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

/**
 * Map a Shrs (a_l, a_h, count)
 */
428
429
static int map_Shrs(ir_node *call, void *ctx)
{
Michael Beck's avatar
Michael Beck committed
430
431
432
433
434
435
436
437
438
	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));
439
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
440
441
	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
442
	(void) ctx;
443

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

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

454
455
			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);
456
457
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
458
			l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
459

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

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

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

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

	c_mode = get_irn_mode(cnt);
477
	irn    = new_r_Const_long(irg, c_mode, 32);
478
479
	irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
	irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)));
480
	irn    = new_r_Proj(irn, mode_b, pn_Cmp_Eq);
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
507
508

	/* move it down */
	set_nodes_block(call, block);
	for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
		set_nodes_block(irn, block);
509
510
511
512
513

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

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

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

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

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

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

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

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

	return 1;
}

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

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

621
	resolve_call(call, l_res, h_res, current_ir_graph, block);
622
623
624
625

	return 1;
}

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

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

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

672
	resolve_call(call, l_res, h_res, current_ir_graph, block);
673
674
675

	return 1;
}
676
#endif
677

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

Matthias Braun's avatar
Matthias Braun committed
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
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;
}

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

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

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

734
735
736
	return 1;
}

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

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

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

771
	return 1;
772
773
774
}

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

	if (n == 1) {
789
790
		ir_node *float_to_ll;

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

798
799
800
801
		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);

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

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

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

			set_irn_in(lower_blk, 2, in);

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

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

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

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

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

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);

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

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

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

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

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

874
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
875
876

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

	return 1;
}

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

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

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

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
954
	elt.i_call.ctx      = context;
955
956
957
	elt.i_call.link     = NULL;

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