ia32_emitter.c 41.1 KB
Newer Older
1
2
3
4
5
6
/**
 * This file implements the node emitter.
 *
 * $Id$
 */

Christian Würdig's avatar
Christian Würdig committed
7
8
9
10
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Christian Würdig's avatar
Christian Würdig committed
11
12
#include <limits.h>

13
#include "xmalloc.h"
14
15
#include "tv.h"
#include "iredges.h"
Christian Würdig's avatar
Christian Würdig committed
16
17
18
19
#include "debug.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irop_t.h"
Christian Würdig's avatar
Christian Würdig committed
20
#include "irargs_t.h"
21
#include "irprog_t.h"
22
#include "iredges_t.h"
Christian Würdig's avatar
Christian Würdig committed
23

24
#include "../besched_t.h"
Christian Würdig's avatar
Christian Würdig committed
25
#include "../benode_t.h"
Christian Würdig's avatar
Christian Würdig committed
26

27
#include "ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
28
#include "gen_ia32_emitter.h"
Christian Würdig's avatar
Christian Würdig committed
29
#include "gen_ia32_regalloc_if.h"
30
31
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
Christian Würdig's avatar
Christian Würdig committed
32
33
#include "ia32_map_regs.h"

Christian Würdig's avatar
Christian Würdig committed
34
35
36
37
38
39
40
41
#ifdef obstack_chunk_alloc
# undef obstack_chunk_alloc
# define obstack_chunk_alloc xmalloc
#else
# define obstack_chunk_alloc xmalloc
# define obstack_chunk_free free
#endif

42
#define BLOCK_PREFIX(x) ".L" x
Michael Beck's avatar
Michael Beck committed
43

44
45
extern int obstack_printf(struct obstack *obst, char *fmt, ...);

Christian Würdig's avatar
Christian Würdig committed
46
47
#define SNPRINTF_BUF_LEN 128

48
/* global arch_env for lc_printf functions */
Christian Würdig's avatar
Christian Würdig committed
49
static const arch_env_t *arch_env = NULL;
50

51
52
53
54
/* indicates whether blocks are scheduled or not
   (this variable is set automatically) */
static int have_block_sched       = 0;

Christian Würdig's avatar
Christian Würdig committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/

/* We always pass the ir_node which is a pointer. */
static int ia32_get_arg_type(const lc_arg_occ_t *occ) {
	return lc_arg_type_ptr;
69
70
}

Christian Würdig's avatar
Christian Würdig committed
71
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
 */
Christian Würdig's avatar
Christian Würdig committed
75
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
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
88
89
90
91
92
93
	assert(reg && "no in register found");
	return reg;
}

/**
 * Returns the register at out position pos.
 */
Christian Würdig's avatar
Christian Würdig committed
94
static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
Christian Würdig's avatar
Christian Würdig committed
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
	ir_node                *proj;
	const arch_register_t  *reg = NULL;

	/* 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);
	}
	else if (is_ia32_irn(irn)) {
		reg = get_ia32_out_reg(irn, pos);
	}
	else {
		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
123
124
125
	return reg;
}

Michael Beck's avatar
Michael Beck committed
126
127
128
129
130
enum io_direction {
  IN_REG,
  OUT_REG
};

Christian Würdig's avatar
Christian Würdig committed
131
132
133
/**
 * Returns the name of the in register at position pos.
 */
Michael Beck's avatar
Michael Beck committed
134
static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in_out) {
Christian Würdig's avatar
Christian Würdig committed
135
	const arch_register_t *reg;
Christian Würdig's avatar
Christian Würdig committed
136
137
138
	const char            *name;
	static char           *buf = NULL;
	int                    len;
Christian Würdig's avatar
Christian Würdig committed
139

Michael Beck's avatar
Michael Beck committed
140
	if (in_out == IN_REG) {
Christian Würdig's avatar
Christian Würdig committed
141
142
143
		reg = get_in_reg(irn, pos);
	}
	else {
Christian Würdig's avatar
Christian Würdig committed
144
		/* destination address mode nodes don't have outputs */
145
		if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) {
Christian Würdig's avatar
Christian Würdig committed
146
147
148
			return "MEM";
		}

Christian Würdig's avatar
Christian Würdig committed
149
150
151
		reg = get_out_reg(irn, pos);
	}

Christian Würdig's avatar
Christian Würdig committed
152
153
154
155
156
157
158
159
160
161
162
163
	name = arch_register_get_name(reg);

	if (buf) {
		free(buf);
	}

	len = strlen(name) + 2;
	buf = xcalloc(1, len);

	snprintf(buf, len, "%%%s", name);

	return buf;
Christian Würdig's avatar
Christian Würdig committed
164
165
166
167
168
169
170
171
172
173
174
175
176
}

/**
 * Get the register name for a node.
 */
static int ia32_get_reg_name(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
	const char *buf;
	ir_node    *X  = arg->v_ptr;
	int         nr = occ->width - 1;

	if (!X)
Christian Würdig's avatar
Christian Würdig committed
177
		return lc_appendable_snadd(app, "(null)", 6);
Christian Würdig's avatar
Christian Würdig committed
178

Christian Würdig's avatar
Christian Würdig committed
179
	buf = get_ia32_reg_name(X, nr, occ->conversion == 'S' ? IN_REG : OUT_REG);
Christian Würdig's avatar
Christian Würdig committed
180

Christian Würdig's avatar
Christian Würdig committed
181
	return lc_appendable_snadd(app, buf, strlen(buf));
182
183
}

Christian Würdig's avatar
Christian Würdig committed
184
/**
185
 * Returns the tarval, offset or scale of an ia32 as a string.
Christian Würdig's avatar
Christian Würdig committed
186
187
188
189
190
191
192
193
194
195
 */
static int ia32_const_to_str(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
	const char *buf;
	ir_node    *X = arg->v_ptr;

	if (!X)
		return lc_arg_append(app, occ, "(null)", 6);

196
	if (occ->conversion == 'C') {
Christian Würdig's avatar
Christian Würdig committed
197
		buf = get_ia32_cnst(X);
Christian Würdig's avatar
Christian Würdig committed
198
	}
199
	else { /* 'O' */
Christian Würdig's avatar
Christian Würdig committed
200
		buf = get_ia32_am_offs(X);
Christian Würdig's avatar
Christian Würdig committed
201
202
	}

Christian Würdig's avatar
Christian Würdig committed
203
	return buf ? lc_appendable_snadd(app, buf, strlen(buf)) : 0;
Christian Würdig's avatar
Christian Würdig committed
204
205
206
207
208
209
210
211
}

/**
 * Determines the SSE suffix depending on the mode.
 */
static int ia32_get_mode_suffix(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
Christian Würdig's avatar
Christian Würdig committed
212
	ir_node *X    = arg->v_ptr;
213
214
215
216
217
	ir_mode *mode = get_irn_mode(X);

	if (mode == mode_T) {
		mode = is_ia32_AddrModeS(X) || is_ia32_AddrModeD(X) ? get_ia32_ls_mode(X) : get_ia32_res_mode(X);
	}
Christian Würdig's avatar
Christian Würdig committed
218
219
220
221

	if (!X)
		return lc_arg_append(app, occ, "(null)", 6);

Christian Würdig's avatar
Christian Würdig committed
222
223
224
225
226
227
	if (mode_is_float(mode)) {
		return lc_appendable_chadd(app, get_mode_size_bits(mode) == 32 ? 's' : 'd');
	}
	else {
		return lc_appendable_chadd(app, mode_is_signed(mode) ? 's' : 'z');
	}
Christian Würdig's avatar
Christian Würdig committed
228
229
230
231
232
233
234
}

/**
 * Return the ia32 printf arg environment.
 * We use the firm environment with some additional handlers.
 */
const lc_arg_env_t *ia32_get_arg_env(void) {
Christian Würdig's avatar
Christian Würdig committed
235
	static lc_arg_env_t *env = NULL;
Christian Würdig's avatar
Christian Würdig committed
236

Christian Würdig's avatar
Christian Würdig committed
237
238
239
	static const lc_arg_handler_t ia32_reg_handler   = { ia32_get_arg_type, ia32_get_reg_name };
	static const lc_arg_handler_t ia32_const_handler = { ia32_get_arg_type, ia32_const_to_str };
	static const lc_arg_handler_t ia32_mode_handler  = { ia32_get_arg_type, ia32_get_mode_suffix };
Christian Würdig's avatar
Christian Würdig committed
240

Christian Würdig's avatar
Christian Würdig committed
241
242
243
	if(env == NULL) {
		/* extend the firm printer */
		env = firm_get_arg_env();
Christian Würdig's avatar
Christian Würdig committed
244

245
246
247
248
249
		lc_arg_register(env, "ia32:sreg", 'S', &ia32_reg_handler);
		lc_arg_register(env, "ia32:dreg", 'D', &ia32_reg_handler);
		lc_arg_register(env, "ia32:cnst", 'C', &ia32_const_handler);
		lc_arg_register(env, "ia32:offs", 'O', &ia32_const_handler);
		lc_arg_register(env, "ia32:mode", 'M', &ia32_mode_handler);
Christian Würdig's avatar
Christian Würdig committed
250
	}
Christian Würdig's avatar
Christian Würdig committed
251

Christian Würdig's avatar
Christian Würdig committed
252
	return env;
Christian Würdig's avatar
Christian Würdig committed
253
254
}

Christian Würdig's avatar
Christian Würdig committed
255
256
257
258
259
260
261
static char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) {
	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:
Christian Würdig's avatar
Christian Würdig committed
262
			return (char *)arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
263
264
265
	}
}

Christian Würdig's avatar
Christian Würdig committed
266
267
268
/**
 * Emits registers and/or address mode of a binary operation.
 */
269
char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
270
	static char *buf = NULL;
Christian Würdig's avatar
Christian Würdig committed
271

Christian Würdig's avatar
Christian Würdig committed
272
	/* verify that this function is never called on non-AM supporting operations */
Christian Würdig's avatar
Christian Würdig committed
273
	//assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
Christian Würdig's avatar
Christian Würdig committed
274

275
276
277
278
279
280
#define PRODUCES_RESULT(n)   \
	(!(is_ia32_St(n)      || \
	is_ia32_Store8Bit(n)  || \
	is_ia32_CondJmp(n)    || \
	is_ia32_fCondJmp(n)   || \
	is_ia32_SwitchJmp(n)))
Christian Würdig's avatar
Christian Würdig committed
281

Christian Würdig's avatar
Christian Würdig committed
282
283
284
285
286
287
288
289
290
	if (! buf) {
		buf = xcalloc(1, SNPRINTF_BUF_LEN);
	}
	else {
		memset(buf, 0, SNPRINTF_BUF_LEN);
	}

	switch(get_ia32_op_type(n)) {
		case ia32_Normal:
291
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
Christian Würdig's avatar
Christian Würdig committed
292
293
294
295
296
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
			}
			else {
				const arch_register_t *in1 = get_in_reg(n, 2);
				const arch_register_t *in2 = get_in_reg(n, 3);
Christian Würdig's avatar
Christian Würdig committed
297
				const arch_register_t *out = PRODUCES_RESULT(n) ? get_out_reg(n, 0) : NULL;
Christian Würdig's avatar
Christian Würdig committed
298
299
300
301
302
				const arch_register_t *in;

				in  = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
				out = out ? out : in1;

Christian Würdig's avatar
Christian Würdig committed
303
				snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", \
Christian Würdig's avatar
Christian Würdig committed
304
305
306
307
					arch_register_get_name(out), arch_register_get_name(in));
			}
			break;
		case ia32_AddrModeS:
308
309
310
311
312
313
314
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
				assert(! PRODUCES_RESULT(n) && "Source AM with Const must not produce result");
				snprintf(buf, SNPRINTF_BUF_LEN, "%s, %s", get_ia32_cnst(n), ia32_emit_am(n, env));
			}
			else {
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n, env));
			}
Christian Würdig's avatar
Christian Würdig committed
315
316
			break;
		case ia32_AddrModeD:
317
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
318
319
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s,%s%s",
					ia32_emit_am(n, env),
320
321
					is_ia32_ImmSymConst(n) ? " OFFSET FLAT:" : " ",  /* In case of a symconst we must add OFFSET to */
					get_ia32_cnst(n));                               /* tell the assembler to store it's address.   */
Christian Würdig's avatar
Christian Würdig committed
322
323
			}
			else {
324
				const arch_register_t *in1 = get_in_reg(n, 2);
Christian Würdig's avatar
Christian Würdig committed
325
				ir_mode              *mode = get_ia32_res_mode(n);
326
327

				mode = mode ? mode : get_ia32_ls_mode(n);
Christian Würdig's avatar
Christian Würdig committed
328
329
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s",
					ia32_emit_am(n, env), ia32_get_reg_name_for_mode(env, mode, in1));
Christian Würdig's avatar
Christian Würdig committed
330
331
332
333
334
335
			}
			break;
		default:
			assert(0 && "unsupported op type");
	}

Christian Würdig's avatar
Christian Würdig committed
336
337
#undef PRODUCES_RESULT

Christian Würdig's avatar
Christian Würdig committed
338
339
340
341
342
343
	return buf;
}

/**
 * Emits registers and/or address mode of a unary operation.
 */
344
char *ia32_emit_unop(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
345
346
347
348
349
350
351
352
353
354
355
	static char *buf = NULL;

	if (! buf) {
		buf = xcalloc(1, SNPRINTF_BUF_LEN);
	}
	else {
		memset(buf, 0, SNPRINTF_BUF_LEN);
	}

	switch(get_ia32_op_type(n)) {
		case ia32_Normal:
356
357
358
359
360
361
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%C", n);
			}
			else {
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
			}
Christian Würdig's avatar
Christian Würdig committed
362
363
			break;
		case ia32_am_Dest:
364
			snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n, env));
Christian Würdig's avatar
Christian Würdig committed
365
366
367
368
369
370
371
372
373
			break;
		default:
			assert(0 && "unsupported op type");
	}

	return buf;
}

/**
374
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
375
 */
376
char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
	ia32_am_flavour_t am_flav    = get_ia32_am_flavour(n);
	int               had_output = 0;
	char             *s;
	int               size;
	static struct obstack *obst  = NULL;
	ir_mode *mode = get_ia32_ls_mode(n);

	if (! is_ia32_Lea(n))
		assert(mode && "AM node must have ls_mode attribute set.");

	if (! obst) {
		obst = xcalloc(1, sizeof(*obst));
	}
	else {
		obstack_free(obst, NULL);
	}

	/* obstack_free with NULL results in an uninitialized obstack */
	obstack_init(obst);

	if (mode) {
		switch (get_mode_size_bits(mode)) {
			case 8:
Christian Würdig's avatar
Christian Würdig committed
400
				obstack_printf(obst, "BYTE PTR ");
Christian Würdig's avatar
Christian Würdig committed
401
402
				break;
			case 16:
Christian Würdig's avatar
Christian Würdig committed
403
404
405
406
				obstack_printf(obst, "WORD PTR ");
				break;
			case 32:
				obstack_printf(obst, "DWORD PTR ");
Christian Würdig's avatar
Christian Würdig committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
				break;
			default:
				break;
		}
	}

	obstack_printf(obst, "[");

	if (am_flav & ia32_B) {
		lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
		had_output = 1;
	}

	if (am_flav & ia32_I) {
		if (had_output) {
			obstack_printf(obst, "+");
		}

		lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);

		if (am_flav & ia32_S) {
			obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
		}

		had_output = 1;
	}

	if (am_flav & ia32_O) {
435
436
437
438
439
440
441
		s = get_ia32_am_offs(n);

		/* omit exlicit + if there was no base or index */
		if (! had_output && s[0] == '+')
			s++;

		obstack_printf(obst, s);
Christian Würdig's avatar
Christian Würdig committed
442
443
444
445
446
447
448
449
450
451
452
453
454
	}

	obstack_printf(obst, "] ");

	size        = obstack_object_size(obst);
	s           = obstack_finish(obst);
	s[size - 1] = '\0';

	return s;
}



Christian Würdig's avatar
Christian Würdig committed
455
456
457
/**
 * Formated print of commands and comments.
 */
Christian Würdig's avatar
Christian Würdig committed
458
459
460
461
462
463
464
465
static void ia32_fprintf_format(FILE *F, const ir_node *irn, char *cmd_buf, char *cmnt_buf) {
	unsigned lineno;
	const char *name = irn ? be_retrieve_dbg_info(get_irn_dbg_info((ir_node *)irn), &lineno) : NULL;

	if (name)
		fprintf(F, "\t%-35s %-60s /* %s:%u */\n", cmd_buf, cmnt_buf, name, lineno);
	else
		fprintf(F, "\t%-35s %-60s\n", cmd_buf, cmnt_buf);
Christian Würdig's avatar
Christian Würdig committed
466
467
468
469
}



Christian Würdig's avatar
Christian Würdig committed
470
/**
Christian Würdig's avatar
Christian Würdig committed
471
472
 * Add a number to a prefix. This number will not be used a second time.
 */
Christian Würdig's avatar
Christian Würdig committed
473
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
Christian Würdig's avatar
Christian Würdig committed
474
475
476
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
477
478
}

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

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

Christian Würdig's avatar
Christian Würdig committed
481
482
483
484
485
486
487
488
489
490
/*************************************************
 *                 _ _                         _
 *                (_) |                       | |
 *   ___ _ __ ___  _| |_    ___ ___  _ __   __| |
 *  / _ \ '_ ` _ \| | __|  / __/ _ \| '_ \ / _` |
 * |  __/ | | | | | | |_  | (_| (_) | | | | (_| |
 *  \___|_| |_| |_|_|\__|  \___\___/|_| |_|\__,_|
 *
 *************************************************/

Christian Würdig's avatar
Christian Würdig committed
491
#undef IA32_DO_EMIT
Christian Würdig's avatar
Christian Würdig committed
492
#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf)
Christian Würdig's avatar
Christian Würdig committed
493

494
495
496
497
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
498
499
	const char *name;
	pn_Cmp      num;
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
};

/*
 * positive conditions for signed compares
 */
static const struct cmp2conditon_t cmp2condition_s[] = {
  { 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 },     /* != */
  { "ordered",         pn_Cmp_Leg },    /* Floating point: ordered */
  { "unordered",       pn_Cmp_Uo },     /* FLoting point: unordered */
  { "unordered or ==", pn_Cmp_Ue },     /* Floating point: unordered or == */
  { "unordered or <",  pn_Cmp_Ul },     /* Floating point: unordered or < */
  { "unordered or <=", pn_Cmp_Ule },    /* Floating point: unordered or <= */
  { "unordered or >",  pn_Cmp_Ug },     /* Floating point: unordered or > */
  { "unordered or >=", pn_Cmp_Uge },    /* Floating point: unordered or >= */
  { "unordered or !=", pn_Cmp_Ne },     /* Floating point: unordered or != */
  { NULL,              pn_Cmp_True },   /* always true */
};

/*
 * positive conditions for unsigned compares
 */
static const struct cmp2conditon_t cmp2condition_u[] = {
Christian Würdig's avatar
Christian Würdig committed
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
	{	"be",              pn_Cmp_Le },     /* <= */
	{ "a",               pn_Cmp_Gt },     /* > */
	{ "ae",              pn_Cmp_Ge },     /* >= */
	{ "ne",              pn_Cmp_Lg },     /* != */
	{ "ordered",         pn_Cmp_Leg },    /* Floating point: ordered */
	{ "unordered",       pn_Cmp_Uo },     /* FLoting point: unordered */
	{ "unordered or ==", pn_Cmp_Ue },     /* Floating point: unordered or == */
	{ "unordered or <",  pn_Cmp_Ul },     /* Floating point: unordered or < */
	{ "unordered or <=", pn_Cmp_Ule },    /* Floating point: unordered or <= */
	{ "unordered or >",  pn_Cmp_Ug },     /* Floating point: unordered or > */
	{ "unordered or >=", pn_Cmp_Uge },    /* Floating point: unordered or >= */
	{ "unordered or !=", pn_Cmp_Ne },     /* Floating point: unordered or != */
	{ NULL,              pn_Cmp_True },   /* always true */
544
545
546
547
548
};

/*
 * returns the condition code
 */
Christian Würdig's avatar
Christian Würdig committed
549
static const char *get_cmp_suffix(int cmp_code, int unsigned_cmp)
550
{
Christian Würdig's avatar
Christian Würdig committed
551
552
	assert(cmp2condition_s[cmp_code].num == cmp_code);
	assert(cmp2condition_u[cmp_code].num == cmp_code);
553

Christian Würdig's avatar
Christian Würdig committed
554
	return unsigned_cmp ? cmp2condition_u[cmp_code & 7].name : cmp2condition_s[cmp_code & 7].name;
555
556
}

557
558
559
560
561
562
563
/**
 * Returns the target block for a control flow node.
 */
static ir_node *get_cfop_target_block(const ir_node *irn) {
	return get_irn_link(irn);
}

Christian Würdig's avatar
Christian Würdig committed
564
565
566
567
/**
 * Returns the target label for a control flow node.
 */
static char *get_cfop_target(const ir_node *irn, char *buf) {
568
	ir_node *bl = get_cfop_target_block(irn);
569

Michael Beck's avatar
Michael Beck committed
570
	snprintf(buf, SNPRINTF_BUF_LEN, BLOCK_PREFIX("%ld"), get_irn_node_nr(bl));
Christian Würdig's avatar
Christian Würdig committed
571
572
	return buf;
}
573

574
575
/** Return the next block in Block schedule */
static ir_node *next_blk_sched(const ir_node *block) {
Christian Würdig's avatar
Christian Würdig committed
576
	return have_block_sched ? get_irn_link(block) : NULL;
577
578
}

Christian Würdig's avatar
Christian Würdig committed
579
580
581
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
582
583
584
static void finish_CondJmp(FILE *F, const ir_node *irn, ir_mode *mode) {
	const ir_node   *proj1, *proj2 = NULL;
	const ir_node   *block, *next_bl = NULL;
Christian Würdig's avatar
Christian Würdig committed
585
586
	const ir_edge_t *edge;
	char buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
587
588
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
589

590
	/* get both Proj's */
Christian Würdig's avatar
Christian Würdig committed
591
	edge = get_irn_out_edge_first(irn);
592
593
	proj1 = get_edge_src_irn(edge);
	assert(is_Proj(proj1) && "CondJmp with a non-Proj");
Christian Würdig's avatar
Christian Würdig committed
594

595
596
597
598
	edge = get_irn_out_edge_next(irn, edge);
	if (edge) {
		proj2 = get_edge_src_irn(edge);
		assert(is_Proj(proj2) && "CondJmp with a non-Proj");
Christian Würdig's avatar
Christian Würdig committed
599
	}
600
601
602

	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);
603
	if (proj2) {
604
		/* we have a block schedule */
605
		next_bl = next_blk_sched(block);
606
607
608
609
610
611
612
613
614
615
616

		if (get_cfop_target_block(proj1) == next_bl) {
			/* exchange both proj's so the second one can be omitted */
			const ir_node *t = proj1;
			proj1 = proj2;
			proj2 = t;
		}
	}

	/* the first Proj must always be created */
	if (get_Proj_proj(proj1) == pn_Cond_true) {
Christian Würdig's avatar
Christian Würdig committed
617
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
Christian Würdig's avatar
Christian Würdig committed
618
					get_cmp_suffix(get_ia32_pncode(irn), !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
619
					get_cfop_target(proj1, buf));
Christian Würdig's avatar
Christian Würdig committed
620
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == TRUE */");
Christian Würdig's avatar
Christian Würdig committed
621
622
	}
	else  {
623
624
625
626
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
					get_cmp_suffix(get_negated_pnc(get_ia32_pncode(irn), mode),
					!mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
					get_cfop_target(proj1, buf));
Christian Würdig's avatar
Christian Würdig committed
627
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == FALSE */");
Christian Würdig's avatar
Christian Würdig committed
628
	}
Christian Würdig's avatar
Christian Würdig committed
629
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
630

631
632
633
634
	/* the second Proj might be a fallthrough */
	if (proj2) {
		if (get_cfop_target_block(proj2) != next_bl) {
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(proj2, buf));
Christian Würdig's avatar
Christian Würdig committed
635
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* otherwise */");
636
637
638
		}
		else {
			cmd_buf[0] = '\0';
Christian Würdig's avatar
Christian Würdig committed
639
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrogh %s */", get_cfop_target(proj2, buf));
640
		}
Christian Würdig's avatar
Christian Würdig committed
641
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
642
643
644
645
	}
}

/**
Christian Würdig's avatar
Christian Würdig committed
646
 * Emits code for conditional jump.
Christian Würdig's avatar
Christian Würdig committed
647
 */
648
static void CondJmp_emitter(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
649
	FILE *F = env->out;
Christian Würdig's avatar
Christian Würdig committed
650
651
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
652

653
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cmp %s", ia32_emit_binop(irn, env));
Christian Würdig's avatar
Christian Würdig committed
654
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
Christian Würdig's avatar
Christian Würdig committed
655
	IA32_DO_EMIT(irn);
656
	finish_CondJmp(F, irn, get_irn_mode(get_irn_n(irn, 2)));
Christian Würdig's avatar
Christian Würdig committed
657
658
}

Christian Würdig's avatar
Christian Würdig committed
659
660
661
/**
 * Emits code for conditional jump with two variables.
 */
662
static void emit_ia32_CondJmp(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
663
664
665
	CondJmp_emitter(irn, env);
}

Christian Würdig's avatar
Christian Würdig committed
666
667
668
/**
 * Emits code for conditional jump with immediate.
 */
Michael Beck's avatar
Michael Beck committed
669
static void emit_ia32_CondJmp_i(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
670
	CondJmp_emitter(irn, env);
Christian Würdig's avatar
Christian Würdig committed
671
672
}

673
674
675
676
/**
 * Emits code for conditional test and jump.
 */
static void TestJmp_emitter(const ir_node *irn, ia32_emit_env_t *env) {
677
678
679

#define IA32_IS_IMMOP (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn))

Christian Würdig's avatar
Christian Würdig committed
680
	FILE       *F   = env->out;
Michael Beck's avatar
Michael Beck committed
681
	const char *op1 = arch_register_get_name(get_in_reg(irn, 0));
682
	const char *op2 = IA32_IS_IMMOP ? get_ia32_cnst(irn) : NULL;
Christian Würdig's avatar
Christian Würdig committed
683
684
	char        cmd_buf[SNPRINTF_BUF_LEN];
	char        cmnt_buf[SNPRINTF_BUF_LEN];
Michael Beck's avatar
Michael Beck committed
685

Christian Würdig's avatar
Christian Würdig committed
686
	if (! op2)
Michael Beck's avatar
Michael Beck committed
687
		op2 = arch_register_get_name(get_in_reg(irn, 1));
Christian Würdig's avatar
Christian Würdig committed
688

689
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "test %%%s,%s%s ", op1, IA32_IS_IMMOP ? " " : " %", op2);
Christian Würdig's avatar
Christian Würdig committed
690
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
691

Christian Würdig's avatar
Christian Würdig committed
692
	IA32_DO_EMIT(irn);
693
	finish_CondJmp(F, irn, get_irn_mode(get_irn_n(irn, 0)));
694
695

#undef IA32_IS_IMMOP
696
697
698
699
700
701
702
703
704
}

/**
 * Emits code for conditional test and jump with two variables.
 */
static void emit_ia32_TestJmp(const ir_node *irn, ia32_emit_env_t *env) {
	TestJmp_emitter(irn, env);
}

705
706
707
708
709
710
711
static void emit_ia32_CJmp(const ir_node *irn, ia32_emit_env_t *env) {
	FILE *F = env->out;
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];

	snprintf(cmd_buf, SNPRINTF_BUF_LEN, " ");
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F omitted redundant test/cmp */", irn);
Christian Würdig's avatar
Christian Würdig committed
712
	IA32_DO_EMIT(irn);
713
714
	finish_CondJmp(F, irn, get_irn_mode(get_irn_n(irn, 0)));
}
715

716
717
718
719
720
721
722
static void emit_ia32_CJmpAM(const ir_node *irn, ia32_emit_env_t *env) {
	FILE *F = env->out;
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];

	snprintf(cmd_buf, SNPRINTF_BUF_LEN, " ");
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F omitted redundant test/cmp */", irn);
Christian Würdig's avatar
Christian Würdig committed
723
	IA32_DO_EMIT(irn);
724
725
	finish_CondJmp(F, irn, get_irn_mode(get_irn_n(irn, 2)));
}
Christian Würdig's avatar
Christian Würdig committed
726
727
728
729
730
731
732
733
734
735
736
737
738

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

/* jump table entry (target and corresponding number) */
Christian Würdig's avatar
Christian Würdig committed
739
740
741
742
743
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

Christian Würdig's avatar
Christian Würdig committed
744
/* jump table for switch generation */
Christian Würdig's avatar
Christian Würdig committed
745
typedef struct _jmp_tbl_t {
Christian Würdig's avatar
Christian Würdig committed
746
747
748
749
750
751
	ir_node  *defProj;         /**< default target */
	int       min_value;       /**< smallest switch case */
	int       max_value;       /**< largest switch case */
	int       num_branches;    /**< number of jumps */
	char     *label;           /**< label of the jump table */
	branch_t *branches;        /**< jump array */
Christian Würdig's avatar
Christian Würdig committed
752
753
} jmp_tbl_t;

Christian Würdig's avatar
Christian Würdig committed
754
755
756
/**
 * Compare two variables of type branch_t. Used to sort all switch cases
 */
Christian Würdig's avatar
Christian Würdig committed
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
static int ia32_cmp_branch_t(const void *a, const void *b) {
	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
 */
Michael Beck's avatar
Michael Beck committed
772
static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
773
774
775
776
777
778
779
780
	unsigned long       interval;
	char                buf[SNPRINTF_BUF_LEN];
	int                 last_value, i, pn, do_jmp_tbl = 1;
	jmp_tbl_t           tbl;
	ir_node            *proj;
	const ir_edge_t    *edge;
	const lc_arg_env_t *env = ia32_get_arg_env();
	FILE               *F   = emit_env->out;
Christian Würdig's avatar
Christian Würdig committed
781
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
782
783

	/* fill the table structure */
784
	tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
Christian Würdig's avatar
Christian Würdig committed
785
786
787
	tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
	tbl.defProj      = NULL;
	tbl.num_branches = get_irn_n_edges(irn);
788
	tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
Christian Würdig's avatar
Christian Würdig committed
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
	tbl.min_value    = INT_MAX;
	tbl.max_value    = INT_MIN;

	i = 0;
	/* go over all proj's and collect them */
	foreach_out_edge(irn, edge) {
		proj = get_edge_src_irn(edge);
		assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");

		pn = get_Proj_proj(proj);

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

		tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
		tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;

		/* check for default proj */
		if (pn == get_ia32_pncode(irn)) {
			assert(tbl.defProj == NULL && "found two defProjs at SwitchJmp");
			tbl.defProj = proj;
		}

		i++;
	}

	/* sort the branches by their number */
Christian Würdig's avatar
Christian Würdig committed
817
	qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), ia32_cmp_branch_t);
Christian Würdig's avatar
Christian Würdig committed
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834

	/* two-complement's magic make this work without overflow */
	interval = tbl.max_value - tbl.min_value;

	/* check value interval */
	if (interval > 16 * 1024) {
		do_jmp_tbl = 0;
	}

	/* check ratio of value interval to number of branches */
	if ((float)(interval + 1) / (float)tbl.num_branches > 8.0) {
		do_jmp_tbl = 0;
	}

	if (do_jmp_tbl) {
		/* emit the table */
		if (tbl.min_value != 0) {
Christian Würdig's avatar
Christian Würdig committed
835
			lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %lu, -%d(%1S)",
Christian Würdig's avatar
Christian Würdig committed
836
				interval, tbl.min_value, irn);
Christian Würdig's avatar
Christian Würdig committed
837
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* first switch value is not 0 */");
Christian Würdig's avatar
Christian Würdig committed
838

Christian Würdig's avatar
Christian Würdig committed
839
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
840
841
		}
		else {
Christian Würdig's avatar
Christian Würdig committed
842
			lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %lu, %1S", interval, irn);
Christian Würdig's avatar
Christian Würdig committed
843
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* compare for switch */");
Christian Würdig's avatar
Christian Würdig committed
844

Christian Würdig's avatar
Christian Würdig committed
845
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
846
847
		}

Christian Würdig's avatar
Christian Würdig committed
848
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "ja %s", get_cfop_target(tbl.defProj, buf));
Christian Würdig's avatar
Christian Würdig committed
849
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default jump if out of range  */");
Christian Würdig's avatar
Christian Würdig committed
850
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
851
852
853
854

		if (tbl.num_branches > 1) {
			/* create table */

Christian Würdig's avatar
Christian Würdig committed
855
			lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "jmp [%1S*4+%s]", irn, tbl.label);
Christian Würdig's avatar
Christian Würdig committed
856
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get jump table entry as target */");
Christian Würdig's avatar
Christian Würdig committed
857
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
858

Christian Würdig's avatar
Christian Würdig committed
859
			fprintf(F, "\t.section\t.rodata\n");
Christian Würdig's avatar
Christian Würdig committed
860
861
862
			fprintf(F, "\t.align 4\n");

			fprintf(F, "%s:\n", tbl.label);
Christian Würdig's avatar
Christian Würdig committed
863
864
865

			snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[0].target, buf));
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */\n",  tbl.branches[0].value);
Christian Würdig's avatar
Christian Würdig committed
866
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
867
868
869
870

			last_value = tbl.branches[0].value;
			for (i = 1; i < tbl.num_branches; ++i) {
				while (++last_value < tbl.branches[i].value) {
Christian Würdig's avatar
Christian Würdig committed
871
					snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.defProj, buf));
Christian Würdig's avatar
Christian Würdig committed
872
					snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */");
Christian Würdig's avatar
Christian Würdig committed
873
					IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
874
				}
875
				snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf));
Christian Würdig's avatar
Christian Würdig committed
876
				snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value);
Christian Würdig's avatar
Christian Würdig committed
877
				IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
878
879
			}

Christian Würdig's avatar
Christian Würdig committed
880
			fprintf(F, "\t.text");
Christian Würdig's avatar
Christian Würdig committed
881
882
883
		}
		else {
			/* one jump is enough */
Christian Würdig's avatar
Christian Würdig committed
884
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.branches[0].target, buf));
Christian Würdig's avatar
Christian Würdig committed
885
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* only one case given */");
Christian Würdig's avatar
Christian Würdig committed
886
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
887
888
889
890
		}
	}
	else { // no jump table
		for (i = 0; i < tbl.num_branches; ++i) {
Christian Würdig's avatar
Christian Würdig committed
891
			lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %d, %1S", tbl.branches[i].value, irn);
Christian Würdig's avatar
Christian Würdig committed
892
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", i);
Christian Würdig's avatar
Christian Würdig committed
893
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
894
895
896
			fprintf(F, "\tje %s\n", get_cfop_target(tbl.branches[i].target, buf));
		}

Christian Würdig's avatar
Christian Würdig committed
897
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.defProj, buf));
Christian Würdig's avatar
Christian Würdig committed
898
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */");
Christian Würdig's avatar
Christian Würdig committed
899
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
900
901
	}

Christian Würdig's avatar
Christian Würdig committed
902
903
	if (tbl.label)
		free(tbl.label);
Christian Würdig's avatar
Christian Würdig committed
904
905
906
907
908
909
910
	if (tbl.branches)
		free(tbl.branches);
}

/**
 * Emits code for a unconditional jump.
 */
Michael Beck's avatar
Michael Beck committed
911
static void emit_Jmp(const ir_node *irn, ia32_emit_env_t *env) {
912
	ir_node *block, *next_bl;
Christian Würdig's avatar
Christian Würdig committed
913
	FILE *F = env->out;
Christian Würdig's avatar
Christian Würdig committed
914
	char buf[SNPRINTF_BUF_LEN], cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
915

916
917
918
	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);

919
920
	/* we have a block schedule */
	next_bl = next_blk_sched(block);
921
922
	if (get_cfop_target_block(irn) != next_bl) {
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(irn, buf));
Christian Würdig's avatar
Christian Würdig committed
923
		lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%+F) */", irn, get_cfop_target_block(irn));
924
925
926
	}
	else {
		cmd_buf[0] = '\0';
Christian Würdig's avatar
Christian Würdig committed
927
		lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough %s */", get_cfop_target(irn, buf));
928
	}
Christian Würdig's avatar
Christian Würdig committed
929
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
930
931
}

Christian Würdig's avatar
Christian Würdig committed
932
933
934
935
936
937
938
939
940
941
942
/****************************
 *                  _
 *                 (_)
 *  _ __  _ __ ___  _  ___
 * | '_ \| '__/ _ \| |/ __|
 * | |_) | | | (_) | |\__ \
 * | .__/|_|  \___/| ||___/
 * | |            _/ |
 * |_|           |__/
 ****************************/

Christian Würdig's avatar
Christian Würdig committed
943
944
945
/**
 * Emits code for a proj -> node
 */
Michael Beck's avatar
Michael Beck committed
946
static void emit_Proj(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
947
948
	ir_node *pred = get_Proj_pred(irn);

Christian Würdig's avatar
Christian Würdig committed
949
	if (get_irn_op(pred) == op_Start) {
Christian Würdig's avatar
Christian Würdig committed
950
951
952
953
954
955
956
957
958
959
		switch(get_Proj_proj(irn)) {
			case pn_Start_X_initial_exec:
				emit_Jmp(irn, env);
				break;
			default:
				break;
		}
	}
}

960
961
962
963
964
965
966
967
968
969
970
/**********************************
 *   _____                  ____
 *  / ____|                |  _ \
 * | |     ___  _ __  _   _| |_) |
 * | |    / _ \| '_ \| | | |  _ <
 * | |___| (_) | |_) | |_| | |_) |
 *  \_____\___/| .__/ \__, |____/
 *             | |     __/ |
 *             |_|    |___/
 **********************************/

971
972
973
/**
 * Emit movsb/w instructions to make mov count divideable by 4
 */
974
static void emit_CopyB_prolog(FILE *F, int rem, int size) {
Christian Würdig's avatar
Christian Würdig committed
975
976
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

977
	fprintf(F, "\t/* memcopy %d bytes*/\n", size);
Christian Würdig's avatar
Christian Würdig committed
978
979
980

	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cld");
	snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* copy direction forward*/");
Christian Würdig's avatar
Christian Würdig committed
981
	IA32_DO_EMIT(NULL);
982
983
984

	switch(rem) {
		case 1:
Christian Würdig's avatar
Christian Würdig committed
985
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb");
Christian Würdig's avatar
Christian Würdig committed
986
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 1 */");
987
988
			break;
		case 2:
Christian Würdig's avatar
Christian Würdig committed
989
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw");
Christian Würdig's avatar
Christian Würdig committed
990
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 2 */");
991
992
			break;
		case 3:
Christian Würdig's avatar
Christian Würdig committed
993
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb");
Christian Würdig's avatar
Christian Würdig committed
994
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */");
Christian Würdig's avatar
Christian Würdig committed
995
			IA32_DO_EMIT(NULL);
Christian Würdig's avatar
Christian Würdig committed
996
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw");
Christian Würdig's avatar
Christian Würdig committed
997
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */");
998
999
			break;
	}
Christian Würdig's avatar
Christian Würdig committed
1000

Christian Würdig's avatar
Christian Würdig committed
1001
	IA32_DO_EMIT(NULL);
1002
1003
}

1004
1005
1006
/**
 * Emit rep movsd instruction for memcopy.
 */
Michael Beck's avatar
Michael Beck committed
1007
static void emit_ia32_CopyB(const ir_node *irn, ia32_emit_env_t *emit_env) {
1008
1009
1010
1011
	FILE   *F    = emit_env->out;
	tarval *tv   = get_ia32_Immop_tarval(irn);
	int     rem  = get_tarval_long(tv);
	int     size = get_tarval_long(get_ia32_Immop_tarval(get_irn_n(irn, 2)));
Christian Würdig's avatar
Christian Würdig committed
1012
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1013
1014
1015

	emit_CopyB_prolog(F, rem, size);

Christian Würdig's avatar
Christian Würdig committed
1016
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "rep movsd");
Christian Würdig's avatar
Christian Würdig committed
1017
	snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy */");
Christian Würdig's avatar
Christian Würdig committed
1018
	IA32_DO_EMIT(irn);
1019
1020
}

1021
1022
1023
/**
 * Emits unrolled memcopy.
 */
Michael Beck's avatar
Michael Beck committed
1024
static void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) {
1025
1026
1027
	tarval *tv   = get_ia32_Immop_tarval(irn);
	int     size = get_tarval_long(tv);
	FILE   *F    = emit_env->out;
Christian Würdig's avatar
Christian Würdig committed
1028
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1029
1030
1031
1032
1033

	emit_CopyB_prolog(F, size & 0x3, size);

	size >>= 2;
	while (size--) {
Christian Würdig's avatar
Christian Würdig committed
1034
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsd");
Christian Würdig's avatar
Christian Würdig committed
1035
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy unrolled */");
Christian Würdig's avatar
Christian Würdig committed
1036
		IA32_DO_EMIT(irn);
1037
1038
1039
	}
}

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


1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
/***************************
 *   _____
 *  / ____|
 * | |     ___  _ ____   __
 * | |    / _ \| '_ \ \ / /
 * | |___| (_) | | | \ V /
 *  \_____\___/|_| |_|\_/
 *
 ***************************/

/**
 * Emit code for conversions (I, FP), (FP, I) and (FP, FP).
 */
Christian Würdig's avatar
Christian Würdig committed
1055
static void emit_ia32_Conv_with_FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
1056
1057
1058
1059
	FILE               *F    = emit_env->out;
	const lc_arg_env_t *env  = ia32_get_arg_env();
	char               *from, *to, buf[64];
	ir_mode *src_mode, *tgt_mode;
Christian Würdig's avatar
Christian Würdig committed
1060
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072

	src_mode = is_ia32_AddrModeS(irn) ? get_ia32_ls_mode(irn) : get_irn_mode(get_irn_n(irn, 2));
	tgt_mode = get_ia32_res_mode(irn);

	from = mode_is_float(src_mode) ? (get_mode_size_bits(src_mode) == 32 ? "ss" : "sd") : "si";
	to   = mode_is_float(tgt_mode) ? (get_mode_size_bits(tgt_mode) == 32 ? "ss" : "sd") : "si";

	switch(get_ia32_op_type(irn)) {
		case ia32_Normal:
			lc_esnprintf(env, buf, sizeof(buf), "%1D, %3S", irn, irn);
			break;
		case ia32_AddrModeS:
1073
			lc_esnprintf(env, buf, sizeof(buf), "%1D, %s", irn, ia32_emit_am(irn, emit_env));
1074
1075
1076
1077
1078
			break;
		default:
			assert(0 && "unsupported op type for Conv");
	}

Christian Würdig's avatar
Christian Würdig committed
1079
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cvt%s2%s %s", from, to, buf);
Christian Würdig's avatar
Christian Würdig committed
1080
	lc_esnprintf(env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%+F, %+F) */", irn, src_mode, tgt_mode);
Christian Würdig's avatar
Christian Würdig committed
1081
	IA32_DO_EMIT(irn);
1082
1083
}

Michael Beck's avatar
Michael Beck committed
1084
static void emit_ia32_Conv_I2FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
1085
	emit_ia32_Conv_with_FP(irn, emit_env);
1086
1087
}

Michael Beck's avatar
Michael Beck committed
1088
static void emit_ia32_Conv_FP2I(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
1089
	emit_ia32_Conv_with_FP(irn, emit_env);
1090
1091
}

Michael Beck's avatar
Michael Beck committed
1092
static void emit_ia32_Conv_FP2FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
1093
	emit_ia32_Conv_with_FP(irn, emit_env);
1094
1095
}

Christian Würdig's avatar
Christian Würdig committed
1096
1097
1098
/**
 * Emits code for an Int conversion.
 */
Michael Beck's avatar
Michael Beck committed
1099
static void emit_ia32_Conv_I2I(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
1100
1101
1102
1103
1104
1105
1106
	FILE               *F    = emit_env->out;
	const lc_arg_env_t *env  = ia32_get_arg_env();
	char *move_cmd, *conv_cmd;
	ir_mode *src_mode, *tgt_mode;
	int n, m;
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
	const arch_register_t *in_reg, *out_reg;
1107

Christian Würdig's avatar
Christian Würdig committed
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
	src_mode = is_ia32_AddrModeS(irn) ? get_ia32_ls_mode(irn) : get_irn_mode(get_irn_n(irn, 2));
	tgt_mode = get_ia32_res_mode(irn);

	n = get_mode_size_bits(src_mode);
	m = get_mode_size_bits(tgt_mode);

	if (mode_is_signed(n < m ? src_mode : tgt_mode)) {
		move_cmd = "movsx";
		if (n == 8 || m == 8)
			conv_cmd = "cbw";
		else if (n == 16 || m == 16)
			conv_cmd = "cwde";
		else
			assert(0 && "unsupported Conv_I2I");
	}
	else {
		move_cmd = "movzx";
		conv_cmd = NULL;
	}

	switch(</