ia32_intrinsics.c 27.4 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
 *
 * 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
29
30
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

31
#include "irgmod.h"
32
33
34
35
#include "irop.h"
#include "irnode_t.h"
#include "ircons.h"
#include "irprog_t.h"
36
#include "lowering.h"
37
38
#include "array.h"

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

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

/** An array to cache all entities */
47
static ir_entity *i_ents[iro_MaxOpcode];
48

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.
 */
void ia32_handle_intrinsics(void) {
Michael Beck's avatar
Michael Beck committed
55
56
57
	if (intrinsics && ARR_LEN(intrinsics) > 0) {
		lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
	}
58
59
60
61
62
63
64
}

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

65
66
67
/**
 * Replace a call be a tuple of l_res, h_res.
 */
68
69
static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
	ir_node *res, *in[2];
70
71
72

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

	turn_into_tuple(call, pn_Call_max);
	set_Tuple_pred(call, pn_Call_M_regular,        get_irg_no_mem(irg));
Matthias Braun's avatar
Matthias Braun committed
77
78
79
80
81
	/* Matze: the new_r_Jmp here sometimes CSEs and then bad things happen
	 * (in movgen.c from 186.crafty for example) I don't know why it is here
	 * and if this fix is correct... */
	/*set_Tuple_pred(call, pn_Call_X_regular,        new_r_Jmp(irg, block));*/
	set_Tuple_pred(call, pn_Call_X_regular,        get_irg_bad(irg));
82
83
	set_Tuple_pred(call, pn_Call_X_except,         get_irg_bad(irg));
	set_Tuple_pred(call, pn_Call_T_result,         res);
Christian Würdig's avatar
Christian Würdig committed
84
	set_Tuple_pred(call, pn_Call_M_except,         get_irg_no_mem(irg));
85
	set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
86
87
88
89
90
91
}

/**
 * Map an Add (a_l, a_h, b_l, b_h)
 */
static int map_Add(ir_node *call, void *ctx) {
92
93
94
95
96
97
98
99
100
101
102
103
104
105
	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
106
	(void) ctx;
107
108
109

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

111
112
113
114
115
116
	add_low  = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
	flags    = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
	add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);

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

118
	resolve_call(call, l_res, h_res, irg, block);
119
120
121
122
123
124
	return 1;
}

/**
 * Map a Sub (a_l, a_h, b_l, b_h)
 */
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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
141
	(void) ctx;
142
143

	/* l_res = a_l - b_l */
144
	/* h_res = a_h - b_h - carry */
145

146
147
148
149
150
151
	sub_low  = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, mode_T);
	flags    = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
	sub_high = new_rd_ia32_l_Sbb(dbg, irg, block, a_h, b_h, flags, h_mode);

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

153
	resolve_call(call, l_res, h_res, irg, block);
154
155
156
	return 1;
}

157
158
159
160
/**
 * Map a Shl (a_l, a_h, count)
 */
static int map_Shl(ir_node *call, void *ctx) {
161
162
163
164
165
166
167
168
169
	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));
170
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
171
172
	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
173
	(void) ctx;
174

Michael Beck's avatar
Michael Beck committed
175
176
177
178
179
180
181
	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.  */
182
183
			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);
Michael Beck's avatar
Michael Beck committed
184
185
			l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));

186
187
		} else {
			/* h_res = SHLD a_h, a_l, cnt */
188
			h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
189
190
191

			/* l_res = SHL a_l, cnt */
			l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
Michael Beck's avatar
Michael Beck committed
192
		}
193
194
195

		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
196
197
198
199
200
	}

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

201
	/* h_res = SHLD a_h, a_l, cnt */
202
	h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
203
204

	/* l_res = SHL a_l, cnt */
Michael Beck's avatar
Michael Beck committed
205
206
207
208
209
210
211
212
213
214
215
216
217
218
	l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);

	c_mode = get_irn_mode(cnt);
	irn    = new_r_Const_long(irg, upper, c_mode, 32);
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
	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]);
219
	h2      = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
220
221
222
223
224
225
226
227
228
229
230
231
	l2      = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
	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);
	set_irn_link(block, l_res);

	in[0] = h1;
	in[1] = h2;
232
	h_res = new_r_Phi(irg, block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
233
234
235
236
237
238
239
	set_irn_link(l_res, h_res);
	set_irn_link(h_res, NULL);

	/* 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);
240
241
242
243
244
245
246
247
248

	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) {
249
250
251
252
253
254
255
256
257
	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));
258
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
259
260
	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
261
	(void) ctx;
262

Michael Beck's avatar
Michael Beck committed
263
264
265
266
267
268
269
	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.  */
270
271
272
			ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
			h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
			l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
273
274
275
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
			l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
276

277
			/* h_res = SHR a_h, cnt */
278
			h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
279
		}
280
281
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
282
283
284
285
286
	}

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

287
	/* l_res = SHRD a_h:a_l, cnt */
Michael Beck's avatar
Michael Beck committed
288
	l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
289

290
	/* h_res = SHR a_h, cnt */
291
	h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
292
293
294
295
296
297
298
299
300
301
302
303
304

	c_mode = get_irn_mode(cnt);
	irn    = new_r_Const_long(irg, upper, c_mode, 32);
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
	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]);
305
306
	l2      = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
	h2      = new_r_Const(irg, n_block, l_mode, get_mode_null(h_mode));
Michael Beck's avatar
Michael Beck committed
307
308
309
310
311
312
313
314
315
316
317
	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);
	set_irn_link(block, l_res);

	in[0] = h1;
	in[1] = h2;
318
	h_res = new_r_Phi(irg, block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
319
320
321
322
323
324
325
	set_irn_link(l_res, h_res);
	set_irn_link(h_res, NULL);

	/* 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);
326
327
328
329
330
331
332
333
334

	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
335
336
337
338
339
340
341
342
343
	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));
344
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
Michael Beck's avatar
Michael Beck committed
345
346
	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
347
	(void) ctx;
348

Michael Beck's avatar
Michael Beck committed
349
350
351
352
353
354
355
	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.  */
356
357
			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
358

359
360
			h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
			l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
361
362
363
		} else {
			/* l_res = SHRD a_h:a_l, cnt */
			l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
Michael Beck's avatar
Michael Beck committed
364

365
			/* h_res = SAR a_h, cnt */
366
			h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
Michael Beck's avatar
Michael Beck committed
367
		}
368
369
		resolve_call(call, l_res, h_res, irg, block);
		return 1;
Michael Beck's avatar
Michael Beck committed
370
371
372
373
374
	}

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

375
	/* l_res = SHRD a_h:a_l, cnt */
Michael Beck's avatar
Michael Beck committed
376
	l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
377
378

	/* h_res = SAR a_h, cnt */
379
	h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
Michael Beck's avatar
Michael Beck committed
380
381
382
383
384
385
386
387
388
389
390
391
392

	c_mode = get_irn_mode(cnt);
	irn    = new_r_Const_long(irg, upper, c_mode, 32);
	irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
	irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
	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]);
393
394
	l2      = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
	h2      = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
Michael Beck's avatar
Michael Beck committed
395
396
397
398
399
400
401
402
403
404
405
	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);
	set_irn_link(block, l_res);

	in[0] = h1;
	in[1] = h2;
406
	h_res = new_r_Phi(irg, block, 2, in, h_mode);
Michael Beck's avatar
Michael Beck committed
407
408
409
410
411
412
413
	set_irn_link(l_res, h_res);
	set_irn_link(h_res, NULL);

	/* 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);
414
415
416
417
418
419
420
421
422

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

/**
 * 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
423
424
425
426
427
428
429
430
431
432
	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));
433
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
434
	ir_node  *l_res, *h_res, *mul, *pEDX, *add;
Matthias Braun's avatar
Matthias Braun committed
435
	(void) ctx;
436
437
438
439
440
441
442
443
444
445

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

447
448
	/* handle the often used case of 32x32=64 mul */
	if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
449
450
		ir_node *c1 = get_Shrs_right(a_h);

451
		if (is_Const(c1)) {
452
453
454
			tarval *tv = get_Const_tarval(c1);

			if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
455
456
457
458
459
				/* a is a sign extend */

				if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
					/* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
					mul   = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
460
					h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
461
462
463
464
					l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);

					goto end;
				}
465
				/* we rely here on Consts being on the right side */
466
467
468
469
470
471
472
473
474
475
476
				if (is_Const(b_h) && is_Const(b_l)) {
					tarval *th = get_Const_tarval(b_h);
					tarval *tl = get_Const_tarval(b_l);

					if (tarval_is_long(th) && tarval_is_long(tl)) {
						long h = get_tarval_long(th);
						long l = get_tarval_long(tl);

						if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
							/* b is a sign extended const */
							mul   = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
477
							h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
478
479
480
481
482
483
							l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);

							goto end;
						}
					}
				}
484
485
486
487
			}
		}
	}

488
	mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
489
	pEDX  = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
Michael Beck's avatar
Michael Beck committed
490
	l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
491

492
493
494
495
496
497
	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);
498

499
end:
500
501
502
503
504
	resolve_call(call, l_res, h_res, irg, block);

	return 1;
}

505
506
507
508
/**
 * Map a Minus (a_l, a_h)
 */
static int map_Minus(ir_node *call, void *ctx) {
Michael Beck's avatar
Michael Beck committed
509
510
511
512
513
514
515
516
	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));
517
	ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
518
	ir_node  *l_res, *h_res, *res;
Matthias Braun's avatar
Matthias Braun committed
519
	(void) ctx;
520

521
	res   = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
Michael Beck's avatar
Michael Beck committed
522
	l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
523
	h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
524
525
526
527
528
529

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

	return 1;
}

530
531
532
533
/**
 * Map a Abs (a_l, a_h)
 */
static int map_Abs(ir_node *call, void *ctx) {
534
535
536
537
538
539
540
541
542
543
544
	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;
545
	ir_node  *sign_l;
546
547
	ir_node  *l_sub;
	ir_node  *flags;
Matthias Braun's avatar
Matthias Braun committed
548
	(void) ctx;
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563

	/*
		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
564
	/* TODO: give a hint to the backend somehow to not create a cltd here... */
565
566
567
568
	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);
569
570
571
572
573

	l_sub  = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
	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);
	h_res  = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
574
575
576
577
578
579

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

	return 1;
}

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

582
/**
583
 * Maps a Div. Change into a library call
584
 */
585
static int map_Div(ir_node *call, void *ctx) {
586
	ia32_intrinsic_env_t *env = ctx;
Michael Beck's avatar
Michael Beck committed
587
	ir_type   *method    = get_Call_type(call);
588
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
589
590
591
	ir_node   *ptr;
	ir_entity *ent;
	symconst_symbol sym;
592

593
	if (mode_is_signed(h_mode)) {
594
595
596
597
598
599
600
601
602
		/* 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 {
603
		/* 64bit unsigned Division */
604
605
606
607
608
609
610
		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"));
		}
611
	}
612
613
614
	sym.entity_p = ent;
	ptr = get_Call_ptr(call);
	set_SymConst_symbol(ptr, sym);
615
616
617
	return 1;
}

618
619
620
/**
 * Maps a Mod. Change into a library call
 */
621
static int map_Mod(ir_node *call, void *ctx) {
622
623
	ia32_intrinsic_env_t *env = ctx;
	ir_type   *method    = get_Call_type(call);
624
	ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 0));
625
626
627
628
	ir_node   *ptr;
	ir_entity *ent;
	symconst_symbol sym;

629
	if (mode_is_signed(h_mode)) {
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
		/* 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;
652
653
654
}

/**
655
 * Maps a Conv.
656
657
658
 */
static int map_Conv(ir_node *call, void *ctx) {
	ia32_intrinsic_env_t *env = ctx;
659
660
661
662
663
664
665
666
667
668
669
	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);
	int       gp_bytes    = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
	ir_entity *ent;
	ir_node   *l_res, *h_res, *frame, *fres;
	ir_node   *store_l, *store_h;
	ir_node   *op_mem[2], *mem;
670
671
672
673
674
675
676
677
678
679

	if (n == 1) {
		/* 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");

		/* allocate memory on frame to store args */
680
		ent = env->irg == irg ? env->d_ll_conv : NULL;
681
		if (! ent) {
682
683
			ent      = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
			env->irg = irg;
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
		}

		/* Store arg */
		frame = get_irg_frame(irg);

		/*
			Now we create a node to move the value from a XMM register into
			x87 FPU because it is unknown here, which FPU is used.
			This node is killed in transformation phase when not needed.
			Otherwise it is split up into a movsd + fld
		*/
		a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
		set_ia32_frame_ent(a_f, ent);
		set_ia32_use_frame(a_f);
		set_ia32_ls_mode(a_f, mode_D);

		/* store from FPU as Int */
		a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
		set_ia32_frame_ent(a_f, ent);
		set_ia32_use_frame(a_f);
Michael Beck's avatar
Michael Beck committed
704
		set_ia32_ls_mode(a_f, mode_Ls);
705
		mem = a_f;
706
707
708
709
710
711
712
713
714
715
716

		/* load low part of the result */
		l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
		set_ia32_frame_ent(l_res, ent);
		set_ia32_use_frame(l_res);
		set_ia32_ls_mode(l_res, l_res_mode);
		l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);

		/* load hight part of the result */
		h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
		set_ia32_frame_ent(h_res, ent);
717
		add_ia32_am_offs_int(h_res, gp_bytes);
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
		set_ia32_use_frame(h_res);
		set_ia32_ls_mode(h_res, h_res_mode);
		h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);

		/* lower the call */
		resolve_call(call, l_res, h_res, irg, block);
	}
	else if (n == 2) {
		/* 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 *mode_a_l  = get_irn_mode(a_l);
		ir_mode *mode_a_h  = get_irn_mode(a_h);
		ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));

		assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");

		/* allocate memory on frame to store args */
736
		ent = env->irg == irg ? env->ll_d_conv : NULL;
737
738
		if (! ent) {
			ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
739
			env->irg = irg;
740
741
742
743
744
745
746
747
748
749
		}

		/* Store arg */
		frame = get_irg_frame(irg);

		/* store first arg (low part) */
		store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
		set_ia32_frame_ent(store_l, ent);
		set_ia32_use_frame(store_l);
		set_ia32_ls_mode(store_l, get_irn_mode(a_l));
750
		op_mem[0] = store_l;
751
752
753
754

		/* store second arg (high part) */
		store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
		set_ia32_frame_ent(store_h, ent);
755
		add_ia32_am_offs_int(store_h, gp_bytes);
756
757
		set_ia32_use_frame(store_h);
		set_ia32_ls_mode(store_h, get_irn_mode(a_h));
758
		op_mem[1] = store_h;
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790

		mem = new_r_Sync(irg, block, 2, op_mem);

		/* Load arg into x87 FPU (implicit convert) */
		fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
		set_ia32_frame_ent(fres, ent);
		set_ia32_use_frame(fres);
		set_ia32_ls_mode(fres, mode_D);
		mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
		fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);

		/*
			Now we create a node to move the loaded value into a XMM
			register because it is unknown here, which FPU is used.
			This node is killed in transformation phase when not needed.
			Otherwise it is split up into a fst + movsd
		*/
		fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
		set_ia32_frame_ent(fres, ent);
		set_ia32_use_frame(fres);
		set_ia32_ls_mode(fres, fres_mode);

		/* lower the call */
		resolve_call(call, fres, NULL, irg, block);
	}
	else {
		assert(0 && "unexpected Conv call");
	}

	return 1;
}

791
/* Ia32 implementation of intrinsic mapping. */
792
793
794
ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                     const ir_mode *imode, const ir_mode *omode,
                                     void *context)
795
796
{
	i_record      elt;
797
	ir_entity     **ent = NULL;
798
799
800
801
802
803
804
805
806
807
808
809
810
811
	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;
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
	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;
828
829
830
831
832
833
834
835
	case iro_Minus:
		ent    = &i_ents[iro_Minus];
		mapper = map_Minus;
		break;
	case iro_Abs:
		ent    = &i_ents[iro_Abs];
		mapper = map_Abs;
		break;
836
837
838
839
840
841
842
843
844
845
846
847
	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;
848
	default:
Christian Würdig's avatar
Christian Würdig committed
849
		fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
850
851
852
853
854
855
		return def_create_intrinsic_fkt(method, op, imode, omode, context);
	}

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

Sebastian Hack's avatar
Sebastian Hack committed
856
		ident *id = mangle(IDENT("L"), get_op_ident(op));
857
858
859
860
861
862
		*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;
863
	elt.i_call.ctx      = context;
864
865
866
	elt.i_call.link     = NULL;

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