ia32_emitter.c 60.4 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
68
#define SNPRINTF_BUF_LEN 128

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

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

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

89
90
91
92
93
	if(reg == &ia32_gp_regs[REG_GP_NOREG])
		panic("trying to emit noreg");

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

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

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

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

/**
 * Returns the register at out position pos.
 */
115
116
117
118
119
120
121
static
const arch_register_t *get_out_reg(ia32_emit_env_t *env, const ir_node *irn,
                                   int pos)
{
	const arch_env_t      *arch_env = env->arch_env;
	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
129

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

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

180
181
static
int produces_result(const ir_node *node) {
182
183
184
185
186
187
188
	return
		!is_ia32_CmpSet(node)    &&
		!is_ia32_CondJmp(node)   &&
		!is_ia32_St(node)        &&
		!is_ia32_SwitchJmp(node) &&
		!is_ia32_TestJmp(node)   &&
		!is_ia32_xCmpSet(node)   &&
189
190
191
192
193
		!is_ia32_xCondJmp(node)  &&
		!is_ia32_CmpCMov(node)   &&
		!is_ia32_TestCMov(node)  &&
		!is_ia32_CmpSet(node)    && /* this is correct, the Cmp has no result */
		!is_ia32_TestSet(node);
194
195
}

196
197
198
static
const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode,
                                       const arch_register_t *reg) {
199
200
201
202
203
204
205
	switch(get_mode_size_bits(mode)) {
		case 8:
			return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
		case 16:
			return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg);
		default:
			return (char *)arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
206
	}
Christian Würdig's avatar
Christian Würdig committed
207
208
}

Michael Beck's avatar
Michael Beck committed
209
/**
210
 * Add a number to a prefix. This number will not be used a second time.
Michael Beck's avatar
Michael Beck committed
211
 */
212
213
static
char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}

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

Matthias Braun's avatar
Matthias Braun committed
230
231
232
233
234
235
236
// we have no C++ and can't define an implicit ia32_emit_env_t* cast to
// be_emit_env_t* so we cheat a bit...
#define be_emit_char(env,c)             be_emit_char(env->emit,c)
#define be_emit_string(env,s)           be_emit_string(env->emit,s)
#undef be_emit_cstring
#define be_emit_cstring(env,x)          { be_emit_string_len(env->emit, x, sizeof(x)-1); }
#define be_emit_ident(env,i)            be_emit_ident(env->emit,i)
237
#define be_emit_tarval(env,tv)          be_emit_tarval(env->emit,tv)
Matthias Braun's avatar
Matthias Braun committed
238
239
240
#define be_emit_write_line(env)         be_emit_write_line(env->emit)
#define be_emit_finish_line_gas(env,n)  be_emit_finish_line_gas(env->emit,n)
#define be_emit_pad_comment(env)        be_emit_pad_comment(env->emit)
Michael Beck's avatar
Michael Beck committed
241

242
void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
Christian Würdig's avatar
Christian Würdig committed
243
{
244
	const arch_register_t *reg = get_in_reg(env, node, pos);
245
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
246

247
	assert(pos < get_irn_arity(node));
Christian Würdig's avatar
Christian Würdig committed
248

Matthias Braun's avatar
Matthias Braun committed
249
250
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
251
252
}

Michael Beck's avatar
Michael Beck committed
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
void ia32_emit_8bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
{
	const arch_register_t *reg = get_in_reg(env, node, pos);
	const char *reg_name = arch_register_get_name(reg);

	assert(pos < get_irn_arity(node));

	be_emit_char(env, '%');
	be_emit_char(env, reg_name[1]);
	be_emit_char(env, 'l');
}

void ia32_emit_16bit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos)
{
	const arch_register_t *reg = get_in_reg(env, node, pos);
	const char *reg_name = arch_register_get_name(reg);

	assert(pos < get_irn_arity(node));

	be_emit_char(env, '%');
	be_emit_string(env, &reg_name[1]);
}

276
void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos) {
277
	const arch_register_t *reg = get_out_reg(env, node, pos);
278
	const char *reg_name = arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
279

Matthias Braun's avatar
Matthias Braun committed
280
281
	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
Christian Würdig's avatar
Christian Würdig committed
282
283
}

284
285
286
287
288
289
290
291
static void ia32_emit_register(ia32_emit_env_t *env, const arch_register_t *reg)
{
	const char *reg_name = arch_register_get_name(reg);

	be_emit_char(env, '%');
	be_emit_string(env, reg_name);
}

292
void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos)
Christian Würdig's avatar
Christian Würdig committed
293
{
294
	const ia32_x87_attr_t *attr = get_ia32_x87_attr_const(node);
295

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

301
302
303
void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node)
{
	tarval *tv;
304
	ir_entity *ent;
305
	ident *id;
Christian Würdig's avatar
Christian Würdig committed
306

307
308
	be_emit_char(env, '$');

309
310
311
	switch(get_ia32_immop_type(node)) {
	case ia32_ImmConst:
		tv = get_ia32_Immop_tarval(node);
312
		be_emit_tarval(env, tv);
313
		return;
314
	case ia32_ImmSymConst:
315
		ent = get_ia32_Immop_symconst(node);
Michael Beck's avatar
Michael Beck committed
316
		set_entity_backend_marked(ent, 1);
317
		id = get_entity_ld_ident(ent);
318
		be_emit_ident(env, id);
319
		return;
320
321
	case ia32_ImmNone:
		break;
Christian Würdig's avatar
Christian Würdig committed
322
	}
Christian Würdig's avatar
Christian Würdig committed
323

324
325
326
	assert(0);
	be_emit_string(env, "BAD");
	return;
327
}
Christian Würdig's avatar
Christian Würdig committed
328

Matthias Braun's avatar
Matthias Braun committed
329
330
static
void ia32_emit_mode_suffix_mode(ia32_emit_env_t *env, const ir_mode *mode)
331
{
Matthias Braun's avatar
Matthias Braun committed
332
	be_emit_char(env, get_mode_suffix(mode));
Christian Würdig's avatar
Christian Würdig committed
333
334
}

Matthias Braun's avatar
Matthias Braun committed
335
void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
336
337
{
	ir_mode *mode = get_ia32_ls_mode(node);
Matthias Braun's avatar
Matthias Braun committed
338
339
340
341
	if(mode == NULL)
		mode = mode_Iu;

	ia32_emit_mode_suffix_mode(env, mode);
342
343
}

344
345
346
347
348
349
350
void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
	if(mode != NULL)
		ia32_emit_mode_suffix_mode(env, mode);
}

351
352
static
char get_xmm_mode_suffix(ir_mode *mode)
353
354
355
356
357
358
359
360
361
362
363
364
365
{
	assert(mode_is_float(mode));
	switch(get_mode_size_bits(mode)) {
	case 32:
		return 's';
	case 64:
		return 'd';
	default:
		assert(0);
	}
	return '%';
}

366
367
368
void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
369
	assert(mode != NULL);
Matthias Braun's avatar
Matthias Braun committed
370
371
	be_emit_char(env, 's');
	be_emit_char(env, get_xmm_mode_suffix(mode));
372
373
374
375
376
377
}

void ia32_emit_xmm_mode_suffix_s(ia32_emit_env_t *env, const ir_node *node)
{
	ir_mode *mode = get_ia32_ls_mode(node);
	assert(mode != NULL);
Matthias Braun's avatar
Matthias Braun committed
378
	be_emit_char(env, get_xmm_mode_suffix(mode));
379
380
}

381
382
383
384
385
void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode)
{
	if(get_mode_size_bits(mode) == 32)
		return;
	if(mode_is_signed(mode)) {
Matthias Braun's avatar
Matthias Braun committed
386
		be_emit_char(env, 's');
387
	} else {
Matthias Braun's avatar
Matthias Braun committed
388
389
390
391
		be_emit_char(env, 'z');
	}
}

392
393
static
void ia32_emit_function_object(ia32_emit_env_t *env, const char *name)
Matthias Braun's avatar
Matthias Braun committed
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
		be_emit_cstring(env, "\t.type\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ", @function\n");
		be_emit_write_line(env);
		break;
	case GAS_FLAVOUR_MINGW:
		be_emit_cstring(env, "\t.def\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ";\t.scl\t2;\t.type\t32;\t.endef\n");
		be_emit_write_line(env);
		break;
	default:
		break;
	}
}

413
414
static
void ia32_emit_function_size(ia32_emit_env_t *env, const char *name)
Matthias Braun's avatar
Matthias Braun committed
415
416
417
418
419
420
421
422
423
424
425
426
{
	switch (be_gas_flavour) {
	case GAS_FLAVOUR_NORMAL:
		be_emit_cstring(env, "\t.size\t");
		be_emit_string(env, name);
		be_emit_cstring(env, ", .-");
		be_emit_string(env, name);
		be_emit_char(env, '\n');
		be_emit_write_line(env);
		break;
	default:
		break;
Christian Würdig's avatar
Christian Würdig committed
427
428
429
	}
}

Matthias Braun's avatar
Matthias Braun committed
430

431
432
static
void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node);
Matthias Braun's avatar
Matthias Braun committed
433

Christian Würdig's avatar
Christian Würdig committed
434
435
436
/**
 * Emits registers and/or address mode of a binary operation.
 */
437
void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) {
438
	int            right_pos;
439
	const ir_node *right_op = get_irn_n(node, 3);
Christian Würdig's avatar
Christian Würdig committed
440

441
442
443
444
445
446
	switch(get_ia32_op_type(node)) {
	case ia32_Normal:
		if(is_ia32_Immediate(right_op)) {
			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_source_register(env, node, 2);
Christian Würdig's avatar
Christian Würdig committed
447
			break;
448
449
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
450
			be_emit_cstring(env, ", ");
451
452
453
454
455
456
457
458
			ia32_emit_source_register(env, node, 2);
		} else {
			const arch_register_t *in1 = get_in_reg(env, node, 2);
			const arch_register_t *in2 = get_in_reg(env, node, 3);
			const arch_register_t *out = produces_result(node) ? get_out_reg(env, node, 0) : NULL;
			const arch_register_t *in;
			const char            *in_name;

459
			in      = out ? ((out == in2) ? in1 : in2) : in2;
460
461
462
463
			out     = out ? out : in1;
			in_name = arch_register_get_name(in);

			if (is_ia32_emit_cl(node)) {
464
				assert(in == &ia32_gp_regs[REG_ECX]);
465
				in_name = "cl";
466
			}
Christian Würdig's avatar
Christian Würdig committed
467

468
469
470
471
472
473
474
475
			be_emit_char(env, '%');
			be_emit_string(env, in_name);
			be_emit_cstring(env, ", %");
			be_emit_string(env, arch_register_get_name(out));
		}
		break;
	case ia32_AddrModeS:
		if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
476
477
			assert(!produces_result(node) &&
					"Source AM with Const must not produce result");
478
			ia32_emit_immediate(env, node);
479
480
481
482
483
484
485
486
487
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		} else if(is_ia32_Immediate(right_op)) {
			assert(!produces_result(node) &&
					"Source AM with Const must not produce result");

			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
488
		} else if (produces_result(node)) {
489
490
			ia32_emit_am(env, node);
			be_emit_cstring(env, ", ");
491
492
			ia32_emit_dest_register(env, node, 0);
		} else {
493
494
			ia32_emit_am(env, node);
			be_emit_cstring(env, ", ");
495
496
497
498
			ia32_emit_source_register(env, node, 2);
		}
		break;
	case ia32_AddrModeD:
499
		right_pos = get_irn_arity(node) >= 5 ? 3 : 2;
500
		right_op  = get_irn_n(node, right_pos);
501
502
503
504
505
506
507
508
509
510
		if(is_ia32_Immediate(right_op)) {
			emit_ia32_Immediate(env, right_op);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
			break;
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		} else {
511
			const arch_register_t *in1 = get_in_reg(env, node, right_pos);
512
513
			ir_mode               *mode = get_ia32_ls_mode(node);
			const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
514

515
			in_name = ia32_get_reg_name_for_mode(env, mode, in1);
516

517
			if (is_ia32_emit_cl(node)) {
518
				assert(in1 == &ia32_gp_regs[REG_ECX]);
519
				in_name = "cl";
Christian Würdig's avatar
Christian Würdig committed
520
			}
521
522
523
524
525
526
527
528
529

			be_emit_char(env, '%');
			be_emit_string(env, in_name);
			be_emit_cstring(env, ", ");
			ia32_emit_am(env, node);
		}
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
530
	}
531
532
}

533
534
535
/**
 * Emits registers and/or address mode of a binary operation.
 */
536
537
void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) {
	switch(get_ia32_op_type(node)) {
538
		case ia32_Normal:
539
540
541
542
			if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
				// should not happen...
				assert(0);
			} else {
543
544
545
546
				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];
547
548
				const arch_register_t *in;

549
				in  = out ? ((out == in2) ? in1 : in2) : in2;
550
				out = out ? out : in1;
551

Matthias Braun's avatar
Matthias Braun committed
552
553
554
555
				be_emit_char(env, '%');
				be_emit_string(env, arch_register_get_name(in));
				be_emit_cstring(env, ", %");
				be_emit_string(env, arch_register_get_name(out));
556
557
558
559
			}
			break;
		case ia32_AddrModeS:
		case ia32_AddrModeD:
560
			ia32_emit_am(env, node);
561
562
563
564
565
566
			break;
		default:
			assert(0 && "unsupported op type");
	}
}

567
568
569
570
571
572
573
574
575
576
void ia32_emit_am_or_dest_register(ia32_emit_env_t *env, const ir_node *node,
                                   int pos) {
	if(get_ia32_op_type(node) == ia32_Normal) {
		ia32_emit_dest_register(env, node, pos);
	} else {
		assert(get_ia32_op_type(node) == ia32_AddrModeD);
		ia32_emit_am(env, node);
	}
}

Christian Würdig's avatar
Christian Würdig committed
577
578
579
/**
 * Emits registers and/or address mode of a unary operation.
 */
580
581
582
void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node, int pos) {
	const ir_node *op;

583
	switch(get_ia32_op_type(node)) {
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
	case ia32_Normal:
		op = get_irn_n(node, pos);
		if (is_ia32_Immediate(op)) {
			emit_ia32_Immediate(env, op);
		} else if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
			ia32_emit_immediate(env, node);
		} else {
			ia32_emit_source_register(env, node, pos);
		}
		break;
	case ia32_AddrModeS:
	case ia32_AddrModeD:
		ia32_emit_am(env, node);
		break;
	default:
		assert(0 && "unsupported op type");
Christian Würdig's avatar
Christian Würdig committed
600
601
602
603
	}
}

/**
604
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
605
 */
606
void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) {
607
608
609
610
611
612
	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
613

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

617
	/* emit offset */
618
619
620
	if (ent != NULL) {
		ident *id;

Michael Beck's avatar
Michael Beck committed
621
		set_entity_backend_marked(ent, 1);
622
		id = get_entity_ld_ident(ent);
623
		if (is_ia32_am_sc_sign(node))
Matthias Braun's avatar
Matthias Braun committed
624
625
			be_emit_char(env, '-');
		be_emit_ident(env, id);
Matthias Braun's avatar
Matthias Braun committed
626
627
628
629
630
631
632
633

		if(get_entity_owner(ent) == get_tls_type()) {
			if (get_entity_visibility(ent) == visibility_external_allocated) {
				be_emit_cstring(env, "@INDNTPOFF");
			} else {
				be_emit_cstring(env, "@NTPOFF");
			}
		}
Christian Würdig's avatar
Christian Würdig committed
634
635
	}

636
	if(offs != 0) {
637
		if(ent != NULL) {
Matthias Braun's avatar
Matthias Braun committed
638
			be_emit_irprintf(env->emit, "%+d", offs);
639
		} else {
Matthias Braun's avatar
Matthias Braun committed
640
			be_emit_irprintf(env->emit, "%d", offs);
641
		}
642
	}
Christian Würdig's avatar
Christian Würdig committed
643

644
	if (has_base || has_index) {
Matthias Braun's avatar
Matthias Braun committed
645
		be_emit_char(env, '(');
Christian Würdig's avatar
Christian Würdig committed
646

647
		/* emit base */
648
		if (has_base) {
649
			ia32_emit_source_register(env, node, 0);
Christian Würdig's avatar
Christian Würdig committed
650
651
		}

652
		/* emit index + scale */
653
654
		if (has_index) {
			int scale;
Matthias Braun's avatar
Matthias Braun committed
655
			be_emit_char(env, ',');
656
			ia32_emit_source_register(env, node, 1);
657

658
659
			scale = get_ia32_am_scale(node);
			if (scale > 0) {
Matthias Braun's avatar
Matthias Braun committed
660
				be_emit_irprintf(env->emit, ",%d", 1 << get_ia32_am_scale(node));
661
662
			}
		}
Matthias Braun's avatar
Matthias Braun committed
663
		be_emit_char(env, ')');
Christian Würdig's avatar
Christian Würdig committed
664
	}
665
666
667
668
669

	/* special case if nothing is set */
	if(ent == NULL && offs == 0 && !has_base && !has_index) {
		be_emit_char(env, '0');
	}
670
}
Christian Würdig's avatar
Christian Würdig committed
671

Christian Würdig's avatar
Christian Würdig committed
672
673
674
675
676
677
678
679
680
681
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
682
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
683
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
684

685
686
687
688
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
689
690
	const char *name;
	pn_Cmp      num;
691
692
693
694
695
};

/*
 * positive conditions for signed compares
 */
696
697
static
const struct cmp2conditon_t cmp2condition_s[] = {
698
699
700
701
702
703
704
705
	{ 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 },     /* != */
	{ NULL,              pn_Cmp_Leg},     /* Floating point: ordered */
706
707
708
709
710
};

/*
 * positive conditions for unsigned compares
 */
711
712
static
const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
713
714
715
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
716
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
717
718
719
720
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
	{ NULL,              pn_Cmp_True },   /* always true */
721
722
723
724
725
};

/*
 * returns the condition code
 */
726
static
Matthias Braun's avatar
Matthias Braun committed
727
const char *get_cmp_suffix(pn_Cmp cmp_code)
728
{
729
	assert( (cmp2condition_s[cmp_code & 7].num) == (cmp_code & 7));
730
	assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7));
731

732
733
734
	if((cmp_code & ia32_pn_Cmp_Unsigned)) {
		return cmp2condition_u[cmp_code & 7].name;
	} else {
735
		return cmp2condition_s[cmp_code & 7].name;
736
	}
737
738
}

739
740
void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc)
{
Matthias Braun's avatar
Matthias Braun committed
741
	be_emit_string(env, get_cmp_suffix(pnc));
742
743
744
}


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

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

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

775
	ia32_emit_block_name(env, block);
Christian Würdig's avatar
Christian Würdig committed
776
}
777

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

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

791
	assert(get_irn_mode(node) == mode_T && "expected mode_T node");
792

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

818
	/* get both Proj's */
819
	proj_true = get_proj(node, pn_Cond_true);
820
	assert(proj_true && "CondJmp without true Proj");
Christian Würdig's avatar
Christian Würdig committed
821

822
	proj_false = get_proj(node, pn_Cond_false);
823
824
	assert(proj_false && "CondJmp without false Proj");

825
	/* for now, the code works for scheduled and non-schedules blocks */
826
	block = get_nodes_block(node);
827
828

	/* we have a block schedule */
829
	next_block = next_blk_sched(block);
830

831
	if (get_cfop_target_block(proj_true) == next_block) {
832
		/* exchange both proj's so the second one can be omitted */
833
834
		const ir_node *t = proj_true;

835
836
837
838
		proj_true  = proj_false;
		proj_false = t;
		flipped    = 1;
		pnc        = get_negated_pnc(pnc, mode);
839
840
	}

841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
	if (mode_is_float(mode)) {
		/* Some floating point comparisons require a test of the parity flag, which
		 * indicates that the result is unordered */
		switch (pnc) {
			case pn_Cmp_Uo:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				break;

			case pn_Cmp_Leg:
				be_emit_cstring(env, "\tjnp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				break;

			case pn_Cmp_Eq:
			case pn_Cmp_Lt:
			case pn_Cmp_Le:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_false);
				be_emit_finish_line_gas(env, proj_false);
				goto float_jcc;

			case pn_Cmp_Ug:
			case pn_Cmp_Uge:
			case pn_Cmp_Ne:
				be_emit_cstring(env, "\tjp ");
				ia32_emit_cfop_target(env, proj_true);
				be_emit_finish_line_gas(env, proj_true);
				goto float_jcc;

			default:
			float_jcc:
				/* The bits set by floating point compares correspond to unsigned
				 * comparisons */
				pnc |= ia32_pn_Cmp_Unsigned;
				goto emit_jcc;
		}
	} else {
emit_jcc:
		be_emit_cstring(env, "\tj");
		ia32_emit_cmp_suffix(env, pnc);
		be_emit_char(env, ' ');
885
		ia32_emit_cfop_target(env, proj_true);
Matthias Braun's avatar
Matthias Braun committed
886
		be_emit_finish_line_gas(env, proj_true);
887
888
	}

889
	/* the second Proj might be a fallthrough */
890
	if (get_cfop_target_block(proj_false) != next_block) {
Matthias Braun's avatar
Matthias Braun committed
891
		be_emit_cstring(env, "\tjmp ");
892
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
893
		be_emit_finish_line_gas(env, proj_false);
894
	} else {
895
		be_emit_cstring(env, "\t/* fallthrough to ");
896
		ia32_emit_cfop_target(env, proj_false);
Matthias Braun's avatar
Matthias Braun committed
897
898
		be_emit_cstring(env, " */");
		be_emit_finish_line_gas(env, proj_false);
899
	}
Christian Würdig's avatar
Christian Würdig committed
900
901
902
}

/**
Christian Würdig's avatar
Christian Würdig committed
903
 * Emits code for conditional jump.
Christian Würdig's avatar
Christian Würdig committed
904
 */
905
906
static
void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
907
908
909
	be_emit_cstring(env, "\tcmp");
	ia32_emit_mode_suffix(env, node);
	be_emit_char(env, ' ');
910
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
911
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
912

913
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
914
915
}

Christian Würdig's avatar
Christian Würdig committed
916
917
918
/**
 * Emits code for conditional jump with two variables.
 */
919
920
static
void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) {
921
	CondJmp_emitter(env, node);
Christian Würdig's avatar
Christian Würdig committed
922
923
}

924
925
926
/**
 * Emits code for conditional test and jump.
 */
927
928
static
void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
929
930
931
932
	be_emit_cstring(env, "\ttest");
	ia32_emit_mode_suffix(env, node);
	be_emit_char(env, ' ');

933
934
935
	ia32_emit_binop(env, node);
	be_emit_finish_line_gas(env, node);

936
	finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node));
937
938
939
940
941
}

/**
 * Emits code for conditional test and jump with two variables.
 */
942
943
static
void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) {
944
	TestJmp_emitter(env, node);
945
946
}

Christian Würdig's avatar
Christian Würdig committed
947
948
949
/**
 * Emits code for conditional SSE floating point jump with two variables.
 */
950
951
static
void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) {
Matthias Braun's avatar
Matthias Braun committed
952
	be_emit_cstring(env, "\tucomi");
Matthias Braun's avatar
Matthias Braun committed
953
	ia32_emit_xmm_mode_suffix(env, node);
Matthias Braun's avatar
Matthias Braun committed
954
	be_emit_char(env, ' ');
955
	ia32_emit_binop(env, node);
Matthias Braun's avatar
Matthias Braun committed
956
	be_emit_finish_line_gas(env, node);
Christian Würdig's avatar
Christian Würdig committed
957

958
	finish_CondJmp(env, node, mode_F, get_ia32_pncode(node));
Christian Würdig's avatar
Christian Würdig committed
959
960
}

Michael Beck's avatar
Michael Beck committed
961
962
963
/**
 * Emits code for conditional x87 floating point jump with two variables.
 */
964
965
static
void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) {
966
967
968
	const ia32_x87_attr_t *x87_attr = get_ia32_x87_attr_const(node);
	const char            *reg      = x87_attr->x87[1]->name;
	long                   pnc      = get_ia32_pncode(node);
Michael Beck's avatar
Michael Beck committed
969

970
	switch (get_ia32_irn_opcode(node)) {
Michael Beck's avatar
Michael Beck committed
971
	case iro_ia32_fcomrJmp:
972
		pnc = get_inversed_pnc(pnc);
973
		reg = x87_attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
974
975
	case iro_ia32_fcomJmp:
	default:
Matthias Braun's avatar
Matthias Braun committed
976
		be_emit_cstring(env, "\tfucom ");
Michael Beck's avatar
Michael Beck committed
977
978
		break;
	case iro_ia32_fcomrpJmp:
979
		pnc = get_inversed_pnc(pnc);
980
		reg = x87_attr->x87[0]->name;
Michael Beck's avatar
Michael Beck committed
981
	case iro_ia32_fcompJmp:
Matthias Braun's avatar
Matthias Braun committed
982
		be_emit_cstring(env, "\tfucomp ");
Michael Beck's avatar
Michael Beck committed
983
984
		break;
	case iro_ia32_fcomrppJmp:
985
		pnc = get_inversed_pnc(pnc);
Michael Beck's avatar
Michael Beck committed
986
	case iro_ia32_fcomppJmp:
Matthias Braun's avatar
Matthias Braun committed
987
		be_emit_cstring(env, "\tfucompp ");
Michael Beck's avatar
Michael Beck committed
988
989
990
991
		reg = "";
		break;
	}

992
	if(reg[0] != '\0') {
Matthias Braun's avatar
Matthias Braun committed
993
994
		be_emit_char(env, '%');
		be_emit_string(env, reg);
995
	}
Matthias Braun's avatar
Matthias Braun committed
996
	be_emit_finish_line_gas(env, node);
Michael Beck's avatar
Michael Beck committed
997

Matthias Braun's avatar
Matthias Braun committed
998
999
1000
1001
	be_emit_cstring(env, "\tfnstsw %ax");
	be_emit_finish_line_gas(env, node);
	be_emit_cstring(env, "\tsahf");
	be_emit_finish_line_gas(env, node);
Michael Beck's avatar
Michael Beck committed
1002

1003
	finish_CondJmp(env, node, mode_E, pnc);
Michael Beck's avatar
Michael Beck committed
1004
1005
}

1006
static
Matthias Braun's avatar
Matthias Braun committed
1007
1008
void CMov_emitter(ia32_emit_env_t *env, const ir_node *node)
{
Christian Würdig's avatar
Christian Würdig committed
1009
	const arch_register_t *in1, *in2, *out;
1010
	long  pnc = get_ia32_pncode(node);
Christian Würdig's avatar
Christian Würdig committed
1011

1012
	out = arch_get_irn_register(env->arch_env, node);
Christian Würdig's avatar
Christian Würdig committed
1013

Christian Würdig's avatar
Christian Würdig committed