ia32_emitter.c 53.2 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"
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
354
355
356
357
358
		break;
	default:
		break;
	}
}

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

Matthias Braun's avatar
Matthias Braun committed
376

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

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

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

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

446
				in  = out ? ((out == in2) ? in1 : in2) : in2;
447
				out = out ? out : in1;
448

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

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

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

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

/**
499
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
500
 */
501
void ia32_emit_am(const ir_node *node) {
502
503
504
505
506
507
	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
508

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

512
	/* emit offset */
513
514
515
	if (ent != NULL) {
		ident *id;

Michael Beck's avatar
Michael Beck committed
516
		set_entity_backend_marked(ent, 1);
517
		id = get_entity_ld_ident(ent);
518
		if (is_ia32_am_sc_sign(node))
519
520
			be_emit_char('-');
		be_emit_ident(id);
Matthias Braun's avatar
Matthias Braun committed
521
522
523

		if(get_entity_owner(ent) == get_tls_type()) {
			if (get_entity_visibility(ent) == visibility_external_allocated) {
524
				be_emit_cstring("@INDNTPOFF");
Matthias Braun's avatar
Matthias Braun committed
525
			} else {
526
				be_emit_cstring("@NTPOFF");
Matthias Braun's avatar
Matthias Braun committed
527
528
			}
		}
Christian Würdig's avatar
Christian Würdig committed
529
530
	}

531
	if(offs != 0) {
532
		if(ent != NULL) {
533
			be_emit_irprintf("%+d", offs);
534
		} else {
535
			be_emit_irprintf("%d", offs);
536
		}
537
	}
Christian Würdig's avatar
Christian Würdig committed
538

539
	if (has_base || has_index) {
540
		be_emit_char('(');
Christian Würdig's avatar
Christian Würdig committed
541

542
		/* emit base */
543
		if (has_base) {
544
545
			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
546
547
		}

548
		/* emit index + scale */
549
		if (has_index) {
550
			const arch_register_t *reg = get_in_reg(node, n_ia32_index);
551
			int scale;
552
553
			be_emit_char(',');
			emit_register(reg, NULL);
554

555
556
			scale = get_ia32_am_scale(node);
			if (scale > 0) {
557
				be_emit_irprintf(",%d", 1 << get_ia32_am_scale(node));
558
559
			}
		}
560
		be_emit_char(')');
Christian Würdig's avatar
Christian Würdig committed
561
	}
562
563
564

	/* special case if nothing is set */
	if(ent == NULL && offs == 0 && !has_base && !has_index) {
565
		be_emit_char('0');
566
	}
567
}
Christian Würdig's avatar
Christian Würdig committed
568

Matthias Braun's avatar
Matthias Braun committed
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
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
589
590
591
592
593
594
595
596
597
598
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
599
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
600
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
601

602
603
604
605
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
606
	const char *name;
607
	int         num;
608
609
610
611
612
};

/*
 * positive conditions for signed compares
 */
613
static const struct cmp2conditon_t cmp2condition_s[] = {
614
615
616
617
618
619
620
	{ 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 },     /* != */
621
	{ NULL,              pn_Cmp_Leg},     /* always true */
622
623
624
625
626
};

/*
 * positive conditions for unsigned compares
 */
627
static const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
628
629
630
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
631
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
632
633
634
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
635
	{ NULL,              pn_Cmp_Leg },   /* always true  */
636
637
};

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

702
		flags_attr = get_ia32_attr_const(cmp);
703
		if(flags_attr->data.ins_permuted)
704
705
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
Matthias Braun's avatar
Matthias Braun committed
706
707
	} else if(is_ia32_Ucomi(flags) || is_ia32_Fucomi(flags)
			|| is_ia32_Fucompi(flags)) {
708
709
		flags_attr = get_ia32_attr_const(flags);

710
		if(flags_attr->data.ins_permuted)
711
712
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
713
	} else {
714
#if 0
715
716
		assert(is_ia32_Cmp(flags) || is_ia32_Test(flags)
				|| is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
717
#endif
718
719
		flags_attr = get_ia32_attr_const(flags);

720
		if(flags_attr->data.ins_permuted)
721
722
723
			pnc = get_mirrored_pnc(pnc);
		if(flags_attr->data.cmp_unsigned)
			pnc |= ia32_pn_Cmp_unsigned;
724
	}
725
726

	return pnc;
727
728
}

729
static void ia32_emit_cmp_suffix(int pnc)
730
{
731
732
733
734
735
736
737
738
739
740
741
742
	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;
	}

743
	be_emit_string(str);
744
745
}

746
void ia32_emit_cmp_suffix_node(const ir_node *node,
747
748
                               int flags_pos)
{
749
750
	const ia32_attr_t *attr = get_ia32_attr_const(node);

Michael Beck's avatar
Michael Beck committed
751
	pn_Cmp pnc = get_ia32_condcode(node);
752
753

	pnc = determine_final_pnc(node, flags_pos, pnc);
754
755
756
757
758
759
760
761
	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);
		}
	}

762
	ia32_emit_cmp_suffix(pnc);
763
}
764

765
766
767
/**
 * Returns the target block for a control flow node.
 */
768
769
static
ir_node *get_cfop_target_block(const ir_node *irn) {
770
771
772
	return get_irn_link(irn);
}

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

Christian Würdig's avatar
Christian Würdig committed
788
/**
789
 * Emits the target label for a control flow node.
Christian Würdig's avatar
Christian Würdig committed
790
 */
791
792
static void ia32_emit_cfop_target(const ir_node *node)
{
793
	ir_node *block = get_cfop_target_block(node);
794

795
	ia32_emit_block_name(block);
Christian Würdig's avatar
Christian Würdig committed
796
}
797

798
/** Return the next block in Block schedule */
799
800
static ir_node *next_blk_sched(const ir_node *block)
{
Michael Beck's avatar
Michael Beck committed
801
	return get_irn_link(block);
802
803
}

804
805
806
/**
 * Returns the Proj with projection number proj and NOT mode_M
 */
807
static ir_node *get_proj(const ir_node *node, long proj) {
808
809
810
	const ir_edge_t *edge;
	ir_node         *src;

811
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
812

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

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

839
840
841
	/* get both Projs */
	proj_true = get_proj(node, pn_ia32_Jcc_true);
	assert(proj_true && "Jcc without true Proj");
842

843
844
	proj_false = get_proj(node, pn_ia32_Jcc_false);
	assert(proj_false && "Jcc without false Proj");
845

846
	block      = get_nodes_block(node);
847
	next_block = next_blk_sched(block);
848

849
	if (get_cfop_target_block(proj_true) == next_block) {
850
		/* exchange both proj's so the second one can be omitted */
851
852
		const ir_node *t = proj_true;

853
854
		proj_true  = proj_false;
		proj_false = t;
855
856
857
858
859
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
860
861
	}

862
863
864
865
	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) {
866
			case pn_Cmp_Uo:
867
868
869
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
870
871
872
				break;

			case pn_Cmp_Leg:
873
874
875
				be_emit_cstring("\tjnp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
876
877
878
879
880
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
			case pn_Cmp_Le:
881
882
883
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_false);
				be_emit_finish_line_gas(proj_false);
884
				goto emit_jcc;
885
886
887
888

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
			case pn_Cmp_Ne:
889
890
891
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
892
				goto emit_jcc;
893
894
895
896
897
898

			default:
				goto emit_jcc;
		}
	} else {
emit_jcc:
899
900
901
902
903
		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);
904
905
	}

906
	/* the second Proj might be a fallthrough */
907
	if (get_cfop_target_block(proj_false) != next_block) {
908
909
910
		be_emit_cstring("\tjmp ");
		ia32_emit_cfop_target(proj_false);
		be_emit_finish_line_gas(proj_false);
911
	} else {
912
913
914
915
		be_emit_cstring("\t/* fallthrough to ");
		ia32_emit_cfop_target(proj_false);
		be_emit_cstring(" */");
		be_emit_finish_line_gas(proj_false);
916
	}
Michael Beck's avatar
Michael Beck committed
917
918
}

919
static void emit_ia32_CMov(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
920
{
921
922
923
	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
924
	pn_Cmp                 pnc          = get_ia32_condcode(node);
925
926
927
928
929
	const arch_register_t *in_true;
	const arch_register_t *in_false;

	pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);

930
	in_true  = arch_get_irn_register(arch_env,
931
	                                 get_irn_n(node, n_ia32_CMov_val_true));
932
	in_false = arch_get_irn_register(arch_env,
933
934
935
936
937
938
939
940
	                                 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;

941
942
943
		assert(get_ia32_op_type(node) == ia32_Normal);

		ins_permuted = !ins_permuted;
944
945
946
947

		tmp      = in_true;
		in_true  = in_false;
		in_false = tmp;
948
	} else {
949
		/* we need a mov */
950
951
952
953
954
		be_emit_cstring("\tmovl ");
		emit_register(in_false, NULL);
		be_emit_cstring(", ");
		emit_register(out, NULL);
		be_emit_finish_line_gas(node);
955
	}
956

957
958
959
960
961
962
963
964
	if(ins_permuted) {
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
	}

965
966
	/* TODO: handling of Nans isn't correct yet */

967
968
969
	be_emit_cstring("\tcmov");
	ia32_emit_cmp_suffix(pnc);
	be_emit_char(' ');
970
	if(get_ia32_op_type(node) == ia32_AddrModeS) {
971
		ia32_emit_am(node);
972
	} else {
973
		emit_register(in_true, get_ia32_ls_mode(node));
974
	}
975
976
977
	be_emit_cstring(", ");
	emit_register(out, get_ia32_ls_mode(node));
	be_emit_finish_line_gas(node);
978
979
}

Christian Würdig's avatar
Christian Würdig committed
980
981
982
983
984
985
986
987
988
989
990
991
/*********************************************************
 *                 _ _       _
 *                (_) |     (_)
 *   ___ _ __ ___  _| |_     _ _   _ _ __ ___  _ __  ___
 *  / _ \ '_ ` _ \| | __|   | | | | | '_ ` _ \| '_ \/ __|
 * |  __/ | | | | | | |_    | | |_| | | | | | | |_) \__ \
 *  \___|_| |_| |_|_|\__|   | |\__,_|_| |_| |_| .__/|___/
 *                         _/ |               | |
 *                        |__/                |_|
 *********************************************************/

/* jump table entry (target and corresponding number) */
Christian Würdig's avatar
Christian Würdig committed
992
993
994
995
996
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

Christian Würdig's avatar
Christian Würdig committed
997
/* jump table for switch generation */
Christian Würdig's avatar
Christian Würdig committed
998
typedef struct _jmp_tbl_t {
Christian Würdig's avatar
Christian Würdig committed
999
	ir_node  *defProj;         /**< default target */
Matthias Braun's avatar
Matthias Braun committed
1000
1001
1002
	long      min_value;       /**< smallest switch case */
	long      max_value;       /**< largest switch case */
	long      num_branches;    /**< number of jumps */
Christian Würdig's avatar
Christian Würdig committed
1003
1004
	char     *label;           /**< label of the jump table */
	branch_t *branches;        /**< jump array */