ia32_emitter.c 54 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * 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"
45
#include "dbginfo.h"
Christian Würdig's avatar
Christian Würdig committed
46

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

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

64
65
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

66
#define BLOCK_PREFIX ".L"
Michael Beck's avatar
Michael Beck committed
67

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

70
71
72
73
static const arch_env_t *arch_env;
static const ia32_isa_t *isa;
static ia32_code_gen_t  *cg;

Christian Würdig's avatar
Christian Würdig committed
74
/**
Christian Würdig's avatar
Christian Würdig committed
75
 * Returns the register at in position pos.
Christian Würdig's avatar
Christian Würdig committed
76
 */
77
static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
78
{
79
80
	ir_node               *op;
	const arch_register_t *reg = NULL;
Christian Würdig's avatar
Christian Würdig committed
81
82
83
84
85
86
87

	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
88
	reg = arch_get_irn_register(arch_env, op);
Christian Würdig's avatar
Christian Würdig committed
89

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

92
	if(reg == &ia32_gp_regs[REG_GP_NOREG])
93
		panic("trying to emit noreg for %+F input %d", irn, pos);
94
95
96

	/* 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
97
		const arch_register_req_t *req;
98
99

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

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

Christian Würdig's avatar
Christian Würdig committed
112
113
114
115
116
117
	return reg;
}

/**
 * Returns the register at out position pos.
 */
118
static const arch_register_t *get_out_reg(const ir_node *irn, int pos)
119
120
121
{
	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

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

Michael Beck's avatar
Michael Beck committed
150
/**
151
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
152
 */
153
154
static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
{
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

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

171
172
static void emit_8bit_register(const arch_register_t *reg)
{
173
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
174

175
176
177
178
179
180
181
182
	be_emit_char('%');
	be_emit_char(reg_name[1]);
	be_emit_char('l');
}

static void emit_16bit_register(const arch_register_t *reg)
{
	const char *reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
Christian Würdig's avatar
Christian Würdig committed
183

184
185
	be_emit_char('%');
	be_emit_string(reg_name);
186
187
}

188
189
190
191
192
193
194
195
196
197
198
199
200
static void emit_register(const arch_register_t *reg, const ir_mode *mode)
{
	const char *reg_name;

	if(mode != NULL) {
		int size = get_mode_size_bits(mode);
		if(size == 8) {
			emit_8bit_register(reg);
			return;
		} else if(size == 16) {
			emit_16bit_register(reg);
			return;
		} else {
201
			assert(mode_is_float(mode) || size == 32);
202
203
204
205
		}
	}

	reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
206

207
208
	be_emit_char('%');
	be_emit_string(reg_name);
Christian Würdig's avatar
Christian Würdig committed
209
210
}

211
void ia32_emit_source_register(const ir_node *node, int pos)
212
{
213
	const arch_register_t *reg      = get_in_reg(node, pos);
214

215
	emit_register(reg, NULL);
216
217
}

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
static void emit_ia32_Immediate(const ir_node *node);

void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
{
	const arch_register_t *reg;
	ir_node               *in = get_irn_n(node, pos);
	if(is_ia32_Immediate(in)) {
		emit_ia32_Immediate(in);
		return;
	}

	reg = get_in_reg(node, pos);
	emit_8bit_register(reg);
}

void ia32_emit_dest_register(const ir_node *node, int pos)
{
	const arch_register_t *reg  = get_out_reg(node, pos);

	emit_register(reg, NULL);
}

void ia32_emit_8bit_dest_register(const ir_node *node, int pos)
{
	const arch_register_t *reg  = get_out_reg(node, pos);

	emit_register(reg, mode_Bu);
}

void ia32_emit_x87_register(const ir_node *node, int pos)
Christian Würdig's avatar
Christian Würdig committed
248
{
249
	const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
250

Matthias Braun's avatar
Matthias Braun committed
251
	assert(pos < 3);
252
253
	be_emit_char('%');
	be_emit_string(attr->x87[pos]->name);
254
}
Christian Würdig's avatar
Christian Würdig committed
255

Matthias Braun's avatar
Matthias Braun committed
256
static void ia32_emit_mode_suffix_mode(const ir_mode *mode)
257
{
Matthias Braun's avatar
Matthias Braun committed
258
259
260
261
	if(mode_is_float(mode)) {
		switch(get_mode_size_bits(mode)) {
		case 32: be_emit_char('s'); return;
		case 64: be_emit_char('l'); return;
262
263
		case 80:
		case 96: be_emit_char('t'); return;
Matthias Braun's avatar
Matthias Braun committed
264
265
266
267
268
269
270
271
272
273
274
275
276
		}
	} else {
		assert(mode_is_int(mode) || mode_is_reference(mode));
		switch(get_mode_size_bits(mode)) {
		case 64: be_emit_cstring("ll"); return;
				 /* gas docu says q is the suffix but gcc, objdump and icc use
				 	ll apparently */
		case 32: be_emit_char('l'); return;
		case 16: be_emit_char('w'); return;
		case 8:  be_emit_char('b'); return;
		}
	}
	panic("Can't output mode_suffix for %+F\n", mode);
Christian Würdig's avatar
Christian Würdig committed
277
278
}

279
void ia32_emit_mode_suffix(const ir_node *node)
280
281
{
	ir_mode *mode = get_ia32_ls_mode(node);
Matthias Braun's avatar
Matthias Braun committed
282
283
284
	if(mode == NULL)
		mode = mode_Iu;

285
	ia32_emit_mode_suffix_mode(mode);
286
287
}

288
void ia32_emit_x87_mode_suffix(const ir_node *node)
289
290
{
	ir_mode *mode = get_ia32_ls_mode(node);
291
292
293
	assert(mode != NULL);
	/* we only need to emit the mode on address mode */
	if(get_ia32_op_type(node) != ia32_Normal)
294
		ia32_emit_mode_suffix_mode(mode);
295
296
}

297
298
static
char get_xmm_mode_suffix(ir_mode *mode)
299
300
301
302
303
304
305
306
307
308
309
310
311
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

312
void ia32_emit_xmm_mode_suffix(const ir_node *node)
313
314
{
	ir_mode *mode = get_ia32_ls_mode(node);
315
	assert(mode != NULL);
316
317
	be_emit_char('s');
	be_emit_char(get_xmm_mode_suffix(mode));
318
319
}

320
void ia32_emit_xmm_mode_suffix_s(const ir_node *node)
321
322
323
{
	ir_mode *mode = get_ia32_ls_mode(node);
	assert(mode != NULL);
324
	be_emit_char(get_xmm_mode_suffix(mode));
325
326
}

327
void ia32_emit_extend_suffix(const ir_mode *mode)
328
329
330
331
{
	if(get_mode_size_bits(mode) == 32)
		return;
	if(mode_is_signed(mode)) {
332
		be_emit_char('s');
333
	} else {
334
		be_emit_char('z');
Matthias Braun's avatar
Matthias Braun committed
335
336
337
	}
}

338
static
339
void ia32_emit_function_object(const char *name)
Matthias Braun's avatar
Matthias Braun committed
340
341
342
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
343
344
345
346
		be_emit_cstring("\t.type\t");
		be_emit_string(name);
		be_emit_cstring(", @function\n");
		be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
347
348
		break;
	case GAS_FLAVOUR_MINGW:
349
350
351
352
		be_emit_cstring("\t.def\t");
		be_emit_string(name);
		be_emit_cstring(";\t.scl\t2;\t.type\t32;\t.endef\n");
		be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
353
		break;
354
355
	case GAS_FLAVOUR_YASM:
		break;
Matthias Braun's avatar
Matthias Braun committed
356
357
358
359
360
	default:
		break;
	}
}

361
static
362
void ia32_emit_function_size(const char *name)
Matthias Braun's avatar
Matthias Braun committed
363
364
365
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
366
367
368
369
370
371
		be_emit_cstring("\t.size\t");
		be_emit_string(name);
		be_emit_cstring(", .-");
		be_emit_string(name);
		be_emit_char('\n');
		be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
372
		break;
373
374
375
	case GAS_FLAVOUR_MINGW:
	case GAS_FLAVOUR_YASM:
		break;
Matthias Braun's avatar
Matthias Braun committed
376
377
	default:
		break;
Christian Würdig's avatar
Christian Würdig committed
378
379
380
	}
}

Matthias Braun's avatar
Matthias Braun committed
381

382
void ia32_emit_source_register_or_immediate(const ir_node *node, int pos)
383
384
385
{
	ir_node *in = get_irn_n(node, pos);
	if(is_ia32_Immediate(in)) {
386
		emit_ia32_Immediate(in);
387
	} else {
388
389
390
		const ir_mode         *mode = get_ia32_ls_mode(node);
		const arch_register_t *reg  = get_in_reg(node, pos);
		emit_register(reg, mode);
391
392
393
	}
}

Christian Würdig's avatar
Christian Würdig committed
394
395
396
/**
 * Emits registers and/or address mode of a binary operation.
 */
397
void ia32_emit_binop(const ir_node *node) {
398
399
400
	const ir_node         *right_op  = get_irn_n(node, n_ia32_binary_right);
	const ir_mode         *mode      = get_ia32_ls_mode(node);
	const arch_register_t *reg_left;
Christian Würdig's avatar
Christian Würdig committed
401

402
403
	switch(get_ia32_op_type(node)) {
	case ia32_Normal:
404
		reg_left = get_in_reg(node, n_ia32_binary_left);
405
		if(is_ia32_Immediate(right_op)) {
406
407
408
			emit_ia32_Immediate(right_op);
			be_emit_cstring(", ");
			emit_register(reg_left, mode);
Christian Würdig's avatar
Christian Würdig committed
409
			break;
410
		} else {
411
412
413
414
415
			const arch_register_t *reg_right
				= get_in_reg(node, n_ia32_binary_right);
			emit_register(reg_right, mode);
			be_emit_cstring(", ");
			emit_register(reg_left, mode);
416
417
418
		}
		break;
	case ia32_AddrModeS:
419
		if(is_ia32_Immediate(right_op)) {
420
421
422
			emit_ia32_Immediate(right_op);
			be_emit_cstring(", ");
			ia32_emit_am(node);
423
		} else {
424
425
426
427
			reg_left = get_in_reg(node, n_ia32_binary_left);
			ia32_emit_am(node);
			be_emit_cstring(", ");
			emit_register(reg_left, mode);
428
429
430
		}
		break;
	case ia32_AddrModeD:
431
		panic("DestMode can't be output by %%binop anymore");
432
433
434
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
435
	}
436
437
}

438
439
440
/**
 * Emits registers and/or address mode of a binary operation.
 */
441
void ia32_emit_x87_binop(const ir_node *node) {
442
	switch(get_ia32_op_type(node)) {
443
		case ia32_Normal:
444
			{
445
446
447
448
				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];
449
450
				const arch_register_t *in;

451
				in  = out ? ((out == in2) ? in1 : in2) : in2;
452
				out = out ? out : in1;
453

454
455
456
457
				be_emit_char('%');
				be_emit_string(arch_register_get_name(in));
				be_emit_cstring(", %");
				be_emit_string(arch_register_get_name(out));
458
459
460
			}
			break;
		case ia32_AddrModeS:
461
			ia32_emit_am(node);
462
			break;
463
		case ia32_AddrModeD:
464
465
466
467
468
		default:
			assert(0 && "unsupported op type");
	}
}

469
void ia32_emit_am_or_dest_register(const ir_node *node,
470
471
                                   int pos) {
	if(get_ia32_op_type(node) == ia32_Normal) {
472
		ia32_emit_dest_register(node, pos);
473
474
	} else {
		assert(get_ia32_op_type(node) == ia32_AddrModeD);
475
		ia32_emit_am(node);
476
477
478
	}
}

Christian Würdig's avatar
Christian Würdig committed
479
480
481
/**
 * Emits registers and/or address mode of a unary operation.
 */
482
void ia32_emit_unop(const ir_node *node, int pos) {
483
484
	const ir_node *op;

485
	switch(get_ia32_op_type(node)) {
486
487
488
	case ia32_Normal:
		op = get_irn_n(node, pos);
		if (is_ia32_Immediate(op)) {
489
			emit_ia32_Immediate(op);
490
		} else {
491
			ia32_emit_source_register(node, pos);
492
493
494
495
		}
		break;
	case ia32_AddrModeS:
	case ia32_AddrModeD:
496
		ia32_emit_am(node);
497
498
499
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
500
501
502
	}
}

503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
static void ia32_emit_entity(ir_entity *entity)
{
	ident *id;

	set_entity_backend_marked(entity, 1);
	id = get_entity_ld_ident(entity);
	be_emit_ident(id);

	if(get_entity_owner(entity) == get_tls_type()) {
		if (get_entity_visibility(entity) == visibility_external_allocated) {
			be_emit_cstring("@INDNTPOFF");
		} else {
			be_emit_cstring("@NTPOFF");
		}
	}
}

Christian Würdig's avatar
Christian Würdig committed
520
/**
521
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
522
 */
523
void ia32_emit_am(const ir_node *node) {
524
525
526
527
528
529
	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
530

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

534
	/* emit offset */
535
	if (ent != NULL) {
536
		if (is_ia32_am_sc_sign(node))
537
			be_emit_char('-');
538
		ia32_emit_entity(ent);
Christian Würdig's avatar
Christian Würdig committed
539
540
	}

541
	if(offs != 0) {
542
		if(ent != NULL) {
543
			be_emit_irprintf("%+d", offs);
544
		} else {
545
			be_emit_irprintf("%d", offs);
546
		}
547
	}
Christian Würdig's avatar
Christian Würdig committed
548

549
	if (has_base || has_index) {
550
		be_emit_char('(');
Christian Würdig's avatar
Christian Würdig committed
551

552
		/* emit base */
553
		if (has_base) {
554
555
			const arch_register_t *reg = get_in_reg(node, n_ia32_base);
			emit_register(reg, NULL);
Christian Würdig's avatar
Christian Würdig committed
556
557
		}

558
		/* emit index + scale */
559
		if (has_index) {
560
			const arch_register_t *reg = get_in_reg(node, n_ia32_index);
561
			int scale;
562
563
			be_emit_char(',');
			emit_register(reg, NULL);
564

565
566
			scale = get_ia32_am_scale(node);
			if (scale > 0) {
567
				be_emit_irprintf(",%d", 1 << get_ia32_am_scale(node));
568
569
			}
		}
570
		be_emit_char(')');
Christian Würdig's avatar
Christian Würdig committed
571
	}
572
573
574

	/* special case if nothing is set */
	if(ent == NULL && offs == 0 && !has_base && !has_index) {
575
		be_emit_char('0');
576
	}
577
}
Christian Würdig's avatar
Christian Würdig committed
578

Matthias Braun's avatar
Matthias Braun committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
static void emit_ia32_IMul(const ir_node *node)
{
	ir_node               *left    = get_irn_n(node, n_ia32_IMul_left);
	const arch_register_t *out_reg = get_out_reg(node, pn_ia32_IMul_res);

	be_emit_cstring("\timul");
	ia32_emit_mode_suffix(node);
	be_emit_char(' ');

	ia32_emit_binop(node);

	/* do we need the 3-address form? */
	if(is_ia32_NoReg_GP(left) ||
			get_in_reg(node, n_ia32_IMul_left) != out_reg) {
		be_emit_cstring(", ");
		emit_register(out_reg, get_ia32_ls_mode(node));
	}
	be_emit_finish_line_gas(node);
}

Christian Würdig's avatar
Christian Würdig committed
599
600
601
602
603
604
605
606
607
608
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
609
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
610
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
611

612
613
614
615
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
616
	const char *name;
617
	int         num;
618
619
620
621
622
};

/*
 * positive conditions for signed compares
 */
623
static const struct cmp2conditon_t cmp2condition_s[] = {
624
625
626
627
628
629
630
	{ 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 },     /* != */
631
	{ NULL,              pn_Cmp_Leg},     /* always true */
632
633
634
635
636
};

/*
 * positive conditions for unsigned compares
 */
637
static const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
638
639
640
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
641
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
642
643
644
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
645
	{ NULL,              pn_Cmp_Leg },   /* always true  */
646
647
};

648
649
650
651
652
653
654
655
enum {
	ia32_pn_Cmp_unsigned = 0x1000,
	ia32_pn_Cmp_float    = 0x2000,
};

/**
 * walks up a tree of copies/perms/spills/reloads to find the original value
 * that is moved around
656
 */
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
static ir_node *find_original_value(ir_node *node)
{
	inc_irg_visited(current_ir_graph);
	while(1) {
		mark_irn_visited(node);
		if(be_is_Copy(node)) {
			node = be_get_Copy_op(node);
		} else if(be_is_CopyKeep(node)) {
			node = be_get_CopyKeep_op(node);
		} else if(is_Proj(node)) {
			ir_node *pred = get_Proj_pred(node);
			if(be_is_Perm(pred)) {
				node = get_irn_n(pred, get_Proj_proj(node));
			} else if(be_is_MemPerm(pred)) {
				node = get_irn_n(pred, get_Proj_proj(node) + 1);
			} else if(is_ia32_Load(pred)) {
				node = get_irn_n(pred, n_ia32_Load_mem);
			} else {
				return node;
			}
677
		} else if(is_ia32_Store(node)) {
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
			node = get_irn_n(node, n_ia32_Store_val);
		} else if(is_Phi(node)) {
			int i, arity;
			arity = get_irn_arity(node);
			for(i = 0; i < arity; ++i) {
				ir_node *in = get_irn_n(node, i);
				if(irn_visited(in))
					continue;
				node = in;
				break;
			}
			assert(i < arity);
		} else {
			return node;
		}
	}
}

static int determine_final_pnc(const ir_node *node, int flags_pos,
                               int pnc)
698
{
699
700
701
702
703
704
	ir_node           *flags = get_irn_n(node, flags_pos);
	const ia32_attr_t *flags_attr;
	flags = skip_Proj(flags);

	if(is_ia32_Sahf(flags)) {
		ir_node *cmp = get_irn_n(flags, n_ia32_Sahf_val);
705
706
		if(!(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
				|| is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp))) {
707
708
			cmp = find_original_value(cmp);
			assert(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
709
			       || is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp));
710
		}
711

712
		flags_attr = get_ia32_attr_const(cmp);
713
		if(flags_attr->data.ins_permuted)
714
715
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
Matthias Braun's avatar
Matthias Braun committed
716
717
	} else if(is_ia32_Ucomi(flags) || is_ia32_Fucomi(flags)
			|| is_ia32_Fucompi(flags)) {
718
719
		flags_attr = get_ia32_attr_const(flags);

720
		if(flags_attr->data.ins_permuted)
721
722
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
723
	} else {
724
#if 0
725
726
		assert(is_ia32_Cmp(flags) || is_ia32_Test(flags)
				|| is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
727
#endif
728
729
		flags_attr = get_ia32_attr_const(flags);

730
		if(flags_attr->data.ins_permuted)
731
732
733
			pnc = get_mirrored_pnc(pnc);
		if(flags_attr->data.cmp_unsigned)
			pnc |= ia32_pn_Cmp_unsigned;
734
	}
735
736

	return pnc;
737
738
}

739
static void ia32_emit_cmp_suffix(int pnc)
740
{
741
742
743
744
745
746
747
748
749
750
751
752
	const char        *str;

	if((pnc & ia32_pn_Cmp_float) || (pnc & ia32_pn_Cmp_unsigned)) {
		pnc = pnc & 7;
		assert(cmp2condition_u[pnc].num == pnc);
		str = cmp2condition_u[pnc].name;
	} else {
		pnc = pnc & 7;
		assert(cmp2condition_s[pnc].num == pnc);
		str = cmp2condition_s[pnc].name;
	}

753
	be_emit_string(str);
754
755
}

756
void ia32_emit_cmp_suffix_node(const ir_node *node,
757
758
                               int flags_pos)
{
759
760
	const ia32_attr_t *attr = get_ia32_attr_const(node);

Michael Beck's avatar
Michael Beck committed
761
	pn_Cmp pnc = get_ia32_condcode(node);
762
763

	pnc = determine_final_pnc(node, flags_pos, pnc);
764
765
766
767
768
769
770
771
	if(attr->data.ins_permuted) {
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
	}

772
	ia32_emit_cmp_suffix(pnc);
773
}
774

775
776
777
/**
 * Returns the target block for a control flow node.
 */
778
779
static
ir_node *get_cfop_target_block(const ir_node *irn) {
780
781
782
	return get_irn_link(irn);
}

783
784
785
/**
 * Emits a block label for the given block.
 */
786
static
787
void ia32_emit_block_name(const ir_node *block)
788
{
Michael Beck's avatar
Michael Beck committed
789
	if (has_Block_label(block)) {
790
791
		be_emit_string(be_gas_label_prefix());
		be_emit_irprintf("%u", (unsigned)get_Block_label(block));
Michael Beck's avatar
Michael Beck committed
792
	} else {
793
794
		be_emit_cstring(BLOCK_PREFIX);
		be_emit_irprintf("%d", get_irn_node_nr(block));
Michael Beck's avatar
Michael Beck committed
795
	}
796
797
}

Christian Würdig's avatar
Christian Würdig committed
798
/**
799
 * Emits the target label for a control flow node.
Christian Würdig's avatar
Christian Würdig committed
800
 */
801
802
static void ia32_emit_cfop_target(const ir_node *node)
{
803
	ir_node *block = get_cfop_target_block(node);
804

805
	ia32_emit_block_name(block);
Christian Würdig's avatar
Christian Würdig committed
806
}
807

808
/** Return the next block in Block schedule */
809
810
static ir_node *next_blk_sched(const ir_node *block)
{
Michael Beck's avatar
Michael Beck committed
811
	return get_irn_link(block);
812
813
}

814
815
816
/**
 * Returns the Proj with projection number proj and NOT mode_M
 */
817
static ir_node *get_proj(const ir_node *node, long proj) {
818
819
820
	const ir_edge_t *edge;
	ir_node         *src;

821
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
822

823
	foreach_out_edge(node, edge) {
824
825
826
827
828
829
830
831
832
833
834
835
		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
836
837
838
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
839
static void emit_ia32_Jcc(const ir_node *node)
840
{
841
842
843
844
	const ir_node *proj_true;
	const ir_node *proj_false;
	const ir_node *block;
	const ir_node *next_block;
Michael Beck's avatar
Michael Beck committed
845
	pn_Cmp         pnc = get_ia32_condcode(node);
Christian Würdig's avatar
Christian Würdig committed
846

847
	pnc = determine_final_pnc(node, 0, pnc);
Christian Würdig's avatar
Christian Würdig committed
848

849
850
851
	/* get both Projs */
	proj_true = get_proj(node, pn_ia32_Jcc_true);
	assert(proj_true && "Jcc without true Proj");
852

853
854
	proj_false = get_proj(node, pn_ia32_Jcc_false);
	assert(proj_false && "Jcc without false Proj");
855

856
	block      = get_nodes_block(node);
857
	next_block = next_blk_sched(block);
858

859
	if (get_cfop_target_block(proj_true) == next_block) {
860
		/* exchange both proj's so the second one can be omitted */
861
862
		const ir_node *t = proj_true;

863
864
		proj_true  = proj_false;
		proj_false = t;
865
866
867
868
869
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
870
871
	}

872
873
874
875
	if (pnc & ia32_pn_Cmp_float) {
		/* Some floating point comparisons require a test of the parity flag,
		 * which indicates that the result is unordered */
		switch (pnc & 15) {
876
			case pn_Cmp_Uo:
877
878
879
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
880
881
882
				break;

			case pn_Cmp_Leg:
883
884
885
				be_emit_cstring("\tjnp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
886
887
888
889
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
890
891
892
893
			case pn_Cmp_Le: {
				ir_node *dest_block = get_cfop_target_block(proj_false);
				mark_Block_block_visited(dest_block);

894
895
896
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_false);
				be_emit_finish_line_gas(proj_false);
897
				goto emit_jcc;
898
			}
899
900
901

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
902
903
904
905
			case pn_Cmp_Ne: {
				ir_node *dest_block = get_cfop_target_block(proj_false);
				mark_Block_block_visited(dest_block);

906
907
908
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
909
				goto emit_jcc;
910
			}
911
912
913
914
915
916

			default:
				goto emit_jcc;
		}
	} else {
emit_jcc:
917
918
919
920
921
		be_emit_cstring("\tj");
		ia32_emit_cmp_suffix(pnc);
		be_emit_char(' ');
		ia32_emit_cfop_target(proj_true);
		be_emit_finish_line_gas(proj_true);
922
923
	}

924
	/* the second Proj might be a fallthrough */
925
	if (get_cfop_target_block(proj_false) != next_block) {
926
927
928
		be_emit_cstring("\tjmp ");
		ia32_emit_cfop_target(proj_false);
		be_emit_finish_line_gas(proj_false);
929
	} else {
930
931
932
933
		be_emit_cstring("\t/* fallthrough to ");
		ia32_emit_cfop_target(proj_false);
		be_emit_cstring(" */");
		be_emit_finish_line_gas(proj_false);
934
	}
Michael Beck's avatar
Michael Beck committed
935
936
}

937
static void emit_ia32_CMov(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
938
{
939
940
941
	const ia32_attr_t     *attr         = get_ia32_attr_const(node);
	int                    ins_permuted = attr->data.ins_permuted;
	const arch_register_t *out          = arch_get_irn_register(arch_env, node);
Michael Beck's avatar
Michael Beck committed
942
	pn_Cmp                 pnc          = get_ia32_condcode(node);
943
944
945
946
947
	const arch_register_t *in_true;
	const arch_register_t *in_false;

	pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);

948
	in_true  = arch_get_irn_register(arch_env,
949
	                                 get_irn_n(node, n_ia32_CMov_val_true));
950
	in_false = arch_get_irn_register(arch_env,
951
952
953
954
955
956
957
958
	                                 get_irn_n(node, n_ia32_CMov_val_false));

	/* should be same constraint fullfilled? */
	if(out == in_false) {
		/* yes -> nothing to do */
	} else if(out == in_true) {
		const arch_register_t *tmp;

959
960
961
		assert(get_ia32_op_type(node) == ia32_Normal);

		ins_permuted = !ins_permuted;
962
963
964
965

		tmp      = in_true;
		in_true  = in_false;
		in_false = tmp;
966
	} else {
967
		/* we need a mov */
968
969
970
971
972
		be_emit_cstring("\tmovl ");
		emit_register(in_false, NULL);
		be_emit_cstring(", ");
		emit_register(out, NULL);
		be_emit_finish_line_gas(node);
973
	}
974

975
976
977
978
979
980
981
982
	if(ins_permuted) {
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
	}

983
984
	/* TODO: handling of Nans isn't correct yet */

985
986
987
	be_emit_cstring("\tcmov");
	ia32_emit_cmp_suffix(pnc);
	be_emit_char(' ');
988
	if(get_ia32_op_type(node) == ia32_AddrModeS) {
989
		ia32_emit_am(node);
990
	} else {
991
		emit_register(in_true, get_ia32_ls_mode(node));
992
	}
993
994
995
	be_emit_cstring(", ");
	emit_register(out, get_ia32_ls_mode(node));
	be_emit_finish_line_gas(node);
996
997
}

Christian Würdig's avatar
Christian Würdig committed
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
/*********************************************************
 *                 _ _       _
 *                (_) |     (_)
 *   ___ _ __ ___  _| |_     _ _   _ _ __ ___  _ __  ___
 *  / _ \ '_ ` _ \| | __|   | | | | | '_ ` _ \| '_ \/ __|
 * |  __/ | | | | | | |_    | | |_| | | | | | | |_) \__ \
 *  \___|_| |_| |_|_|\__|   | |\__,_|_| |_| |_| .__/|___/
 *                         _/ |               | |
 *                        |__/                |_|
 *********************************************************/