ia32_emitter.c 60.5 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

20
/**
21
 * @file
Christian Würdig's avatar
Christian Würdig committed
22
23
24
 * @brief       This file implements the ia32 node emitter.
 * @author      Christian Wuerdig, Matthias Braun
 * @version     $Id$
25
 */
Christian Würdig's avatar
Christian Würdig committed
26
#ifdef HAVE_CONFIG_H
27
#include "config.h"
Christian Würdig's avatar
Christian Würdig committed
28
29
#endif

Christian Würdig's avatar
Christian Würdig committed
30
31
#include <limits.h>

32
#include "xmalloc.h"
33
34
#include "tv.h"
#include "iredges.h"
Christian Würdig's avatar
Christian Würdig committed
35
36
37
38
#include "debug.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irop_t.h"
Christian Würdig's avatar
Christian Würdig committed
39
#include "irargs_t.h"
40
#include "irprog_t.h"
41
#include "iredges_t.h"
42
#include "execfreq.h"
43
#include "error.h"
Matthias Braun's avatar
Matthias Braun committed
44
#include "raw_bitset.h"
Christian Würdig's avatar
Christian Würdig committed
45

46
#include "../besched_t.h"
Christian Würdig's avatar
Christian Würdig committed
47
#include "../benode_t.h"
Michael Beck's avatar
Michael Beck committed
48
#include "../beabi.h"
49
#include "../be_dbgout.h"
Matthias Braun's avatar
Matthias Braun committed
50
51
#include "../beemitter.h"
#include "../begnuas.h"
52
#include "../beirg_t.h"
Christian Würdig's avatar
Christian Würdig committed
53

54
#include "ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
55
#include "gen_ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
56
#include "gen_ia32_regalloc_if.h"
57
58
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
Christian Würdig's avatar
Christian Würdig committed
59
#include "ia32_map_regs.h"
Christian Würdig's avatar
Christian Würdig committed
60
#include "bearch_ia32_t.h"
Christian Würdig's avatar
Christian Würdig committed
61

62
63
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

64
#define BLOCK_PREFIX ".L"
Michael Beck's avatar
Michael Beck committed
65

Christian Würdig's avatar
Christian Würdig committed
66
67
68
#define SNPRINTF_BUF_LEN 128

/**
Christian Würdig's avatar
Christian Würdig committed
69
 * Returns the register at in position pos.
Christian Würdig's avatar
Christian Würdig committed
70
 */
71
72
73
74
75
static
const arch_register_t *get_in_reg(ia32_emit_env_t *env, const ir_node *irn,
                                  int pos)
{
	const arch_env_t       *arch_env = env->arch_env;
Christian Würdig's avatar
Christian Würdig committed
76
77
78
79
80
81
82
83
84
	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
85
	reg = arch_get_irn_register(arch_env, op);
Christian Würdig's avatar
Christian Würdig committed
86

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

89
90
91
92
93
	if(reg == &ia32_gp_regs[REG_GP_NOREG])
		panic("trying to emit noreg");

	/* in case of unknown register: just return a valid register */
	if (reg == &ia32_gp_regs[REG_GP_UKNWN]) {
Matthias Braun's avatar
Matthias Braun committed
94
		const arch_register_req_t *req;
95
96

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

Matthias Braun's avatar
Matthias Braun committed
99
		if (arch_register_req_is(req, limited)) {
100
			/* in case of limited requirements: get the first allowed register */
Matthias Braun's avatar
Matthias Braun committed
101
102
			unsigned idx = rbitset_next(req->limited, 0, 1);
			reg = arch_register_for_index(req->cls, idx);
103
		} else {
104
			/* otherwise get first register in class */
Matthias Braun's avatar
Matthias Braun committed
105
			reg = arch_register_for_index(req->cls, 0);
106
107
		}
	}
108

Christian Würdig's avatar
Christian Würdig committed
109
110
111
112
113
114
	return reg;
}

/**
 * Returns the register at out position pos.
 */
115
116
117
118
119
120
121
static
const arch_register_t *get_out_reg(ia32_emit_env_t *env, const ir_node *irn,
                                   int pos)
{
	const arch_env_t      *arch_env = env->arch_env;
	ir_node               *proj;
	const arch_register_t *reg = NULL;
Christian Würdig's avatar
Christian Würdig committed
122
123
124
125
126
127
128
129

	/* 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);
130
	} else if (is_ia32_irn(irn)) {
Christian Würdig's avatar
Christian Würdig committed
131
		reg = get_ia32_out_reg(irn, pos);
132
	} else {
Christian Würdig's avatar
Christian Würdig committed
133
134
135
136
137
138
139
140
141
142
143
144
145
		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
146
147
148
	return reg;
}

149
150
151
/**
 * Determine the gnu assembler suffix that indicates a mode
 */
152
153
static
char get_mode_suffix(const ir_mode *mode) {
154
155
156
157
158
159
160
	if(mode_is_float(mode)) {
		switch(get_mode_size_bits(mode)) {
		case 32:
			return 's';
		case 64:
			return 'l';
		case 80:
161
		case 96:
162
			return 't';
163
		}
164
	} else {
165
		assert(mode_is_int(mode) || mode_is_reference(mode));
166
167
168
169
170
171
172
173
174
		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
175
		}
176
177
178
	}
	panic("Can't output mode_suffix for %+F\n", mode);
}
Christian Würdig's avatar
Christian Würdig committed
179

180
181
static
int produces_result(const ir_node *node) {
182
183
184
185
186
187
188
	return
		!is_ia32_CmpSet(node)    &&
		!is_ia32_CondJmp(node)   &&
		!is_ia32_St(node)        &&
		!is_ia32_SwitchJmp(node) &&
		!is_ia32_TestJmp(node)   &&
		!is_ia32_xCmpSet(node)   &&
189
190
191
192
193
		!is_ia32_xCondJmp(node)  &&
		!is_ia32_CmpCMov(node)   &&
		!is_ia32_TestCMov(node)  &&
		!is_ia32_CmpSet(node)    && /* this is correct, the Cmp has no result */
		!is_ia32_TestSet(node);
194
195
}

196
197
198
static
const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode,
                                       const arch_register_t *reg) {
199
200
201
202
203
204
205
	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
206
	}
Christian Würdig's avatar
Christian Würdig committed
207
208
}

Michael Beck's avatar
Michael Beck committed
209
/**
210
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
211
 */
212
213
static
char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

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

Matthias Braun's avatar
Matthias Braun committed
230
231
232
233
234
235
236
// 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)
237
#define be_emit_tarval(env,tv)          be_emit_tarval(env->emit,tv)
Matthias Braun's avatar
Matthias Braun committed
238
239
240
#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
241

242
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
243
{
244
	const arch_register_t *reg = get_in_reg(env, node, pos);
245
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
246

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

Matthias Braun's avatar
Matthias Braun committed
249
250
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
251
252
}

Michael Beck's avatar
Michael Beck committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
{
	const arch_register_t *reg = get_in_reg(env, node, pos);
	const char *reg_name = arch_register_get_name(reg);

	assert(pos < get_irn_arity(node));

	be_emit_char(env, '%');
	be_emit_char(env, reg_name[1]);
	be_emit_char(env, 'l');
}

void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
{
	const arch_register_t *reg = get_in_reg(env, node, pos);
	const char *reg_name = arch_register_get_name(reg);

	assert(pos < get_irn_arity(node));

	be_emit_char(env, '%');
	be_emit_string(env, &reg_name[1]);
}

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

Matthias Braun's avatar
Matthias Braun committed
280
281
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
Christian Würdig's avatar
Christian Würdig committed
282
283
}

284
285
286
287
288
289
290
291
static void ia32_emit_register(ia32_emit_env_t *env, const arch_register_t *reg)
{
	const char *reg_name = arch_register_get_name(reg);

	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
}

292
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
293
{
294
	const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
295

Matthias Braun's avatar
Matthias Braun committed
296
	assert(pos < 3);
Matthias Braun's avatar
Matthias Braun committed
297
298
	be_emit_char(env, '%');
	be_emit_string(env, attr->x87[pos]->name);
299
}
Christian Würdig's avatar
Christian Würdig committed
300

301
302
303
void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
{
	tarval *tv;
304
	ir_entity *ent;
305
	ident *id;
Christian Würdig's avatar
Christian Würdig committed
306

307
308
	be_emit_char(env, '$');

309
310
311
	switch(get_ia32_immop_type(node)) {
	case ia32_ImmConst:
		tv = get_ia32_Immop_tarval(node);
312
		be_emit_tarval(env, tv);
313
		return;
314
	case ia32_ImmSymConst:
315
		ent = get_ia32_Immop_symconst(node);
Michael Beck's avatar
Michael Beck committed
316
		set_entity_backend_marked(ent, 1);
317
		id = get_entity_ld_ident(ent);
318
		be_emit_ident(env, id);
319
		return;
320
321
	case ia32_ImmNone:
		break;
Christian Würdig's avatar
Christian Würdig committed
322
	}
Christian Würdig's avatar
Christian Würdig committed
323

324
325
326
	assert(0);
	be_emit_string(env, "BAD");
	return;
327
}
Christian Würdig's avatar
Christian Würdig committed
328

Matthias Braun's avatar
Matthias Braun committed
329
330
static
void ia32_emit_mode_suffix_mode(ia32_emit_env_t *env, const ir_mode *mode)
331
{
Matthias Braun's avatar
Matthias Braun committed
332
	be_emit_char(env, get_mode_suffix(mode));
Christian Würdig's avatar
Christian Würdig committed
333
334
}

Matthias Braun's avatar
Matthias Braun committed
335
void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
336
337
{
	ir_mode *mode = get_ia32_ls_mode(node);
Matthias Braun's avatar
Matthias Braun committed
338
339
340
341
	if(mode == NULL)
		mode = mode_Iu;

	ia32_emit_mode_suffix_mode(env, mode);
342
343
}

344
345
346
347
348
349
350
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_mode(env, mode);
}

351
352
static
char get_xmm_mode_suffix(ir_mode *mode)
353
354
355
356
357
358
359
360
361
362
363
364
365
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

366
367
368
void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
369
	assert(mode != NULL);
Matthias Braun's avatar
Matthias Braun committed
370
371
	be_emit_char(env, 's');
	be_emit_char(env, get_xmm_mode_suffix(mode));
372
373
374
375
376
377
}

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
378
	be_emit_char(env, get_xmm_mode_suffix(mode));
379
380
}

381
382
383
384
385
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
386
		be_emit_char(env, 's');
387
	} else {
Matthias Braun's avatar
Matthias Braun committed
388
389
390
391
		be_emit_char(env, 'z');
	}
}

392
393
static
void ia32_emit_function_object(ia32_emit_env_t *env, const char *name)
Matthias Braun's avatar
Matthias Braun committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
{
	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;
	}
}

413
414
static
void ia32_emit_function_size(ia32_emit_env_t *env, const char *name)
Matthias Braun's avatar
Matthias Braun committed
415
416
417
418
419
420
421
422
423
424
425
426
{
	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
427
428
429
	}
}

Matthias Braun's avatar
Matthias Braun committed
430

431
432
static
void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node);
Matthias Braun's avatar
Matthias Braun committed
433

Christian Würdig's avatar
Christian Würdig committed
434
435
436
/**
 * Emits registers and/or address mode of a binary operation.
 */
437
void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) {
438
	int            right_pos;
439
	const ir_node *right_op = get_irn_n(node, 3);
Christian Würdig's avatar
Christian Würdig committed
440

441
442
443
444
445
446
	switch(get_ia32_op_type(node)) {
	case ia32_Normal:
		if(is_ia32_Immediate(right_op)) {
			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_source_register(env, node, 2);
Christian Würdig's avatar
Christian Würdig committed
447
			break;
448
449
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
450
			be_emit_cstring(env, ", ");
451
452
453
454
455
456
457
458
			ia32_emit_source_register(env, node, 2);
		} else {
			const arch_register_t *in1 = get_in_reg(env, node, 2);
			const arch_register_t *in2 = get_in_reg(env, node, 3);
			const arch_register_t *out = produces_result(node) ? get_out_reg(env, node, 0) : NULL;
			const arch_register_t *in;
			const char            *in_name;

459
			in      = out ? ((out == in2) ? in1 : in2) : in2;
460
461
462
463
			out     = out ? out : in1;
			in_name = arch_register_get_name(in);

			if (is_ia32_emit_cl(node)) {
464
				assert(in == &ia32_gp_regs[REG_ECX]);
465
				in_name = "cl";
466
			}
Christian Würdig's avatar
Christian Würdig committed
467

468
469
470
471
472
473
474
475
			be_emit_char(env, '%');
			be_emit_string(env, in_name);
			be_emit_cstring(env, ", %");
			be_emit_string(env, arch_register_get_name(out));
		}
		break;
	case ia32_AddrModeS:
		if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
476
477
			assert(!produces_result(node) &&
					"Source AM with Const must not produce result");
478
			ia32_emit_immediate(env, node);
479
480
481
482
483
484
485
486
487
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		} else if(is_ia32_Immediate(right_op)) {
			assert(!produces_result(node) &&
					"Source AM with Const must not produce result");

			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
488
		} else if (produces_result(node)) {
489
490
			ia32_emit_am(env, node);
			be_emit_cstring(env, ", ");
491
492
			ia32_emit_dest_register(env, node, 0);
		} else {
493
494
			ia32_emit_am(env, node);
			be_emit_cstring(env, ", ");
495
496
497
498
			ia32_emit_source_register(env, node, 2);
		}
		break;
	case ia32_AddrModeD:
499
		right_pos = get_irn_arity(node) >= 5 ? 3 : 2;
500
		right_op  = get_irn_n(node, right_pos);
501
502
503
504
505
506
507
508
509
510
		if(is_ia32_Immediate(right_op)) {
			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
			break;
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		} else {
511
			const arch_register_t *in1 = get_in_reg(env, node, right_pos);
512
513
			ir_mode               *mode = get_ia32_ls_mode(node);
			const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
514

515
			in_name = ia32_get_reg_name_for_mode(env, mode, in1);
516

517
			if (is_ia32_emit_cl(node)) {
518
				assert(in1 == &ia32_gp_regs[REG_ECX]);
519
				in_name = "cl";
Christian Würdig's avatar
Christian Würdig committed
520
			}
521
522
523
524
525
526
527
528
529

			be_emit_char(env, '%');
			be_emit_string(env, in_name);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		}
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
530
	}
531
532
}

533
534
535
/**
 * Emits registers and/or address mode of a binary operation.
 */
536
537
void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
538
		case ia32_Normal:
539
540
541
542
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
				// should not happen...
				assert(0);
			} else {
543
544
545
546
				const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node);
				const arch_register_t *in1      = x87_attr->x87[0];
				const arch_register_t *in2      = x87_attr->x87[1];
				const arch_register_t *out      = x87_attr->x87[2];
547
548
				const arch_register_t *in;

549
				in  = out ? ((out == in2) ? in1 : in2) : in2;
550
				out = out ? out : in1;
551

Matthias Braun's avatar
Matthias Braun committed
552
553
554
555
				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));
556
557
558
559
			}
			break;
		case ia32_AddrModeS:
		case ia32_AddrModeD:
560
			ia32_emit_am(env, node);
561
562
563
564
565
566
			break;
		default:
			assert(0 && "unsupported op type");
	}
}

567
568
569
570
571
572
573
574
575
576
void ia32_emit_am_or_dest_register(ia32_emit_env_t *env, const ir_node *node,
                                   int pos) {
	if(get_ia32_op_type(node) == ia32_Normal) {
		ia32_emit_dest_register(env, node, pos);
	} else {
		assert(get_ia32_op_type(node) == ia32_AddrModeD);
		ia32_emit_am(env, node);
	}
}

Christian Würdig's avatar
Christian Würdig committed
577
578
579
/**
 * Emits registers and/or address mode of a unary operation.
 */
580
581
582
void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node, int pos) {
	const ir_node *op;

583
	switch(get_ia32_op_type(node)) {
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
	case ia32_Normal:
		op = get_irn_n(node, pos);
		if (is_ia32_Immediate(op)) {
			emit_ia32_Immediate(env, op);
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
		} else {
			ia32_emit_source_register(env, node, pos);
		}
		break;
	case ia32_AddrModeS:
	case ia32_AddrModeD:
		ia32_emit_am(env, node);
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
600
601
602
603
	}
}

/**
604
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
605
 */
606
void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) {
607
608
609
610
611
612
	ir_entity *ent       = get_ia32_am_sc(node);
	int        offs      = get_ia32_am_offs_int(node);
	ir_node   *base      = get_irn_n(node, 0);
	int        has_base  = !is_ia32_NoReg_GP(base);
	ir_node   *index     = get_irn_n(node, 1);
	int        has_index = !is_ia32_NoReg_GP(index);
Christian Würdig's avatar
Christian Würdig committed
613

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

617
	/* emit offset */
618
619
620
	if (ent != NULL) {
		ident *id;

Michael Beck's avatar
Michael Beck committed
621
		set_entity_backend_marked(ent, 1);
622
		id = get_entity_ld_ident(ent);
623
		if (is_ia32_am_sc_sign(node))
Matthias Braun's avatar
Matthias Braun committed
624
625
			be_emit_char(env, '-');
		be_emit_ident(env, id);
Matthias Braun's avatar
Matthias Braun committed
626
627
628
629
630
631
632
633

		if(get_entity_owner(ent) == get_tls_type()) {
			if (get_entity_visibility(ent) == visibility_external_allocated) {
				be_emit_cstring(env, "@INDNTPOFF");
			} else {
				be_emit_cstring(env, "@NTPOFF");
			}
		}
Christian Würdig's avatar
Christian Würdig committed
634
635
	}

636
	if(offs != 0) {
637
		if(ent != NULL) {
Matthias Braun's avatar
Matthias Braun committed
638
			be_emit_irprintf(env->emit, "%+d", offs);
639
		} else {
Matthias Braun's avatar
Matthias Braun committed
640
			be_emit_irprintf(env->emit, "%d", offs);
641
		}
642
	}
Christian Würdig's avatar
Christian Würdig committed
643

644
	if (has_base || has_index) {
Matthias Braun's avatar
Matthias Braun committed
645
		be_emit_char(env, '(');
Christian Würdig's avatar
Christian Würdig committed
646

647
		/* emit base */
648
		if (has_base) {
649
			ia32_emit_source_register(env, node, 0);
Christian Würdig's avatar
Christian Würdig committed
650
651
		}

652
		/* emit index + scale */
653
654
		if (has_index) {
			int scale;
Matthias Braun's avatar
Matthias Braun committed
655
			be_emit_char(env, ',');
656
			ia32_emit_source_register(env, node, 1);
657

658
659
			scale = get_ia32_am_scale(node);
			if (scale > 0) {
Matthias Braun's avatar
Matthias Braun committed
660
				be_emit_irprintf(env->emit, ",%d", 1 << get_ia32_am_scale(node));
661
662
			}
		}
Matthias Braun's avatar
Matthias Braun committed
663
		be_emit_char(env, ')');
Christian Würdig's avatar
Christian Würdig committed
664
	}
665
}
Christian Würdig's avatar
Christian Würdig committed
666

Christian Würdig's avatar
Christian Würdig committed
667
668
669
670
671
672
673
674
675
676
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
677
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
678
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
679

680
681
682
683
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
684
685
	const char *name;
	pn_Cmp      num;
686
687
688
689
690
};

/*
 * positive conditions for signed compares
 */
691
692
static
const struct cmp2conditon_t cmp2condition_s[] = {
693
694
695
696
697
698
699
700
	{ 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 */
701
702
703
704
705
};

/*
 * positive conditions for unsigned compares
 */
706
707
static
const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
708
709
710
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
711
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
712
713
714
715
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
	{ NULL,              pn_Cmp_True },   /* always true */
716
717
718
719
720
};

/*
 * returns the condition code
 */
721
static
Matthias Braun's avatar
Matthias Braun committed
722
const char *get_cmp_suffix(pn_Cmp cmp_code)
723
{
724
	assert( (cmp2condition_s[cmp_code & 7].num) == (cmp_code & 7));
725
	assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7));
726

727
728
729
	if((cmp_code & ia32_pn_Cmp_Unsigned)) {
		return cmp2condition_u[cmp_code & 7].name;
	} else {
730
		return cmp2condition_s[cmp_code & 7].name;
731
	}
732
733
}

734
735
void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc)
{
Matthias Braun's avatar
Matthias Braun committed
736
	be_emit_string(env, get_cmp_suffix(pnc));
737
738
739
}


740
741
742
/**
 * Returns the target block for a control flow node.
 */
743
744
static
ir_node *get_cfop_target_block(const ir_node *irn) {
745
746
747
	return get_irn_link(irn);
}

748
749
750
/**
 * Emits a block label for the given block.
 */
751
752
753
static
void ia32_emit_block_name(ia32_emit_env_t *env, const ir_node *block)
{
Michael Beck's avatar
Michael Beck committed
754
755
756
757
758
759
760
	if (has_Block_label(block)) {
		be_emit_string(env, be_gas_label_prefix());
		be_emit_irprintf(env->emit, "%u", (unsigned)get_Block_label(block));
	} else {
		be_emit_cstring(env, BLOCK_PREFIX);
		be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block));
	}
761
762
}

Christian Würdig's avatar
Christian Würdig committed
763
/**
764
 * Emits the target label for a control flow node.
Christian Würdig's avatar
Christian Würdig committed
765
 */
766
static
767
768
void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) {
	ir_node *block = get_cfop_target_block(node);
769

770
	ia32_emit_block_name(env, block);
Christian Würdig's avatar
Christian Würdig committed
771
}
772

773
774
/** Return the next block in Block schedule */
static ir_node *next_blk_sched(const ir_node *block) {
Michael Beck's avatar
Michael Beck committed
775
	return get_irn_link(block);
776
777
}

778
779
780
/**
 * Returns the Proj with projection number proj and NOT mode_M
 */
781
782
static
ir_node *get_proj(const ir_node *node, long proj) {
783
784
785
	const ir_edge_t *edge;
	ir_node         *src;

786
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
787

788
	foreach_out_edge(node, edge) {
789
790
791
792
793
794
795
796
797
798
799
800
		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
801
802
803
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
804
805
806
static
void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode,
                    long pnc) {
807
808
809
810
811
	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
812

813
	/* get both Proj's */
814
	proj_true = get_proj(node, pn_Cond_true);
815
	assert(proj_true && "CondJmp without true Proj");
Christian Würdig's avatar
Christian Würdig committed
816

817
	proj_false = get_proj(node, pn_Cond_false);
818
819
	assert(proj_false && "CondJmp without false Proj");

820
	/* for now, the code works for scheduled and non-schedules blocks */
821
	block = get_nodes_block(node);
822
823

	/* we have a block schedule */
824
	next_block = next_blk_sched(block);
825

826
	if (get_cfop_target_block(proj_true) == next_block) {
827
		/* exchange both proj's so the second one can be omitted */
828
829
		const ir_node *t = proj_true;

830
831
832
833
		proj_true  = proj_false;
		proj_false = t;
		flipped    = 1;
		pnc        = get_negated_pnc(pnc, mode);
834
835
	}

836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
	if (mode_is_float(mode)) {
		/* Some floating point comparisons require a test of the parity flag, which
		 * indicates that the result is unordered */
		switch (pnc) {
			case pn_Cmp_Uo:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				break;

			case pn_Cmp_Leg:
				be_emit_cstring(env, "\tjnp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
			case pn_Cmp_Le:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_false);
				be_emit_finish_line_gas(env, proj_false);
				goto float_jcc;

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
			case pn_Cmp_Ne:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				goto float_jcc;

			default:
			float_jcc:
				/* The bits set by floating point compares correspond to unsigned
				 * comparisons */
				pnc |= ia32_pn_Cmp_Unsigned;
				goto emit_jcc;
		}
	} else {
emit_jcc:
		be_emit_cstring(env, "\tj");
		ia32_emit_cmp_suffix(env, pnc);
		be_emit_char(env, ' ');
880
		ia32_emit_cfop_target(env, proj_true);
Matthias Braun's avatar
Matthias Braun committed
881
		be_emit_finish_line_gas(env, proj_true);
882
883
	}

884
	/* the second Proj might be a fallthrough */
885
	if (get_cfop_target_block(proj_false) != next_block) {
Matthias Braun's avatar
Matthias Braun committed
886
		be_emit_cstring(env, "\tjmp ");
887
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
888
		be_emit_finish_line_gas(env, proj_false);
889
	} else {
890
		be_emit_cstring(env, "\t/* fallthrough to ");
891
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
892
893
		be_emit_cstring(env, " */");
		be_emit_finish_line_gas(env, proj_false);
894
	}
Christian Würdig's avatar
Christian Würdig committed
895
896
897
}

/**
Christian Würdig's avatar
Christian Würdig committed
898
 * Emits code for conditional jump.
Christian Würdig's avatar
Christian Würdig committed
899
 */
900
901
static
void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
902
903
904
	be_emit_cstring(env, "\tcmp");
	ia32_emit_mode_suffix(env, node);
	be_emit_char(env, ' ');
905
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
906
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
907

908
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
909
910
}

Christian Würdig's avatar
Christian Würdig committed
911
912
913
/**
 * Emits code for conditional jump with two variables.
 */
914
915
static
void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) {
916
	CondJmp_emitter(env, node);
Christian Würdig's avatar
Christian Würdig committed
917
918
}

919
920
921
/**
 * Emits code for conditional test and jump.
 */
922
923
static
void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
924
925
926
927
	be_emit_cstring(env, "\ttest");
	ia32_emit_mode_suffix(env, node);
	be_emit_char(env, ' ');

928
929
930
	ia32_emit_binop(env, node);
	be_emit_finish_line_gas(env, node);

931
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
932
933
934
935
936
}

/**
 * Emits code for conditional test and jump with two variables.
 */
937
938
static
void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) {
939
	TestJmp_emitter(env, node);
940
941
}

Christian Würdig's avatar
Christian Würdig committed
942
943
944
/**
 * Emits code for conditional SSE floating point jump with two variables.
 */
945
946
static
void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
947
	be_emit_cstring(env, "\tucomi");
Matthias Braun's avatar
Matthias Braun committed
948
	ia32_emit_xmm_mode_suffix(env, node);
Matthias Braun's avatar
Matthias Braun committed
949
	be_emit_char(env, ' ');
950
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
951
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
952

953
	finish_CondJmp(env, node, mode_F, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
954
955
}

Michael Beck's avatar
Michael Beck committed
956
957
958
/**
 * Emits code for conditional x87 floating point jump with two variables.
 */
959
960
static
void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) {
961
962
963
	const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node);
	const char            *reg      = x87_attr->x87[1]->name;
	long                   pnc      = get_ia32_pncode(node);
Michael Beck's avatar
Michael Beck committed
964

965
	switch (get_ia32_irn_opcode(node)) {
Michael Beck's avatar
Michael Beck committed
966
	case iro_ia32_fcomrJmp:
967
		pnc = get_inversed_pnc(pnc);
968
		reg = x87_attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
969
970
	case iro_ia32_fcomJmp:
	default:
Matthias Braun's avatar
Matthias Braun committed
971
		be_emit_cstring(env, "\tfucom ");
Michael Beck's avatar
Michael Beck committed
972
973
		break;
	case iro_ia32_fcomrpJmp:
974
		pnc = get_inversed_pnc(pnc);
975
		reg = x87_attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
976
	case iro_ia32_fcompJmp:
Matthias Braun's avatar
Matthias Braun committed
977
		be_emit_cstring(env, "\tfucomp ");
Michael Beck's avatar
Michael Beck committed
978
979
		break;
	case iro_ia32_fcomrppJmp:
980
		pnc = get_inversed_pnc(pnc);
Michael Beck's avatar
Michael Beck committed
981
	case iro_ia32_fcomppJmp:
Matthias Braun's avatar
Matthias Braun committed
982
		be_emit_cstring(env, "\tfucompp ");
Michael Beck's avatar
Michael Beck committed
983
984
985
986
		reg = "";
		break;
	}

987
	if(reg[0] != '\0') {
Matthias Braun's avatar
Matthias Braun committed
988
989
		be_emit_char(env, '%');
		be_emit_string(env, reg);
990
	}
Matthias Braun's avatar
Matthias Braun committed
991
	be_emit_finish_line_gas(env, node);
Michael Beck's avatar
Michael Beck committed
992

Matthias Braun's avatar
Matthias Braun committed
993
994
995
996
	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
997

998
	finish_CondJmp(env, node, mode_E, pnc);
Michael Beck's avatar
Michael Beck committed
999
1000
}

1001
static
Matthias Braun's avatar
Matthias Braun committed
1002
1003
void CMov_emitter(ia32_emit_env_t *env, const ir_node *node)
{
Christian Würdig's avatar
Christian Würdig committed
1004
	const arch_register_t *in1, *in2, *out;
1005
	long  pnc = get_ia32_pncode(node);
Christian Würdig's avatar
Christian Würdig committed
1006

1007
	out = arch_get_irn_register(env->arch_env, node);
Christian Würdig's avatar
Christian Würdig committed
1008

Christian Würdig's avatar
Christian Würdig committed
1009
1010
	/* we have to emit the cmp first, because the destination register */
	/* could be one of the compare registers                           */
1011
	if (is_ia32_xCmpCMov(node)) {
Matthias Braun's avatar