ia32_intrinsics.c 10.3 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

6
/**
Christian Würdig's avatar
Christian Würdig committed
7
8
9
10
 * @file
 * @brief       This file implements the mapping of 64Bit intrinsic
 *              functions to code or library calls.
 * @author      Michael Beck
11
 */
12
#include "iredges.h"
13
#include "irgmod.h"
14
15
#include "irop.h"
#include "irnode_t.h"
16
#include "ircons_t.h"
17
#include "irprog_t.h"
18
#include "iroptimize.h"
19
#include "lower_dw.h"
20
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
21
#include "panic.h"
22
#include "util.h"
23

24
#include "ia32_new_nodes.h"
25
26
#include "bearch_ia32_t.h"
#include "gen_ia32_regalloc_if.h"
Matthias Braun's avatar
Matthias Braun committed
27
#include "begnuas.h"
28

29
/**
Matthias Braun's avatar
Matthias Braun committed
30
31
 * lower 64bit addition: an 32bit add for the lower parts, an add with
 * carry for the higher parts.
32
 */
Matthias Braun's avatar
Matthias Braun committed
33
static void ia32_lower_add64(ir_node *node, ir_mode *mode)
34
{
Matthias Braun's avatar
Matthias Braun committed
35
36
37
38
39
40
41
42
	dbg_info *dbg        = get_irn_dbg_info(node);
	ir_node  *block      = get_nodes_block(node);
	ir_node  *left       = get_Add_left(node);
	ir_node  *right      = get_Add_right(node);
	ir_node  *left_low   = get_lowered_low(left);
	ir_node  *left_high  = get_lowered_high(left);
	ir_node  *right_low  = get_lowered_low(right);
	ir_node  *right_high = get_lowered_high(right);
43

Matthias Braun's avatar
Matthias Braun committed
44
45
46
	/* l_res = a_l + b_l */
	ir_node  *add_low
		= new_bd_ia32_l_Add(dbg, block, left_low, right_low);
47
	ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
48
	ir_node  *res_low    = new_r_Proj(add_low, ia32_mode_gp, pn_ia32_l_Add_res);
Matthias Braun's avatar
Matthias Braun committed
49
	ir_node  *flags      = new_r_Proj(add_low, mode_flags, pn_ia32_l_Add_flags);
50
51

	/* h_res = a_h + b_h + carry */
Matthias Braun's avatar
Matthias Braun committed
52
53
54
	ir_node  *add_high
		= new_bd_ia32_l_Adc(dbg, block, left_high, right_high, flags, mode);
	ir_set_dw_lowered(node, res_low, add_high);
55
56
57
}

/**
Matthias Braun's avatar
Matthias Braun committed
58
59
 * lower 64bit subtraction: a 32bit sub for the lower parts, a sub borrow
 * for the higher parts.
60
 */
Matthias Braun's avatar
Matthias Braun committed
61
static void ia32_lower_sub64(ir_node *node, ir_mode *mode)
62
{
Matthias Braun's avatar
Matthias Braun committed
63
64
65
66
67
68
69
70
	dbg_info *dbg        = get_irn_dbg_info(node);
	ir_node  *block      = get_nodes_block(node);
	ir_node  *left       = get_Sub_left(node);
	ir_node  *right      = get_Sub_right(node);
	ir_node  *left_low   = get_lowered_low(left);
	ir_node  *left_high  = get_lowered_high(left);
	ir_node  *right_low  = get_lowered_low(right);
	ir_node  *right_high = get_lowered_high(right);
71
72

	/* l_res = a_l - b_l */
Matthias Braun's avatar
Matthias Braun committed
73
74
75
	ir_node  *sub_low
		= new_bd_ia32_l_Sub(dbg, block, left_low, right_low);
	ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
76
	ir_node  *res_low    = new_r_Proj(sub_low, ia32_mode_gp, pn_ia32_l_Sub_res);
Matthias Braun's avatar
Matthias Braun committed
77
	ir_node  *flags      = new_r_Proj(sub_low, mode_flags, pn_ia32_l_Sub_flags);
78

Matthias Braun's avatar
Matthias Braun committed
79
80
81
82
	/* h_res = a_h - b_h - carry */
	ir_node  *sub_high
		= new_bd_ia32_l_Sbb(dbg, block, left_high, right_high, flags, mode);
	ir_set_dw_lowered(node, res_low, sub_high);
83
84
}

85
/**
Matthias Braun's avatar
Matthias Braun committed
86
 * Checks whether node high is a sign extension of low.
87
 */
Matthias Braun's avatar
Matthias Braun committed
88
static bool is_sign_extend(ir_node *low, ir_node *high)
89
90
{
	if (is_Shrs(high)) {
Matthias Braun's avatar
Matthias Braun committed
91
92
		ir_node *high_r = get_Shrs_right(high);
		if (!is_Const(high_r)) return false;
93

Matthias Braun's avatar
Matthias Braun committed
94
95
96
		ir_tarval *shift_count = get_Const_tarval(high_r);
		if (!tarval_is_long(shift_count))       return false;
		if (get_tarval_long(shift_count) != 31) return false;
97

Matthias Braun's avatar
Matthias Braun committed
98
		ir_node *high_l = get_Shrs_left(high);
99

Matthias Braun's avatar
Matthias Braun committed
100
101
		if (is_Conv(low)    && get_Conv_op(low)    == high_l) return true;
		if (is_Conv(high_l) && get_Conv_op(high_l) == low)    return true;
102
	} else if (is_Const(low) && is_Const(high)) {
Matthias Braun's avatar
Matthias Braun committed
103
104
		ir_tarval *tl = get_Const_tarval(low);
		ir_tarval *th = get_Const_tarval(high);
105
106
107
108
109
110
111
112
113

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

Matthias Braun's avatar
Matthias Braun committed
114
	return false;
115
116
}

117
/**
Matthias Braun's avatar
Matthias Braun committed
118
 * lower 64bit Mul operation.
119
 */
Matthias Braun's avatar
Matthias Braun committed
120
static void ia32_lower_mul64(ir_node *node, ir_mode *mode)
121
{
Matthias Braun's avatar
Matthias Braun committed
122
123
124
125
126
127
128
129
	dbg_info *dbg        = get_irn_dbg_info(node);
	ir_node  *block      = get_nodes_block(node);
	ir_node  *left       = get_Mul_left(node);
	ir_node  *right      = get_Mul_right(node);
	ir_node  *left_low   = get_lowered_low(left);
	ir_node  *left_high  = get_lowered_high(left);
	ir_node  *right_low  = get_lowered_low(right);
	ir_node  *right_high = get_lowered_high(right);
130
131

	/*
Matthias Braun's avatar
Matthias Braun committed
132
		EDX:EAX = left_low * right_low
133
134
		l_res   = EAX

Matthias Braun's avatar
Matthias Braun committed
135
		t1 = right_low * left_high
136
		t2 = t1 + EDX
Matthias Braun's avatar
Matthias Braun committed
137
		t3 = left_low * right_high
138
139
		h_res = t2 + t3
	*/
Michael Beck's avatar
Michael Beck committed
140

141
	/* handle the often used case of 32x32=64 mul */
Matthias Braun's avatar
Matthias Braun committed
142
143
144
145
146
147
	ir_node *h_res;
	ir_node *l_res;
	if (is_sign_extend(left_low, left_high)
	    && is_sign_extend(right_low, right_high)) {
		ir_node *mul = new_bd_ia32_l_IMul(dbg, block, left_low, right_low);
		h_res = new_rd_Proj(dbg, mul, mode, pn_ia32_l_IMul_res_high);
148
		l_res = new_rd_Proj(dbg, mul, ia32_mode_gp, pn_ia32_l_IMul_res_low);
149
150
	} else {
		/* note that zero extension is handled hare efficiently */
Matthias Braun's avatar
Matthias Braun committed
151
152
		ir_node *mul  = new_bd_ia32_l_Mul(dbg, block, left_low, right_low);
		ir_node *pEDX = new_rd_Proj(dbg, mul, mode, pn_ia32_l_Mul_res_high);
153
		l_res = new_rd_Proj(dbg, mul, ia32_mode_gp, pn_ia32_l_Mul_res_low);
Matthias Braun's avatar
Matthias Braun committed
154
155
156
157
158
159
160

		ir_node *right_lowc = new_rd_Conv(dbg, block, right_low, mode);
		ir_node *mul1 = new_rd_Mul(dbg, block, left_high, right_lowc, mode);
		ir_node *add        = new_rd_Add(dbg, block, mul1, pEDX, mode);
		ir_node *left_lowc  = new_rd_Conv(dbg, block, left_low, mode);
		ir_node *mul2 = new_rd_Mul(dbg, block, left_lowc, right_high, mode);
		h_res = new_rd_Add(dbg, block, add, mul2, mode);
161
	}
Matthias Braun's avatar
Matthias Braun committed
162
	ir_set_dw_lowered(node, l_res, h_res);
163
164
}

165
/**
Matthias Braun's avatar
Matthias Braun committed
166
 * lower 64bit minus operation
167
 */
Matthias Braun's avatar
Matthias Braun committed
168
static void ia32_lower_minus64(ir_node *node, ir_mode *mode)
169
{
Matthias Braun's avatar
Matthias Braun committed
170
171
172
173
174
175
	dbg_info *dbg     = get_irn_dbg_info(node);
	ir_node  *block   = get_nodes_block(node);
	ir_node  *op      = get_Minus_op(node);
	ir_node  *op_low  = get_lowered_low(op);
	ir_node  *op_high = get_lowered_high(op);
	ir_node  *minus   = new_bd_ia32_l_Minus64(dbg, block, op_low, op_high);
176
	ir_node  *l_res   = new_r_Proj(minus, ia32_mode_gp, pn_ia32_Minus64_res_low);
Matthias Braun's avatar
Matthias Braun committed
177
178
	ir_node  *h_res   = new_r_Proj(minus, mode, pn_ia32_Minus64_res_high);
	ir_set_dw_lowered(node, l_res, h_res);
179
180
181
}

/**
Matthias Braun's avatar
Matthias Braun committed
182
 * lower 64bit conversions
183
 */
Matthias Braun's avatar
Matthias Braun committed
184
static void ia32_lower_conv64(ir_node *node, ir_mode *mode)
185
{
Matthias Braun's avatar
Matthias Braun committed
186
187
188
189
	dbg_info  *dbg       = get_irn_dbg_info(node);
	ir_node   *op        = get_Conv_op(node);
	ir_mode   *mode_from = get_irn_mode(op);
	ir_mode   *mode_to   = get_irn_mode(node);
190

Matthias Braun's avatar
Matthias Braun committed
191
192
	if (mode_is_float(mode_from) && get_mode_size_bits(mode_to) == 64
	    && get_mode_arithmetic(mode_to) == irma_twos_complement) {
193
		/* We have a Conv float -> long long here */
Matthias Braun's avatar
Matthias Braun committed
194
195
196
197
		ir_node *float_to_ll;
		ir_node *l_res;
		ir_node *h_res;
		if (mode_is_signed(mode)) {
198
			/* convert from float to signed 64bit */
Matthias Braun's avatar
Matthias Braun committed
199
200
			ir_node *block = get_nodes_block(node);
			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, op);
201
			l_res = new_r_Proj(float_to_ll, ia32_mode_gp,
202
			                   pn_ia32_l_FloattoLL_res_low);
Matthias Braun's avatar
Matthias Braun committed
203
			h_res = new_r_Proj(float_to_ll, mode,
204
205
							   pn_ia32_l_FloattoLL_res_high);
		} else {
Christoph Mallon's avatar
Christoph Mallon committed
206
			/* Convert from float to unsigned 64bit. */
Matthias Braun's avatar
Matthias Braun committed
207
208
209
210
211
212
213
			ir_graph  *irg = get_irn_irg(node);
			ir_tarval *flt_tv
				= new_tarval_from_str("9223372036854775808", 19, ia32_mode_E);
			ir_node   *flt_corr  = new_r_Const(irg, flt_tv);

			ir_node *lower_blk = part_block_dw(node);
			ir_node *upper_blk = get_nodes_block(node);
214
			set_dw_control_flow_changed();
Matthias Braun's avatar
Matthias Braun committed
215
216
217
218
219
220
221
222
223
224

			ir_node *opc  = new_rd_Conv(dbg, upper_blk, op, ia32_mode_E);
			ir_node *cmp  = new_rd_Cmp(dbg, upper_blk, opc, flt_corr,
			                           ir_relation_less);
			ir_node *cond = new_rd_Cond(dbg, upper_blk, cmp);
			ir_node *in[] = {
				new_r_Proj(cond, mode_X, pn_Cond_true),
				new_r_Proj(cond, mode_X, pn_Cond_false)
			};
			ir_node *blk   = new_r_Block(irg, 1, &in[1]);
225
			in[1] = new_r_Jmp(blk);
226
227
228
229

			set_irn_in(lower_blk, 2, in);

			/* create to Phis */
Matthias Braun's avatar
Matthias Braun committed
230
			ir_node *phi_in[] = {
231
				new_r_Const_null(irg, mode),
Matthias Braun's avatar
Matthias Braun committed
232
233
234
235
236
237
238
239
240
241
242
243
				new_r_Const_long(irg, mode, 0x80000000)
			};
			ir_node *int_phi
				= new_r_Phi(lower_blk, ARRAY_SIZE(phi_in), phi_in, mode);

			ir_node *fphi_in[] = {
				opc,
				new_rd_Sub(dbg, upper_blk, opc, flt_corr, ia32_mode_E)
			};
			ir_node *flt_phi
				= new_r_Phi(lower_blk, ARRAY_SIZE(fphi_in), fphi_in,
				            ia32_mode_E);
244

245
			/* fix Phi links for next part_block() */
246
247
248
249
			if (is_Phi(int_phi))
				add_Block_phi(lower_blk, int_phi);
			if (is_Phi(flt_phi))
				add_Block_phi(lower_blk, flt_phi);
250
251

			float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
252
			l_res = new_r_Proj(float_to_ll, ia32_mode_gp,
253
							   pn_ia32_l_FloattoLL_res_low);
Matthias Braun's avatar
Matthias Braun committed
254
			h_res = new_r_Proj(float_to_ll, mode,
255
							   pn_ia32_l_FloattoLL_res_high);
Matthias Braun's avatar
Matthias Braun committed
256
			h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, mode);
257
258

			/* move the call and its Proj's to the lower block */
Matthias Braun's avatar
Matthias Braun committed
259
260
			set_nodes_block(node, lower_blk);
			for (ir_node *proj = (ir_node*)get_irn_link(node); proj != NULL;
261
			     proj = (ir_node*)get_irn_link(proj)) {
262
				set_nodes_block(proj, lower_blk);
263
			}
264
		}
Matthias Braun's avatar
Matthias Braun committed
265
266
267
268
		ir_set_dw_lowered(node, l_res, h_res);
	} else if (get_mode_size_bits(mode_from) == 64
	           && get_mode_arithmetic(mode_from) == irma_twos_complement
	           && mode_is_float(mode_to)) {
269
		/* We have a Conv long long -> float here */
Matthias Braun's avatar
Matthias Braun committed
270
271
272
273
274
		ir_node *op_low  = get_lowered_low(op);
		ir_node *op_high = get_lowered_high(op);
		ir_node *block   = get_nodes_block(node);
		ir_node *ll_to_float
			= new_bd_ia32_l_LLtoFloat(dbg, block, op_high, op_low, mode_to);
275

Matthias Braun's avatar
Matthias Braun committed
276
		exchange(node, ll_to_float);
277
	} else {
Matthias Braun's avatar
Matthias Braun committed
278
		ir_default_lower_dw_Conv(node, mode);
279
280
281
	}
}

Matthias Braun's avatar
Matthias Braun committed
282
283
284
static ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
                                            const ir_mode *imode,
                                            const ir_mode *omode, void *context)
285
{
Matthias Braun's avatar
Matthias Braun committed
286
287
288
289
290
291
292
293
294
295
	(void)omode;
	(void)context;

	const char *name;
	if (op == op_Div) {
		name = mode_is_signed(imode) ? "__divdi3" : "__udivdi3";
	} else if (op == op_Mod) {
		name = mode_is_signed(imode) ? "__moddi3" : "__umoddi3";
	} else {
		panic("ia32: Unexpected lowering of 64bit op %s", get_op_name(op));
296
	}
Matthias Braun's avatar
Matthias Braun committed
297
298
	return create_compilerlib_entity(new_id_from_str(name), method);
}
299

Matthias Braun's avatar
Matthias Braun committed
300
301
302
void ia32_lower64(void)
{
	/* perform doubleword lowering */
303
304
	ir_mode *word_unsigned = ia32_reg_classes[CLASS_ia32_gp].mode;
	ir_mode *word_signed   = find_signed_mode(word_unsigned);
Matthias Braun's avatar
Matthias Braun committed
305
306
	lwrdw_param_t lower_dw_params = {
		ia32_create_intrinsic_fkt,
Matthias Braun's avatar
Matthias Braun committed
307
		NULL,
308
309
		word_unsigned,
		word_signed,
Matthias Braun's avatar
Matthias Braun committed
310
311
		64,    /* doubleword size */
		be_is_big_endian(),
Matthias Braun's avatar
Matthias Braun committed
312
313
314
315
316
317
318
319
320
	};

	ir_prepare_dw_lowering(&lower_dw_params);
	ir_register_dw_lower_function(op_Add,   ia32_lower_add64);
	ir_register_dw_lower_function(op_Sub,   ia32_lower_sub64);
	ir_register_dw_lower_function(op_Mul,   ia32_lower_mul64);
	ir_register_dw_lower_function(op_Minus, ia32_lower_minus64);
	ir_register_dw_lower_function(op_Conv,  ia32_lower_conv64);
	ir_lower_dw_ops();
321
}