ia32_emitter.c 55.4 KB
Newer Older
1
2
/**
 * This file implements the node emitter.
3
 * @author Christian Wuerdig, Matthias Braun
4
5
 * $Id$
 */
Christian Würdig's avatar
Christian Würdig committed
6
#ifdef HAVE_CONFIG_H
7
#include <config.h>
Christian Würdig's avatar
Christian Würdig committed
8
9
#endif

Christian Würdig's avatar
Christian Würdig committed
10
11
#include <limits.h>

12
#include "xmalloc.h"
13
14
#include "tv.h"
#include "iredges.h"
Christian Würdig's avatar
Christian Würdig committed
15
16
17
18
#include "debug.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irop_t.h"
Christian Würdig's avatar
Christian Würdig committed
19
#include "irargs_t.h"
20
#include "irprog_t.h"
21
#include "iredges_t.h"
22
#include "execfreq.h"
23
#include "error.h"
Matthias Braun's avatar
Matthias Braun committed
24
#include "raw_bitset.h"
Christian Würdig's avatar
Christian Würdig committed
25

26
#include "../besched_t.h"
Christian Würdig's avatar
Christian Würdig committed
27
#include "../benode_t.h"
Michael Beck's avatar
Michael Beck committed
28
#include "../beabi.h"
29
#include "../be_dbgout.h"
Matthias Braun's avatar
Matthias Braun committed
30
31
#include "../beemitter.h"
#include "../begnuas.h"
Christian Würdig's avatar
Christian Würdig committed
32

33
#include "ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
34
#include "gen_ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
35
#include "gen_ia32_regalloc_if.h"
36
37
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
Christian Würdig's avatar
Christian Würdig committed
38
#include "ia32_map_regs.h"
Christian Würdig's avatar
Christian Würdig committed
39
#include "bearch_ia32_t.h"
Christian Würdig's avatar
Christian Würdig committed
40

41
#define BLOCK_PREFIX ".L"
Michael Beck's avatar
Michael Beck committed
42

Christian Würdig's avatar
Christian Würdig committed
43
44
#define SNPRINTF_BUF_LEN 128

45
/* global arch_env for lc_printf functions */
Christian Würdig's avatar
Christian Würdig committed
46
static const arch_env_t *arch_env = NULL;
47

Christian Würdig's avatar
Christian Würdig committed
48
/**
Christian Würdig's avatar
Christian Würdig committed
49
 * Returns the register at in position pos.
Christian Würdig's avatar
Christian Würdig committed
50
 */
Christian Würdig's avatar
Christian Würdig committed
51
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
Christian Würdig's avatar
Christian Würdig committed
52
53
54
55
56
57
58
59
60
	ir_node                *op;
	const arch_register_t  *reg = NULL;

	assert(get_irn_arity(irn) > pos && "Invalid IN position");

	/* The out register of the operator at position pos is the
	   in register we need. */
	op = get_irn_n(irn, pos);

Christian Würdig's avatar
Christian Würdig committed
61
	reg = arch_get_irn_register(arch_env, op);
Christian Würdig's avatar
Christian Würdig committed
62

Christian Würdig's avatar
Christian Würdig committed
63
	assert(reg && "no in register found");
64

65
66
	/* in case of a joker register: just return a valid register */
	if (arch_register_type_is(reg, joker)) {
Matthias Braun's avatar
Matthias Braun committed
67
		const arch_register_req_t *req;
68
69

		/* ask for the requirements */
Matthias Braun's avatar
Matthias Braun committed
70
		req = arch_get_register_req(arch_env, irn, pos);
71

Matthias Braun's avatar
Matthias Braun committed
72
		if (arch_register_req_is(req, limited)) {
73
			/* in case of limited requirements: get the first allowed register */
Matthias Braun's avatar
Matthias Braun committed
74
75
			unsigned idx = rbitset_next(req->limited, 0, 1);
			reg = arch_register_for_index(req->cls, idx);
76
		} else {
77
			/* otherwise get first register in class */
Matthias Braun's avatar
Matthias Braun committed
78
			reg = arch_register_for_index(req->cls, 0);
79
80
		}
	}
81

Christian Würdig's avatar
Christian Würdig committed
82
83
84
85
86
87
	return reg;
}

/**
 * Returns the register at out position pos.
 */
Christian Würdig's avatar
Christian Würdig committed
88
static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
Christian Würdig's avatar
Christian Würdig committed
89
90
91
92
93
94
95
96
97
98
	ir_node                *proj;
	const arch_register_t  *reg = NULL;

	/* 1st case: irn is not of mode_T, so it has only                 */
	/*           one OUT register -> good                             */
	/* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
	/*           Proj with the corresponding projnum for the register */

	if (get_irn_mode(irn) != mode_T) {
		reg = arch_get_irn_register(arch_env, irn);
99
	} else if (is_ia32_irn(irn)) {
Christian Würdig's avatar
Christian Würdig committed
100
		reg = get_ia32_out_reg(irn, pos);
101
	} else {
Christian Würdig's avatar
Christian Würdig committed
102
103
104
105
106
107
108
109
110
111
112
113
114
		const ir_edge_t *edge;

		foreach_out_edge(irn, edge) {
			proj = get_edge_src_irn(edge);
			assert(is_Proj(proj) && "non-Proj from mode_T node");
			if (get_Proj_proj(proj) == pos) {
				reg = arch_get_irn_register(arch_env, proj);
				break;
			}
		}
	}

	assert(reg && "no out register found");
Christian Würdig's avatar
Christian Würdig committed
115
116
117
118
	return reg;
}

/**
119
 * Returns an ident for the given tarval tv.
Christian Würdig's avatar
Christian Würdig committed
120
 */
121
122
123
124
125
126
static ident *get_ident_for_tv(tarval *tv) {
	char buf[256];
	int len = tarval_snprintf(buf, sizeof(buf), tv);
	assert(len);
	return new_id_from_str(buf);
}
127

128
129
130
131
132
133
134
135
136
137
138
139
/**
 * Determine the gnu assembler suffix that indicates a mode
 */
static char get_mode_suffix(const ir_mode *mode) {
	if(mode_is_float(mode)) {
		switch(get_mode_size_bits(mode)) {
		case 32:
			return 's';
		case 64:
			return 'l';
		case 80:
			return 't';
140
		}
141
142
143
144
145
146
147
148
149
150
151
	} else {
		assert(mode_is_int(mode) || mode_is_reference(mode));
		switch(get_mode_size_bits(mode)) {
		case 64:
			return 'q';
		case 32:
			return 'l';
		case 16:
			return 'w';
		case 8:
			return 'b';
Christian Würdig's avatar
Christian Würdig committed
152
		}
153
154
155
	}
	panic("Can't output mode_suffix for %+F\n", mode);
}
Christian Würdig's avatar
Christian Würdig committed
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
static int produces_result(const ir_node *node) {
	return !(is_ia32_St(node) ||
		is_ia32_Store8Bit(node) ||
		is_ia32_CondJmp(node) ||
		is_ia32_xCondJmp(node) ||
		is_ia32_CmpSet(node) ||
		is_ia32_xCmpSet(node) ||
		is_ia32_SwitchJmp(node));
}

static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) {
	switch(get_mode_size_bits(mode)) {
		case 8:
			return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
		case 16:
			return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg);
		default:
			return (char *)arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
175
	}
Christian Würdig's avatar
Christian Würdig committed
176
177
}

Michael Beck's avatar
Michael Beck committed
178
/**
179
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
180
 */
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/

Matthias Braun's avatar
Matthias Braun committed
198
199
200
201
202
203
204
205
206
207
// we have no C++ and can't define an implicit ia32_emit_env_t* cast to
// be_emit_env_t* so we cheat a bit...
#define be_emit_char(env,c)             be_emit_char(env->emit,c)
#define be_emit_string(env,s)           be_emit_string(env->emit,s)
#undef be_emit_cstring
#define be_emit_cstring(env,x)          { be_emit_string_len(env->emit, x, sizeof(x)-1); }
#define be_emit_ident(env,i)            be_emit_ident(env->emit,i)
#define be_emit_write_line(env)         be_emit_write_line(env->emit)
#define be_emit_finish_line_gas(env,n)  be_emit_finish_line_gas(env->emit,n)
#define be_emit_pad_comment(env)        be_emit_pad_comment(env->emit)
Michael Beck's avatar
Michael Beck committed
208

209
void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
Christian Würdig's avatar
Christian Würdig committed
210
{
211
212
	const arch_register_t *reg = get_in_reg(node, pos);
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
213

214
	assert(pos < get_irn_arity(node));
Christian Würdig's avatar
Christian Würdig committed
215

Matthias Braun's avatar
Matthias Braun committed
216
217
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
218
219
220
221
222
}

void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos) {
	const arch_register_t *reg = get_out_reg(node, pos);
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
223

Matthias Braun's avatar
Matthias Braun committed
224
225
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
Christian Würdig's avatar
Christian Würdig committed
226
227
}

228
void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos)
Christian Würdig's avatar
Christian Würdig committed
229
{
230
	ia32_attr_t *attr = get_ia32_attr(node);
231

Matthias Braun's avatar
Matthias Braun committed
232
	assert(pos < 3);
Matthias Braun's avatar
Matthias Braun committed
233
234
	be_emit_char(env, '%');
	be_emit_string(env, attr->x87[pos]->name);
235
}
Christian Würdig's avatar
Christian Würdig committed
236

237
238
239
240
void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
{
	tarval *tv;
	ident *id;
Christian Würdig's avatar
Christian Würdig committed
241

242
243
244
245
246
247
248
249
250
251
	switch(get_ia32_immop_type(node)) {
	case ia32_ImmConst:
		tv = get_ia32_Immop_tarval(node);
		id = get_ident_for_tv(tv);
		break;
	case ia32_ImmSymConst:
		id = get_ia32_Immop_symconst(node);
		break;
	default:
		assert(0);
Matthias Braun's avatar
Matthias Braun committed
252
		be_emit_string(env, "BAD");
253
		return;
Christian Würdig's avatar
Christian Würdig committed
254
	}
Christian Würdig's avatar
Christian Würdig committed
255

Matthias Braun's avatar
Matthias Braun committed
256
	be_emit_ident(env, id);
257
}
Christian Würdig's avatar
Christian Würdig committed
258

259
260
void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_mode *mode)
{
Matthias Braun's avatar
Matthias Braun committed
261
	be_emit_char(env, get_mode_suffix(mode));
Christian Würdig's avatar
Christian Würdig committed
262
263
}

264
265
266
267
268
269
270
void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
	if(mode != NULL)
		ia32_emit_mode_suffix(env, mode);
}

271
272
273
274
275
276
277
278
279
280
281
282
283
284
static char get_xmm_mode_suffix(ir_mode *mode)
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

285
286
287
void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
288
	assert(mode != NULL);
Matthias Braun's avatar
Matthias Braun committed
289
290
	be_emit_char(env, 's');
	be_emit_char(env, get_xmm_mode_suffix(mode));
291
292
293
294
295
296
}

void ia32_emit_xmm_mode_suffix_s(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
	assert(mode != NULL);
Matthias Braun's avatar
Matthias Braun committed
297
	be_emit_char(env, get_xmm_mode_suffix(mode));
298
299
}

300
301
302
303
304
void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode)
{
	if(get_mode_size_bits(mode) == 32)
		return;
	if(mode_is_signed(mode)) {
Matthias Braun's avatar
Matthias Braun committed
305
		be_emit_char(env, 's');
306
	} else {
Matthias Braun's avatar
Matthias Braun committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
		be_emit_char(env, 'z');
	}
}

static void ia32_emit_function_object(ia32_emit_env_t *env, const char *name)
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
		be_emit_cstring(env, "\t.type\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ", @function\n");
		be_emit_write_line(env);
		break;
	case GAS_FLAVOUR_MINGW:
		be_emit_cstring(env, "\t.def\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ";\t.scl\t2;\t.type\t32;\t.endef\n");
		be_emit_write_line(env);
		break;
	default:
		break;
	}
}

static void ia32_emit_function_size(ia32_emit_env_t *env, const char *name)
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
		be_emit_cstring(env, "\t.size\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ", .-");
		be_emit_string(env, name);
		be_emit_char(env, '\n');
		be_emit_write_line(env);
		break;
	default:
		break;
Christian Würdig's avatar
Christian Würdig committed
344
345
346
	}
}

Matthias Braun's avatar
Matthias Braun committed
347
348


Christian Würdig's avatar
Christian Würdig committed
349
350
351
/**
 * Emits registers and/or address mode of a binary operation.
 */
352
353
void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
Christian Würdig's avatar
Christian Würdig committed
354
		case ia32_Normal:
355
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
356
				be_emit_char(env, '$');
357
				ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
358
				be_emit_cstring(env, ", ");
359
360
361
362
363
				ia32_emit_source_register(env, node, 2);
			} else {
				const arch_register_t *in1 = get_in_reg(node, 2);
				const arch_register_t *in2 = get_in_reg(node, 3);
				const arch_register_t *out = produces_result(node) ? get_out_reg(node, 0) : NULL;
Christian Würdig's avatar
Christian Würdig committed
364
				const arch_register_t *in;
Christian Würdig's avatar
Christian Würdig committed
365
				const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
366

Christian Würdig's avatar
Christian Würdig committed
367
368
369
				in      = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
				out     = out ? out : in1;
				in_name = arch_register_get_name(in);
Christian Würdig's avatar
Christian Würdig committed
370

371
				if (is_ia32_emit_cl(node)) {
Christian Würdig's avatar
Christian Würdig committed
372
373
374
375
					assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in) && "shift operation needs ecx");
					in_name = "cl";
				}

Matthias Braun's avatar
Matthias Braun committed
376
377
378
379
				be_emit_char(env, '%');
				be_emit_string(env, in_name);
				be_emit_cstring(env, ", %");
				be_emit_string(env, arch_register_get_name(out));
Christian Würdig's avatar
Christian Würdig committed
380
381
382
			}
			break;
		case ia32_AddrModeS:
383
384
385
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
				assert(!produces_result(node) && "Source AM with Const must not produce result");
				ia32_emit_am(env, node);
Matthias Braun's avatar
Matthias Braun committed
386
				be_emit_cstring(env, ", $");
387
388
389
				ia32_emit_immediate(env, node);
			} else if (produces_result(node)) {
				ia32_emit_am(env, node);
Matthias Braun's avatar
Matthias Braun committed
390
				be_emit_cstring(env, ", ");
391
392
393
				ia32_emit_dest_register(env, node, 0);
			} else {
				ia32_emit_am(env, node);
Matthias Braun's avatar
Matthias Braun committed
394
				be_emit_cstring(env, ", ");
395
				ia32_emit_source_register(env, node, 2);
396
			}
Christian Würdig's avatar
Christian Würdig committed
397
398
			break;
		case ia32_AddrModeD:
399
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
400
				be_emit_char(env, '$');
401
				ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
402
				be_emit_cstring(env, ", ");
403
404
405
406
				ia32_emit_am(env, node);
			} else {
				const arch_register_t *in1 = get_in_reg(node, get_irn_arity(node) == 5 ? 3 : 2);
				ir_mode               *mode = get_ia32_ls_mode(node);
Christian Würdig's avatar
Christian Würdig committed
407
				const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
408
409
410

				in_name = ia32_get_reg_name_for_mode(env, mode, in1);

411
				if (is_ia32_emit_cl(node)) {
Christian Würdig's avatar
Christian Würdig committed
412
413
414
					assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in1) && "shift operation needs ecx");
					in_name = "cl";
				}
415

Matthias Braun's avatar
Matthias Braun committed
416
417
418
				be_emit_char(env, '%');
				be_emit_string(env, in_name);
				be_emit_cstring(env, ", ");
419
				ia32_emit_am(env, node);
Christian Würdig's avatar
Christian Würdig committed
420
421
422
423
424
			}
			break;
		default:
			assert(0 && "unsupported op type");
	}
425
426
}

427
428
429
/**
 * Emits registers and/or address mode of a binary operation.
 */
430
431
void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
432
		case ia32_Normal:
433
434
435
436
437
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
				// should not happen...
				assert(0);
			} else {
				ia32_attr_t *attr = get_ia32_attr(node);
438
439
440
441
442
				const arch_register_t *in1 = attr->x87[0];
				const arch_register_t *in2 = attr->x87[1];
				const arch_register_t *out = attr->x87[2];
				const arch_register_t *in;

443
444
				in  = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
				out = out ? out : in1;
445

Matthias Braun's avatar
Matthias Braun committed
446
447
448
449
				be_emit_char(env, '%');
				be_emit_string(env, arch_register_get_name(in));
				be_emit_cstring(env, ", %");
				be_emit_string(env, arch_register_get_name(out));
450
451
452
453
			}
			break;
		case ia32_AddrModeS:
		case ia32_AddrModeD:
454
			ia32_emit_am(env, node);
455
456
457
458
459
460
			break;
		default:
			assert(0 && "unsupported op type");
	}
}

Christian Würdig's avatar
Christian Würdig committed
461
462
463
/**
 * Emits registers and/or address mode of a unary operation.
 */
464
465
void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
Christian Würdig's avatar
Christian Würdig committed
466
		case ia32_Normal:
467
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
468
				be_emit_char(env, '$');
469
470
				ia32_emit_immediate(env, node);
			} else {
Matthias Braun's avatar
Matthias Braun committed
471
				if (is_ia32_Mul(node) || is_ia32_IMul1OP(node)) {
472
					ia32_emit_source_register(env, node, 3);
Matthias Braun's avatar
Matthias Braun committed
473
474
				} else if(is_ia32_IDiv(node) || is_ia32_Div(node)) {
					ia32_emit_source_register(env, node, 4);
475
476
477
478
				} else if(is_ia32_Push(node)) {
					ia32_emit_source_register(env, node, 2);
				} else if(is_ia32_Pop(node)) {
					ia32_emit_dest_register(env, node, 1);
479
				} else {
480
					ia32_emit_dest_register(env, node, 0);
481
				}
482
			}
Christian Würdig's avatar
Christian Würdig committed
483
			break;
484
		case ia32_AddrModeS:
485
486
		case ia32_AddrModeD:
			ia32_emit_am(env, node);
487
			break;
Christian Würdig's avatar
Christian Würdig committed
488
489
490
491
492
493
		default:
			assert(0 && "unsupported op type");
	}
}

/**
494
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
495
 */
496
497
498
499
void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) {
	ia32_am_flavour_t am_flav = get_ia32_am_flavour(node);
	ident *id = get_ia32_am_sc(node);
	int offs = get_ia32_am_offs_int(node);
Christian Würdig's avatar
Christian Würdig committed
500

501
	/* just to be sure... */
502
	assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL);
Christian Würdig's avatar
Christian Würdig committed
503

504
505
506
	/* emit offset */
	if (id != NULL) {
		if (is_ia32_am_sc_sign(node))
Matthias Braun's avatar
Matthias Braun committed
507
508
			be_emit_char(env, '-');
		be_emit_ident(env, id);
Christian Würdig's avatar
Christian Würdig committed
509
510
	}

511
512
	if(offs != 0) {
		if(id != NULL) {
Matthias Braun's avatar
Matthias Braun committed
513
			be_emit_irprintf(env->emit, "%+d", offs);
514
		} else {
Matthias Braun's avatar
Matthias Braun committed
515
			be_emit_irprintf(env->emit, "%d", offs);
516
		}
517
	}
Christian Würdig's avatar
Christian Würdig committed
518

519
	if (am_flav & (ia32_B | ia32_I)) {
Matthias Braun's avatar
Matthias Braun committed
520
		be_emit_char(env, '(');
Christian Würdig's avatar
Christian Würdig committed
521

522
523
524
		/* emit base */
		if (am_flav & ia32_B) {
			ia32_emit_source_register(env, node, 0);
Christian Würdig's avatar
Christian Würdig committed
525
526
		}

527
528
		/* emit index + scale */
		if (am_flav & ia32_I) {
Matthias Braun's avatar
Matthias Braun committed
529
			be_emit_char(env, ',');
530
			ia32_emit_source_register(env, node, 1);
531

532
			if (am_flav & ia32_S) {
Matthias Braun's avatar
Matthias Braun committed
533
				be_emit_irprintf(env->emit, ",%d", 1 << get_ia32_am_scale(node));
534
535
			}
		}
Matthias Braun's avatar
Matthias Braun committed
536
		be_emit_char(env, ')');
Christian Würdig's avatar
Christian Würdig committed
537
	}
538
}
Christian Würdig's avatar
Christian Würdig committed
539

Christian Würdig's avatar
Christian Würdig committed
540
541
542
543
544
545
546
547
548
549
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
550
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
551
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
552

553
554
555
556
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
557
558
	const char *name;
	pn_Cmp      num;
559
560
561
562
563
564
};

/*
 * positive conditions for signed compares
 */
static const struct cmp2conditon_t cmp2condition_s[] = {
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "l",               pn_Cmp_Lt },     /* < */
	{ "le",              pn_Cmp_Le },     /* <= */
	{ "g",               pn_Cmp_Gt },     /* > */
	{ "ge",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
	{ NULL,              pn_Cmp_Leg},     /* Floating point: ordered */
	{ NULL,              pn_Cmp_Uo },     /* Floating point: unordered */
	{ "e",               pn_Cmp_Ue },     /* Floating point: unordered or == */
	{ "b",               pn_Cmp_Ul },     /* Floating point: unordered or < */
	{ "be",              pn_Cmp_Ule },    /* Floating point: unordered or <= */
	{ "a",               pn_Cmp_Ug },     /* Floating point: unordered or > */
	{ "ae",              pn_Cmp_Uge },    /* Floating point: unordered or >= */
	{ "ne",              pn_Cmp_Ne },     /* Floating point: unordered or != */
	{ NULL,              pn_Cmp_True },   /* always true */
581
582
583
584
585
586
};

/*
 * positive conditions for unsigned compares
 */
static const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
587
588
589
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
590
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
591
592
593
594
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
	{ NULL,              pn_Cmp_True },   /* always true */
595
596
597
598
599
};

/*
 * returns the condition code
 */
600
static const char *get_cmp_suffix(int cmp_code)
601
{
602
603
	assert( (cmp2condition_s[cmp_code & 15].num) == (cmp_code & 15));
	assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7));
604

605
606
607
608
609
	if((cmp_code & ia32_pn_Cmp_Unsigned)) {
		return cmp2condition_u[cmp_code & 7].name;
	} else {
		return cmp2condition_s[cmp_code & 15].name;
	}
610
611
}

612
613
void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc)
{
Matthias Braun's avatar
Matthias Braun committed
614
	be_emit_string(env, get_cmp_suffix(pnc));
615
616
617
}


618
619
620
621
622
623
624
/**
 * Returns the target block for a control flow node.
 */
static ir_node *get_cfop_target_block(const ir_node *irn) {
	return get_irn_link(irn);
}

Christian Würdig's avatar
Christian Würdig committed
625
626
627
/**
 * Returns the target label for a control flow node.
 */
628
629
void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) {
	ir_node *block = get_cfop_target_block(node);
630

Matthias Braun's avatar
Matthias Braun committed
631
632
	be_emit_cstring(env, BLOCK_PREFIX);
	be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block));
Christian Würdig's avatar
Christian Würdig committed
633
}
634

635
636
/** Return the next block in Block schedule */
static ir_node *next_blk_sched(const ir_node *block) {
Michael Beck's avatar
Michael Beck committed
637
	return get_irn_link(block);
638
639
}

640
641
642
/**
 * Returns the Proj with projection number proj and NOT mode_M
 */
643
static ir_node *get_proj(const ir_node *node, long proj) {
644
645
646
	const ir_edge_t *edge;
	ir_node         *src;

647
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
648

649
	foreach_out_edge(node, edge) {
650
651
652
653
654
655
656
657
658
659
660
661
		src = get_edge_src_irn(edge);

		assert(is_Proj(src) && "Proj expected");
		if (get_irn_mode(src) == mode_M)
			continue;

		if (get_Proj_proj(src) == proj)
			return src;
	}
	return NULL;
}

Christian Würdig's avatar
Christian Würdig committed
662
663
664
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
665
666
static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node,
                           ir_mode *mode, long pnc) {
667
668
669
670
671
	const ir_node *proj_true;
	const ir_node *proj_false;
	const ir_node *block;
	const ir_node *next_block;
	int flipped = 0;
Christian Würdig's avatar
Christian Würdig committed
672

673
	/* get both Proj's */
674
	proj_true = get_proj(node, pn_Cond_true);
675
	assert(proj_true && "CondJmp without true Proj");
Christian Würdig's avatar
Christian Würdig committed
676

677
	proj_false = get_proj(node, pn_Cond_false);
678
679
	assert(proj_false && "CondJmp without false Proj");

680
	/* for now, the code works for scheduled and non-schedules blocks */
681
	block = get_nodes_block(node);
682
683

	/* we have a block schedule */
684
	next_block = next_blk_sched(block);
685

686
	if (get_cfop_target_block(proj_true) == next_block) {
687
		/* exchange both proj's so the second one can be omitted */
688
689
		const ir_node *t = proj_true;

690
691
692
693
		proj_true  = proj_false;
		proj_false = t;
		flipped    = 1;
		pnc        = get_negated_pnc(pnc, mode);
694
695
	}

696
697
	/* in case of unordered compare, check for parity */
	if (pnc & pn_Cmp_Uo) {
Matthias Braun's avatar
Matthias Braun committed
698
		be_emit_cstring(env, "\tjp ");
699
		ia32_emit_cfop_target(env, proj_true);
Matthias Braun's avatar
Matthias Braun committed
700
		be_emit_finish_line_gas(env, proj_true);
701
702
	}

Matthias Braun's avatar
Matthias Braun committed
703
	be_emit_cstring(env, "\tj");
704
	ia32_emit_cmp_suffix(env, pnc);
Matthias Braun's avatar
Matthias Braun committed
705
	be_emit_char(env, ' ');
706
	ia32_emit_cfop_target(env, proj_true);
Matthias Braun's avatar
Matthias Braun committed
707
	be_emit_finish_line_gas(env, proj_true);
Christian Würdig's avatar
Christian Würdig committed
708

709
	/* the second Proj might be a fallthrough */
710
	if (get_cfop_target_block(proj_false) != next_block) {
Matthias Braun's avatar
Matthias Braun committed
711
		be_emit_cstring(env, "\tjmp ");
712
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
713
		be_emit_finish_line_gas(env, proj_false);
714
	} else {
Matthias Braun's avatar
Matthias Braun committed
715
		be_emit_cstring(env, "\t/* fallthrough to");
716
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
717
718
		be_emit_cstring(env, " */");
		be_emit_finish_line_gas(env, proj_false);
719
	}
Christian Würdig's avatar
Christian Würdig committed
720
721
722
}

/**
Christian Würdig's avatar
Christian Würdig committed
723
 * Emits code for conditional jump.
Christian Würdig's avatar
Christian Würdig committed
724
 */
725
static void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
726
	be_emit_cstring(env, "\tcmp ");
727
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
728
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
729

730
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
731
732
}

Christian Würdig's avatar
Christian Würdig committed
733
734
735
/**
 * Emits code for conditional jump with two variables.
 */
736
737
static void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) {
	CondJmp_emitter(env, node);
Christian Würdig's avatar
Christian Würdig committed
738
739
}

740
741
742
/**
 * Emits code for conditional test and jump.
 */
743
744
static void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
	if(is_ia32_ImmSymConst(node) || is_ia32_ImmConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
745
		be_emit_cstring(env, "\ttest $");
746
		ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
747
		be_emit_cstring(env, ", ");
748
		ia32_emit_source_register(env, node, 0);
Matthias Braun's avatar
Matthias Braun committed
749
		be_emit_finish_line_gas(env, node);
750
	} else {
Matthias Braun's avatar
Matthias Braun committed
751
		be_emit_cstring(env, "\ttest ");
752
		ia32_emit_source_register(env, node, 1);
Matthias Braun's avatar
Matthias Braun committed
753
		be_emit_cstring(env, ", ");
754
		ia32_emit_source_register(env, node, 0);
Matthias Braun's avatar
Matthias Braun committed
755
		be_emit_finish_line_gas(env, node);
756
757
	}
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
758
759
760
761
762
}

/**
 * Emits code for conditional test and jump with two variables.
 */
763
764
static void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) {
	TestJmp_emitter(env, node);
765
766
}

767
static void emit_ia32_CJmp(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
768
769
	be_emit_cstring(env, "/* omitted redundant test */");
	be_emit_finish_line_gas(env, node);
770

771
	finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node));
772
}
773

774
static void emit_ia32_CJmpAM(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
775
776
	be_emit_cstring(env, "/* omitted redundant test/cmp */");
	be_emit_finish_line_gas(env, node);
777

778
	finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node));
779
}
Christian Würdig's avatar
Christian Würdig committed
780

Christian Würdig's avatar
Christian Würdig committed
781
782
783
/**
 * Emits code for conditional SSE floating point jump with two variables.
 */
784
static void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
785
	be_emit_cstring(env, "\tucomi");
Matthias Braun's avatar
Matthias Braun committed
786
	ia32_emit_xmm_mode_suffix(env, node);
Matthias Braun's avatar
Matthias Braun committed
787
	be_emit_char(env, ' ');
788
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
789
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
790

791
	finish_CondJmp(env, node, mode_F, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
792
793
}

Michael Beck's avatar
Michael Beck committed
794
795
796
/**
 * Emits code for conditional x87 floating point jump with two variables.
 */
797
798
static void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) {
	ia32_attr_t *attr = get_ia32_attr(node);
Michael Beck's avatar
Michael Beck committed
799
	const char *reg = attr->x87[1]->name;
800
	long pnc = get_ia32_pncode(node);
Michael Beck's avatar
Michael Beck committed
801

802
	switch (get_ia32_irn_opcode(node)) {
Michael Beck's avatar
Michael Beck committed
803
	case iro_ia32_fcomrJmp:
804
		pnc = get_inversed_pnc(pnc);
805
		reg = attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
806
807
	case iro_ia32_fcomJmp:
	default:
Matthias Braun's avatar
Matthias Braun committed
808
		be_emit_cstring(env, "\tfucom ");
Michael Beck's avatar
Michael Beck committed
809
810
		break;
	case iro_ia32_fcomrpJmp:
811
		pnc = get_inversed_pnc(pnc);
812
		reg = attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
813
	case iro_ia32_fcompJmp:
Matthias Braun's avatar
Matthias Braun committed
814
		be_emit_cstring(env, "\tfucomp ");
Michael Beck's avatar
Michael Beck committed
815
816
		break;
	case iro_ia32_fcomrppJmp:
817
		pnc = get_inversed_pnc(pnc);
Michael Beck's avatar
Michael Beck committed
818
	case iro_ia32_fcomppJmp:
Matthias Braun's avatar
Matthias Braun committed
819
		be_emit_cstring(env, "\tfucompp ");
Michael Beck's avatar
Michael Beck committed
820
821
822
823
		reg = "";
		break;
	}

824
	if(reg[0] != '\0') {
Matthias Braun's avatar
Matthias Braun committed
825
826
		be_emit_char(env, '%');
		be_emit_string(env, reg);
827
	}
Matthias Braun's avatar
Matthias Braun committed
828
	be_emit_finish_line_gas(env, node);
Michael Beck's avatar
Michael Beck committed
829

Matthias Braun's avatar
Matthias Braun committed
830
831
832
833
	be_emit_cstring(env, "\tfnstsw %ax");
	be_emit_finish_line_gas(env, node);
	be_emit_cstring(env, "\tsahf");
	be_emit_finish_line_gas(env, node);
Michael Beck's avatar
Michael Beck committed
834

835
	finish_CondJmp(env, node, mode_E, pnc);
Michael Beck's avatar
Michael Beck committed
836
837
}

838
839
840
static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) {
	long pnc = get_ia32_pncode(node);
	int is_PsiCondCMov = is_ia32_PsiCondCMov(node);
Matthias Braun's avatar
Matthias Braun committed
841
842
	int idx_left  = 2 - is_PsiCondCMov;
	int idx_right = 3 - is_PsiCondCMov;
Christian Würdig's avatar
Christian Würdig committed
843
844
	const arch_register_t *in1, *in2, *out;

845
846
847
	out = arch_get_irn_register(env->arch_env, node);
	in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_left));
	in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_right));
Christian Würdig's avatar
Christian Würdig committed
848

Christian Würdig's avatar
Christian Würdig committed
849
850
	/* we have to emit the cmp first, because the destination register */
	/* could be one of the compare registers                           */
851
	if (is_ia32_CmpCMov(node)) {
Matthias Braun's avatar
Matthias Braun committed
852
		be_emit_cstring(env, "\tcmp ");
853
		ia32_emit_source_register(env, node, 1);
Matthias Braun's avatar
Matthias Braun committed
854
		be_emit_cstring(env, ", ");
855
856
		ia32_emit_source_register(env, node, 0);
	} else if (is_ia32_xCmpCMov(node)) {
Matthias Braun's avatar
Matthias Braun committed
857
		be_emit_cstring(env, "\tucomis");
858
		ia32_emit_mode_suffix(env, get_irn_mode(node));
Matthias Braun's avatar
Matthias Braun committed
859
		be_emit_char(env, ' ');
860
		ia32_emit_source_register(env, node, 1);
Matthias Braun's avatar
Matthias Braun committed
861
		be_emit_cstring(env, ", ");
862
863
		ia32_emit_source_register(env, node, 0);
	} else if (is_PsiCondCMov) {
864
		/* omit compare because flags are already set by And/Or */
Matthias Braun's avatar
Matthias Braun committed
865
		be_emit_cstring(env, "\ttest ");
866
		ia32_emit_source_register(env, node, 0);
Matthias Braun's avatar
Matthias Braun committed
867
		be_emit_cstring(env, ", ");
868
869
		ia32_emit_source_register(env, node, 0);
	} else {
870
871
		assert(0 && "unsupported CMov");
	}
Matthias Braun's avatar
Matthias Braun committed
872
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
873

Christian Würdig's avatar
Christian Würdig committed
874
875
	if (REGS_ARE_EQUAL(out, in2)) {
		/* best case: default in == out -> do nothing */
876
877
	} else if (REGS_ARE_EQUAL(out, in1)) {
		ir_node *n = (ir_node*) node;
Christian Würdig's avatar
Christian Würdig committed
878
		/* true in == out -> need complement compare and exchange true and default in */
879
880
881
		ir_node *t = get_irn_n(n, idx_left);
		set_irn_n(n, idx_left, get_irn_n(n, idx_right));
		set_irn_n(n, idx_right, t);
Christian Würdig's avatar
Christian Würdig committed
882

883
884
		pnc = get_negated_pnc(pnc, get_irn_mode(node));
	} else {
Christian Würdig's avatar
Christian Würdig committed
885
		/* out is different from in: need copy default -> out */
886
		if (is_PsiCondCMov) {
Matthias Braun's avatar
Matthias Braun committed
887
			be_emit_cstring(env, "\tmovl ");
888
			ia32_emit_dest_register(env, node, 2);
Matthias Braun's avatar
Matthias Braun committed
889
			be_emit_cstring(env, ", ");
890
891
			ia32_emit_dest_register(env, node, 0);
		} else {
Matthias Braun's avatar
Matthias Braun committed
892
			be_emit_cstring(env, "\tmovl ");
893
			ia32_emit_source_register(env, node, 3);
Matthias Braun's avatar
Matthias Braun committed
894
			be_emit_cstring(env, ", ");
895
896
			ia32_emit_dest_register(env, node, 0);
		}
Matthias Braun's avatar
Matthias Braun committed
897
		be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
898
	}
899

900
	if (is_PsiCondCMov) {
Matthias Braun's avatar
Matthias Braun committed
901
		be_emit_cstring(env, "\tcmov");
902
		ia32_emit_cmp_suffix(env, pnc);
Matthias Braun's avatar
Matthias Braun committed
903
		be_emit_cstring(env, "l ");
904
		ia32_emit_source_register(env, node, 1);
Matthias Braun's avatar
Matthias Braun committed
905
		be_emit_cstring(env, ", ");
906
907