sparc_emitter.c 41.6 KB
Newer Older
Hannes Rapp's avatar
Hannes Rapp committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Hannes Rapp's avatar
Hannes Rapp committed
4
5
6
7
8
 */

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

13
#include "bearch_sparc_t.h"
14
#include "beasm.h"
15
#include "beblocksched.h"
16
#include "bediagnostic.h"
17
18
19
20
21
22
#include "begnuas.h"
#include "beirg.h"
#include "benode.h"
#include "bepeephole.h"
#include "besched.h"
#include "bestack.h"
23
#include "beutil.h"
Hannes Rapp's avatar
Hannes Rapp committed
24
#include "debug.h"
25
26
27
28
#include "execfreq_t.h"
#include "gen_sparc_emitter.h"
#include "gen_sparc_regalloc_if.h"
#include "heights.h"
Hannes Rapp's avatar
Hannes Rapp committed
29
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
30
#include "panic.h"
31
#include "pmap.h"
Hannes Rapp's avatar
Hannes Rapp committed
32
33
#include "sparc_emitter.h"
#include "sparc_new_nodes.h"
34
#include "util.h"
Hannes Rapp's avatar
Hannes Rapp committed
35

Hannes Rapp's avatar
Hannes Rapp committed
36
37
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

38
39
40
static ir_heights_t *heights;
static unsigned     *delay_slot_fillers;
static pmap         *delay_slots;
41

42
43
static bool emitting_delay_slot;

44
45
46
47
48
/**
 * indent before instruction. (Adds additional indentation when emitting
 * delay slots)
 */
static void sparc_emit_indent(void)
49
50
51
52
53
{
	be_emit_char('\t');
	if (emitting_delay_slot)
		be_emit_char(' ');
}
54

55
static void sparc_emit_immediate(int32_t value, ir_entity *entity)
Hannes Rapp's avatar
Hannes Rapp committed
56
{
57
	if (entity == NULL) {
58
		be_emit_irprintf("%"PRId32, value);
59
	} else {
60
		if (is_tls_entity(entity)) {
61
62
63
64
			be_emit_cstring("%tle_lox10(");
		} else {
			be_emit_cstring("%lo(");
		}
65
		be_gas_emit_entity(entity);
66
		if (value != 0) {
67
			be_emit_irprintf("%+"PRId32, value);
68
69
70
		}
		be_emit_char(')');
	}
71
72
}

73
static void sparc_emit_high_immediate(ir_node const *node)
74
{
75
76
77
78
79
	const sparc_attr_t *attr   = get_sparc_attr_const(node);
	ir_entity          *entity = attr->immediate_value_entity;

	if (entity == NULL) {
		uint32_t value = (uint32_t) attr->immediate_value;
80
		be_emit_irprintf("%%hi(0x%X)", value);
81
	} else {
82
		if (is_tls_entity(entity)) {
83
84
85
86
			be_emit_cstring("%tle_hix22(");
		} else {
			be_emit_cstring("%hi(");
		}
87
88
		be_gas_emit_entity(entity);
		if (attr->immediate_value != 0) {
89
			be_emit_irprintf("%+"PRId32, attr->immediate_value);
90
		}
91
		be_emit_char(')');
92
	}
Hannes Rapp's avatar
Hannes Rapp committed
93
94
}

95
static void sparc_emit_register(const arch_register_t *const reg)
Hannes Rapp's avatar
Hannes Rapp committed
96
97
{
	be_emit_char('%');
98
	be_emit_string(reg->name);
Hannes Rapp's avatar
Hannes Rapp committed
99
100
}

101
102
103
104
105
106
static void sparc_emit_source_register(ir_node const *node, int const pos)
{
	const arch_register_t *reg = arch_get_irn_register_in(node, pos);
	sparc_emit_register(reg);
}

107
static void sparc_emit_dest_register(ir_node const *const node, int const pos)
Hannes Rapp's avatar
Hannes Rapp committed
108
{
Matthias Braun's avatar
Matthias Braun committed
109
	const arch_register_t *reg = arch_get_irn_register_out(node, pos);
110
	sparc_emit_register(reg);
Hannes Rapp's avatar
Hannes Rapp committed
111
112
}

113
114
115
/**
 * emit SP offset
 */
116
static void sparc_emit_offset(const ir_node *node, int offset_node_pos)
Hannes Rapp's avatar
Hannes Rapp committed
117
{
118
	const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
119

120
121
122
123
124
125
126
	if (attr->is_reg_reg) {
		assert(!attr->is_frame_entity);
		assert(attr->base.immediate_value == 0);
		assert(attr->base.immediate_value_entity == NULL);
		be_emit_char('+');
		sparc_emit_source_register(node, offset_node_pos);
	} else if (attr->is_frame_entity) {
127
128
		int32_t offset = attr->base.immediate_value;
		if (offset != 0) {
129
			assert(sparc_is_value_imm_encodeable(offset));
130
			be_emit_irprintf("%+"PRId32, offset);
131
		}
132
133
	} else if (attr->base.immediate_value != 0
			|| attr->base.immediate_value_entity != NULL) {
134
		be_emit_char('+');
135
136
		sparc_emit_immediate(attr->base.immediate_value,
		                     attr->base.immediate_value_entity);
137
	}
Hannes Rapp's avatar
Hannes Rapp committed
138
139
140
}

/**
141
 *  Emit load mode
Hannes Rapp's avatar
Hannes Rapp committed
142
 */
143
static void sparc_emit_load_mode(ir_node const *const node)
Hannes Rapp's avatar
Hannes Rapp committed
144
145
{
	const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
146
147
148
149
	ir_mode *mode      = attr->load_store_mode;
	int      bits      = get_mode_size_bits(mode);
	bool     is_signed = mode_is_signed(mode);

150
151
152
153
154
155
156
	switch (bits) {
	case   8: be_emit_string(is_signed ? "sb" : "ub"); break;
	case  16: be_emit_string(is_signed ? "sh" : "uh"); break;
	case  32: break;
	case  64: be_emit_char('d'); break;
	case 128: be_emit_char('q'); break;
	default:  panic("invalid load/store mode %+F", mode);
157
	}
Hannes Rapp's avatar
Hannes Rapp committed
158
159
160
161
162
}

/**
 * Emit store mode char
 */
163
static void sparc_emit_store_mode(ir_node const *const node)
Hannes Rapp's avatar
Hannes Rapp committed
164
165
{
	const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(node);
166
167
168
	ir_mode *mode      = attr->load_store_mode;
	int      bits      = get_mode_size_bits(mode);

169
170
171
172
173
174
175
	switch (bits) {
	case   8: be_emit_char('b'); break;
	case  16: be_emit_char('h'); break;
	case  32: break;
	case  64: be_emit_char('d'); break;
	case 128: be_emit_char('q'); break;
	default:  panic("invalid load/store mode %+F", mode);
176
	}
Hannes Rapp's avatar
Hannes Rapp committed
177
178
}

179
static void emit_fp_suffix(const ir_mode *mode)
Hannes Rapp's avatar
Hannes Rapp committed
180
{
181
	assert(mode_is_float(mode));
182
183
184
185
186
	switch (get_mode_size_bits(mode)) {
	case  32: be_emit_char('s'); break;
	case  64: be_emit_char('d'); break;
	case 128: be_emit_char('q'); break;
	default:  panic("invalid FP mode");
187
	}
Hannes Rapp's avatar
Hannes Rapp committed
188
189
}

190
191
192
193
194
static void set_jump_target(ir_node *jump, ir_node *target)
{
	set_irn_link(jump, target);
}

195
196
static ir_node *get_jump_target(const ir_node *jump)
{
197
	return (ir_node*)get_irn_link(jump);
198
199
}

Hannes Rapp's avatar
Hannes Rapp committed
200
201
202
203
204
/**
 * Returns the target label for a control flow node.
 */
static void sparc_emit_cfop_target(const ir_node *node)
{
205
	ir_node *block = get_jump_target(node);
206
	be_gas_emit_block_name(block);
Hannes Rapp's avatar
Hannes Rapp committed
207
208
}

209
210
211
212
213
214
215
216
217
/**
 * returns true if a sparc_call calls a register and not an immediate
 */
static bool is_sparc_reg_call(const ir_node *node)
{
	const sparc_attr_t *attr = get_sparc_attr_const(node);
	return attr->immediate_value_entity == NULL;
}

218
219
static int get_sparc_Call_dest_addr_pos(const ir_node *node)
{
220
	assert(is_sparc_reg_call(node));
221
222
223
224
225
226
	return get_irn_arity(node)-1;
}

static bool ba_is_fallthrough(const ir_node *node)
{
	ir_node *block      = get_nodes_block(node);
227
	ir_node *next_block = (ir_node*)get_irn_link(block);
228
	return get_jump_target(node) == next_block;
229
230
231
232
233
234
}

static bool is_no_instruction(const ir_node *node)
{
	/* copies are nops if src_reg == dest_reg */
	if (be_is_Copy(node) || be_is_CopyKeep(node)) {
Matthias Braun's avatar
Matthias Braun committed
235
236
		const arch_register_t *src_reg  = arch_get_irn_register_in(node, 0);
		const arch_register_t *dest_reg = arch_get_irn_register_out(node, 0);
237
238
239
240

		if (src_reg == dest_reg)
			return true;
	}
241
242
	if (be_is_IncSP(node) && be_get_IncSP_offset(node) == 0)
		return true;
243
244
245
246
	/* Ba is not emitted if it is a simple fallthrough */
	if (is_sparc_Ba(node) && ba_is_fallthrough(node))
		return true;

247
	return be_is_Keep(node) || is_sparc_Start(node) || is_Phi(node);
248
249
250
251
}

static bool has_delay_slot(const ir_node *node)
{
252
253
254
	if (is_sparc_Ba(node)) {
		return !ba_is_fallthrough(node);
	}
255

256
	return arch_get_irn_flags(node) & sparc_arch_irn_flag_has_delay_slot;
257
258
259
260
261
262
263
264
265
266
267
268
269
}

/** returns true if the emitter for this sparc node can produce more than one
 * actual sparc instruction.
 * Usually it is a bad sign if we have to add instructions here. We should
 * rather try to get them lowered down. So we can actually put them into
 * delay slots and make them more accessible to the scheduler.
 */
static bool emits_multiple_instructions(const ir_node *node)
{
	if (has_delay_slot(node))
		return true;

270
	if (is_sparc_Call(node))
Matthias Braun's avatar
Matthias Braun committed
271
		return arch_get_irn_flags(node) & sparc_arch_irn_flag_aggregate_return;
272

273
274
	return is_sparc_SMulh(node) || is_sparc_UMulh(node)
		|| is_sparc_SDiv(node) || is_sparc_UDiv(node)
Manuel Mohr's avatar
Manuel Mohr committed
275
		|| be_is_MemPerm(node) || be_is_Perm(node)
276
		|| is_sparc_SubSP(node) || is_sparc_ASM(node);
277
278
}

279
static bool uses_reg(const ir_node *node, unsigned reg_index, unsigned width)
280
281
{
	int arity = get_irn_arity(node);
Matthias Braun's avatar
Matthias Braun committed
282
	for (int i = 0; i < arity; ++i) {
283
284
285
286
287
288
		const arch_register_t     *in_reg = arch_get_irn_register_in(node, i);
		const arch_register_req_t *in_req = arch_get_irn_register_req_in(node, i);
		if (in_reg == NULL)
			continue;
		if (reg_index < (unsigned)in_reg->global_index + in_req->width
			&& reg_index + width > in_reg->global_index)
289
290
291
292
293
			return true;
	}
	return false;
}

294
static bool writes_reg(const ir_node *node, unsigned reg_index, unsigned width)
295
{
296
	be_foreach_out(node, o) {
Matthias Braun's avatar
Matthias Braun committed
297
		const arch_register_t *out_reg = arch_get_irn_register_out(node, o);
298
299
300
301
302
		if (out_reg == NULL)
			continue;
		const arch_register_req_t *out_req = arch_get_irn_register_req_out(node, o);
		if (reg_index < (unsigned)out_reg->global_index + out_req->width
			&& reg_index + width > out_reg->global_index)
303
304
305
306
307
			return true;
	}
	return false;
}

308
309
310
311
312
313
314
315
static bool is_legal_delay_slot_filler(const ir_node *node)
{
	if (is_no_instruction(node))
		return false;
	if (emits_multiple_instructions(node))
		return false;
	if (rbitset_is_set(delay_slot_fillers, get_irn_idx(node)))
		return false;
316
317
	if (is_sparc_Save(node))
		return false;
318
319
320
321
	return true;
}

static bool can_move_down_into_delayslot(const ir_node *node, const ir_node *to)
322
{
323
324
325
	if (!is_legal_delay_slot_filler(node))
		return false;

326
	if (!be_can_move_down(heights, node, to, sparc_get_frame_entity))
327
328
329
330
		return false;

	if (is_sparc_Call(to)) {
		ir_node *check;
331
		/** all inputs are used after the delay slot so, we're fine */
332
333
334
335
336
337
		if (!is_sparc_reg_call(to))
			return true;

		check = get_irn_n(to, get_sparc_Call_dest_addr_pos(to));
		if (skip_Proj(check) == node)
			return false;
338

339
340
341
		/* the Call also destroys the value of %o7, but since this is
		 * currently marked as ignore register in the backend, it
		 * should never be used by the instruction in the delay slot. */
342
		if (uses_reg(node, REG_O7, 1))
343
344
345
346
347
			return false;
		return true;
	} else if (is_sparc_Return(to)) {
		/* return uses the value of %o7, all other values are not
		 * immediately used */
348
		if (writes_reg(node, REG_O7, 1))
349
350
351
352
			return false;
		return true;
	} else {
		/* the node must not use our computed values */
353
		foreach_irn_in(to, i, in) {
354
355
356
357
			if (skip_Proj(in) == node)
				return false;
		}
		return true;
358
359
360
	}
}

361
362
363
364
365
366
static bool can_move_up_into_delayslot(const ir_node *node, const ir_node *to)
{
	if (!be_can_move_up(heights, node, to))
		return false;

	/* node must not use any results of 'to' */
367
	foreach_irn_in(node, i, in) {
368
369
370
371
372
373
374
		ir_node *skipped = skip_Proj(in);
		if (skipped == to)
			return false;
	}

	/* register window cycling effects at Restore aren't correctly represented
	 * in the graph yet so we need this exception here */
375
	if (is_sparc_Restore(node) || is_sparc_RestoreZero(node)) {
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
		return false;
	} else if (is_sparc_Call(to)) {
		/* node must not overwrite any of the inputs of the call,
		 * (except for the dest_addr) */
		int dest_addr_pos = is_sparc_reg_call(to)
			? get_sparc_Call_dest_addr_pos(to) : -1;

		int call_arity = get_irn_arity(to);
		for (int i = 0; i < call_arity; ++i) {
			if (i == dest_addr_pos)
				continue;
			const arch_register_t *reg = arch_get_irn_register_in(to, i);
			if (reg == NULL)
				continue;
			const arch_register_req_t *req = arch_get_irn_register_req_in(to, i);
			if (writes_reg(node, reg->global_index, req->width))
				return false;
		}

		/* node must not write to one of the call outputs */
396
		be_foreach_out(to, o) {
397
398
399
400
401
402
403
404
405
406
			const arch_register_t *reg = arch_get_irn_register_out(to, o);
			if (reg == NULL)
				continue;
			const arch_register_req_t *req = arch_get_irn_register_req_out(to, o);
			if (writes_reg(node, reg->global_index, req->width))
				return false;
		}
	} else if (is_sparc_SDiv(to) || is_sparc_UDiv(to)) {
		/* node will be inserted between wr and div so it must not overwrite
		 * anything except the wr input */
Matthias Braun's avatar
Matthias Braun committed
407
		for (int i = 0, arity = get_irn_arity(to); i < arity; ++i) {
408
			assert((unsigned)n_sparc_SDiv_dividend_high == (unsigned)n_sparc_UDiv_dividend_high);
409
410
411
412
413
414
415
416
417
			if (i == n_sparc_SDiv_dividend_high)
				continue;
			const arch_register_t *reg = arch_get_irn_register_in(to, i);
			if (reg == NULL)
				continue;
			const arch_register_req_t *req = arch_get_irn_register_req_in(to, i);
			if (writes_reg(node, reg->global_index, req->width))
				return false;
		}
yb9976's avatar
yb9976 committed
418
	}
419
420
421
422
423
424
425
426
	return true;
}

static void optimize_fallthrough(ir_node *node)
{
	ir_node *proj_true  = NULL;
	ir_node *proj_false = NULL;

427
428
	assert((unsigned)pn_sparc_Bicc_false == (unsigned)pn_sparc_fbfcc_false);
	assert((unsigned)pn_sparc_Bicc_true  == (unsigned)pn_sparc_fbfcc_true);
429
430
	foreach_out_edge(node, edge) {
		ir_node *proj = get_edge_src_irn(edge);
431
432
		unsigned pn   = get_Proj_num(proj);
		if (pn == pn_sparc_Bicc_true) {
433
434
			proj_true = proj;
		} else {
435
			assert(pn == pn_sparc_Bicc_false);
436
437
438
439
440
441
442
443
444
445
446
447
448
			proj_false = proj;
		}
	}
	assert(proj_true != NULL && proj_false != NULL);

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

	/* we have a block schedule */
	const ir_node *next_block = (ir_node*)get_irn_link(block);

	if (get_jump_target(proj_true) == next_block) {
		/* exchange both proj destinations so the second one can be omitted */
449
450
		set_Proj_num(proj_true,  pn_sparc_Bicc_false);
		set_Proj_num(proj_false, pn_sparc_Bicc_true);
451
452
453
454
455
456

		sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr(node);
		attr->relation = get_negated_relation(attr->relation);
	}
}

Hannes Rapp's avatar
Hannes Rapp committed
457
/**
458
 * search for an instruction that can fill the delay slot of @p node
Hannes Rapp's avatar
Hannes Rapp committed
459
 */
460
static ir_node *pick_delay_slot_for(ir_node *node)
Hannes Rapp's avatar
Hannes Rapp committed
461
{
462
	static const unsigned PICK_DELAY_SLOT_MAX_DISTANCE = 10;
463
464
	assert(has_delay_slot(node));

465
466
467
	if (is_sparc_Bicc(node) || is_sparc_fbfcc(node)) {
		optimize_fallthrough(node);
	}
468

469
	unsigned tries = 0;
470
	sched_foreach_reverse_before(node, schedpoint) {
471
472
		if (has_delay_slot(schedpoint))
			break;
473
474
		if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE)
			break;
475

476
		if (!can_move_down_into_delayslot(schedpoint, node))
477
478
			continue;

479
480
481
482
483
484
		/* found something */
		return schedpoint;
	}

	/* search after the current position */
	tries = 0;
485
	sched_foreach_after(node, schedpoint) {
486
487
		if (has_delay_slot(schedpoint))
			break;
488
489
		if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE)
			break;
490
		if (!is_legal_delay_slot_filler(schedpoint))
491
			continue;
492
		if (!can_move_up_into_delayslot(schedpoint, node))
493
494
495
496
497
498
			continue;

		/* found something */
		return schedpoint;
	}

499
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
528
529
530
	/* look in successor blocks */
	ir_node *block = get_nodes_block(node);
	/* TODO: sort succs by execution frequency */
	foreach_block_succ(block, edge) {
		ir_node *succ = get_edge_src_irn(edge);
		/* we can't easily move up stuff from blocks with multiple predecessors
		 * since the instruction is lacking for the other preds then.
		 * (We also don't have to do any phi translation) */
		if (get_Block_n_cfgpreds(succ) > 1)
			continue;

		tries = 0;
		sched_foreach(succ, schedpoint) {
			if (has_delay_slot(schedpoint))
				break;
			/* can't move pinned nodes accross blocks */
			if (get_irn_pinned(schedpoint) == op_pin_state_pinned)
				continue;
			/* restore doesn't model register window switching correctly,
			 * so it appears like we could move it, which is not true */
			if (is_sparc_Restore(schedpoint)
			    || is_sparc_RestoreZero(schedpoint))
				continue;
			if (tries++ >= PICK_DELAY_SLOT_MAX_DISTANCE)
				break;
			if (!is_legal_delay_slot_filler(schedpoint))
				continue;
			if (can_move_up_into_delayslot(schedpoint, node)) {
				/* it's fine to move the insn accross blocks */
				return schedpoint;
			} else if (is_sparc_Bicc(node) || is_sparc_fbfcc(node)) {
				ir_node *proj = get_Block_cfgpred(succ, 0);
531
				unsigned nr   = get_Proj_num(proj);
532
533
534
535
536
537
538
539
540
541
542
				if ((nr == pn_sparc_Bicc_true || nr == pn_sparc_fbfcc_true)
					&& be_can_move_up(heights, schedpoint, succ)) {
					/* we can use it with the annul flag */
					sparc_jmp_cond_attr_t *attr = get_sparc_jmp_cond_attr(node);
					attr->annul_delay_slot = true;
					return schedpoint;
				}
			}
		}
	}

543
	return NULL;
Hannes Rapp's avatar
Hannes Rapp committed
544
545
}

546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
void sparc_emitf(ir_node const *const node, char const *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	sparc_emit_indent();
	for (;;) {
		char const *start = fmt;

		while (*fmt != '%' && *fmt != '\0')
			++fmt;
		be_emit_string_len(start, fmt - start);
		if (*fmt == '\0')
			break;
		++fmt;

		bool plus = false;
		if (*fmt == '+') {
			plus = true;
			++fmt;
		}

		switch (*fmt++) {
		case '%':
			be_emit_char('%');
			break;

572
573
574
575
576
577
578
579
580
		case 'A': {
			const sparc_jmp_cond_attr_t *attr
				= get_sparc_jmp_cond_attr_const(node);
			if (attr->annul_delay_slot) {
				be_emit_cstring(",a");
			}
			break;
		}

581
		case 'D':
582
			if (!is_digit(*fmt))
583
584
585
586
587
588
589
590
				goto unknown;
			sparc_emit_dest_register(node, *fmt++ - '0');
			break;

		case 'E': {
			sparc_attr_t const *const attr = get_sparc_attr_const(node);
			be_gas_emit_entity(attr->immediate_value_entity);
			if (attr->immediate_value != 0) {
591
				be_emit_irprintf(plus ? "%+"PRId32 : "%"PRId32, attr->immediate_value);
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
			}
			break;
		}

		case 'F': {
			ir_mode *mode;
			switch (*fmt++) {
			case 'D': mode = get_sparc_fp_conv_attr_const(node)->dest_mode; break;
			case 'M': mode = get_sparc_fp_attr_const(node)->fp_mode;        break;
			case 'S': mode = get_sparc_fp_conv_attr_const(node)->src_mode;  break;
			default:  goto unknown;
			}
			emit_fp_suffix(mode);
			break;
		}

		case 'H':
			sparc_emit_high_immediate(node);
			break;

612
613
614
		case 'L': {
			ir_node *n = va_arg(ap, ir_node*);
			sparc_emit_cfop_target(n);
615
			break;
616
		}
617
618
619

		case 'M':
			switch (*fmt++) {
620
621
622
623
624
625
626
627
628
629
630
			case 'O': {
				if (!is_digit(*fmt))
					goto unknown;
				unsigned const pos = *fmt++ - '0';
				be_emit_char('[');
				sparc_emit_source_register(node, pos);
				sparc_emit_offset(node, pos + 1);
				be_emit_char(']');
				break;
			}

631
632
633
634
635
636
637
638
639
			case 'L': sparc_emit_load_mode(node);  break;
			case 'S': sparc_emit_store_mode(node); break;
			default:  goto unknown;
			}
			break;

		case 'R': {
			arch_register_t const *const reg = va_arg(ap, const arch_register_t*);
			be_emit_char('%');
640
			be_emit_string(reg->name);
641
642
643
644
645
646
647
648
649
			break;
		}

		case 'S': {
			bool imm = false;
			if (*fmt == 'I') {
				imm = true;
				++fmt;
			}
650
			if (!is_digit(*fmt))
651
652
653
				goto unknown;
			unsigned const pos = *fmt++ - '0';
			if (imm && arch_get_irn_flags(node) & (arch_irn_flags_t)sparc_arch_irn_flag_immediate_form) {
654
655
656
				const sparc_attr_t *const attr = get_sparc_attr_const(node);
				sparc_emit_immediate(attr->immediate_value,
				                     attr->immediate_value_entity);
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
			} else {
				sparc_emit_source_register(node, pos);
			}
			break;
		}

		case 'd': {
			int const num = va_arg(ap, int);
			be_emit_irprintf(plus ? "%+d" : "%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(plus ? "%+u" : "%u", num);
			break;
		}

681
682
683
684
685
686
		case 'X': {
			unsigned const num = va_arg(ap, unsigned);
			be_emit_irprintf("%X", num);
			break;
		}

687
688
689
690
691
692
693
694
695
		default:
unknown:
			panic("unknown format conversion in sparc_emitf()");
		}
	}
	be_emit_finish_line_gas(node);
	va_end(ap);
}

Hannes Rapp's avatar
Hannes Rapp committed
696
697
698
699
700
/**
 * Emits code for stack space management
 */
static void emit_be_IncSP(const ir_node *irn)
{
701
	int offset = be_get_IncSP_offset(irn);
Hannes Rapp's avatar
Hannes Rapp committed
702

703
	if (offset == 0)
704
		return;
Hannes Rapp's avatar
Hannes Rapp committed
705

706
	/* SPARC stack grows downwards */
707
708
	char const *const insn = offset > 0 ? offset = -offset, "add" : "sub";
	sparc_emitf(irn, "%s %S0, %d, %D0", insn, offset);
709
}
710

711
static void emit_sparc_asm_operand(ir_node const *const node, char const modifier, unsigned const pos)
712
{
713
714
715
	if (modifier != '\0') {
		be_errorf(node, "asm contains unknown modifier '%c'", modifier);
		return;
716
717
	}

718
719
720
	sparc_asm_attr_t    const *const attr = get_sparc_asm_attr_const(node);
	sparc_asm_operand_t const *const op   = &attr->operands[pos];
	switch (op->kind) {
721
	case ASM_OPERAND_IMMEDIATE:
722
723
724
		sparc_emit_immediate(op->immediate_value, op->immediate_value_entity);
		return;

725
	case ASM_OPERAND_INPUT_VALUE:
726
727
728
		sparc_emit_register(arch_get_irn_register_in(node, op->pos));
		return;

729
	case ASM_OPERAND_OUTPUT_VALUE:
730
731
		sparc_emit_register(arch_get_irn_register_out(node, op->pos));
		return;
732
733
734
735
736
737

	case ASM_OPERAND_MEMORY:
		be_emit_char('[');
		sparc_emit_register(arch_get_irn_register_in(node, op->pos));
		be_emit_char(']');
		return;
738
	}
739
	panic("invalid asm operand kind");
740
741
}

742
743
static void emit_sparc_ASM(const ir_node *node)
{
744
745
	sparc_asm_attr_t const *const attr = get_sparc_asm_attr_const(node);
	be_emit_asm(node, attr->text, ARR_LEN(attr->operands), emit_sparc_asm_operand);
746
747
}

Manuel Mohr's avatar
Manuel Mohr committed
748
749
750
751
752
/**
 * Emits code for stack space management.
 */
static void emit_sparc_SubSP(const ir_node *irn)
{
753
754
	sparc_emitf(irn, "sub %S0, %SI1, %D0");
	sparc_emitf(irn, "add %S0, %u, %D1", SPARC_MIN_STACKSIZE);
Hannes Rapp's avatar
Hannes Rapp committed
755
}
756

757
static void fill_delay_slot(const ir_node *node)
758
{
759
	emitting_delay_slot = true;
760
761
762
763
	const ir_node *filler = pmap_get(ir_node, delay_slots, node);
	if (filler != NULL) {
		assert(!is_no_instruction(filler));
		assert(!emits_multiple_instructions(filler));
764
		be_emit_node(filler);
765
	} else {
766
		sparc_emitf(NULL, "nop");
767
	}
768
	emitting_delay_slot = false;
769
770
}

771
static void emit_sparc_Div(const ir_node *node, char const *const insn)
772
{
773
	sparc_emitf(node, "wr %S1, 0, %%y");
774

Matthias Braun's avatar
Matthias Braun committed
775
776
777
778
	/* TODO: we should specify number of delayslots in an architecture
	 * specification */
	unsigned wry_delay_count = 3;
	for (unsigned i = 0; i < wry_delay_count; ++i) {
779
780
781
782
783
784
785
		if (i == 0) {
			fill_delay_slot(node);
		} else {
			emitting_delay_slot = true;
			sparc_emitf(NULL, "nop");
			emitting_delay_slot = false;
		}
786
787
	}

788
	sparc_emitf(node, "%s %S2, %SI3, %D0", insn);
789
790
791
792
}

static void emit_sparc_SDiv(const ir_node *node)
{
793
	emit_sparc_Div(node, "sdiv");
794
795
796
797
}

static void emit_sparc_UDiv(const ir_node *node)
{
798
	emit_sparc_Div(node, "udiv");
799
800
}

801
static void emit_sparc_Call(const ir_node *node)
Hannes Rapp's avatar
Hannes Rapp committed
802
{
803
804
	if (is_sparc_reg_call(node)) {
		int dest_addr = get_sparc_Call_dest_addr_pos(node);
805
		sparc_emitf(node, "call %R", arch_get_irn_register_in(node, dest_addr));
806
	} else {
807
		sparc_emitf(node, "call %E, 0");
Hannes Rapp's avatar
Hannes Rapp committed
808
	}
809

810
	fill_delay_slot(node);
811

Matthias Braun's avatar
Matthias Braun committed
812
	if (arch_get_irn_flags(node) & sparc_arch_irn_flag_aggregate_return) {
813
		sparc_emitf(NULL, "unimp 8");
814
	}
Hannes Rapp's avatar
Hannes Rapp committed
815
816
}

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
static void emit_sparc_Cas(const ir_node *node)
{
	/* custom emiter is just here to check for should_be_same constraint
	 * which isn't guaranteed to be fulfilled in current firm backend */
	if (arch_get_irn_register_out(node, pn_sparc_Cas_res) !=
	    arch_get_irn_register_in(node, n_sparc_Cas_new)) {
	    panic("sparc: should_be_same in Cas not fulfilled");
	}
	/* except for some patched gaisler binutils nobody understands cas
	 * in v8/leon mode, so we encode the cas in binary form */
#if 0
	sparc_emitf(node, "cas [%S0], %S1, %S2");
#else
	const arch_register_t *reg_new
		= arch_get_irn_register_in(node, n_sparc_Cas_new);
	const arch_register_t *reg_ptr
		= arch_get_irn_register_in(node, n_sparc_Cas_ptr);
	const arch_register_t *reg_old
		= arch_get_irn_register_in(node, n_sparc_Cas_old);
	uint32_t encoding = 3u<<30 | (reg_new->encoding<<25) | (0x3C << 19)
	       | (reg_ptr->encoding<<14) | (0x80<<5) | (reg_old->encoding);
	sparc_emitf(node, ".long 0x%X  /* cas [%S0], %S1, %S2", encoding);
#endif
}

842
843
static void emit_be_Perm(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
844
845
	ir_mode *mode = get_irn_mode(get_irn_n(irn, 0));
	if (mode_is_float(mode)) {
846
847
		arch_register_t const *const reg0 = arch_get_irn_register_out(irn, 0);
		arch_register_t const *const reg1 = arch_get_irn_register_out(irn, 1);
Matthias Braun's avatar
Matthias Braun committed
848
849
		unsigned reg_idx0 = reg0->global_index;
		unsigned reg_idx1 = reg1->global_index;
850
		unsigned width    = arch_get_irn_register_req_out(irn, 0)->width;
Matthias Braun's avatar
Matthias Braun committed
851
852
853
854
855
856
857
858
		for (unsigned i = 0; i < width; ++i) {
			const arch_register_t *r0 = &sparc_registers[reg_idx0+i];
			const arch_register_t *r1 = &sparc_registers[reg_idx1+i];
			sparc_emitf(irn, "fmovs %R, %%f31", r0);
			sparc_emitf(irn, "fmovs %R, %R", r1, r0);
			sparc_emitf(irn, "fmovs %%f31, %R", r1);
		}
	} else {
859
860
861
		sparc_emitf(irn, "xor %D1, %D0, %D0");
		sparc_emitf(irn, "xor %D1, %D0, %D1");
		sparc_emitf(irn, "xor %D1, %D0, %D0");
Matthias Braun's avatar
Matthias Braun committed
862
	}
863
864
}

865
static unsigned get_aligned_sp_change(const unsigned num_regs)
866
{
867
	const unsigned bytes = num_regs * SPARC_REGISTER_SIZE;
868
	return round_up2(bytes, SPARC_STACK_ALIGNMENT);
869
870
}

871
872
873
/* Spill register l0 or both l0 and l1, depending on n_spilled and n_to_spill.*/
static void memperm_emit_spill_registers(const ir_node *node, int n_spilled,
                                         int n_to_spill)
Hannes Rapp's avatar
Hannes Rapp committed
874
{
875
	assert(n_spilled < n_to_spill);
876

877
878
879
880
881
882
	if (n_spilled == 0) {
		/* We always reserve stack space for two registers because during copy
		 * processing we don't know yet if we also need to handle a cycle which
		 * needs two registers.  More complicated code in emit_MemPerm would
		 * prevent wasting SPARC_REGISTER_SIZE bytes of stack space but
		 * it is not worth the worse readability of emit_MemPerm. */
Hannes Rapp's avatar
Hannes Rapp committed
883

884
		const unsigned sp_change = get_aligned_sp_change(2);
885
886
		sparc_emitf(node, "sub %%sp, %u, %%sp", sp_change);
		sparc_emitf(node, "st %%l0, [%%sp%+d]", SPARC_MIN_STACKSIZE);
887
	}
Hannes Rapp's avatar
Hannes Rapp committed
888

889
	if (n_to_spill == 2) {
890
		sparc_emitf(node, "st %%l1, [%%sp%+d]", SPARC_MIN_STACKSIZE + SPARC_REGISTER_SIZE);
891
892
	}
}
893

894
895
896
897
/* Restore register l0 or both l0 and l1, depending on n_spilled. */
static void memperm_emit_restore_registers(const ir_node *node, int n_spilled)
{
	if (n_spilled == 2) {
898
		sparc_emitf(node, "ld [%%sp%+d], %%l1", SPARC_MIN_STACKSIZE + SPARC_REGISTER_SIZE);
899
	}
Hannes Rapp's avatar
Hannes Rapp committed
900

901
	sparc_emitf(node, "ld [%%sp%+d], %%l0", SPARC_MIN_STACKSIZE);
902
	const unsigned sp_change = get_aligned_sp_change(2);
903
	sparc_emitf(node, "add %%sp, %u, %%sp", sp_change);
904
905
}

906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
static int get_real_entity_offset(const ir_node *node, ir_entity *ent)
{
	ir_graph          *irg     = get_irn_irg(node);
	be_stack_layout_t *layout  = be_get_irg_stack_layout(irg);
	const int          off_ent = be_get_stack_entity_offset(layout, ent, 0);

	if (layout->sp_relative) {
		ir_entity *ent_ref   = be_get_MemPerm_in_entity(node, 0);
		const int  off_ref   = be_get_stack_entity_offset(layout, ent_ref, 0);
		const int  delta_ent = off_ent - off_ref;
		const int  offset    = be_get_MemPerm_offset(node);
		const int  sp_change = (int)get_aligned_sp_change(2);
		return offset + delta_ent + sp_change;
	} else {
		return off_ent;
	}
}

924
925
926
927
928
static void memperm_emit_copy(const ir_node *node, ir_entity *in_ent,
                              ir_entity *out_ent)
{
	ir_graph          *irg     = get_irn_irg(node);
	be_stack_layout_t *layout  = be_get_irg_stack_layout(irg);
929
930
931
	const char        *reg     = layout->sp_relative ? "sp" : "fp";
	const int          off_in  = get_real_entity_offset(node, in_ent);
	const int          off_out = get_real_entity_offset(node, out_ent);
932

933
934
	sparc_emitf(node, "ld [%%%s%+d], %%l0", reg, off_in);
	sparc_emitf(node, "st %%l0, [%%%s%+d]", reg, off_out);
935
936
937
938
939
}

static void memperm_emit_swap(const ir_node *node, ir_entity *ent1,
                              ir_entity *ent2)
{
940
941
942
943
944
945
946
947
948
949
	ir_graph          *irg    = get_irn_irg(node);
	be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
	const char        *reg    = layout->sp_relative ? "sp" : "fp";
	const int          off1   = get_real_entity_offset(node, ent1);
	const int          off2   = get_real_entity_offset(node, ent2);

	sparc_emitf(node, "ld [%%%s%+d], %%l0", reg, off1);
	sparc_emitf(node, "ld [%%%s%+d], %%l1", reg, off2);
	sparc_emitf(node, "st %%l0, [%%%s%+d]", reg, off2);
	sparc_emitf(node, "st %%l1, [%%%s%+d]", reg, off1);
950
951
952
953
}

static int get_index(ir_entity **ents, int n, ir_entity *ent)
{
Matthias Braun's avatar
Matthias Braun committed
954
	for (int i = 0; i < n; ++i) {
955
956
		if (ents[i] == ent)
			return i;
Matthias Braun's avatar
Matthias Braun committed
957
	}
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984

	return -1;
}

/*
 * Emit code for a MemPerm node.
 *
 * Analyze MemPerm for copy chains and cyclic swaps and resolve them using
 * loads and stores.
 * This function is conceptually very similar to permute_values in
 * beprefalloc.c.
 */
static void emit_be_MemPerm(const ir_node *node)
{
	int         memperm_arity = be_get_MemPerm_entity_arity(node);
	/* Upper limit for the number of participating entities is twice the
	 * arity, e.g., for a simple copying MemPerm node with one input/output. */
	int         max_size      = 2 * memperm_arity;
	ir_entity **entities      = ALLOCANZ(ir_entity *, max_size);
	/* sourceof contains the input entity for each entity.  If an entity is
	 * never used as an output, its entry in sourceof is a fix point. */
	int        *sourceof      = ALLOCANZ(int,         max_size);
	/* n_users counts how many output entities use this entity as their input.*/
	int        *n_users       = ALLOCANZ(int,         max_size);
	/* n_spilled records the number of spilled registers, either 1 or 2. */
	int         n_spilled     = 0;

Matthias Braun's avatar
Matthias Braun committed
985
	for (int i = 0; i < max_size; ++i) {
986
		sourceof[i] = i;
Hannes Rapp's avatar
Hannes Rapp committed
987
988
	}

Matthias Braun's avatar
Matthias Braun committed
989
990
	int n = 0;
	for (int i = 0; i < memperm_arity; ++i) {
991
992
		ir_entity *out  = be_get_MemPerm_out_entity(node, i);
		ir_entity *in   = be_get_MemPerm_in_entity(node, i);
993

994
995
996
997
998
		/* Insert into entities to be able to operate on unique indices. */
		if (get_index(entities, n, out) == -1)
			entities[n++] = out;
		if (get_index(entities, n, in) == -1)
			entities[n++] = in;
Hannes Rapp's avatar
Hannes Rapp committed
999

Matthias Braun's avatar
Matthias Braun committed
1000
		int oidx = get_index(entities, n, out);
For faster browsing, not all history is shown. View entire blame