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

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

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

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

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

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

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

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

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

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

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

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

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

	/* 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
95
		const arch_register_req_t *req;
96
97

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

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

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

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

	/* 1st case: irn is not of mode_T, so it has only                 */
	/*           one OUT register -> good                             */
	/* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
	/*           Proj with the corresponding projnum for the register */

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

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

Michael Beck's avatar
Michael Beck committed
178
/**
179
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
180
 */
181
182
static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
{
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

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

199
200
static void emit_8bit_register(const arch_register_t *reg)
{
201
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
202

203
204
205
206
207
208
209
210
	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
211

212
213
	be_emit_char('%');
	be_emit_string(reg_name);
214
215
}

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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 {
			assert(size == 32);
		}
	}

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

235
236
	be_emit_char('%');
	be_emit_string(reg_name);
Christian Würdig's avatar
Christian Würdig committed
237
238
}

239
void ia32_emit_source_register(const ir_node *node, int pos)
240
{
241
	const arch_register_t *reg      = get_in_reg(node, pos);
242

243
	emit_register(reg, NULL);
244
245
}

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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
276
{
277
	const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
278

Matthias Braun's avatar
Matthias Braun committed
279
	assert(pos < 3);
280
281
	be_emit_char('%');
	be_emit_string(attr->x87[pos]->name);
282
}
Christian Würdig's avatar
Christian Würdig committed
283

Matthias Braun's avatar
Matthias Braun committed
284
static
285
void ia32_emit_mode_suffix_mode(const ir_mode *mode)
286
{
287
	be_emit_char(get_mode_suffix(mode));
Christian Würdig's avatar
Christian Würdig committed
288
289
}

290
void ia32_emit_mode_suffix(const ir_node *node)
291
292
{
	ir_mode *mode = get_ia32_ls_mode(node);
Matthias Braun's avatar
Matthias Braun committed
293
294
295
	if(mode == NULL)
		mode = mode_Iu;

296
	ia32_emit_mode_suffix_mode(mode);
297
298
}

299
void ia32_emit_x87_mode_suffix(const ir_node *node)
300
301
302
{
	ir_mode *mode = get_ia32_ls_mode(node);
	if(mode != NULL)
303
		ia32_emit_mode_suffix_mode(mode);
304
305
}

306
307
static
char get_xmm_mode_suffix(ir_mode *mode)
308
309
310
311
312
313
314
315
316
317
318
319
320
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

321
void ia32_emit_xmm_mode_suffix(const ir_node *node)
322
323
{
	ir_mode *mode = get_ia32_ls_mode(node);
324
	assert(mode != NULL);
325
326
	be_emit_char('s');
	be_emit_char(get_xmm_mode_suffix(mode));
327
328
}

329
void ia32_emit_xmm_mode_suffix_s(const ir_node *node)
330
331
332
{
	ir_mode *mode = get_ia32_ls_mode(node);
	assert(mode != NULL);
333
	be_emit_char(get_xmm_mode_suffix(mode));
334
335
}

336
void ia32_emit_extend_suffix(const ir_mode *mode)
337
338
339
340
{
	if(get_mode_size_bits(mode) == 32)
		return;
	if(mode_is_signed(mode)) {
341
		be_emit_char('s');
342
	} else {
343
		be_emit_char('z');
Matthias Braun's avatar
Matthias Braun committed
344
345
346
	}
}

347
static
348
void ia32_emit_function_object(const char *name)
Matthias Braun's avatar
Matthias Braun committed
349
350
351
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
352
353
354
355
		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
356
357
		break;
	case GAS_FLAVOUR_MINGW:
358
359
360
361
		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
362
363
364
365
366
367
		break;
	default:
		break;
	}
}

368
static
369
void ia32_emit_function_size(const char *name)
Matthias Braun's avatar
Matthias Braun committed
370
371
372
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
373
374
375
376
377
378
		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
379
380
381
		break;
	default:
		break;
Christian Würdig's avatar
Christian Würdig committed
382
383
384
	}
}

Matthias Braun's avatar
Matthias Braun committed
385

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

Christian Würdig's avatar
Christian Würdig committed
398
399
400
/**
 * Emits registers and/or address mode of a binary operation.
 */
401
402
403
404
void ia32_emit_binop(const ir_node *node, int produces_result) {
	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
405

406
407
	switch(get_ia32_op_type(node)) {
	case ia32_Normal:
408
		reg_left = get_in_reg(node, n_ia32_binary_left);
409
		if(is_ia32_Immediate(right_op)) {
410
411
412
			emit_ia32_Immediate(right_op);
			be_emit_cstring(", ");
			emit_register(reg_left, mode);
Christian Würdig's avatar
Christian Würdig committed
413
			break;
414
		} else {
415
416
417
418
419
			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);
420
421
422
		}
		break;
	case ia32_AddrModeS:
423
		if(is_ia32_Immediate(right_op)) {
424
			assert(!produces_result && "Source AM with Const must not produce result");
425

426
427
428
			emit_ia32_Immediate(right_op);
			be_emit_cstring(", ");
			ia32_emit_am(node);
429
		} else {
430
431
432
433
			reg_left = get_in_reg(node, n_ia32_binary_left);
			ia32_emit_am(node);
			be_emit_cstring(", ");
			emit_register(reg_left, mode);
434
435
436
		}
		break;
	case ia32_AddrModeD:
437
		panic("DestMode can't be output by %%binop anymore");
438
439
440
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
441
	}
442
443
}

444
445
446
/**
 * Emits registers and/or address mode of a binary operation.
 */
447
void ia32_emit_x87_binop(const ir_node *node) {
448
	switch(get_ia32_op_type(node)) {
449
		case ia32_Normal:
450
			{
451
452
453
454
				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];
455
456
				const arch_register_t *in;

457
				in  = out ? ((out == in2) ? in1 : in2) : in2;
458
				out = out ? out : in1;
459

460
461
462
463
				be_emit_char('%');
				be_emit_string(arch_register_get_name(in));
				be_emit_cstring(", %");
				be_emit_string(arch_register_get_name(out));
464
465
466
			}
			break;
		case ia32_AddrModeS:
467
			ia32_emit_am(node);
468
			break;
469
		case ia32_AddrModeD:
470
471
472
473
474
		default:
			assert(0 && "unsupported op type");
	}
}

475
void ia32_emit_am_or_dest_register(const ir_node *node,
476
477
                                   int pos) {
	if(get_ia32_op_type(node) == ia32_Normal) {
478
		ia32_emit_dest_register(node, pos);
479
480
	} else {
		assert(get_ia32_op_type(node) == ia32_AddrModeD);
481
		ia32_emit_am(node);
482
483
484
	}
}

Christian Würdig's avatar
Christian Würdig committed
485
486
487
/**
 * Emits registers and/or address mode of a unary operation.
 */
488
void ia32_emit_unop(const ir_node *node, int pos) {
489
490
	const ir_node *op;

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

/**
510
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
511
 */
512
void ia32_emit_am(const ir_node *node) {
513
514
515
516
517
518
	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
519

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

523
	/* emit offset */
524
525
526
	if (ent != NULL) {
		ident *id;

Michael Beck's avatar
Michael Beck committed
527
		set_entity_backend_marked(ent, 1);
528
		id = get_entity_ld_ident(ent);
529
		if (is_ia32_am_sc_sign(node))
530
531
			be_emit_char('-');
		be_emit_ident(id);
Matthias Braun's avatar
Matthias Braun committed
532
533
534

		if(get_entity_owner(ent) == get_tls_type()) {
			if (get_entity_visibility(ent) == visibility_external_allocated) {
535
				be_emit_cstring("@INDNTPOFF");
Matthias Braun's avatar
Matthias Braun committed
536
			} else {
537
				be_emit_cstring("@NTPOFF");
Matthias Braun's avatar
Matthias Braun committed
538
539
			}
		}
Christian Würdig's avatar
Christian Würdig committed
540
541
	}

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

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

553
		/* emit base */
554
		if (has_base) {
555
556
			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
557
558
		}

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

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

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

Christian Würdig's avatar
Christian Würdig committed
580
581
582
583
584
585
586
587
588
589
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
590
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
591
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
592

593
594
595
596
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
597
	const char *name;
598
	int         num;
599
600
601
602
603
};

/*
 * positive conditions for signed compares
 */
604
static const struct cmp2conditon_t cmp2condition_s[] = {
605
606
607
608
609
610
611
	{ 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 },     /* != */
612
	{ NULL,              pn_Cmp_Leg},     /* always true */
613
614
615
616
617
};

/*
 * positive conditions for unsigned compares
 */
618
static const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
619
620
621
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
622
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
623
624
625
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
626
	{ NULL,              pn_Cmp_Leg },   /* always true  */
627
628
};

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

693
694
695
696
697
698
699
700
701
702
		flags_attr = get_ia32_attr_const(cmp);
		if(flags_attr->data.cmp_flipped)
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
	} else if(is_ia32_Ucomi(flags)) {
		flags_attr = get_ia32_attr_const(flags);

		if(flags_attr->data.cmp_flipped)
			pnc = get_mirrored_pnc(pnc);
		pnc |= ia32_pn_Cmp_float;
703
	} else {
704
705
706
707
708
709
710
711
		assert(is_ia32_Cmp(flags) || is_ia32_Test(flags)
				|| is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
		flags_attr = get_ia32_attr_const(flags);

		if(flags_attr->data.cmp_flipped)
			pnc = get_mirrored_pnc(pnc);
		if(flags_attr->data.cmp_unsigned)
			pnc |= ia32_pn_Cmp_unsigned;
712
	}
713
714

	return pnc;
715
716
}

717
static void ia32_emit_cmp_suffix(int pnc)
718
{
719
720
721
722
723
724
725
726
727
728
729
730
	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;
	}

731
	be_emit_string(str);
732
733
}

734
void ia32_emit_cmp_suffix_node(const ir_node *node,
735
736
737
738
739
                               int flags_pos)
{
	pn_Cmp pnc = get_ia32_pncode(node);

	pnc = determine_final_pnc(node, flags_pos, pnc);
740
	ia32_emit_cmp_suffix(pnc);
741
}
742

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

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

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

773
	ia32_emit_block_name(block);
Christian Würdig's avatar
Christian Würdig committed
774
}
775

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

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

789
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
790

791
	foreach_out_edge(node, edge) {
792
793
794
795
796
797
798
799
800
801
802
803
		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
804
805
806
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
807
static void emit_ia32_Jcc(const ir_node *node)
808
{
809
810
811
812
	const ir_node *proj_true;
	const ir_node *proj_false;
	const ir_node *block;
	const ir_node *next_block;
813
	pn_Cmp         pnc = get_ia32_pncode(node);
Christian Würdig's avatar
Christian Würdig committed
814

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

817
818
819
	/* get both Projs */
	proj_true = get_proj(node, pn_ia32_Jcc_true);
	assert(proj_true && "Jcc without true Proj");
820

821
822
	proj_false = get_proj(node, pn_ia32_Jcc_false);
	assert(proj_false && "Jcc without false Proj");
823

824
	block      = get_nodes_block(node);
825
	next_block = next_blk_sched(block);
826

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

831
832
		proj_true  = proj_false;
		proj_false = t;
833
834
835
836
837
		if(pnc & ia32_pn_Cmp_float) {
			pnc = get_negated_pnc(pnc, mode_F);
		} else {
			pnc = get_negated_pnc(pnc, mode_Iu);
		}
838
839
	}

840
841
842
843
	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) {
844
			case pn_Cmp_Uo:
845
846
847
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
848
849
850
				break;

			case pn_Cmp_Leg:
851
852
853
				be_emit_cstring("\tjnp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
854
855
856
857
858
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
			case pn_Cmp_Le:
859
860
861
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_false);
				be_emit_finish_line_gas(proj_false);
862
				goto emit_jcc;
863
864
865
866

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
			case pn_Cmp_Ne:
867
868
869
				be_emit_cstring("\tjp ");
				ia32_emit_cfop_target(proj_true);
				be_emit_finish_line_gas(proj_true);
870
				goto emit_jcc;
871
872
873
874
875
876

			default:
				goto emit_jcc;
		}
	} else {
emit_jcc:
877
878
879
880
881
		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);
882
883
	}

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

897
static void emit_ia32_CMov(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
898
{
899
	const arch_register_t *out = arch_get_irn_register(arch_env, node);
900
901
902
903
904
905
	const arch_register_t *in_true;
	const arch_register_t *in_false;
	pn_Cmp                 pnc = get_ia32_pncode(node);

	pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc);

906
	in_true  = arch_get_irn_register(arch_env,
907
	                                 get_irn_n(node, n_ia32_CMov_val_true));
908
	in_false = arch_get_irn_register(arch_env,
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	                                 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;

		/* swap left/right and negate pnc */
		pnc = get_negated_pnc(pnc, mode_Iu);

		tmp      = in_true;
		in_true  = in_false;
		in_false = tmp;
923
	} else {
924
		/* we need a mov */
925
926
927
928
929
		be_emit_cstring("\tmovl ");
		emit_register(in_false, NULL);
		be_emit_cstring(", ");
		emit_register(out, NULL);
		be_emit_finish_line_gas(node);
930
	}
931

932
933
934
	be_emit_cstring("\tcmov");
	ia32_emit_cmp_suffix(pnc);
	be_emit_char(' ');
935
	if(get_ia32_op_type(node) == ia32_AddrModeS) {
936
		ia32_emit_am(node);
937
	} else {
938
		emit_register(in_true, get_ia32_ls_mode(node));
939
	}
940
941
942
	be_emit_cstring(", ");
	emit_register(out, get_ia32_ls_mode(node));
	be_emit_finish_line_gas(node);
943
944
}

Christian Würdig's avatar
Christian Würdig committed
945
946
947
948
949
950
951
952
953
954
955
956
/*********************************************************
 *                 _ _       _
 *                (_) |     (_)
 *   ___ _ __ ___  _| |_     _ _   _ _ __ ___  _ __  ___
 *  / _ \ '_ ` _ \| | __|   | | | | | '_ ` _ \| '_ \/ __|
 * |  __/ | | | | | | |_    | | |_| | | | | | | |_) \__ \
 *  \___|_| |_| |_|_|\__|   | |\__,_|_| |_| |_| .__/|___/
 *                         _/ |               | |
 *                        |__/                |_|
 *********************************************************/

/* jump table entry (target and corresponding number) */
Christian Würdig's avatar
Christian Würdig committed
957
958
959
960
961
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

Christian Würdig's avatar
Christian Würdig committed
962
/* jump table for switch generation */
Christian Würdig's avatar
Christian Würdig committed
963
typedef struct _jmp_tbl_t {
Christian Würdig's avatar
Christian Würdig committed
964
	ir_node  *defProj;         /**< default target */
Matthias Braun's avatar
Matthias Braun committed
965
966
967
	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
968
969
	char     *label;           /**< label of the jump table */
	branch_t *branches;        /**< jump array */
Christian Würdig's avatar
Christian Würdig committed
970
971
} jmp_tbl_t;

Christian Würdig's avatar
Christian Würdig committed
972
973
974
/**
 * Compare two variables of type branch_t. Used to sort all switch cases
 */
975
976
static
int ia32_cmp_branch_t(const void *a, const void *b) {
Christian Würdig's avatar
Christian Würdig committed
977
978
979
980
981
982
983
984
985
986
987
988
989
990
	branch_t *b1 = (branch_t *)a;
	branch_t *b2 = (branch_t *)b;

	if (b1->value <= b2->value)
		return -1;
	else
		return 1;
}

/**
 * Emits code for a SwitchJmp (creates a jump table if
 * possible otherwise a cmp-jmp cascade). Port from
 * cggg ia32 backend
 */
991
static
992
void emit_ia32_SwitchJmp(const ir_node *node) {
Christian Würdig's avatar
Christian Würdig committed
993
	unsigned long       interval;
994
995
	int                 last_value, i;
	long                pnc;
Christian Würdig's avatar
Christian Würdig committed
996
997
998
999
1000
	jmp_tbl_t           tbl;
	ir_node            *proj;
	const ir_edge_t    *edge;

	/* fill the table structure */
1001
	tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
1002
	tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, ".TBL_");
Christian Würdig's avatar
Christian Würdig committed
1003
	tbl.defProj      = NULL;
1004
	tbl.num_branches = get_irn_n_edges(node);
1005
	tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
Christian Würdig's avatar
Christian Würdig committed
1006
1007
1008
1009
1010
	tbl.min_value    = INT_MAX;
	tbl.max_value    = INT_MIN;

	i = 0;
	/* go over all proj's and collect them */
1011
	foreach_out_edge(node, edge) {
Christian Würdig's avatar
Christian Würdig committed
1012
1013
1014
		proj = get_edge_src_irn(edge);
		assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");

1015
		pnc = get_Proj_proj(proj);
Christian Würdig's avatar
Christian Würdig committed
1016
1017
1018

		/* create branch entry */
		tbl.branches[i].target = proj;