ia32_intrinsics.c 24.2 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 "irgmod.h"
30
31
32
33
#include "irop.h"
#include "irnode_t.h"
#include "ircons.h"
#include "irprog_t.h"
34
#include "lowering.h"
35
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
36
#include "error.h"
37

38
#include "ia32_new_nodes.h"
39
40
#include "bearch_ia32_t.h"
#include "gen_ia32_regalloc_if.h"
41

42
43
44
/** The array of all intrinsics that must be mapped. */
static i_record *intrinsics;

45
/** An array to cache all entities. */
46
static ir_entity *i_ents[iro_Last + 1];
47

48
/*
49
50
51
52
53
 * Maps all intrinsic calls that the backend support
 * and map all instructions the backend did not support
 * to runtime calls.
 */
void ia32_handle_intrinsics(void) {
Michael Beck's avatar
Michael Beck committed
54
55
56
	if (intrinsics && ARR_LEN(intrinsics) > 0) {
		lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
	}
57
58
59
60
61
62
63
}

#define BINOP_Left_Low   0
#define BINOP_Left_High  1
#define BINOP_Right_Low  2
#define BINOP_Right_High 3

64
65
66
/**
 * Replace a call be a tuple of l_res, h_res.
 */
67
static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
68
	ir_node *jmp, *res, *in[2];
Christoph Mallon's avatar
Christoph Mallon committed
69
70
	ir_node *bad   = get_irg_bad(irg);
	ir_node *nomem = get_irg_no_mem(irg);
71
	int     old_cse;
72
73
74

	in[0] = l_res;
	in[1] = h_res;
75
	res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
76
77

	turn_into_tuple(call, pn_Call_max);
Christoph Mallon's avatar
Christoph Mallon committed
78
	set_Tuple_pred(call, pn_Call_M_regular,        nomem);
79
80
81
82
83
84
85
86
87
88
89
90
91
	/*
	 * 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);
	jmp = new_r_Jmp(irg, block);
	set_opt_cse(old_cse);

	set_Tuple_pred(call, pn_Call_X_regular,        jmp);
Christoph Mallon's avatar
Christoph Mallon committed
92
	set_Tuple_pred(call, pn_Call_X_except,         bad);
93
	set_Tuple_pred(call, pn_Call_T_result,         res);
Christoph Mallon's avatar
Christoph Mallon committed
94
95
	set_Tuple_pred(call, pn_Call_M_except,         nomem);
	set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
96
97
98
99
100
101
}

/**
 * Map an Add (a_l, a_h, b_l, b_h)
 */
static int map_Add(ir_node *call, void *ctx) {
102
103
104
105
106
107
108
109
110
111
112
113
114
115
	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  *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
116
	(void) ctx;
117
118
119

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

121
	add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
122
	flags    = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
123
	add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
124
125
126

	l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
	h_res = add_high;
127

128
	resolve_call(call, l_res, h_res, irg, block);
129
130
131
132
133
134
	return 1;
}

/**
 * Map a Sub (a_l, a_h, b_l, b_h)
 */
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
static int map_Sub(ir_node *call, void *ctx)
{
	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  *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
151
	(void) ctx;
152
153

	/* l_res = a_l - b_l */
154
	/* h_res = a_h - b_h - carry */
155

156
	sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
157
	flags    = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
158
	sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
159
160
161

	l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
	h_res = sub_high;
162

163
	resolve_call(call, l_res, h_res, irg, block);
164
165
166
	return 1;
}

167
168
169
170
/**
 * Map a Shl (a_l, a_h, count)
 */
static int map_Shl(ir_node *call, void *ctx) {
171
172
173
174
175
176
177
178
179
	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));
180
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
181
182
	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
183
	(void) ctx;
184

Michael Beck's avatar
Michael Beck committed
185
186
187
188
189
190
191
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
		tarval *tv = get_Const_tarval(cnt);

		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.  */
192
193
			ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
			h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
194
			l_res = new_rd_Const(dbg, irg, l_mode, get_mode_null(l_mode));
Michael Beck's avatar
Michael Beck committed
195

196
197
		} else {
			/* h_res = SHLD a_h, a_l, cnt */
198
			h_res = new_bd_ia32_l_ShlD(dbg, block, a_h, a_l, cnt, h_mode);
199
200

			/* l_res = SHL a_l, cnt */
201
			l_res = new_bd_ia32_l_ShlDep(dbg, block, a_l, cnt, h_res, l_mode);
Michael Beck's avatar
Michael Beck committed
202
		}
203
204
205

		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
206
207
208
209
210
	}

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

211
	/* h_res = SHLD a_h, a_l, cnt */
212
	h1 = new_bd_ia32_l_ShlD(dbg, upper, a_h, a_l, cnt, h_mode);
213
214

	/* l_res = SHL a_l, cnt */
215
	l1 = new_bd_ia32_l_ShlDep(dbg, upper, a_l, cnt, h1, l_mode);
Michael Beck's avatar
Michael Beck committed
216
217

	c_mode = get_irn_mode(cnt);
218
	irn    = new_r_Const_long(irg, c_mode, 32);
Michael Beck's avatar
Michael Beck committed
219
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
220
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
Michael Beck's avatar
Michael Beck committed
221
222
223
224
225
226
227
228
	irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
	cond   = new_rd_Cond(dbg, irg, upper, irn);

	in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);

	/* the block for cnt >= 32 */
	n_block = new_rd_Block(dbg, irg, 1, &in[1]);
229
	h2      = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
230
	l2      = new_r_Const(irg, l_mode, get_mode_null(l_mode));
Michael Beck's avatar
Michael Beck committed
231
232
233
234
235
236
237
	in[1]   = new_r_Jmp(irg, n_block);

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
	l_res = new_r_Phi(irg, block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
238
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
239
240
241

	in[0] = h1;
	in[1] = h2;
242
	h_res = new_r_Phi(irg, block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
243
244
	set_Phi_next(l_res, h_res);
	set_Phi_next(h_res, NULL);
Michael Beck's avatar
Michael Beck committed
245
246
247
248
249

	/* 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);
250
251
252
253
254
255
256
257
258

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

/**
 * Map a Shr (a_l, a_h, count)
 */
static int map_Shr(ir_node *call, void *ctx) {
259
260
261
262
263
264
265
266
267
	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));
268
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
269
270
	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
271
	(void) ctx;
272

Michael Beck's avatar
Michael Beck committed
273
274
275
276
277
278
279
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
		tarval *tv = get_Const_tarval(cnt);

		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.  */
280
			ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
281
			h_res = new_rd_Const(dbg, irg, h_mode, get_mode_null(h_mode));
282
			l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
283
284
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
285
			l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
286

287
			/* h_res = SHR a_h, cnt */
288
			h_res = new_bd_ia32_l_ShrDep(dbg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
289
		}
290
291
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
292
293
294
295
296
	}

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

297
	/* l_res = SHRD a_h:a_l, cnt */
298
	l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
299

300
	/* h_res = SHR a_h, cnt */
301
	h1 = new_bd_ia32_l_ShrDep(dbg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
302
303

	c_mode = get_irn_mode(cnt);
304
	irn    = new_r_Const_long(irg, c_mode, 32);
Michael Beck's avatar
Michael Beck committed
305
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
306
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
Michael Beck's avatar
Michael Beck committed
307
308
309
310
311
312
313
314
	irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
	cond   = new_rd_Cond(dbg, irg, upper, irn);

	in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);

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

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
	l_res = new_r_Phi(irg, block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
324
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
325
326
327

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

	/* 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);
336
337
338
339
340
341
342
343
344

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

/**
 * Map a Shrs (a_l, a_h, count)
 */
static int map_Shrs(ir_node *call, void *ctx) {
Michael Beck's avatar
Michael Beck committed
345
346
347
348
349
350
351
352
353
	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));
354
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
355
356
	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
357
	(void) ctx;
358

Michael Beck's avatar
Michael Beck committed
359
360
361
362
363
364
365
	if (is_Const(cnt)) {
		/* the shift count is a const, create better code */
		tarval *tv = get_Const_tarval(cnt);

		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.  */
366
367
			ir_node *conv    = new_rd_Conv(dbg, irg, block, a_h, l_mode);
			ir_mode *c_mode  = get_irn_mode(cnt);
Michael Beck's avatar
Michael Beck committed
368

369
			h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
370
			l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
371
372
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
373
			l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
374

375
			/* h_res = SAR a_h, cnt */
376
			h_res = new_bd_ia32_l_SarDep(dbg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
377
		}
378
379
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
380
381
382
383
384
	}

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

385
	/* l_res = SHRD a_h:a_l, cnt */
386
	l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
387
388

	/* h_res = SAR a_h, cnt */
389
	h1 = new_bd_ia32_l_SarDep(dbg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
390
391

	c_mode = get_irn_mode(cnt);
392
	irn    = new_r_Const_long(irg, c_mode, 32);
Michael Beck's avatar
Michael Beck committed
393
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
394
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
Michael Beck's avatar
Michael Beck committed
395
396
397
398
399
400
401
402
	irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
	cond   = new_rd_Cond(dbg, irg, upper, irn);

	in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
	in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);

	/* the block for cnt >= 32 */
	n_block = new_rd_Block(dbg, irg, 1, &in[1]);
403
	l2      = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
404
	h2      = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
Michael Beck's avatar
Michael Beck committed
405
406
407
408
409
410
411
	in[1]   = new_r_Jmp(irg, n_block);

	set_irn_in(block, 2, in);

	in[0] = l1;
	in[1] = l2;
	l_res = new_r_Phi(irg, block, 2, in, l_mode);
Michael Beck's avatar
Michael Beck committed
412
	set_Block_phis(block, l_res);
Michael Beck's avatar
Michael Beck committed
413
414
415

	in[0] = h1;
	in[1] = h2;
416
	h_res = new_r_Phi(irg, block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
417
418
	set_Phi_next(l_res, h_res);
	set_Phi_next(h_res, NULL);
Michael Beck's avatar
Michael Beck committed
419
420
421
422
423

	/* 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);
424
425
426
427
428

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

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
static int is_sign_extend(ir_node *low, ir_node *high)
{
	if (is_Shrs(high)) {
		ir_node *high_l;
		ir_node *high_r;
		tarval  *shift_count;

		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)) {
		tarval *tl = get_Const_tarval(low);
		tarval *th = get_Const_tarval(high);

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

462
463
464
465
/**
 * Map a Mul (a_l, a_h, b_l, b_h)
 */
static int map_Mul(ir_node *call, void *ctx) {
Michael Beck's avatar
Michael Beck committed
466
467
468
469
470
471
472
473
474
475
	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  *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));
476
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
477
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
478
	(void) ctx;
479
480
481
482
483
484
485
486
487
488

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

490
	/* handle the often used case of 32x32=64 mul */
491
	if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
492
		mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
493
494
495
496
		h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
		l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);

		goto end;
497
498
	}

499
	mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
500
	pEDX  = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
Michael Beck's avatar
Michael Beck committed
501
	l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
502

503
504
505
506
507
508
	b_l   = new_rd_Conv(dbg, irg, block, b_l, h_mode);
	mul   = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
	add   = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
	a_l   = new_rd_Conv(dbg, irg, block, a_l, h_mode);
	mul   = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
	h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
509

510
end:
511
512
513
514
515
	resolve_call(call, l_res, h_res, irg, block);

	return 1;
}

516
517
518
519
/**
 * Map a Minus (a_l, a_h)
 */
static int map_Minus(ir_node *call, void *ctx) {
Michael Beck's avatar
Michael Beck committed
520
521
522
523
524
525
526
527
	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_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
528
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
529
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
530
	(void) ctx;
531

532
	res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
Michael Beck's avatar
Michael Beck committed
533
	l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
534
	h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
535
536
537
538
539
540

	resolve_call(call, l_res, h_res, irg, block);

	return 1;
}

541
542
543
544
/**
 * Map a Abs (a_l, a_h)
 */
static int map_Abs(ir_node *call, void *ctx) {
545
546
547
548
549
550
551
552
553
554
555
	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_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;
556
	ir_node  *sign_l;
557
558
	ir_node  *l_sub;
	ir_node  *flags;
Matthias Braun's avatar
Matthias Braun committed
559
	(void) ctx;
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574

	/*
		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
575
	/* TODO: give a hint to the backend somehow to not create a cltd here... */
576
577
578
579
	sign   = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
	sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
	sub_l  = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
	sub_h  = new_rd_Eor(dbg, irg, block, a_h, sign,   h_mode);
580

581
	l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
582
583
	l_res  = new_r_Proj(irg, block, l_sub, l_mode,     pn_ia32_res);
	flags  = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
584
	h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
585
586
587
588
589
590

	resolve_call(call, l_res, h_res, irg, block);

	return 1;
}

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

593
/**
594
 * Maps a Div. Change into a library call
595
 */
596
static int map_Div(ir_node *call, void *ctx) {
597
	ia32_intrinsic_env_t *env = ctx;
Michael Beck's avatar
Michael Beck committed
598
	ir_type   *method    = get_Call_type(call);
599
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
600
601
602
	ir_node   *ptr;
	ir_entity *ent;
	symconst_symbol sym;
603

604
	if (mode_is_signed(h_mode)) {
605
606
607
608
609
610
611
612
613
		/* 64bit signed Division */
		ent = env->divdi3;
		if (ent == NULL) {
			/* create library entity */
			ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
			set_entity_visibility(ent, visibility_external_allocated);
			set_entity_ld_ident(ent, ID("__divdi3"));
		}
	} else {
614
		/* 64bit unsigned Division */
615
616
617
618
619
620
621
		ent = env->udivdi3;
		if (ent == NULL) {
			/* create library entity */
			ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
			set_entity_visibility(ent, visibility_external_allocated);
			set_entity_ld_ident(ent, ID("__udivdi3"));
		}
622
	}
623
624
625
	sym.entity_p = ent;
	ptr = get_Call_ptr(call);
	set_SymConst_symbol(ptr, sym);
626
627
628
	return 1;
}

629
630
631
/**
 * Maps a Mod. Change into a library call
 */
632
static int map_Mod(ir_node *call, void *ctx) {
633
634
	ia32_intrinsic_env_t *env = ctx;
	ir_type   *method    = get_Call_type(call);
635
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
636
637
638
639
	ir_node   *ptr;
	ir_entity *ent;
	symconst_symbol sym;

640
	if (mode_is_signed(h_mode)) {
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
		/* 64bit signed Modulo */
		ent = env->moddi3;
		if (ent == NULL) {
			/* create library entity */
			ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
			set_entity_visibility(ent, visibility_external_allocated);
			set_entity_ld_ident(ent, ID("__moddi3"));
		}
	} else {
		/* 64bit signed Modulo */
		ent = env->umoddi3;
		if (ent == NULL) {
			/* create library entity */
			ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
			set_entity_visibility(ent, visibility_external_allocated);
			set_entity_ld_ident(ent, ID("__umoddi3"));
		}
	}
	sym.entity_p = ent;
	ptr = get_Call_ptr(call);
	set_SymConst_symbol(ptr, sym);
	return 1;
663
664
665
}

/**
666
 * Maps a Conv.
667
668
 */
static int map_Conv(ir_node *call, void *ctx) {
Matthias Braun's avatar
Matthias Braun committed
669
670
671
672
673
674
675
676
	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;
677
678

	if (n == 1) {
679
680
		ir_node *float_to_ll;

681
682
683
684
685
686
687
		/* 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");

688
		float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
689

690
691
692
693
		l_res = new_r_Proj(irg, block, float_to_ll, l_res_mode,
		                   pn_ia32_l_FloattoLL_res_low);
		h_res = new_r_Proj(irg, block, float_to_ll, h_res_mode,
		                   pn_ia32_l_FloattoLL_res_high);
694
695
696

		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
697
698
699
	} else if (n == 2) {
		ir_node *ll_to_float;

700
701
702
703
704
		/* 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
705
706
		assert(! mode_is_float(get_irn_mode(a_l))
				&& ! mode_is_float(get_irn_mode(a_h)));
707

708
		ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
709
710

		/* lower the call */
711
712
713
		resolve_call(call, ll_to_float, NULL, irg, block);
	} else {
		panic("unexpected Conv call %+F", call);
714
715
716
717
718
	}

	return 1;
}

719
/* Ia32 implementation of intrinsic mapping. */
720
721
722
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
723
724
{
	i_record      elt;
725
	ir_entity     **ent = NULL;
726
727
728
729
730
731
732
733
734
735
736
737
738
739
	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;
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
	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;
756
757
758
759
760
761
762
763
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
	case iro_Abs:
		ent    = &i_ents[iro_Abs];
		mapper = map_Abs;
		break;
764
765
766
767
768
769
770
771
772
773
774
775
	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;
776
	default:
Christian Würdig's avatar
Christian Würdig committed
777
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
778
779
780
781
782
783
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

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

784
		ident *id = id_mangle(IDENT("L"), get_op_ident(op));
785
786
787
788
789
790
		*ent = new_entity(get_glob_type(), id, method);
	}

	elt.i_call.kind     = INTRINSIC_CALL;
	elt.i_call.i_ent    = *ent;
	elt.i_call.i_mapper = mapper;
791
	elt.i_call.ctx      = context;
792
793
794
	elt.i_call.link     = NULL;

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