ia32_emitter.c 54.1 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
static char get_xmm_mode_suffix(ir_mode *mode)
298
299
300
301
302
303
304
305
306
307
308
309
310
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

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

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

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

337
static void ia32_emit_function_object(const char *name)
Matthias Braun's avatar
Matthias Braun committed
338
339
340
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
341
342
343
344
		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
345
346
		break;
	case GAS_FLAVOUR_MINGW:
347
348
349
350
		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
351
		break;
352
353
	case GAS_FLAVOUR_YASM:
		break;
Matthias Braun's avatar
Matthias Braun committed
354
355
356
357
358
	default:
		break;
	}
}

359
static void ia32_emit_function_size(const char *name)
Matthias Braun's avatar
Matthias Braun committed
360
361
362
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
363
364
365
366
367
368
		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
369
		break;
370
371
372
	case GAS_FLAVOUR_MINGW:
	case GAS_FLAVOUR_YASM:
		break;
Matthias Braun's avatar
Matthias Braun committed
373
374
	default:
		break;
Christian Würdig's avatar
Christian Würdig committed
375
376
377
	}
}

Matthias Braun's avatar
Matthias Braun committed
378

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

Christian Würdig's avatar
Christian Würdig committed
391
392
393
/**
 * Emits registers and/or address mode of a binary operation.
 */
394
void ia32_emit_binop(const ir_node *node) {
395
396
397
	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
398

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

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

448
				in  = out ? ((out == in2) ? in1 : in2) : in2;
449
				out = out ? out : in1;
450

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

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

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

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

500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
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
517
/**
518
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
519
 */
520
void ia32_emit_am(const ir_node *node) {
521
522
523
524
525
526
	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
527

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

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

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

546
	if (has_base || has_index) {
547
		be_emit_char('(');
Christian Würdig's avatar
Christian Würdig committed
548

549
		/* emit base */
550
		if (has_base) {
551
552
			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
553
554
		}

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

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

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

Matthias Braun's avatar
Matthias Braun committed
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
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
596
597
598
599
600
601
602
603
604
605
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
606
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
607
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
608

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

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

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

645
646
647
648
649
650
651
652
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
653
 */
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
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;
			}
674
		} else if(is_ia32_Store(node)) {
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
			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)
695
{
696
697
698
699
700
701
	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);
702
703
		if(!(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
				|| is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp))) {
704
705
			cmp = find_original_value(cmp);
			assert(is_ia32_FucomFnstsw(cmp) || is_ia32_FucompFnstsw(cmp)
706
			       || is_ia32_FucomppFnstsw(cmp) || is_ia32_FtstFnstsw(cmp));
707
		}
708

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

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

727
		if(flags_attr->data.ins_permuted)
728
729
730
			pnc = get_mirrored_pnc(pnc);
		if(flags_attr->data.cmp_unsigned)
			pnc |= ia32_pn_Cmp_unsigned;
731
	}
732
733

	return pnc;
734
735
}

736
static void ia32_emit_cmp_suffix(int pnc)
737
{
738
739
740
741
742
743
744
745
746
747
748
749
	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;
	}

750
	be_emit_string(str);
751
752
}

753
void ia32_emit_cmp_suffix_node(const ir_node *node,
754
755
                               int flags_pos)
{
756
757
	const ia32_attr_t *attr = get_ia32_attr_const(node);

Michael Beck's avatar
Michael Beck committed
758
	pn_Cmp pnc = get_ia32_condcode(node);
759
760

	pnc = determine_final_pnc(node, flags_pos, pnc);
761
762
763
764
765
766
767
768
	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);
		}
	}

769
	ia32_emit_cmp_suffix(pnc);
770
}
771

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

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

Christian Würdig's avatar
Christian Würdig committed
793
/**
794
 * Emits the target label for a control flow node.
Christian Würdig's avatar
Christian Würdig committed
795
 */
796
797
static void ia32_emit_cfop_target(const ir_node *node)
{
798
	ir_node *block = get_cfop_target_block(node);
799

800
	ia32_emit_block_name(block);
Christian Würdig's avatar
Christian Würdig committed
801
}
802

803
/** Return the next block in Block schedule */
804
805
static ir_node *next_blk_sched(const ir_node *block)
{
Michael Beck's avatar
Michael Beck committed
806
	return get_irn_link(block);
807
808
}

809
810
811
/**
 * Returns the Proj with projection number proj and NOT mode_M
 */
812
static ir_node *get_proj(const ir_node *node, long proj) {
813
814
815
	const ir_edge_t *edge;
	ir_node         *src;

816
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
817

818
	foreach_out_edge(node, edge) {
819
820
821
822
823
824
825
826
827
828
829
830
		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
831
832
833
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
834
static void emit_ia32_Jcc(const ir_node *node)
835
{
836
	int            need_parity_label = 0;
837
838
839
840
	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
841
	pn_Cmp         pnc = get_ia32_condcode(node);
Christian Würdig's avatar
Christian Würdig committed
842

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

845
846
847
	/* get both Projs */
	proj_true = get_proj(node, pn_ia32_Jcc_true);
	assert(proj_true && "Jcc without true Proj");
848

849
850
	proj_false = get_proj(node, pn_ia32_Jcc_false);
	assert(proj_false && "Jcc without false Proj");
851

852
	block      = get_nodes_block(node);
853
	next_block = next_blk_sched(block);
854

855
	if (get_cfop_target_block(proj_true) == next_block) {
856
		/* exchange both proj's so the second one can be omitted */
857
858
		const ir_node *t = proj_true;

859
860
		proj_true  = proj_false;
		proj_false = t;
861
862
863
864
865
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
866
867
	}

868
869
870
871
	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) {
872
			case pn_Cmp_Uo: {
873
874
875
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
876
				break;
877
			}
878
879

			case pn_Cmp_Leg:
880
881
882
				be_emit_cstring("\tjnp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
883
884
885
886
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
887
888
889
890
891
892
893
894
895
896
			case pn_Cmp_Le:
				/* we need a local label if the false proj is a fallthrough
				 * as the falseblock might have no label emitted then */
				if (get_cfop_target_block(proj_false) == next_block) {
					need_parity_label = 1;
					be_emit_cstring("\tjp 1f");
				} else {
					be_emit_cstring("\tjp ");
					ia32_emit_cfop_target(proj_false);
				}
897
				be_emit_finish_line_gas(proj_false);
898
				goto emit_jcc;
899
900
901

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
902
			case pn_Cmp_Ne:
903
904
905
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
906
				goto emit_jcc;
907
908
909
910
911
912

			default:
				goto emit_jcc;
		}
	} else {
emit_jcc:
913
914
915
916
917
		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);
918
919
	}

920
921
922
923
924
	if(need_parity_label) {
		be_emit_cstring("1:");
		be_emit_write_line();
	}

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

938
static void emit_ia32_CMov(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
939
{
940
941
942
	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
943
	pn_Cmp                 pnc          = get_ia32_condcode(node);
944
945
946
947
948
	const arch_register_t *in_true;
	const arch_register_t *in_false;

	pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);

949
	in_true  = arch_get_irn_register(arch_env,
950
	                                 get_irn_n(node, n_ia32_CMov_val_true));
951
	in_false = arch_get_irn_register(arch_env,
952
953
954
955
956
957
958
959
	                                 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;

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

		ins_permuted = !ins_permuted;
963
964
965
966

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

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

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

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

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

/* jump table entry (target and corresponding number) */