ia32_emitter.c 54.6 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"
54
#include "../be_dbgout.h"
Christian Würdig's avatar
Christian Würdig committed
55

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

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

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

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

71
72
73
static const arch_env_t *arch_env;
static const ia32_isa_t *isa;
static ia32_code_gen_t  *cg;
74
75
static int               do_pic;
static char              pic_base_label[128];
76
static ir_label_t        exc_label_id;
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/** Return the next block in Block schedule */
static ir_node *get_prev_block_sched(const ir_node *block)
{
	return get_irn_link(block);
}

static bool is_fallthrough(const ir_node *cfgpred)
{
	ir_node *pred;

	if(!is_Proj(cfgpred))
		return true;
	pred = get_Proj_pred(cfgpred);
	if(is_ia32_SwitchJmp(pred))
		return false;

	return true;
}

static bool block_needs_label(const ir_node *block)
{
	bool need_label = true;
	int  n_cfgpreds = get_Block_n_cfgpreds(block);

	if (n_cfgpreds == 0) {
		need_label = false;
	} else if (n_cfgpreds == 1) {
		ir_node *cfgpred            = get_Block_cfgpred(block, 0);
		ir_node *cfgpred_block      = get_nodes_block(cfgpred);

		if (get_prev_block_sched(block) == cfgpred_block
				&& is_fallthrough(cfgpred)) {
			need_label = false;
		}
	}

	return need_label;
}

Christian Würdig's avatar
Christian Würdig committed
117
/**
Christian Würdig's avatar
Christian Würdig committed
118
 * Returns the register at in position pos.
Christian Würdig's avatar
Christian Würdig committed
119
 */
120
static const arch_register_t *get_in_reg(const ir_node *irn, int pos)
121
{
122
123
	ir_node               *op;
	const arch_register_t *reg = NULL;
Christian Würdig's avatar
Christian Würdig committed
124
125
126
127
128
129
130

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

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

135
	if(reg == &ia32_gp_regs[REG_GP_NOREG])
136
		panic("trying to emit noreg for %+F input %d", irn, pos);
137
138
139

	/* 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
140
		const arch_register_req_t *req;
141
142

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

Matthias Braun's avatar
Matthias Braun committed
145
		if (arch_register_req_is(req, limited)) {
146
			/* in case of limited requirements: get the first allowed register */
Matthias Braun's avatar
Matthias Braun committed
147
148
			unsigned idx = rbitset_next(req->limited, 0, 1);
			reg = arch_register_for_index(req->cls, idx);
149
		} else {
150
			/* otherwise get first register in class */
Matthias Braun's avatar
Matthias Braun committed
151
			reg = arch_register_for_index(req->cls, 0);
152
153
		}
	}
154

Christian Würdig's avatar
Christian Würdig committed
155
156
157
158
159
160
	return reg;
}

/**
 * Returns the register at out position pos.
 */
161
static const arch_register_t *get_out_reg(const ir_node *irn, int pos)
162
163
164
{
	ir_node               *proj;
	const arch_register_t *reg = NULL;
Christian Würdig's avatar
Christian Würdig committed
165
166
167
168
169
170
171

	/* 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) {
172
		assert(pos == 0);
Christian Würdig's avatar
Christian Würdig committed
173
		reg = arch_get_irn_register(arch_env, irn);
174
	} else if (is_ia32_irn(irn)) {
Christian Würdig's avatar
Christian Würdig committed
175
		reg = get_ia32_out_reg(irn, pos);
176
	} else {
Christian Würdig's avatar
Christian Würdig committed
177
178
179
180
181
182
183
184
185
186
187
188
189
		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
190
191
192
	return reg;
}

Michael Beck's avatar
Michael Beck committed
193
/**
194
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
195
 */
196
197
static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
{
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

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

214
215
static void emit_8bit_register(const arch_register_t *reg)
{
216
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
217

218
219
220
221
222
223
224
225
	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
226

227
228
	be_emit_char('%');
	be_emit_string(reg_name);
229
230
}

231
232
233
234
235
236
237
238
239
240
241
242
243
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 {
244
			assert(mode_is_float(mode) || size == 32);
245
246
247
248
		}
	}

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

250
251
	be_emit_char('%');
	be_emit_string(reg_name);
Christian Würdig's avatar
Christian Würdig committed
252
253
}

254
void ia32_emit_source_register(const ir_node *node, int pos)
255
{
256
	const arch_register_t *reg      = get_in_reg(node, pos);
257

258
	emit_register(reg, NULL);
259
260
}

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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
291
{
292
	const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
293

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

Matthias Braun's avatar
Matthias Braun committed
299
static void ia32_emit_mode_suffix_mode(const ir_mode *mode)
300
{
Matthias Braun's avatar
Matthias Braun committed
301
302
303
304
	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;
305
306
		case 80:
		case 96: be_emit_char('t'); return;
Matthias Braun's avatar
Matthias Braun committed
307
308
309
310
311
312
313
314
315
316
317
318
319
		}
	} 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
320
321
}

322
void ia32_emit_mode_suffix(const ir_node *node)
323
324
{
	ir_mode *mode = get_ia32_ls_mode(node);
Matthias Braun's avatar
Matthias Braun committed
325
326
327
	if(mode == NULL)
		mode = mode_Iu;

328
	ia32_emit_mode_suffix_mode(mode);
329
330
}

331
void ia32_emit_x87_mode_suffix(const ir_node *node)
332
{
333
	/* we only need to emit the mode on address mode */
334
335
336
	if(get_ia32_op_type(node) != ia32_Normal) {
		ir_mode *mode = get_ia32_ls_mode(node);
		assert(mode != NULL);
337
		ia32_emit_mode_suffix_mode(mode);
338
	}
339
340
}

341
static char get_xmm_mode_suffix(ir_mode *mode)
342
343
344
345
346
347
348
349
350
351
352
353
354
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

355
void ia32_emit_xmm_mode_suffix(const ir_node *node)
356
357
{
	ir_mode *mode = get_ia32_ls_mode(node);
358
	assert(mode != NULL);
359
360
	be_emit_char('s');
	be_emit_char(get_xmm_mode_suffix(mode));
361
362
}

363
void ia32_emit_xmm_mode_suffix_s(const ir_node *node)
364
365
366
{
	ir_mode *mode = get_ia32_ls_mode(node);
	assert(mode != NULL);
367
	be_emit_char(get_xmm_mode_suffix(mode));
368
369
}

370
void ia32_emit_extend_suffix(const ir_mode *mode)
371
372
373
374
{
	if(get_mode_size_bits(mode) == 32)
		return;
	if(mode_is_signed(mode)) {
375
		be_emit_char('s');
376
	} else {
377
		be_emit_char('z');
Matthias Braun's avatar
Matthias Braun committed
378
379
380
	}
}

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

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

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

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

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

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

Christian Würdig's avatar
Christian Würdig committed
468
469
470
/**
 * Emits registers and/or address mode of a unary operation.
 */
471
void ia32_emit_unop(const ir_node *node, int pos) {
472
473
	const ir_node *op;

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

492
static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust)
493
494
495
496
497
498
499
{
	ident *id;

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

500
	if (get_entity_owner(entity) == get_tls_type()) {
501
502
503
504
505
506
		if (get_entity_visibility(entity) == visibility_external_allocated) {
			be_emit_cstring("@INDNTPOFF");
		} else {
			be_emit_cstring("@NTPOFF");
		}
	}
507
508
509
510
511
512

	if (!no_pic_adjust && do_pic) {
		/* TODO: only do this when necessary */
		be_emit_char('-');
		be_emit_string(pic_base_label);
	}
513
514
}

Christian Würdig's avatar
Christian Würdig committed
515
/**
516
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
517
 */
518
void ia32_emit_am(const ir_node *node) {
519
520
521
522
523
524
	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
525

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

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

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

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

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

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

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

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

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

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

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

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

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

643
644
645
/**
 * 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
static ir_node *get_cfop_target_block(const ir_node *irn) {
769
	assert(get_irn_mode(irn) == mode_X);
770
771
772
	return get_irn_link(irn);
}

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

787
788
789
790
791
792
/**
 * Emits an exception label for a given node.
 */
static void ia32_emit_exc_label(const ir_node *node)
{
	be_emit_string(be_gas_insn_label_prefix());
793
	be_emit_irprintf("%lu", get_ia32_exc_label_id(node));
794
795
}

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

803
	ia32_emit_block_name(block);
Christian Würdig's avatar
Christian Würdig committed
804
}
805

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

813
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
814

815
	foreach_out_edge(node, edge) {
816
817
818
819
820
821
822
823
824
825
826
827
		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;
}

828
829
830
831
832
833
834
static bool can_be_fallthrough(const ir_node *node)
{
	ir_node *target_block = get_cfop_target_block(node);
	ir_node *block        = get_nodes_block(node);
	return get_prev_block_sched(target_block) == block;
}

Christian Würdig's avatar
Christian Würdig committed
835
836
837
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
838
static void emit_ia32_Jcc(const ir_node *node)
839
{
840
	int            need_parity_label = 0;
841
842
843
	const ir_node *proj_true;
	const ir_node *proj_false;
	const ir_node *block;
Michael Beck's avatar
Michael Beck committed
844
	pn_Cmp         pnc = get_ia32_condcode(node);
Christian Würdig's avatar
Christian Würdig committed
845

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

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

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

855
	block      = get_nodes_block(node);
856

857
	if (can_be_fallthrough(proj_true)) {
858
		/* exchange both proj's so the second one can be omitted */
859
860
		const ir_node *t = proj_true;

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

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

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

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
889
890
891
			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 */
Michael Beck's avatar
Michael Beck committed
892
				if (can_be_fallthrough(proj_false)) {
893
894
895
896
897
898
					need_parity_label = 1;
					be_emit_cstring("\tjp 1f");
				} else {
					be_emit_cstring("\tjp ");
					ia32_emit_cfop_target(proj_false);
				}
899
				be_emit_finish_line_gas(proj_false);
900
				goto emit_jcc;
901
902
903

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

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

922
923
924
925
926
	if(need_parity_label) {
		be_emit_cstring("1:");
		be_emit_write_line();
	}

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

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

	pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);

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

962
963
964
		assert(get_ia32_op_type(node) == ia32_Normal);

		ins_permuted = !ins_permuted;
965
966
967
968

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

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

986
987
	/* TODO: handling of Nans isn't correct yet */

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

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

/* jump table entry (target and corresponding number) */
Christian Würdig's avatar
Christian Würdig committed
1013
1014
1015
1016
1017
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

Christian Würdig's avatar
Christian Würdig committed
1018
/* jump table for switch generation */
Christian Würdig's avatar
Christian Würdig committed
1019
typedef struct _jmp_tbl_t {
Christian Würdig's avatar
Christian Würdig committed
1020