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
static ident *get_ident_for_tv(tarval *tv) {
	char buf[256];
123
	tarval_snprintf(buf, sizeof(buf), tv);
124
125
	return new_id_from_str(buf);
}
126

127
128
129
130
131
132
133
134
135
136
137
138
/**
 * 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';
139
		}
140
141
142
143
144
145
146
147
148
149
150
	} 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
151
		}
152
153
154
	}
	panic("Can't output mode_suffix for %+F\n", mode);
}
Christian Würdig's avatar
Christian Würdig committed
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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
174
	}
Christian Würdig's avatar
Christian Würdig committed
175
176
}

Michael Beck's avatar
Michael Beck committed
177
/**
178
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
179
 */
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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
197
198
199
200
201
202
203
204
205
206
// 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
207

208
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
209
{
210
211
	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
212

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

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

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
222

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

227
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
228
{
229
	ia32_attr_t *attr = get_ia32_attr(node);
230

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

236
237
238
239
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
240

241
242
243
244
245
246
247
248
249
250
	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
251
		be_emit_string(env, "BAD");
252
		return;
Christian Würdig's avatar
Christian Würdig committed
253
	}
Christian Würdig's avatar
Christian Würdig committed
254

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

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

263
264
265
266
267
268
269
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);
}

270
271
272
273
274
275
276
277
278
279
280
281
282
283
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 '%';
}

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

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
296
	be_emit_char(env, get_xmm_mode_suffix(mode));
297
298
}

299
300
301
302
303
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
304
		be_emit_char(env, 's');
305
	} else {
Matthias Braun's avatar
Matthias Braun committed
306
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
		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
343
344
345
	}
}

Matthias Braun's avatar
Matthias Braun committed
346
347


Christian Würdig's avatar
Christian Würdig committed
348
349
350
/**
 * Emits registers and/or address mode of a binary operation.
 */
351
352
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
353
		case ia32_Normal:
354
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
355
				be_emit_char(env, '$');
356
				ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
357
				be_emit_cstring(env, ", ");
358
359
360
361
362
				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
363
				const arch_register_t *in;
Christian Würdig's avatar
Christian Würdig committed
364
				const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
365

Christian Würdig's avatar
Christian Würdig committed
366
367
368
				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
369

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

Matthias Braun's avatar
Matthias Braun committed
375
376
377
378
				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
379
380
381
			}
			break;
		case ia32_AddrModeS:
382
383
384
			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
385
				be_emit_cstring(env, ", $");
386
387
388
				ia32_emit_immediate(env, node);
			} else if (produces_result(node)) {
				ia32_emit_am(env, node);
Matthias Braun's avatar
Matthias Braun committed
389
				be_emit_cstring(env, ", ");
390
391
392
				ia32_emit_dest_register(env, node, 0);
			} else {
				ia32_emit_am(env, node);
Matthias Braun's avatar
Matthias Braun committed
393
				be_emit_cstring(env, ", ");
394
				ia32_emit_source_register(env, node, 2);
395
			}
Christian Würdig's avatar
Christian Würdig committed
396
397
			break;
		case ia32_AddrModeD:
398
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
Matthias Braun's avatar
Matthias Braun committed
399
				be_emit_char(env, '$');
400
				ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
401
				be_emit_cstring(env, ", ");
402
403
404
405
				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
406
				const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
407
408
409

				in_name = ia32_get_reg_name_for_mode(env, mode, in1);

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

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

426
427
428
/**
 * Emits registers and/or address mode of a binary operation.
 */
429
430
void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
431
		case ia32_Normal:
432
433
434
435
436
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
				// should not happen...
				assert(0);
			} else {
				ia32_attr_t *attr = get_ia32_attr(node);
437
438
439
440
441
				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;

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

Matthias Braun's avatar
Matthias Braun committed
445
446
447
448
				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));
449
450
451
452
			}
			break;
		case ia32_AddrModeS:
		case ia32_AddrModeD:
453
			ia32_emit_am(env, node);
454
455
456
457
458
459
			break;
		default:
			assert(0 && "unsupported op type");
	}
}

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

/**
493
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
494
 */
495
496
497
498
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
499

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

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

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

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

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

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

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

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

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

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

/*
 * positive conditions for signed compares
 */
static const struct cmp2conditon_t cmp2condition_s[] = {
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
	{ 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 */
580
581
582
583
584
585
};

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

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

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

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


617
618
619
620
621
622
623
/**
 * 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
624
625
626
/**
 * Returns the target label for a control flow node.
 */
627
628
void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) {
	ir_node *block = get_cfop_target_block(node);
629

Matthias Braun's avatar
Matthias Braun committed
630
631
	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
632
}
633

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

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

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

648
	foreach_out_edge(node, edge) {
649
650
651
652
653
654
655
656
657
658
659
660
		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
661
662
663
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
664
665
static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node,
                           ir_mode *mode, long pnc) {
666
667
668
669
670
	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
671

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

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

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

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

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

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

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

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

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

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

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

Christian Würdig's avatar
Christian Würdig committed
732
733
734
/**
 * Emits code for conditional jump with two variables.
 */
735
736
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
737
738
}

739
740
741
/**
 * Emits code for conditional test and jump.
 */
742
743
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
744
		be_emit_cstring(env, "\ttest $");
745
		ia32_emit_immediate(env, node);
Matthias Braun's avatar
Matthias Braun committed
746
		be_emit_cstring(env, ", ");
747
		ia32_emit_source_register(env, node, 0);
Matthias Braun's avatar
Matthias Braun committed
748
		be_emit_finish_line_gas(env, node);
749
	} else {
Matthias Braun's avatar
Matthias Braun committed
750
		be_emit_cstring(env, "\ttest ");
751
		ia32_emit_source_register(env, node, 1);
Matthias Braun's avatar
Matthias Braun committed
752
		be_emit_cstring(env, ", ");
753
		ia32_emit_source_register(env, node, 0);
Matthias Braun's avatar
Matthias Braun committed
754
		be_emit_finish_line_gas(env, node);
755
756
	}
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
757
758
759
760
761
}

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

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

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

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

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

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

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

Michael Beck's avatar
Michael Beck committed
793
794
795
/**
 * Emits code for conditional x87 floating point jump with two variables.
 */
796
797
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
798
	const char *reg = attr->x87[1]->name;
799
	long pnc = get_ia32_pncode(node);
Michael Beck's avatar
Michael Beck committed
800

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

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

Matthias Braun's avatar
Matthias Braun committed
829
830
831
832
	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
833

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

837
838
839
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
840
841
	int idx_left  = 2 - is_PsiCondCMov;
	int idx_right = 3 - is_PsiCondCMov;
Christian Würdig's avatar
Christian Würdig committed
842
843
	const arch_register_t *in1, *in2, *out;

844
845
846
	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
847

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

Christian Würdig's avatar
Christian Würdig committed
873
874
	if (REGS_ARE_EQUAL(out, in2)) {
		/* best case: default in == out -> do nothing */
875
876
	} else if (REGS_ARE_EQUAL(out, in1)) {
		ir_node *n = (ir_node*) node;
Christian Würdig's avatar
Christian Würdig committed
877
		/* true in == out -> need complement compare and exchange true and default in */
878
879
880
		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
881

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

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