amd64_emitter.c 23.6 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
4
5
6
7
8
9
 */

/**
 * @file
 * @brief   emit assembler for a backend graph
 */
Matthias Braun's avatar
Matthias Braun committed
10
#include <inttypes.h>
11

12
13
14
#include "amd64_emitter.h"
#include "amd64_new_nodes.h"
#include "amd64_nodes_attr.h"
15
#include "be_t.h"
16
#include "beasm.h"
17
#include "beblocksched.h"
18
#include "bediagnostic.h"
19
20
#include "begnuas.h"
#include "beirg.h"
21
#include "benode.h"
22
#include "besched.h"
23
#include "gen_amd64_emitter.h"
24
#include "gen_amd64_regalloc_if.h"
25
26
#include "irgwalk.h"
#include "panic.h"
27

28
29
static be_stack_layout_t *layout;

Christoph Mallon's avatar
Christoph Mallon committed
30
31
32
33
/**
 * Returns the target block for a control flow node.
 */
static ir_node *get_cfop_target_block(const ir_node *irn)
34
{
Christoph Mallon's avatar
Christoph Mallon committed
35
	return (ir_node*)get_irn_link(irn);
36
37
}

38
static char get_gp_mode_suffix(const amd64_insn_mode_t mode)
39
40
{
	switch (mode) {
41
42
43
44
	case INSN_MODE_8:  return 'b';
	case INSN_MODE_16: return 'w';
	case INSN_MODE_32: return 'l';
	case INSN_MODE_64: return 'q';
45
	case INSN_MODE_128:
46
47
	case INSN_MODE_INVALID:
		break;
48
	}
49
50
51
52
53
54
	panic("invalid insn mode");
}

static void amd64_emit_insn_mode_suffix(const amd64_insn_mode_t mode)
{
	be_emit_char(get_gp_mode_suffix(mode));
55
56
}

57
static char get_xmm_mode_suffix(const amd64_insn_mode_t mode)
58
{
59
	switch (mode) {
60
61
62
63
64
65
66
	case INSN_MODE_32:  return 's';
	case INSN_MODE_64:  return 'd';
	case INSN_MODE_128: return 'q';
	case INSN_MODE_8:
	case INSN_MODE_16:
	case INSN_MODE_INVALID:
		break;
67
	}
68
69
70
71
72
73
	panic("invalid insn mode");
}

static void amd64_emit_xmm_mode_suffix(const amd64_insn_mode_t mode)
{
	be_emit_char(get_xmm_mode_suffix(mode));
74
75
}

76
static const char *get_register_name_8bit(const arch_register_t *reg)
77
{
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
	switch (reg->global_index) {
	case REG_RAX: return "al";
	case REG_RBX: return "bl";
	case REG_RCX: return "cl";
	case REG_RDX: return "dl";
	case REG_RSP: return "spl";
	case REG_RBP: return "bpl";
	case REG_RSI: return "sil";
	case REG_RDI: return "dil";
	case REG_R8:  return "r8b";
	case REG_R9:  return "r9b";
	case REG_R10: return "r10b";
	case REG_R11: return "r11b";
	case REG_R12: return "r12b";
	case REG_R13: return "r13b";
	case REG_R14: return "r14b";
	case REG_R15: return "r15b";
95
96
	}
	panic("unexpected register number");
97
98
}

99
100
101
102
103
104
105
106
107
108
109
static const char *get_register_name_8bit_high(const arch_register_t *reg)
{
	switch (reg->global_index) {
	case REG_RAX: return "ah";
	case REG_RBX: return "bh";
	case REG_RCX: return "ch";
	case REG_RDX: return "dh";
	}
	panic("unexpected register number");
}

110
static const char *get_register_name_16bit(const arch_register_t *reg)
111
{
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	switch (reg->global_index) {
	case REG_RAX: return "ax";
	case REG_RBX: return "bx";
	case REG_RCX: return "cx";
	case REG_RDX: return "dx";
	case REG_RSP: return "sp";
	case REG_RBP: return "bp";
	case REG_RSI: return "si";
	case REG_RDI: return "di";
	case REG_R8:  return "r8w";
	case REG_R9:  return "r9w";
	case REG_R10: return "r10w";
	case REG_R11: return "r11w";
	case REG_R12: return "r12w";
	case REG_R13: return "r13w";
	case REG_R14: return "r14w";
	case REG_R15: return "r15w";
129
130
	}
	panic("unexpected register number");
131
132
}

133
static const char *get_register_name_32bit(const arch_register_t *reg)
134
{
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	switch (reg->global_index) {
	case REG_RAX: return "eax";
	case REG_RBX: return "ebx";
	case REG_RCX: return "ecx";
	case REG_RDX: return "edx";
	case REG_RSP: return "esp";
	case REG_RBP: return "ebp";
	case REG_RSI: return "esi";
	case REG_RDI: return "edi";
	case REG_R8:  return "r8d";
	case REG_R9:  return "r9d";
	case REG_R10: return "r10d";
	case REG_R11: return "r11d";
	case REG_R12: return "r12d";
	case REG_R13: return "r13d";
	case REG_R14: return "r14d";
	case REG_R15: return "r15d";
152
153
	}
	panic("unexpected register number");
154
155
156
157
158
159
160
161
}

static void emit_register(const arch_register_t *reg)
{
	be_emit_char('%');
	be_emit_string(reg->name);
}

162
163
static const char *get_register_name_mode(const arch_register_t *reg,
                                          const amd64_insn_mode_t mode)
164
165
{
	switch (mode) {
166
167
168
	case INSN_MODE_8:  return get_register_name_8bit(reg);
	case INSN_MODE_16: return get_register_name_16bit(reg);
	case INSN_MODE_32: return get_register_name_32bit(reg);
169
	case INSN_MODE_64:
170
171
172
	case INSN_MODE_128: return reg->name;
	case INSN_MODE_INVALID:
		break;
173
	}
174
175
176
177
178
179
	panic("invalid mode");
}

static void emit_register_insn_mode(const arch_register_t *reg,
                                    const amd64_insn_mode_t mode)
{
180
	be_emit_char('%');
181
	be_emit_string(get_register_name_mode(reg, mode));
182
183
}

184
static void emit_register_mode(const arch_register_t *reg,
185
186
                               amd64_insn_mode_t insn_mode)
{
187
	if (reg->cls == &amd64_reg_classes[CLASS_amd64_xmm]) {
188
189
190
191
192
193
		emit_register(reg);
	} else {
		emit_register_insn_mode(reg, insn_mode);
	}
}

194
typedef enum amd64_emit_mod_t {
195
196
197
198
199
	EMIT_NONE          = 0,
	EMIT_IGNORE_MODE   = 1U << 1,
	EMIT_FORCE_32      = 1U << 2,
	EMIT_CONV_DEST     = 1U << 3,
	EMIT_INDIRECT_STAR = 1U << 4,
200
} amd64_emit_mod_t;
yb9976's avatar
yb9976 committed
201
ENUM_BITSET(amd64_emit_mod_t)
202

Matthias Braun's avatar
Matthias Braun committed
203
static void emit_relocation_no_offset(x86_immediate_kind_t const kind,
204
                                      ir_entity const *const entity)
205
{
Matthias Braun's avatar
Matthias Braun committed
206
207
	be_gas_emit_entity(entity);
	switch (kind) {
Matthias Braun's avatar
Matthias Braun committed
208
209
210
	case X86_IMM_ADDR:
	case X86_IMM_PCREL:
		return;
Matthias Braun's avatar
Matthias Braun committed
211
	case X86_IMM_GOTPCREL: be_emit_cstring("@GOTPCREL"); return;
Matthias Braun's avatar
Matthias Braun committed
212
213
214
215
216
	case X86_IMM_VALUE:
	case X86_IMM_TLS_IE:
	case X86_IMM_TLS_LE:
	case X86_IMM_PICBASE_REL:
	case X86_IMM_FRAMEOFFSET:
217
218
219
	case X86_IMM_GOT:
	case X86_IMM_GOTOFF:
	case X86_IMM_PLT:
Matthias Braun's avatar
Matthias Braun committed
220
		break;
221
	}
Matthias Braun's avatar
Matthias Braun committed
222
	panic("unexpected or invalid immediate kind");
223
224
}

Matthias Braun's avatar
Matthias Braun committed
225
226
227
228
229
230
231
232
233
234
235
236
237
238
static void amd64_emit_immediate64(const amd64_imm64_t *const imm)
{
	if (imm->kind == X86_IMM_VALUE) {
		assert(imm->entity == NULL);
		be_emit_irprintf("0x%" PRIX64, imm->offset);
		return;
	}
	emit_relocation_no_offset(imm->kind, imm->entity);
	if (imm->offset != 0)
		be_emit_irprintf("%+" PRId64, imm->offset);
}

static void amd64_emit_immediate32(bool const prefix,
                                   x86_imm32_t const *const imm)
Matthias Braun's avatar
Matthias Braun committed
239
{
240
241
	if (prefix)
		be_emit_char('$');
Matthias Braun's avatar
Matthias Braun committed
242
243
244
	if (imm->kind == X86_IMM_VALUE) {
		assert(imm->entity == NULL);
		be_emit_irprintf("%" PRId32, imm->offset);
Matthias Braun's avatar
Matthias Braun committed
245
		return;
Matthias Braun's avatar
Matthias Braun committed
246
	}
Matthias Braun's avatar
Matthias Braun committed
247
248
249
	emit_relocation_no_offset(imm->kind, imm->entity);
	if (imm->offset != 0)
		be_emit_irprintf("%+" PRId32, imm->offset);
Matthias Braun's avatar
Matthias Braun committed
250
251
}

252
253
254
255
256
257
static bool is_fp_relative(const ir_entity *entity)
{
	ir_type *owner = get_entity_owner(entity);
	return is_frame_type(owner) || owner == layout->arg_type;
}

Matthias Braun's avatar
Matthias Braun committed
258
static void amd64_emit_addr(const ir_node *const node,
Matthias Braun's avatar
Matthias Braun committed
259
                            const amd64_addr_t *const addr)
Matthias Braun's avatar
Matthias Braun committed
260
{
Matthias Braun's avatar
Matthias Braun committed
261
	ir_entity *entity = addr->immediate.entity;
Matthias Braun's avatar
Matthias Braun committed
262
	if (entity != NULL) {
263
		if (is_fp_relative(entity)) {
Matthias Braun's avatar
Matthias Braun committed
264
265
			entity = NULL; /* only emit offset for frame entities */
		} else {
266
			emit_relocation_no_offset(addr->immediate.kind, entity);
Matthias Braun's avatar
Matthias Braun committed
267
		}
Matthias Braun's avatar
Matthias Braun committed
268
269
	}

Matthias Braun's avatar
Matthias Braun committed
270
271
272
	int32_t offset      = addr->immediate.offset;
	uint8_t base_input  = addr->base_input;
	uint8_t index_input = addr->index_input;
Matthias Braun's avatar
Matthias Braun committed
273
274
275
	if (offset != 0 || (entity == NULL && base_input == NO_INPUT
	                    && index_input == NO_INPUT)) {
		if (entity != NULL) {
Matthias Braun's avatar
Matthias Braun committed
276
			be_emit_irprintf("%+" PRId32, offset);
Matthias Braun's avatar
Matthias Braun committed
277
		} else {
Matthias Braun's avatar
Matthias Braun committed
278
			be_emit_irprintf("%" PRId32, offset);
Matthias Braun's avatar
Matthias Braun committed
279
280
281
282
283
284
285
286
287
288
289
290
		}
	}

	if (base_input != NO_INPUT || index_input != NO_INPUT) {
		be_emit_char('(');

		if (base_input == RIP_INPUT) {
			be_emit_cstring("%rip");
		} else if (base_input != NO_INPUT) {
			const arch_register_t *reg
				= arch_get_irn_register_in(node, base_input);
			emit_register(reg);
Matthias Braun's avatar
Matthias Braun committed
291
292
293
294
295
296
297
		}

		if (index_input != NO_INPUT) {
			be_emit_char(',');
			const arch_register_t *reg
				= arch_get_irn_register_in(node, index_input);
			emit_register(reg);
Matthias Braun's avatar
Matthias Braun committed
298

Matthias Braun's avatar
Matthias Braun committed
299
			unsigned scale = addr->log_scale;
Matthias Braun's avatar
Matthias Braun committed
300
301
302
303
304
305
306
			if (scale > 0)
				be_emit_irprintf(",%u", 1 << scale);
		}
		be_emit_char(')');
	}
}

307
static void amd64_emit_am(const ir_node *const node, bool indirect_star)
Matthias Braun's avatar
Matthias Braun committed
308
{
Matthias Braun's avatar
Matthias Braun committed
309
	const amd64_addr_attr_t *const attr = get_amd64_addr_attr_const(node);
310

Matthias Braun's avatar
Matthias Braun committed
311
312
313
314
	switch ((amd64_op_mode_t)attr->base.op_mode) {
	case AMD64_OP_REG_IMM: {
		const amd64_binop_addr_attr_t *const binop_attr
			= (const amd64_binop_addr_attr_t*)attr;
315
		amd64_emit_immediate32(true, &binop_attr->u.immediate);
Matthias Braun's avatar
Matthias Braun committed
316
317
		be_emit_cstring(", ");
		const arch_register_t *reg = arch_get_irn_register_in(node, 0);
318
		emit_register_mode(reg, binop_attr->base.insn_mode);
Matthias Braun's avatar
Matthias Braun committed
319
320
		return;
	}
Matthias Braun's avatar
Matthias Braun committed
321
322
323
	case AMD64_OP_REG_REG: {
		const amd64_addr_attr_t *const addr_attr
			= (const amd64_addr_attr_t*)attr;
Matthias Braun's avatar
Matthias Braun committed
324
325
		const arch_register_t *reg0 = arch_get_irn_register_in(node, 0);
		const arch_register_t *reg1 = arch_get_irn_register_in(node, 1);
326
		emit_register_mode(reg1, addr_attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
327
		be_emit_cstring(", ");
328
		emit_register_mode(reg0, addr_attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
329
330
		return;
	}
331
	case AMD64_OP_REG_ADDR: {
Matthias Braun's avatar
Matthias Braun committed
332
333
334
		const amd64_binop_addr_attr_t *const binop_attr
			= (const amd64_binop_addr_attr_t*)attr;
		amd64_emit_addr(node, &attr->addr);
Matthias Braun's avatar
Matthias Braun committed
335
336
		be_emit_cstring(", ");
		const arch_register_t *reg
Matthias Braun's avatar
Matthias Braun committed
337
			= arch_get_irn_register_in(node, binop_attr->u.reg_input);
338
		emit_register_mode(reg, binop_attr->base.insn_mode);
Matthias Braun's avatar
Matthias Braun committed
339
340
		return;
	}
Matthias Braun's avatar
Matthias Braun committed
341
342
343
344
	case AMD64_OP_ADDR_IMM:
		panic("ADDR_IMM TODO");
	case AMD64_OP_ADDR:
		amd64_emit_addr(node, &attr->addr);
Matthias Braun's avatar
Matthias Braun committed
345
		return;
346
347
348
349
350
351
352
353
	case AMD64_OP_ADDR_REG: {
		amd64_binop_addr_attr_t const *const binop_attr = (amd64_binop_addr_attr_t const*)attr;
		arch_register_t const *const reg = arch_get_irn_register_in(node, binop_attr->u.reg_input);
		emit_register_mode(reg, binop_attr->base.insn_mode);
		be_emit_cstring(", ");
		amd64_emit_addr(node, &attr->addr);
		return;
	}
354
	case AMD64_OP_UNOP_REG:
355
356
357
		if (indirect_star)
			be_emit_char('*');
		/* FALLTHROUGH */
Matthias Braun's avatar
Matthias Braun committed
358
359
	case AMD64_OP_REG: {
		const arch_register_t *reg = arch_get_irn_register_in(node, 0);
360
		emit_register_mode(reg, attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
361
362
		return;
	}
363
	case AMD64_OP_UNOP_IMM32:
364
		amd64_emit_immediate32(false, &attr->addr.immediate);
Matthias Braun's avatar
Matthias Braun committed
365
		return;
366
	case AMD64_OP_UNOP_ADDR:
367
368
		if (indirect_star)
			be_emit_char('*');
Matthias Braun's avatar
Matthias Braun committed
369
370
		amd64_emit_addr(node, &attr->addr);
		return;
371
372
373

	case AMD64_OP_RAX_REG: {
		const arch_register_t *reg = arch_get_irn_register_in(node, 1);
374
		emit_register_mode(reg, attr->insn_mode);
375
376
377
378
379
380
		return;
	}

	case AMD64_OP_RAX_ADDR:
		amd64_emit_addr(node, &attr->addr);
		return;
Matthias Braun's avatar
Matthias Braun committed
381
382
383
384
385
386
	case AMD64_OP_IMM32:
	case AMD64_OP_IMM64:
	case AMD64_OP_NONE:
	case AMD64_OP_SHIFT_REG:
	case AMD64_OP_SHIFT_IMM:
		break;
Matthias Braun's avatar
Matthias Braun committed
387
388
389
390
	}
	panic("invalid op_mode");
}

Matthias Braun's avatar
Matthias Braun committed
391
392
static amd64_insn_mode_t get_amd64_insn_mode(const ir_node *node)
{
393
	if (is_amd64_mov_imm(node)) {
Matthias Braun's avatar
Matthias Braun committed
394
395
396
397
398
399
400
401
402
403
		const amd64_movimm_attr_t *const attr
			= get_amd64_movimm_attr_const(node);
		return attr->insn_mode;
	} else {
		amd64_addr_attr_t const *const attr = get_amd64_addr_attr_const(node);
		return attr->insn_mode;
	}
}


Matthias Braun's avatar
Matthias Braun committed
404
405
static void emit_shiftop(const ir_node *const node)
{
Matthias Braun's avatar
Matthias Braun committed
406
	amd64_shift_attr_t const *const attr = get_amd64_shift_attr_const(node);
407

Matthias Braun's avatar
Matthias Braun committed
408
409
410
	switch (attr->base.op_mode) {
	case AMD64_OP_SHIFT_IMM: {
		be_emit_irprintf("$0x%X, ", attr->immediate);
Matthias Braun's avatar
Matthias Braun committed
411
		const arch_register_t *reg = arch_get_irn_register_in(node, 0);
412
		emit_register_mode(reg, attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
413
414
		return;
	}
Matthias Braun's avatar
Matthias Braun committed
415
	case AMD64_OP_SHIFT_REG: {
Matthias Braun's avatar
Matthias Braun committed
416
417
		const arch_register_t *reg0 = arch_get_irn_register_in(node, 0);
		const arch_register_t *reg1 = arch_get_irn_register_in(node, 1);
418
		emit_register_mode(reg1, INSN_MODE_8);
Matthias Braun's avatar
Matthias Braun committed
419
		be_emit_cstring(", ");
420
		emit_register_mode(reg0, attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
421
422
		return;
	}
Matthias Braun's avatar
Matthias Braun committed
423
424
	default:
		break;
Matthias Braun's avatar
Matthias Braun committed
425
426
427
428
	}
	panic("invalid op_mode for shiftop");
}

Christoph Mallon's avatar
Christoph Mallon committed
429
void amd64_emitf(ir_node const *const node, char const *fmt, ...)
430
{
Christoph Mallon's avatar
Christoph Mallon committed
431
432
	va_list ap;
	va_start(ap, fmt);
433

Christoph Mallon's avatar
Christoph Mallon committed
434
435
436
	be_emit_char('\t');
	for (;;) {
		char const *start = fmt;
437

Christoph Mallon's avatar
Christoph Mallon committed
438
439
440
441
442
		while (*fmt != '%' && *fmt != '\n' && *fmt != '\0')
			++fmt;
		if (fmt != start) {
			be_emit_string_len(start, fmt - start);
		}
443

Christoph Mallon's avatar
Christoph Mallon committed
444
445
446
447
448
449
450
		if (*fmt == '\n') {
			be_emit_char('\n');
			be_emit_write_line();
			be_emit_char('\t');
			++fmt;
			continue;
		}
451

Christoph Mallon's avatar
Christoph Mallon committed
452
453
454
455
		if (*fmt == '\0')
			break;

		++fmt;
456
457
458
		amd64_emit_mod_t mod = EMIT_NONE;
		for (;;) {
			switch (*fmt) {
459
460
461
462
			case '^': mod |= EMIT_IGNORE_MODE;   break;
			case '3': mod |= EMIT_FORCE_32;      break;
			case '#': mod |= EMIT_CONV_DEST;     break;
			case '*': mod |= EMIT_INDIRECT_STAR; break;
463
464
465
466
467
468
			default:
				goto end_of_mods;
			}
			++fmt;
		}
end_of_mods:
Christoph Mallon's avatar
Christoph Mallon committed
469
470
471
472
473
474
475
476

		switch (*fmt++) {
			arch_register_t const *reg;

			case '%':
				be_emit_char('%');
				break;

477
478
			case 'A':
				switch (*fmt++) {
Matthias Braun's avatar
Matthias Braun committed
479
				case 'M':
480
					amd64_emit_am(node, mod & EMIT_INDIRECT_STAR);
481
					break;
Matthias Braun's avatar
Matthias Braun committed
482
				default: {
Matthias Braun's avatar
Matthias Braun committed
483
484
485
					amd64_addr_attr_t const *const attr
						= get_amd64_addr_attr_const(node);
					amd64_emit_addr(node, &attr->addr);
Matthias Braun's avatar
Matthias Braun committed
486
					--fmt;
487
488
489
490
				}
				}
				break;

Christoph Mallon's avatar
Christoph Mallon committed
491
			case 'C': {
492
493
				amd64_movimm_attr_t const *const attr
					= get_amd64_movimm_attr_const(node);
Matthias Braun's avatar
Matthias Braun committed
494
				amd64_emit_immediate64(&attr->immediate);
Christoph Mallon's avatar
Christoph Mallon committed
495
496
497
498
				break;
			}

			case 'D':
499
				if (!is_digit(*fmt))
Christoph Mallon's avatar
Christoph Mallon committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
					goto unknown;
				reg = arch_get_irn_register_out(node, *fmt++ - '0');
				goto emit_R;

			case 'E': {
				ir_entity const *const ent = va_arg(ap, ir_entity const*);
				be_gas_emit_entity(ent);
				break;
			}

			case 'L': {
				ir_node *const block = get_cfop_target_block(node);
				be_gas_emit_block_name(block);
				break;
			}

516
517
518
519
520
521
522
523
524
525
526
527
			case 'P': {
				x86_condition_code_t cc;
				if (*fmt == 'X') {
					++fmt;
					cc = (x86_condition_code_t)va_arg(ap, int);
				} else {
					panic("unknown modifier");
				}
				x86_emit_condition_code(cc);
				break;
			}

Christoph Mallon's avatar
Christoph Mallon committed
528
529
			case 'R':
				reg = va_arg(ap, arch_register_t const*);
Matthias Braun's avatar
Matthias Braun committed
530
				goto emit_R;
Christoph Mallon's avatar
Christoph Mallon committed
531
532

			case 'S': {
Matthias Braun's avatar
Matthias Braun committed
533
534
535
536
537
				if (*fmt == 'O') {
					++fmt;
					emit_shiftop(node);
					break;
				}
538
				if (!is_digit(*fmt))
Christoph Mallon's avatar
Christoph Mallon committed
539
					goto unknown;
540
				int const pos = *fmt++ - '0';
Christoph Mallon's avatar
Christoph Mallon committed
541
				reg = arch_get_irn_register_in(node, pos);
Matthias Braun's avatar
Matthias Braun committed
542
543
544
545
emit_R:
				if (mod & EMIT_IGNORE_MODE) {
					emit_register(reg);
				} else if (mod & EMIT_FORCE_32) {
546
					emit_register_mode(reg, INSN_MODE_32);
Matthias Braun's avatar
Matthias Braun committed
547
548
549
550
				} else if (mod & EMIT_CONV_DEST) {
					amd64_insn_mode_t src_mode  = get_amd64_insn_mode(node);
					amd64_insn_mode_t dest_mode = src_mode == INSN_MODE_64
					                            ? INSN_MODE_64 : INSN_MODE_32;
551
					emit_register_mode(reg, dest_mode);
Matthias Braun's avatar
Matthias Braun committed
552
				} else {
553
554
					amd64_insn_mode_t insn_mode = get_amd64_insn_mode(node);
					emit_register_mode(reg, insn_mode);
Matthias Braun's avatar
Matthias Braun committed
555
556
				}
				break;
Christoph Mallon's avatar
Christoph Mallon committed
557
558
			}

559
			case 'M': {
Matthias Braun's avatar
Matthias Braun committed
560
561
562
563
				if (*fmt == 'S') {
					++fmt;
					const amd64_shift_attr_t *attr
						= get_amd64_shift_attr_const(node);
564
					amd64_emit_insn_mode_suffix(attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
565
566
567
568
				} else if (*fmt == 'M') {
					++fmt;
					const amd64_movimm_attr_t *attr
						= get_amd64_movimm_attr_const(node);
569
570
571
					amd64_emit_insn_mode_suffix(attr->insn_mode);
				} else if (*fmt == 'X') {
					++fmt;
572
573
574
					amd64_addr_attr_t const *const attr
						= get_amd64_addr_attr_const(node);
					amd64_emit_xmm_mode_suffix(attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
575
576
577
				} else {
					amd64_addr_attr_t const *const attr
						= get_amd64_addr_attr_const(node);
578
					amd64_emit_insn_mode_suffix(attr->insn_mode);
Matthias Braun's avatar
Matthias Braun committed
579
				}
580
581
582
				break;
			}

Christoph Mallon's avatar
Christoph Mallon committed
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
			case 'd': {
				int const num = va_arg(ap, int);
				be_emit_irprintf("%d", num);
				break;
			}

			case 's': {
				char const *const str = va_arg(ap, char const*);
				be_emit_string(str);
				break;
			}

			case 'u': {
				unsigned const num = va_arg(ap, unsigned);
				be_emit_irprintf("%u", num);
				break;
			}

			default:
unknown:
				panic("unknown format conversion");
		}
	}
606

Christoph Mallon's avatar
Christoph Mallon committed
607
608
	be_emit_finish_line_gas(node);
	va_end(ap);
609
610
}

611
612
613
614
615
/**
 * Returns the next block in a block schedule.
 */
static ir_node *sched_next_block(const ir_node *block)
{
616
    return (ir_node*)get_irn_link(block);
617
618
}

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
static const char *get_register_name_ir_mode(const arch_register_t *reg,
                                             ir_mode *mode)
{
	if (get_mode_arithmetic(mode) != irma_twos_complement)
		return reg->name;
	switch (get_mode_size_bits(mode)) {
	case 8:  return get_register_name_8bit(reg);
	case 16: return get_register_name_16bit(reg);
	case 32: return get_register_name_32bit(reg);
	case 64: return reg->name;
	default:
		panic("unexpected mode size");
	}
}

static void emit_amd64_asm_register(const arch_register_t *reg, char modifier,
                                    ir_mode *mode)
{
	const char *name;
	switch (modifier) {
	case '\0':
		name = mode != NULL ? get_register_name_ir_mode(reg, mode) : reg->name;
		break;
	case  'b': name = get_register_name_8bit(reg); break;
	case  'h': name = get_register_name_8bit_high(reg); break;
	case  'w': name = get_register_name_16bit(reg); break;
	case  'k': name = get_register_name_32bit(reg); break;
	case  'q': name = reg->name; break;
	// gcc also knows 'x' V4SFmode, 't' V8SFmode, 'y' "st(0)" instead of "st",
	// 'd' duplicate operand for AVX instruction
	default:
		panic("invalid asm op modifier");
	}
	be_emit_char('%');
	be_emit_string(name);
}

656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
static void emit_amd64_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
{
	switch (modifier) {
	case '\0':
	case 'b':
	case 'h':
	case 'k':
	case 'q':
	case 'w':
		break;

	default:
		be_errorf(node, "asm contains unknown modifier '%c'", modifier);
		return;
	}

672
673
	be_asm_attr_t     const *const attr = get_be_asm_attr_const(node);
	x86_asm_operand_t const *const op   = &((x86_asm_operand_t const*)attr->operands)[pos];
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
	switch ((x86_asm_operand_kind_t)op->kind) {
	case ASM_OP_INVALID:
		panic("invalid asm operand");

	case ASM_OP_IN_REG: {
		arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
		emit_amd64_asm_register(reg, modifier, op->u.mode);
		return;
	}

	case ASM_OP_OUT_REG: {
		arch_register_t const *const reg = arch_get_irn_register_out(node, op->inout_pos);
		emit_amd64_asm_register(reg, modifier, op->u.mode);
		return;
	}

	case ASM_OP_MEMORY: {
		arch_register_t const *const reg = arch_get_irn_register_in(node, op->inout_pos);
		be_emit_irprintf("(%%%s)", reg->name);
		return;
	}

	case ASM_OP_IMMEDIATE: {
Matthias Braun's avatar
Matthias Braun committed
697
		amd64_emit_immediate32(true, &op->u.imm32);
698
699
700
701
702
703
		return;
	}
	}
	panic("invalid asm operand kind");
}

704
705
static void emit_amd64_asm(const ir_node *node)
{
706
	be_emit_asm(node, emit_amd64_asm_operand);
707
708
}

709
710
711
/**
 * Emit a Jmp.
 */
712
static void emit_amd64_jmp(const ir_node *node)
713
714
715
716
717
718
719
720
721
{
	ir_node *block, *next_block;

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

	/* we have a block schedule */
	next_block = sched_next_block(block);
	if (get_cfop_target_block(node) != next_block) {
Christoph Mallon's avatar
Christoph Mallon committed
722
723
724
		amd64_emitf(node, "jmp %L");
	} else if (be_options.verbose_asm) {
		amd64_emitf(node, "/* fallthrough to %L */");
725
726
727
	}
}

728
static void emit_amd64_jmp_switch(const ir_node *node)
729
730
731
{
	const amd64_switch_jmp_attr_t *attr = get_amd64_switch_jmp_attr_const(node);

732
	amd64_emitf(node, "jmp *%E(,%^S0,8)", attr->table_entity);
733
734
	be_emit_jump_table(node, attr->table, attr->table_entity,
	                   get_cfop_target_block);
735
736
}

737
738
739
/**
 * Emit a Compare with conditional branch.
 */
740
static void emit_amd64_jcc(const ir_node *irn)
741
{
742
743
744
745
	const ir_node         *proj_true  = NULL;
	const ir_node         *proj_false = NULL;
	const ir_node         *block;
	const ir_node         *next_block;
746
747
	const amd64_cc_attr_t *attr = get_amd64_cc_attr_const(irn);
	x86_condition_code_t   cc   = attr->cc;
748
749
750

	foreach_out_edge(irn, edge) {
		ir_node *proj = get_edge_src_irn(edge);
751
		unsigned nr = get_Proj_num(proj);
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
		if (nr == pn_Cond_true) {
			proj_true = proj;
		} else {
			proj_false = proj;
		}
	}

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

	/* we have a block schedule */
	next_block = sched_next_block(block);

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

		proj_true  = proj_false;
		proj_false = t;
771
		cc         = x86_negate_condition_code(cc);
772
773
	}

774
775
776
777
778
779
780
781
782
783
	if (cc & x86_cc_float_parity_cases) {
		/* Some floating point comparisons require a test of the parity flag,
		 * which indicates that the result is unordered */
		if (cc & x86_cc_negated) {
			amd64_emitf(proj_true, "jp %L");
		} else {
			amd64_emitf(proj_false, "jp %L");
		}
	}

784
	/* emit the true proj */
785
	amd64_emitf(proj_true, "j%PX %L", (int)cc);
Christoph Mallon's avatar
Christoph Mallon committed
786

787
788
789
790
	if (get_cfop_target_block(proj_false) == next_block) {
		if (be_options.verbose_asm)
			amd64_emitf(proj_false, "/* fallthrough to %L */");
	} else  {
Christoph Mallon's avatar
Christoph Mallon committed
791
		amd64_emitf(proj_false, "jmp %L");
792
793
794
	}
}

795
static void emit_amd64_mov_gp(const ir_node *node)
796
{
Matthias Braun's avatar
Matthias Braun committed
797
798
	const amd64_addr_attr_t *attr = get_amd64_addr_attr_const(node);
	switch (attr->insn_mode) {
799
800
801
802
803
804
805
	case INSN_MODE_8:  amd64_emitf(node, "movzbq %AM, %^D0"); return;
	case INSN_MODE_16: amd64_emitf(node, "movzwq %AM, %^D0"); return;
	case INSN_MODE_32: amd64_emitf(node, "movl %AM, %3D0");   return;
	case INSN_MODE_64: amd64_emitf(node, "movq %AM, %^D0");   return;
	case INSN_MODE_128:
	case INSN_MODE_INVALID:
		break;
806
	}
807
	panic("invalid insn mode");
808
809
}

810
811
812
813
814
/**
 * emit copy node
 */
static void emit_be_Copy(const ir_node *irn)
{
815
816
	arch_register_t const *const out = arch_get_irn_register_out(irn, 0);
	if (arch_get_irn_register_in(irn, 0) == out) {
817
818
819
820
		/* omitted Copy */
		return;
	}

821
822
	arch_register_class_t const *const cls = out->cls;
	if (cls == &amd64_reg_classes[CLASS_amd64_gp]) {
823
		amd64_emitf(irn, "mov %^S0, %^D0");
824
825
	} else if (cls == &amd64_reg_classes[CLASS_amd64_xmm]) {
		amd64_emitf(irn, "movapd %^S0, %^D0");
826
	} else {
827
		panic("move not supported for this register class");
828
829
	}
}
830

831
832
static void emit_be_Perm(const ir_node *node)
{
833
834
	arch_register_t const *const reg0 = arch_get_irn_register_out(node, 0);
	arch_register_t const *const reg1 = arch_get_irn_register_out(node, 1);
835

836
837
	arch_register_class_t const* const cls = reg0->cls;
	assert(cls == reg1->cls && "Register class mismatch at Perm");
838

839
840
841
842
843
844
845
	if (cls == &amd64_reg_classes[CLASS_amd64_gp]) {
		amd64_emitf(node, "xchg %^R, %^R", reg0, reg1);
	} else if (cls == &amd64_reg_classes[CLASS_amd64_xmm]) {
		amd64_emitf(node, "pxor %^R, %^R", reg0, reg1);
		amd64_emitf(node, "pxor %^R, %^R", reg1, reg0);
		amd64_emitf(node, "pxor %^R, %^R", reg0, reg1);
	} else {
846
847
848
849
		panic("unexpected register class in be_Perm (%+F)", node);
	}
}

850
851
852
853
854
855
856
857
858
859
860
/**
 * Emits code to increase stack pointer.
 */
static void emit_be_IncSP(const ir_node *node)
{
	int offs = be_get_IncSP_offset(node);

	if (offs == 0)
		return;

	if (offs > 0) {
Matthias Braun's avatar
Matthias Braun committed
861
		amd64_emitf(node, "subq $%d, %^D0", offs);
862
	} else {
Matthias Braun's avatar
Matthias Braun committed
863
		amd64_emitf(node, "addq $%d, %^D0", -offs);
864
865
866
	}
}

867
868
869
870
871
872
/**
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
 */
static void amd64_register_emitters(void)
{
873
	be_init_emitters();
874
875
876
877

	/* register all emitter functions defined in spec */
	amd64_register_spec_emitters();

878
879
880
	be_set_emitter(op_amd64_jcc,        emit_amd64_jcc);
	be_set_emitter(op_amd64_jmp,        emit_amd64_jmp);
	be_set_emitter(op_amd64_jmp_switch, emit_amd64_jmp_switch);
881
	be_set_emitter(op_amd64_mov_gp,     emit_amd64_mov_gp);
882
	be_set_emitter(op_be_Asm,           emit_amd64_asm);
883
884
885
886
	be_set_emitter(op_be_Copy,          emit_be_Copy);
	be_set_emitter(op_be_CopyKeep,      emit_be_Copy);
	be_set_emitter(op_be_IncSP,         emit_be_IncSP);
	be_set_emitter(op_be_Perm,          emit_be_Perm);
887
888
889
890
891
892
}

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
893
static void amd64_gen_block(ir_node *block)
894
{
895
	be_gas_begin_block(block, true);
896
897

	sched_foreach(block, node) {
898
		be_emit_node(node);
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
	}
}


/**
 * Sets labels for control flow nodes (jump target)
 * TODO: Jump optimization
 */
static void amd64_gen_labels(ir_node *block, void *env)
{
	ir_node *pred;
	int n = get_Block_n_cfgpreds(block);
	(void) env;

	for (n--; n >= 0; n--) {
		pred = get_Block_cfgpred(block, n);
		set_irn_link(pred, block);
	}
}

919
void amd64_emit_function(ir_graph *irg)
920
{
921
922
	ir_entity *entity = get_irg_entity(irg);
	ir_node  **blk_sched;
923
	size_t i, n;
924

925
926
	layout = be_get_irg_stack_layout(irg);

927
928
929
	/* register all emitter functions */
	amd64_register_emitters();

930
	blk_sched = be_create_block_schedule(irg);
931

932
	be_gas_emit_function_prolog(entity, 4, NULL);
933

934
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
935
	irg_block_walk_graph(irg, amd64_gen_labels, NULL, NULL);
936
937

	n = ARR_LEN(blk_sched);
938
	for (i = 0; i < n; i++) {
939
		ir_node *block = blk_sched[i];
940
		ir_node *next  = (i + 1) < n ? blk_sched[i+1] : NULL;
941

942
		set_irn_link(block, next);
943
944
945
946
	}

	for (i = 0; i < n; ++i) {
		ir_node *block = blk_sched[i];
947
		amd64_gen_block(block);
948
	}
949
	ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
950
951

	be_gas_emit_function_epilog(entity);
952
}