ia32_emitter.c 42.8 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"

34
#define BLOCK_PREFIX(x) ".L" x
Michael Beck's avatar
Michael Beck committed
35

Christian Würdig's avatar
Christian Würdig committed
36
37
#define SNPRINTF_BUF_LEN 128

38
/* global arch_env for lc_printf functions */
Christian Würdig's avatar
Christian Würdig committed
39
static const arch_env_t *arch_env = NULL;
40

Christian Würdig's avatar
Christian Würdig committed
41
42
43
44
45
46
47
48
49
50
51
/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/

52
53
54
/**
 * returns true if a node has x87 registers
 */
55
56
static int has_x87_register(const ir_node *n) {
	return is_irn_machine_user(n, 0);
57
58
}

Christian Würdig's avatar
Christian Würdig committed
59
60
61
/* 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;
62
63
}

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

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

Christian Würdig's avatar
Christian Würdig committed
80
81
82
83
84
85
86
	assert(reg && "no in register found");
	return reg;
}

/**
 * Returns the register at out position pos.
 */
Christian Würdig's avatar
Christian Würdig committed
87
static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
Christian Würdig's avatar
Christian Würdig committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
	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
116
117
118
	return reg;
}

Michael Beck's avatar
Michael Beck committed
119
120
121
122
123
enum io_direction {
  IN_REG,
  OUT_REG
};

Christian Würdig's avatar
Christian Würdig committed
124
125
126
/**
 * Returns the name of the in register at position pos.
 */
Michael Beck's avatar
Michael Beck committed
127
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
128
129
	const arch_register_t *reg;

Michael Beck's avatar
Michael Beck committed
130
	if (in_out == IN_REG) {
Christian Würdig's avatar
Christian Würdig committed
131
		reg = get_in_reg(irn, pos);
132
133
134
135
136
137

		if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]) {
			/* FIXME: works for binop only */
			assert(2 <= pos && pos <= 3);
			reg = get_ia32_attr(irn)->x87[pos - 2];
		}
Christian Würdig's avatar
Christian Würdig committed
138
139
	}
	else {
Christian Würdig's avatar
Christian Würdig committed
140
		/* destination address mode nodes don't have outputs */
141
		if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) {
Christian Würdig's avatar
Christian Würdig committed
142
143
144
			return "MEM";
		}

Christian Würdig's avatar
Christian Würdig committed
145
		reg = get_out_reg(irn, pos);
146
147
		if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp])
			reg = get_ia32_attr(irn)->x87[pos + 2];
Christian Würdig's avatar
Christian Würdig committed
148
	}
149
	return arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
150
151
152
153
154
155
156
157
158
159
160
161
162
}

/**
 * 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
163
		return lc_appendable_snadd(app, "(null)", 6);
Christian Würdig's avatar
Christian Würdig committed
164

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

167
168
	/* append the stupid % to register names */
	lc_appendable_chadd(app, '%');
Christian Würdig's avatar
Christian Würdig committed
169
	return lc_appendable_snadd(app, buf, strlen(buf));
170
171
}

Michael Beck's avatar
Michael Beck committed
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
 * Get the x87 register name for a node.
 */
static int ia32_get_x87_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;
	ia32_attr_t *attr;

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

	attr = get_ia32_attr(X);
	buf = attr->x87[nr]->name;
188
	lc_appendable_chadd(app, '%');
Michael Beck's avatar
Michael Beck committed
189
190
191
	return lc_appendable_snadd(app, buf, strlen(buf));
}

Christian Würdig's avatar
Christian Würdig committed
192
/**
193
 * Returns the tarval, offset or scale of an ia32 as a string.
Christian Würdig's avatar
Christian Würdig committed
194
195
196
197
198
199
200
201
202
203
 */
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);

204
	if (occ->conversion == 'C') {
Christian Würdig's avatar
Christian Würdig committed
205
		buf = get_ia32_cnst(X);
Christian Würdig's avatar
Christian Würdig committed
206
	}
207
	else { /* 'O' */
Christian Würdig's avatar
Christian Würdig committed
208
		buf = get_ia32_am_offs(X);
Christian Würdig's avatar
Christian Würdig committed
209
210
	}

Christian Würdig's avatar
Christian Würdig committed
211
	return buf ? lc_appendable_snadd(app, buf, strlen(buf)) : 0;
Christian Würdig's avatar
Christian Würdig committed
212
213
214
215
216
217
218
219
}

/**
 * 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
220
	ir_node *X    = arg->v_ptr;
221
222
223
224
225
	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
226
227
228
229

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

Christian Würdig's avatar
Christian Würdig committed
230
231
232
233
234
235
	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
236
237
238
239
240
241
242
}

/**
 * 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
243
	static lc_arg_env_t *env = NULL;
Christian Würdig's avatar
Christian Würdig committed
244

Christian Würdig's avatar
Christian Würdig committed
245
246
247
	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 };
Michael Beck's avatar
Michael Beck committed
248
	static const lc_arg_handler_t ia32_x87_handler   = { ia32_get_arg_type, ia32_get_x87_name };
Christian Würdig's avatar
Christian Würdig committed
249

Christian Würdig's avatar
Christian Würdig committed
250
251
252
	if(env == NULL) {
		/* extend the firm printer */
		env = firm_get_arg_env();
Christian Würdig's avatar
Christian Würdig committed
253

254
255
256
257
258
		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);
Michael Beck's avatar
Michael Beck committed
259
		lc_arg_register(env, "ia32:x87",  'X', &ia32_x87_handler);
Christian Würdig's avatar
Christian Würdig committed
260
	}
Christian Würdig's avatar
Christian Würdig committed
261

Christian Würdig's avatar
Christian Würdig committed
262
	return env;
Christian Würdig's avatar
Christian Würdig committed
263
264
}

Christian Würdig's avatar
Christian Würdig committed
265
266
267
268
269
270
271
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
272
			return (char *)arch_register_get_name(reg);
Christian Würdig's avatar
Christian Würdig committed
273
274
275
	}
}

Christian Würdig's avatar
Christian Würdig committed
276
277
278
/**
 * Emits registers and/or address mode of a binary operation.
 */
279
char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
280
	static char *buf = NULL;
Christian Würdig's avatar
Christian Würdig committed
281

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

285
286
287
288
289
290
#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
291

Christian Würdig's avatar
Christian Würdig committed
292
293
294
295
296
297
298
299
300
	if (! buf) {
		buf = xcalloc(1, SNPRINTF_BUF_LEN);
	}
	else {
		memset(buf, 0, SNPRINTF_BUF_LEN);
	}

	switch(get_ia32_op_type(n)) {
		case ia32_Normal:
301
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
Christian Würdig's avatar
Christian Würdig committed
302
303
304
305
306
				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
307
				const arch_register_t *out = PRODUCES_RESULT(n) ? get_out_reg(n, 0) : NULL;
Christian Würdig's avatar
Christian Würdig committed
308
				const arch_register_t *in;
Christian Würdig's avatar
Christian Würdig committed
309
				const char            *in_name;
Christian Würdig's avatar
Christian Würdig committed
310

Christian Würdig's avatar
Christian Würdig committed
311
312
313
				in      = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
				out     = out ? out : in1;
				in_name = arch_register_get_name(in);
Christian Würdig's avatar
Christian Würdig committed
314

Christian Würdig's avatar
Christian Würdig committed
315
316
317
318
319
320
				if (is_ia32_emit_cl(n)) {
					assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in) && "shift operation needs ecx");
					in_name = "cl";
				}

				snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", arch_register_get_name(out), in_name);
Christian Würdig's avatar
Christian Würdig committed
321
322
323
			}
			break;
		case ia32_AddrModeS:
324
325
326
327
328
			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 {
Christian Würdig's avatar
Christian Würdig committed
329
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, ia32_emit_am(n, env));
330
			}
Christian Würdig's avatar
Christian Würdig committed
331
332
			break;
		case ia32_AddrModeD:
333
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
334
335
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s,%s%s",
					ia32_emit_am(n, env),
336
337
					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
338
339
			}
			else {
340
				const arch_register_t *in1 = get_in_reg(n, 2);
Christian Würdig's avatar
Christian Würdig committed
341
				ir_mode              *mode = get_ia32_res_mode(n);
Christian Würdig's avatar
Christian Würdig committed
342
343
344
345
346
347
348
349
350
				const char           *in_name;

				mode    = mode ? mode : get_ia32_ls_mode(n);
				in_name = ia32_get_reg_name_for_mode(env, mode, in1);

				if (is_ia32_emit_cl(n)) {
					assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in1) && "shift operation needs ecx");
					in_name = "cl";
				}
351

Christian Würdig's avatar
Christian Würdig committed
352
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s", ia32_emit_am(n, env), in_name);
Christian Würdig's avatar
Christian Würdig committed
353
354
355
356
357
358
			}
			break;
		default:
			assert(0 && "unsupported op type");
	}

Christian Würdig's avatar
Christian Würdig committed
359
360
#undef PRODUCES_RESULT

Christian Würdig's avatar
Christian Würdig committed
361
362
363
	return buf;
}

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/**
 * Emits registers and/or address mode of a binary operation.
 */
char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env) {
	static char *buf = NULL;

	/* verify that this function is never called on non-AM supporting operations */
	//assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");

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

	switch(get_ia32_op_type(n)) {
		case ia32_Normal:
			if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) {
				lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
			}
			else {
				ia32_attr_t *attr = get_ia32_attr(n);
				const arch_register_t *in1 = attr->x87[0];
				const arch_register_t *in2 = attr->x87[1];
				const arch_register_t *out = attr->x87[2];
				const arch_register_t *in;
				const char            *in_name;

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

				snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", arch_register_get_name(out), in_name);
			}
			break;
		case ia32_AddrModeS:
		case ia32_AddrModeD:
			lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s", ia32_emit_am(n, env));
			break;
		default:
			assert(0 && "unsupported op type");
	}

#undef PRODUCES_RESULT

	return buf;
}

Christian Würdig's avatar
Christian Würdig committed
413
414
415
/**
 * Emits registers and/or address mode of a unary operation.
 */
416
char *ia32_emit_unop(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
417
418
419
420
421
422
423
424
425
426
427
	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:
428
429
430
431
432
433
			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
434
435
			break;
		case ia32_am_Dest:
436
			snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n, env));
Christian Würdig's avatar
Christian Würdig committed
437
438
439
440
441
442
443
444
445
			break;
		default:
			assert(0 && "unsupported op type");
	}

	return buf;
}

/**
446
 * Emits address mode.
Christian Würdig's avatar
Christian Würdig committed
447
 */
448
char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
	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
472
				obstack_printf(obst, "BYTE PTR ");
Christian Würdig's avatar
Christian Würdig committed
473
474
				break;
			case 16:
Christian Würdig's avatar
Christian Würdig committed
475
476
477
478
				obstack_printf(obst, "WORD PTR ");
				break;
			case 32:
				obstack_printf(obst, "DWORD PTR ");
Christian Würdig's avatar
Christian Würdig committed
479
				break;
480
481
			case 64:
				if (has_x87_register(n))
482
					/* ARGHHH: stupid gas x87 wants QWORD PTR but SSE must be WITHOUT */
483
484
485
486
487
488
					obstack_printf(obst, "QWORD PTR ");
				break;
			case 80:
			case 96:
				obstack_printf(obst, "XWORD PTR ");
				break;
Christian Würdig's avatar
Christian Würdig committed
489
490
491
492
493
			default:
				break;
		}
	}

494
495
496
497
498
499
	/* emit address mode symconst */
	if (get_ia32_am_sc(n)) {
		if (is_ia32_am_sc_sign(n))
			obstack_printf(obst, "-");
		obstack_printf(obst, "%s", get_id_str(get_ia32_am_sc(n)));
	}
Christian Würdig's avatar
Christian Würdig committed
500
501

	if (am_flav & ia32_B) {
502
		obstack_printf(obst, "[");
Christian Würdig's avatar
Christian Würdig committed
503
504
505
506
507
508
509
510
		lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
		had_output = 1;
	}

	if (am_flav & ia32_I) {
		if (had_output) {
			obstack_printf(obst, "+");
		}
511
512
513
		else {
			obstack_printf(obst, "[");
		}
Christian Würdig's avatar
Christian Würdig committed
514
515
516
517
518
519
520
521
522
523
524

		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) {
525
526
		s = get_ia32_am_offs(n);

527
528
529
530
531
532
533
		if (s) {
			/* omit explicit + if there was no base or index */
			if (! had_output) {
				obstack_printf(obst, "[");
				if (s[0] == '+')
					s++;
			}
534

535
536
537
			obstack_printf(obst, s);
			had_output = 1;
		}
Christian Würdig's avatar
Christian Würdig committed
538
539
	}

540
541
	if (had_output)
		obstack_printf(obst, "] ");
Christian Würdig's avatar
Christian Würdig committed
542
543
544
545
546
547
548
549
550
551

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

	return s;
}



Christian Würdig's avatar
Christian Würdig committed
552
553
554
/**
 * Formated print of commands and comments.
 */
Christian Würdig's avatar
Christian Würdig committed
555
556
557
558
559
560
561
562
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
563
564
565
566
}



Christian Würdig's avatar
Christian Würdig committed
567
/**
Christian Würdig's avatar
Christian Würdig committed
568
569
 * Add a number to a prefix. This number will not be used a second time.
 */
Christian Würdig's avatar
Christian Würdig committed
570
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
Christian Würdig's avatar
Christian Würdig committed
571
572
573
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
574
575
}

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

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

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

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

591
592
593
594
/*
 * coding of conditions
 */
struct cmp2conditon_t {
Christian Würdig's avatar
Christian Würdig committed
595
596
	const char *name;
	pn_Cmp      num;
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
};

/*
 * 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
625
626
627
	{ NULL,              pn_Cmp_False },  /* always false */
	{ "e",               pn_Cmp_Eq },     /* == */
	{ "b",               pn_Cmp_Lt },     /* < */
Christian Würdig's avatar
Christian Würdig committed
628
	{ "be",              pn_Cmp_Le },     /* <= */
Christian Würdig's avatar
Christian Würdig committed
629
630
631
632
633
634
635
636
637
638
639
640
	{ "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 */
641
642
643
644
645
};

/*
 * returns the condition code
 */
Christian Würdig's avatar
Christian Würdig committed
646
static const char *get_cmp_suffix(int cmp_code, int unsigned_cmp)
647
{
Christian Würdig's avatar
Christian Würdig committed
648
649
	assert(cmp2condition_s[cmp_code].num == cmp_code);
	assert(cmp2condition_u[cmp_code].num == cmp_code);
650

Christian Würdig's avatar
Christian Würdig committed
651
	return unsigned_cmp ? cmp2condition_u[cmp_code & 7].name : cmp2condition_s[cmp_code & 7].name;
652
653
}

654
655
656
657
658
659
660
/**
 * 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
661
662
663
664
/**
 * Returns the target label for a control flow node.
 */
static char *get_cfop_target(const ir_node *irn, char *buf) {
665
	ir_node *bl = get_cfop_target_block(irn);
666

Michael Beck's avatar
Michael Beck committed
667
	snprintf(buf, SNPRINTF_BUF_LEN, BLOCK_PREFIX("%ld"), get_irn_node_nr(bl));
Christian Würdig's avatar
Christian Würdig committed
668
669
	return buf;
}
670

671
672
/** Return the next block in Block schedule */
static ir_node *next_blk_sched(const ir_node *block) {
Michael Beck's avatar
Michael Beck committed
673
	return get_irn_link(block);
674
675
}

Christian Würdig's avatar
Christian Würdig committed
676
677
678
/**
 * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
 */
679
680
681
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
682
683
	const ir_edge_t *edge;
	char buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
684
685
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
686

687
	/* get both Proj's */
Christian Würdig's avatar
Christian Würdig committed
688
	edge = get_irn_out_edge_first(irn);
689
690
	proj1 = get_edge_src_irn(edge);
	assert(is_Proj(proj1) && "CondJmp with a non-Proj");
Christian Würdig's avatar
Christian Würdig committed
691

692
693
694
695
	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
696
	}
697
698
699

	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);
700
	if (proj2) {
701
		/* we have a block schedule */
702
		next_bl = next_blk_sched(block);
703
704
705
706
707
708
709
710
711
712
713

		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
714
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s",
Christian Würdig's avatar
Christian Würdig committed
715
					get_cmp_suffix(get_ia32_pncode(irn), !mode_is_signed(get_irn_mode(get_irn_n(irn, 0)))),
716
					get_cfop_target(proj1, buf));
Christian Würdig's avatar
Christian Würdig committed
717
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == TRUE */");
Christian Würdig's avatar
Christian Würdig committed
718
719
	}
	else  {
720
721
722
723
		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
724
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == FALSE */");
Christian Würdig's avatar
Christian Würdig committed
725
	}
Christian Würdig's avatar
Christian Würdig committed
726
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
727

728
729
730
731
	/* 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
732
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* otherwise */");
733
734
735
		}
		else {
			cmd_buf[0] = '\0';
Christian Würdig's avatar
Christian Würdig committed
736
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrogh %s */", get_cfop_target(proj2, buf));
737
		}
Christian Würdig's avatar
Christian Würdig committed
738
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
739
740
741
742
	}
}

/**
Christian Würdig's avatar
Christian Würdig committed
743
 * Emits code for conditional jump.
Christian Würdig's avatar
Christian Würdig committed
744
 */
745
static void CondJmp_emitter(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
746
	FILE *F = env->out;
Christian Würdig's avatar
Christian Würdig committed
747
748
	char cmd_buf[SNPRINTF_BUF_LEN];
	char cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
749

750
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cmp %s", ia32_emit_binop(irn, env));
Christian Würdig's avatar
Christian Würdig committed
751
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn);
Christian Würdig's avatar
Christian Würdig committed
752
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
753
	finish_CondJmp(F, irn, get_ia32_res_mode(irn));
Christian Würdig's avatar
Christian Würdig committed
754
755
}

Christian Würdig's avatar
Christian Würdig committed
756
757
758
/**
 * Emits code for conditional jump with two variables.
 */
759
static void emit_ia32_CondJmp(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
760
761
762
	CondJmp_emitter(irn, env);
}

763
764
765
766
/**
 * Emits code for conditional test and jump.
 */
static void TestJmp_emitter(const ir_node *irn, ia32_emit_env_t *env) {
767
768
769

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

Christian Würdig's avatar
Christian Würdig committed
770
	FILE       *F   = env->out;
Michael Beck's avatar
Michael Beck committed
771
	const char *op1 = arch_register_get_name(get_in_reg(irn, 0));
772
	const char *op2 = IA32_IS_IMMOP ? get_ia32_cnst(irn) : NULL;
Christian Würdig's avatar
Christian Würdig committed
773
774
	char        cmd_buf[SNPRINTF_BUF_LEN];
	char        cmnt_buf[SNPRINTF_BUF_LEN];
Michael Beck's avatar
Michael Beck committed
775

Christian Würdig's avatar
Christian Würdig committed
776
	if (! op2)
Michael Beck's avatar
Michael Beck committed
777
		op2 = arch_register_get_name(get_in_reg(irn, 1));
Christian Würdig's avatar
Christian Würdig committed
778

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

Christian Würdig's avatar
Christian Würdig committed
782
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
783
	finish_CondJmp(F, irn, get_ia32_res_mode(irn));
784
785

#undef IA32_IS_IMMOP
786
787
788
789
790
791
792
793
794
}

/**
 * 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);
}

795
796
797
798
799
800
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, " ");
Christian Würdig's avatar
Christian Würdig committed
801
	lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F omitted redundant test */", irn);
Christian Würdig's avatar
Christian Würdig committed
802
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
803
	finish_CondJmp(F, irn, get_ia32_res_mode(irn));
804
}
805

806
807
808
809
810
811
812
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
813
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
814
	finish_CondJmp(F, irn, get_ia32_res_mode(irn));
815
}
Christian Würdig's avatar
Christian Würdig committed
816
817
818
819
820
821
822
823
824
825
826
827
828

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

/* jump table entry (target and corresponding number) */
Christian Würdig's avatar
Christian Würdig committed
829
830
831
832
833
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

Christian Würdig's avatar
Christian Würdig committed
834
/* jump table for switch generation */
Christian Würdig's avatar
Christian Würdig committed
835
typedef struct _jmp_tbl_t {
Christian Würdig's avatar
Christian Würdig committed
836
837
838
839
840
841
	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
842
843
} jmp_tbl_t;

Christian Würdig's avatar
Christian Würdig committed
844
845
846
/**
 * Compare two variables of type branch_t. Used to sort all switch cases
 */
Christian Würdig's avatar
Christian Würdig committed
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
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
862
static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) {
Christian Würdig's avatar
Christian Würdig committed
863
864
	unsigned long       interval;
	char                buf[SNPRINTF_BUF_LEN];
865
	int                 last_value, i, pn;
Christian Würdig's avatar
Christian Würdig committed
866
867
868
869
870
	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
871
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
Christian Würdig's avatar
Christian Würdig committed
872
873

	/* fill the table structure */
874
	tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
Christian Würdig's avatar
Christian Würdig committed
875
876
877
	tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
	tbl.defProj      = NULL;
	tbl.num_branches = get_irn_n_edges(irn);
878
	tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
Christian Würdig's avatar
Christian Würdig committed
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
	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
907
	qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), ia32_cmp_branch_t);
Christian Würdig's avatar
Christian Würdig committed
908
909
910
911

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

912
	/* emit the table */
Christian Würdig's avatar
Christian Würdig committed
913
914
915
	lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %u", irn, interval);
	snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* compare for switch */");
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
916

917
918
919
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "ja %s", get_cfop_target(tbl.defProj, buf));
	snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default jump if out of range  */");
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
920

921
922
	if (tbl.num_branches > 1) {
		/* create table */
Christian Würdig's avatar
Christian Würdig committed
923

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

928
929
		fprintf(F, "\t.section\t.rodata\n");
		fprintf(F, "\t.align 4\n");
Christian Würdig's avatar
Christian Würdig committed
930

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

933
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[0].target, buf));
Christian Würdig's avatar
Christian Würdig committed
934
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */",  tbl.branches[0].value);
935
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
936

937
938
939
940
941
		last_value = tbl.branches[0].value;
		for (i = 1; i < tbl.num_branches; ++i) {
			while (++last_value < tbl.branches[i].value) {
				snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.defProj, buf));
				snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */");
Christian Würdig's avatar
Christian Würdig committed
942
				IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
943
			}
944
945
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf));
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value);
Christian Würdig's avatar
Christian Würdig committed
946
			IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
947
948
		}

Christian Würdig's avatar
Christian Würdig committed
949
		fprintf(F, "\n\t.text\n\n");
950
951
952
953
954
	}
	else {
		/* one jump is enough */
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.branches[0].target, buf));
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* only one case given */");
Christian Würdig's avatar
Christian Würdig committed
955
		IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
956
957
	}

Christian Würdig's avatar
Christian Würdig committed
958
959
	if (tbl.label)
		free(tbl.label);
Christian Würdig's avatar
Christian Würdig committed
960
961
962
963
964
965
966
	if (tbl.branches)
		free(tbl.branches);
}

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

972
973
974
	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);

975
976
	/* we have a block schedule */
	next_bl = next_blk_sched(block);
977
978
	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
979
		lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%+F) */", irn, get_cfop_target_block(irn));
980
981
982
	}
	else {
		cmd_buf[0] = '\0';
Christian Würdig's avatar
Christian Würdig committed
983
		lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough %s */", get_cfop_target(irn, buf));
984
	}
Christian Würdig's avatar
Christian Würdig committed
985
	IA32_DO_EMIT(irn);
Christian Würdig's avatar
Christian Würdig committed
986
987
}

Christian Würdig's avatar
Christian Würdig committed
988
989
990
991
992
993
994
995
996
997
998
/****************************
 *                  _
 *                 (_)
 *  _ __  _ __ ___  _  ___
 * | '_ \| '__/ _ \| |/ __|
 * | |_) | | | (_) | |\__ \
 * | .__/|_|  \___/| ||___/
 * | |            _/ |
 * |_|           |__/
 ****************************/

Christian Würdig's avatar
Christian Würdig committed
999
1000
1001
/**
 * Emits code for a proj -> node
 */
Michael Beck's avatar
Michael Beck committed
1002
static void emit_Proj(const ir_node *irn, ia32_emit_env_t *env) {
Christian Würdig's avatar
Christian Würdig committed
1003
1004
	ir_node *pred = get_Proj_pred(irn);

Christian Würdig's avatar
Christian Würdig committed
1005
	if (get_irn_op(pred) == op_Start) {
Christian Würdig's avatar
Christian Würdig committed
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
		switch(get_Proj_proj(irn)) {
			case pn_Start_X_initial_exec:
				emit_Jmp(irn, env);
				break;
			default:
				break;
		}
	}
}

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
/**********************************
 *   _____                  ____
 *  / ____|                |  _ \
 * | |     ___  _ __  _   _| |_) |
 * | |    / _ \| '_ \| | | |  _ <
 * | |___| (_) | |_) | |_| | |_) |
 *  \_____\___/| .__/ \__, |____/
 *             | |     __/ |
 *             |_|    |___/
 **********************************/

1027
1028
1029
/**
 * Emit movsb/w instructions to make mov count divideable by 4
 */
1030
static void emit_CopyB_prolog(FILE *F, int rem, int size) {
Christian Würdig's avatar
Christian Würdig committed
1031
1032
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

1033
	fprintf(F, "\t/* memcopy %d bytes*/\n", size);
Christian Würdig's avatar
Christian Würdig committed
1034
1035
1036

	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
1037
	IA32_DO_EMIT(NULL);
1038
1039
1040

	switch(rem) {
		case 1:
Christian Würdig's avatar
Christian Würdig committed
1041
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb");
Christian Würdig's avatar
Christian Würdig committed
1042
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 1 */");
1043
1044
			break;
		case 2:
Christian Würdig's avatar
Christian Würdig committed
1045
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw");
Christian Würdig's avatar
Christian Würdig committed
1046
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 2 */");
1047
1048
			break;
		case 3:
Christian Würdig's avatar
Christian Würdig committed
1049
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb");
Christian Würdig's avatar
Christian Würdig committed
1050
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */");
Christian Würdig's avatar
Christian Würdig committed
1051
			IA32_DO_EMIT(NULL);
Christian Würdig's avatar
Christian Würdig committed
1052
			snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw");
Christian Würdig's avatar
Christian Würdig committed
1053
			snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */");
1054
1055
			break;
	}
Christian Würdig's avatar
Christian Würdig committed
1056

Christian Würdig's avatar
Christian Würdig committed
1057
	IA32_DO_EMIT(NULL);
1058
1059
}

1060
1061
1062
/**
 * Emit rep movsd instruction for memcopy.
 */
Michael Beck's avatar
Michael Beck committed
1063
static void emit_ia32_CopyB(const ir_node *irn, ia32_emit_env_t *emit_env) {
1064
1065
1066
1067
	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
1068
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1069
1070
1071

	emit_CopyB_prolog(F, rem, size);

Christian Würdig's avatar
Christian Würdig committed
1072
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "rep movsd");
Christian Würdig's avatar
Christian Würdig committed
1073
	snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy */");
Christian Würdig's avatar
Christian Würdig committed
1074
	IA32_DO_EMIT(irn);
1075
1076
}

1077
1078
1079
/**
 * Emits unrolled memcopy.
 */
Michael Beck's avatar
Michael Beck committed
1080
static void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) {
1081
1082
1083
	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
1084
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1085
1086
1087
1088
1089

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

	size >>= 2;
	while (size--) {
Christian Würdig's avatar
Christian Würdig committed
1090
		snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsd");
Christian Würdig's avatar
Christian Würdig committed
1091
		snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy unrolled */");
Christian Würdig's avatar
Christian Würdig committed
1092
		IA32_DO_EMIT(irn);
1093
1094
1095
	}
}

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


1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
/***************************
 *   _____
 *  / ____|
 * | |     ___  _ ____   __
 * | |    / _ \| '_ \ \ / /
 * | |___| (_) | | | \ V /
 *  \_____\___/|_| |_|\_/
 *
 ***************************/

/**
 * Emit code for conversions (I, FP), (FP, I) and (FP, FP).
 */
Christian Würdig's avatar
Christian Würdig committed
1111
static void emit_ia32_Conv_with_FP(const ir_node *irn, ia32_emit_env_t *emit_env) {
1112
1113
1114
1115
	FILE               *F        = emit_env->out;
	const lc_arg_env_t *env      = ia32_get_arg_env();
	ir_mode	           *src_mode = get_ia32_src_mode(irn);
	ir_mode            *tgt_mode = get_ia32_tgt_mode(irn);
1116
	char               *from, *to, buf[64];
Christian Würdig's avatar
Christian Würdig committed
1117
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
1118
1119
1120
1121
1122
1123
1124
1125
1126

	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:
1127
			lc_esnprintf(env, buf, sizeof(buf), "%1D, %s", irn, ia32_emit_am(irn, emit_env));
1128
1129
1130
1131
1132
			break;
		default:
			assert(0 && "unsupported op type for Conv");
	}

Christian Würdig's avatar
Christian Würdig committed
1133
	snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cvt%s2%s %s", from