begnuas.c 41.4 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

20
/**
Christian Würdig's avatar
Christian Würdig committed
21
22
23
24
25
 * @file
 * @brief       Dumps global variables and constants as gas assembler.
 * @author      Christian Wuerdig, Matthias Braun
 * @date        04.11.2005
 * @version     $Id$
26
 */
27
#include "config.h"
28

Matthias Braun's avatar
Matthias Braun committed
29
30
#include "begnuas.h"

31
32
33
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
Christian Würdig's avatar
Christian Würdig committed
34
#include <assert.h>
35

36
#include "obst.h"
37
38
39
#include "tv.h"
#include "irnode.h"
#include "irprog.h"
40
#include "entity_t.h"
41
#include "error.h"
42

Matthias Braun's avatar
Matthias Braun committed
43
44
45
#include "be_t.h"
#include "beemitter.h"
#include "be_dbgout.h"
46

Matthias Braun's avatar
Matthias Braun committed
47
/** by default, we generate assembler code for the Linux gas */
Matthias Braun's avatar
Matthias Braun committed
48
49
object_file_format_t  be_gas_object_file_format = OBJECT_FILE_FORMAT_ELF;
bool                  be_gas_emit_types         = true;
50
char                  be_gas_elf_type_char      = '@';
Matthias Braun's avatar
Matthias Braun committed
51

52
53
static be_gas_section_t current_section = (be_gas_section_t) -1;

Michael Beck's avatar
Michael Beck committed
54
/**
55
56
57
58
 * An environment containing all needed dumper data.
 * Currently we create the file completely in memory first, then
 * write it to the disk. This is an artifact from the old C-generating backend
 * and even there NOT needed. So we might change it in the future.
Michael Beck's avatar
Michael Beck committed
59
 */
60
61
62
63
64
typedef struct _be_gas_decl_env {
	be_gas_section_t     section;
	const be_main_env_t *main_env;
} be_gas_decl_env_t;

Matthias Braun's avatar
Matthias Braun committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
static void emit_section_macho(be_gas_section_t section)
{
	be_gas_section_t  base  = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t  flags = section & ~GAS_SECTION_TYPE_MASK;
	const char       *name;

	if (current_section == section)
		return;
	current_section = section;

	/* shortforms */
	if (flags == 0) {
		switch (base) {
		case GAS_SECTION_TEXT:            name = "text";          break;
		case GAS_SECTION_DATA:            name = "data";          break;
		case GAS_SECTION_RODATA:          name = "const";         break;
		case GAS_SECTION_BSS:             name = "data";          break;
		case GAS_SECTION_CONSTRUCTORS:    name = "mod_init_func"; break;
		case GAS_SECTION_DESTRUCTORS:     name = "mod_term_func"; break;
		case GAS_SECTION_PIC_TRAMPOLINES: name = "section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5"; break;
		case GAS_SECTION_PIC_SYMBOLS:     name = "section\t__IMPORT,__pointers,non_lazy_symbol_pointers"; break;
		case GAS_SECTION_CSTRING:         name = "cstring";       break;
		default: panic("unsupported scetion type 0x%X", section);
		}
		be_emit_irprintf("\t.%s\n", name);
		be_emit_write_line();
	} else if (flags & GAS_SECTION_FLAG_COMDAT) {
		switch (base) {
		case GAS_SECTION_TEXT:            name = "section __TEXT,__textcoal_nt,coalesced,pure_instructions"; break;
		case GAS_SECTION_BSS:
		case GAS_SECTION_DATA:            name = "section __DATA,__datacoal_nt,coalesced"; break;
		case GAS_SECTION_RODATA:          name = "section __TEXT,__const_coal,coalesced"; break;
		case GAS_SECTION_CSTRING:         name = "section __TEXT,__const_coal,coalesced"; break;
		default: panic("unsupported scetion type 0x%X", section);
		}
	} else {
		panic("unsupported section type 0x%X\n", section);
	}
}

105
static void emit_section(be_gas_section_t section, const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
106
{
107
108
	be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
Matthias Braun's avatar
Matthias Braun committed
109
	static const char *const basename[] = {
110
111
		"text", "data", "rodata", "bss", "ctors", "dtors"
	};
Matthias Braun's avatar
Matthias Braun committed
112
	static const char *const type[] = {
Matthias Braun's avatar
Matthias Braun committed
113
		"progbits", "progbits", "progbits", "nobits", "init_array", "fini_array"
Matthias Braun's avatar
Matthias Braun committed
114
115
	};

Matthias Braun's avatar
Matthias Braun committed
116
117
118
119
120
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		emit_section_macho(section);
		return;
	}

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
	if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
		return;
	current_section = section;

	/* shortforms */
	if (flags == 0) {
		switch (base) {
		case GAS_SECTION_TEXT:
			be_emit_cstring("\t.text\n");
			be_emit_write_line();
			return;
		case GAS_SECTION_DATA:
			be_emit_cstring("\t.data\n");
			be_emit_write_line();
			return;
		case GAS_SECTION_RODATA:
			be_emit_cstring("\t.section\t.rodata\n");
			be_emit_write_line();
			return;
		case GAS_SECTION_BSS:
			be_emit_cstring("\t.bss\n");
			be_emit_write_line();
			return;
		default:
			break;
		}
	}

	assert(base < sizeof(basename)/sizeof(basename[0]));
	be_emit_cstring("\t.section\t.");
	/* section name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
	be_emit_string(basename[base]);
	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}

	/* section flags */
	be_emit_cstring(",\"");
	if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF)
		be_emit_char('a');
	if (base != GAS_SECTION_RODATA)
		be_emit_char('w');
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('T');
	if (flags & GAS_SECTION_FLAG_COMDAT)
		be_emit_char('G');
	be_emit_cstring("\",");
	be_emit_char(be_gas_elf_type_char);
	be_emit_string(type[base]);

	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char(',');
		be_gas_emit_entity(entity);
		be_emit_cstring(",comdat");
	}
	be_emit_char('\n');
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
181
182
}

Matthias Braun's avatar
Matthias Braun committed
183
184
void be_gas_emit_switch_section(be_gas_section_t section)
{
185
186
187
188
189
190
191
	/* you have to produce a switch_section call with entity manually
	 * for comdat sections */
	assert( !(section & GAS_SECTION_FLAG_COMDAT));

	emit_section(section, NULL);
}

Matthias Braun's avatar
Matthias Braun committed
192
193
194
195
196
197
198
199
200
201
202
203
204
static tarval *get_initializer_tarval(const ir_initializer_t *initializer)
{
	if (initializer->kind == IR_INITIALIZER_TARVAL)
		return initializer->tarval.value;
	if (initializer->kind == IR_INITIALIZER_CONST) {
		ir_node *node = initializer->consti.value;
		if (is_Const(node)) {
			return get_Const_tarval(node);
		}
	}
	return get_tarval_undefined();
}

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
static int initializer_is_string_const(const ir_initializer_t *initializer)
{
	size_t i, len;
	int found_printable = 0;

	if (initializer->kind != IR_INITIALIZER_COMPOUND)
		return 0;

	len = initializer->compound.n_initializers;
	if (len < 1)
		return 0;
	for (i = 0; i < len; ++i) {
		int               c;
		tarval           *tv;
		ir_mode          *mode;
		ir_initializer_t *sub_initializer
			= initializer->compound.initializers[i];

Matthias Braun's avatar
Matthias Braun committed
223
224
		tv = get_initializer_tarval(sub_initializer);
		if (!tarval_is_constant(tv))
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
			return 0;

		mode = get_tarval_mode(tv);
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
			return 0;

		c = get_tarval_long(tv);
		if (isgraph(c) || isspace(c))
			found_printable = 1;
		else if (c != 0)
			return 0;

		if (i == len - 1 && c != '\0')
			return 0;
	}

	return found_printable;
}

static bool initializer_is_null(const ir_initializer_t *initializer)
{
	switch (initializer->kind) {
	case IR_INITIALIZER_NULL:
		return true;
	case IR_INITIALIZER_TARVAL: {
		tarval *tv = initializer->tarval.value;
		return tarval_is_null(tv);
	}
	case IR_INITIALIZER_CONST: {
		ir_node *value = initializer->consti.value;
		if (!is_Const(value))
			return false;
		return is_Const_null(value);
	}
	case IR_INITIALIZER_COMPOUND: {
		size_t i;
		for (i = 0; i < initializer->compound.n_initializers; ++i) {
			ir_initializer_t *subinitializer
				= initializer->compound.initializers[i];
			if (!initializer_is_null(subinitializer))
				return false;
		}
		return true;
	}
	}
	panic("invalid initializer in initializer_is_null");
}

/**
 * Determine if an entity is a string constant
 * @param ent The entity
 * @return 1 if it is a string constant, 0 otherwise
 */
static int entity_is_string_const(const ir_entity *ent)
{
	ir_type *type, *element_type;
	ir_mode *mode;
	int i, c, n;
283

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
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
	type = get_entity_type(ent);

	/* if it's an array */
	if (!is_Array_type(type))
		return 0;

	element_type = get_array_element_type(type);

	/* and the array's element type is primitive */
	if (!is_Primitive_type(element_type))
		return 0;

	/* and the mode of the element type is an int of
	 * the same size as the byte mode */
	mode = get_type_mode(element_type);
	if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
		return 0;

	if (ent->initializer != NULL) {
		return initializer_is_string_const(ent->initializer);
	} else if (entity_has_compound_ent_values(ent)) {
		int found_printable = 0;
		/* if it contains only printable chars and a 0 at the end */
		n = get_compound_ent_n_values(ent);
		for (i = 0; i < n; ++i) {
			ir_node *irn = get_compound_ent_value(ent, i);
			if (! is_Const(irn))
				return 0;

			c = (int) get_tarval_long(get_Const_tarval(irn));

			if (isgraph(c) || isspace(c))
				found_printable = 1;
			else if (c != 0)
				return 0;

			if (i == n - 1 && c != '\0')
				return 0;
		}
		return found_printable;
	}

	return 0;
}

static bool entity_is_null(const ir_entity *entity)
{
	if (entity->initializer != NULL) {
		return initializer_is_null(entity->initializer);
	} else if (entity_has_compound_ent_values(entity)) {
		/* I'm too lazy to implement this case as compound graph paths will be
		 * remove anyway in the future */
	}
	/* uninitialized, NULL is fine */
	return true;
}

static bool is_comdat(const ir_entity *entity)
{
	ir_linkage linkage = get_entity_linkage(entity);
	return (linkage & IR_LINKAGE_MERGE)
		&& (linkage & IR_LINKAGE_GARBAGE_COLLECT);
}

static be_gas_section_t determine_basic_section(const ir_entity *entity)
{
	ir_linkage linkage;

	if (is_method_entity(entity))
		return GAS_SECTION_TEXT;

	linkage = get_entity_linkage(entity);
	if (linkage & IR_LINKAGE_CONSTANT) {
		/* mach-o is the only one with a cstring section */
		if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
				&& entity_is_string_const(entity))
			return GAS_SECTION_CSTRING;

		return GAS_SECTION_RODATA;
	}
	if (entity_is_null(entity))
		return GAS_SECTION_BSS;

	return GAS_SECTION_DATA;
}

static be_gas_section_t determine_section(be_gas_decl_env_t *env,
                                          const ir_entity *entity)
{
	ir_type *owner = get_entity_owner(entity);

	if (owner == get_segment_type(IR_SEGMENT_GLOBAL)) {
		be_gas_section_t section = determine_basic_section(entity);
		if (is_comdat(entity))
			section |= GAS_SECTION_FLAG_COMDAT;
		return section;
	} else if (env != NULL && owner == env->main_env->pic_symbols_type) {
		return GAS_SECTION_PIC_SYMBOLS;
	} else if (env != NULL && owner == env->main_env->pic_trampolines_type) {
		return GAS_SECTION_PIC_TRAMPOLINES;
	} else if (owner == get_segment_type(IR_SEGMENT_CONSTRUCTORS)) {
		return GAS_SECTION_CONSTRUCTORS;
	} else if (owner == get_segment_type(IR_SEGMENT_DESTRUCTORS)) {
		return GAS_SECTION_DESTRUCTORS;
	} else if (owner == get_segment_type(IR_SEGMENT_THREAD_LOCAL)) {
		be_gas_section_t section = determine_basic_section(entity);
		if (is_comdat(entity))
			section |= GAS_SECTION_FLAG_COMDAT;

		return section | GAS_SECTION_FLAG_TLS;
	}

	panic("Couldn't determine section for %+F?!?", entity);
}

static void emit_weak(const ir_entity *entity)
{
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		be_emit_cstring("\t.weak_reference ");
	} else {
		be_emit_cstring("\t.weak ");
	}
	be_gas_emit_entity(entity);
407
408
	be_emit_char('\n');
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
409
410
}

411
static void emit_visibility(const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
412
{
413
414
	ir_linkage linkage = get_entity_linkage(entity);

415
	if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
416
417
418
419
		emit_weak(entity);
		/* Note: .weak seems to imply .globl so no need to output .globl */
	} else if (get_entity_visibility(entity) == ir_visibility_default) {
		be_emit_cstring(".globl ");
420
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
421
422
		be_emit_char('\n');
		be_emit_write_line();
423
424
425
426
427
	}

	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
			&& (linkage & IR_LINKAGE_HIDDEN_USER)) {
		be_emit_cstring("\t.no_dead_strip ");
428
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
429
430
431
432
433
		be_emit_char('\n');
		be_emit_write_line();
	}
}

434
void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
435
{
436
437
	be_gas_section_t section = determine_section(NULL, entity);
	emit_section(section, entity);
438

Matthias Braun's avatar
Matthias Braun committed
439
440
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
441
442
	be_emit_write_line();
	be_emit_cstring("# -- Begin  ");
443
	be_gas_emit_entity(entity);
444
445
446
	be_emit_char('\n');
	be_emit_write_line();

447
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
448
449
450
451
452
453
		const char *fill_byte = "";
		unsigned    maximum_skip = (1 << po2alignment) - 1;
		/* gcc fills space between function with 0x90... */
		if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
			fill_byte = "0x90";
		}
Michael Beck's avatar
Michael Beck committed
454
		be_emit_cstring("\t.p2align ");
455
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
456
457
		be_emit_write_line();
	}
458
	emit_visibility(entity);
459

Matthias Braun's avatar
Matthias Braun committed
460
461
	switch (be_gas_object_file_format) {
	case OBJECT_FILE_FORMAT_ELF:
462
		be_emit_cstring("\t.type\t");
463
		be_gas_emit_entity(entity);
464
465
466
		be_emit_cstring(", ");
		be_emit_char(be_gas_elf_type_char);
		be_emit_cstring("function\n");
467
468
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
469
	case OBJECT_FILE_FORMAT_COFF:
470
		be_emit_cstring("\t.def\t");
471
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
472
		be_emit_cstring(";");
473
		if (get_entity_visibility(entity) == ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
474
			be_emit_cstring("\t.scl\t3;");
475
		} else {
Matthias Braun's avatar
Matthias Braun committed
476
			be_emit_cstring("\t.scl\t2;");
477
		}
Matthias Braun's avatar
Matthias Braun committed
478
		be_emit_cstring("\t.type\t32;\t.endef\n");
479
480
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
481
	case OBJECT_FILE_FORMAT_MACH_O:
482
483
		break;
	}
484
	be_gas_emit_entity(entity);
485
486
487
488
	be_emit_cstring(":\n");
	be_emit_write_line();
}

489
void be_gas_emit_function_epilog(const ir_entity *entity)
490
{
Matthias Braun's avatar
Matthias Braun committed
491
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
492
		be_emit_cstring("\t.size\t");
493
		be_gas_emit_entity(entity);
494
		be_emit_cstring(", .-");
495
		be_gas_emit_entity(entity);
496
497
498
499
500
		be_emit_char('\n');
		be_emit_write_line();
	}

	be_emit_cstring("# -- End  ");
501
	be_gas_emit_entity(entity);
502
503
504
505
	be_emit_char('\n');
	be_emit_write_line();
}

506
507
/************************************************************************/

Michael Beck's avatar
Michael Beck committed
508
/**
Michael Beck's avatar
Michael Beck committed
509
510
511
512
 * Output a tarval.
 *
 * @param tv     the tarval
 * @param bytes  the width of the tarvals value in bytes
Michael Beck's avatar
Michael Beck committed
513
 */
514
static void emit_arith_tarval(tarval *tv, int bytes)
515
{
516
517
	switch (bytes) {
	case 1:
518
		be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
519
		return;
520
521

	case 2:
522
		be_emit_irprintf("0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
523
		return;
524
525

	case 4:
526
		be_emit_irprintf("0x%02x%02x%02x%02x",
527
			get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
528
		return;
529
530

	case 8:
531
		be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x",
532
533
			get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
			get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
534
		return;
535
536

	case 12:
537
538
539
540
541
542
543
544
545
546
547
548
549
		/* Beware: Mixed endian output!  One little endian number emitted as
		 * three longs.  Each long initializer is written in big endian. */
		be_emit_irprintf(
			"\t.long\t0x%02x%02x%02x%02x\n"
			"\t.long\t0x%02x%02x%02x%02x\n"
			"\t.long\t0x%02x%02x%02x%02x",
			get_tarval_sub_bits(tv,  3), get_tarval_sub_bits(tv,  2),
			get_tarval_sub_bits(tv,  1), get_tarval_sub_bits(tv,  0),
			get_tarval_sub_bits(tv,  7), get_tarval_sub_bits(tv,  6),
			get_tarval_sub_bits(tv,  5), get_tarval_sub_bits(tv,  4),
			get_tarval_sub_bits(tv, 11), get_tarval_sub_bits(tv, 10),
			get_tarval_sub_bits(tv,  9), get_tarval_sub_bits(tv,  8)
		);
Matthias Braun's avatar
Matthias Braun committed
550
		return;
551

552
	case 16:
Matthias Braun's avatar
Matthias Braun committed
553
554
		/* Beware: Mixed endian output!  One little endian number emitted as
		 * three longs.  Each long initializer is written in big endian. */
555
		be_emit_irprintf(
Matthias Braun's avatar
Matthias Braun committed
556
557
558
559
560
561
			"\t.long\t0x%02x%02x%02x%02x\n"
			"\t.long\t0x%02x%02x%02x%02x\n"
			"\t.long\t0x%02x%02x%02x%02x\n"
			"\t.long\t0x%02x%02x%02x%02x",
			get_tarval_sub_bits(tv,  3), get_tarval_sub_bits(tv,  2),
			get_tarval_sub_bits(tv,  1), get_tarval_sub_bits(tv,  0),
562
563
			get_tarval_sub_bits(tv,  7), get_tarval_sub_bits(tv,  6),
			get_tarval_sub_bits(tv,  5), get_tarval_sub_bits(tv,  4),
Matthias Braun's avatar
Matthias Braun committed
564
565
566
567
			get_tarval_sub_bits(tv, 11), get_tarval_sub_bits(tv, 10),
			get_tarval_sub_bits(tv,  9), get_tarval_sub_bits(tv,  8),
			get_tarval_sub_bits(tv, 15), get_tarval_sub_bits(tv, 14),
			get_tarval_sub_bits(tv, 13), get_tarval_sub_bits(tv, 12)
568
		);
Matthias Braun's avatar
Matthias Braun committed
569
		return;
570
	}
Matthias Braun's avatar
Matthias Braun committed
571

572
	panic("Can't dump a tarval with %d bytes", bytes);
573
574
}

575
576
577
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
578
579
const char *be_gas_insn_label_prefix(void)
{
580
581
582
	return ".LE";
}

583
584
/**
 * Return the tarval of an atomic initializer.
Michael Beck's avatar
Michael Beck committed
585
 *
Michael Beck's avatar
Michael Beck committed
586
 * @param init  a node representing the initializer (on the const code irg)
Michael Beck's avatar
Michael Beck committed
587
588
 *
 * @return the tarval
589
 */
590
591
static tarval *get_atomic_init_tv(ir_node *init)
{
592
593
	for (;;) {
		ir_mode *mode = get_irn_mode(init);
594

595
		switch (get_irn_opcode(init)) {
596

597
598
599
		case iro_Cast:
			init = get_Cast_op(init);
			continue;
600

601
602
603
		case iro_Conv:
			init = get_Conv_op(init);
			continue;
604

605
606
		case iro_Const:
			return get_Const_tarval(init);
607

608
609
610
611
		case iro_SymConst:
			switch (get_SymConst_kind(init)) {
			case symconst_type_size:
				return new_tarval_from_long(get_type_size_bytes(get_SymConst_type(init)), mode);
612

613
614
			case symconst_type_align:
				return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
615

Michael Beck's avatar
Michael Beck committed
616
617
618
			case symconst_ofs_ent:
				return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);

619
620
			case symconst_enum_const:
				return get_enumeration_value(get_SymConst_enum(init));
621

622
623
624
			default:
				return NULL;
			}
625
626
627

		default:
			return NULL;
628
		}
629
630
631
	}
}

632
/**
Michael Beck's avatar
Michael Beck committed
633
634
635
636
 * Dump an atomic value.
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
637
 */
638
static void do_emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
639
{
640
641
642
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
	tarval *tv;
643
	ir_entity *ent;
644

645
646
	init = skip_Id(init);

647
648
	switch (get_irn_opcode(init)) {
	case iro_Cast:
649
		do_emit_atomic_init(env, get_Cast_op(init));
650
651
652
		return;

	case iro_Conv:
653
		do_emit_atomic_init(env, get_Conv_op(init));
654
655
656
657
658
659
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

		/* it's a arithmetic value */
660
		emit_arith_tarval(tv, bytes);
661
662
663
664
665
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_name:
666
			be_emit_ident(get_SymConst_name(init));
667
668
669
			break;

		case symconst_addr_ent:
670
			ent = get_SymConst_entity(init);
671
			be_gas_emit_entity(ent);
672
673
			break;

674
		case symconst_ofs_ent:
675
			ent = get_SymConst_entity(init);
676
			be_emit_irprintf("%d", get_entity_offset(ent));
677
678
			break;

679
		case symconst_type_size:
680
			be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
681
682
			break;

683
		case symconst_type_align:
684
			be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
685
686
			break;

Michael Beck's avatar
Michael Beck committed
687
		case symconst_enum_const:
688
			tv = get_enumeration_value(get_SymConst_enum(init));
689
			emit_arith_tarval(tv, bytes);
Michael Beck's avatar
Michael Beck committed
690
691
			break;

692
		default:
693
			assert(!"emit_atomic_init(): don't know how to init from this SymConst");
694
695
696
		}
		return;

Michael Beck's avatar
Michael Beck committed
697
698
699
700
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '+' to work");
		}
701
		do_emit_atomic_init(env, get_Add_left(init));
Michael Beck's avatar
Michael Beck committed
702
		be_emit_cstring(" + ");
703
		do_emit_atomic_init(env, get_Add_right(init));
Michael Beck's avatar
Michael Beck committed
704
		return;
705

Michael Beck's avatar
Michael Beck committed
706
707
708
709
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '-' to work");
		}
710
		do_emit_atomic_init(env, get_Sub_left(init));
Michael Beck's avatar
Michael Beck committed
711
		be_emit_cstring(" - ");
712
		do_emit_atomic_init(env, get_Sub_right(init));
Michael Beck's avatar
Michael Beck committed
713
714
715
716
717
718
		return;

	case iro_Mul:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '*' to work");
		}
719
		do_emit_atomic_init(env, get_Mul_left(init));
Michael Beck's avatar
Michael Beck committed
720
		be_emit_cstring(" * ");
721
		do_emit_atomic_init(env, get_Mul_right(init));
Michael Beck's avatar
Michael Beck committed
722
723
		return;

Olaf Liebe's avatar
Olaf Liebe committed
724
725
726
727
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
728
	default:
729
		panic("emit_atomic_init(): unsupported IR-node %+F", init);
730
	}
731
732
}

733
/**
Michael Beck's avatar
Michael Beck committed
734
735
736
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
737
 */
738
static void emit_size_type(size_t size)
739
{
Christian Würdig's avatar
Christian Würdig committed
740
	switch (size) {
741
	case 1:
742
		be_emit_cstring("\t.byte\t");
743
		break;
744

745
	case 2:
746
		be_emit_cstring("\t.short\t");
747
		break;
748

749
	case 4:
750
		be_emit_cstring("\t.long\t");
751
		break;
752

753
	case 8:
754
		be_emit_cstring("\t.quad\t");
755
		break;
756

757
758
	case 10:
	case 12:
Matthias Braun's avatar
Matthias Braun committed
759
	case 16: /* Note: .octa does not work on mac */
760
761
		/* handled in arith */
		break;
762

763
	default:
764
		panic("Try to dump a type with %u bytes", (unsigned)size);
765
	}
Christian Würdig's avatar
Christian Würdig committed
766
767
}

768
/**
769
 * Emit an atomic value.
Michael Beck's avatar
Michael Beck committed
770
771
772
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
Christian Würdig's avatar
Christian Würdig committed
773
 */
774
static void emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
Christian Würdig's avatar
Christian Würdig committed
775
776
777
{
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
778

779
780
	emit_size_type(bytes);
	do_emit_atomic_init(env, init);
781
782
	be_emit_char('\n');
	be_emit_write_line();
783
784
785
786
787
788
789
}

/************************************************************************/
/* Routines to dump global variables                                    */
/************************************************************************/

/**
Michael Beck's avatar
Michael Beck committed
790
 * Dump a string constant.
791
 * No checks are made!!
Michael Beck's avatar
Michael Beck committed
792
793
 *
 * @param ent  The entity to dump.
794
 */
795
static void emit_string_cst(const ir_entity *ent)
796
{
797
	int      i, len;
798
	int      output_len;
799
800
801
	ir_type *type;
	int      type_size;
	int      remaining_space;
802

803
804
	len        = get_compound_ent_n_values(ent);
	output_len = len;
Matthias Braun's avatar
Matthias Braun committed
805
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
806
807
808
		be_emit_cstring("\t.ascii \"");
	} else {
		be_emit_cstring("\t.string \"");
809
		output_len -= 1;
810
	}
811

812
	for (i = 0; i < output_len; ++i) {
813
814
815
816
817
818
819
		ir_node *irn;
		int c;

		irn = get_compound_ent_value(ent, i);
		c = (int) get_tarval_long(get_Const_tarval(irn));

		switch (c) {
820
821
822
823
824
		case '"' : be_emit_cstring("\\\""); break;
		case '\n': be_emit_cstring("\\n"); break;
		case '\r': be_emit_cstring("\\r"); break;
		case '\t': be_emit_cstring("\\t"); break;
		case '\\': be_emit_cstring("\\\\"); break;
825
826
		default  :
			if (isprint(c))
827
				be_emit_char(c);
828
			else
829
				be_emit_irprintf("\\%o", c);
830
831
832
			break;
		}
	}
833
834
	be_emit_cstring("\"\n");
	be_emit_write_line();
835
836
837

	type            = get_entity_type(ent);
	type_size       = get_type_size_bytes(type);
838
	remaining_space = type_size - len;
839
	assert(remaining_space >= 0);
Michael Beck's avatar
Michael Beck committed
840
	if (remaining_space > 0) {
841
		be_emit_irprintf("\t.space\t%d\n", remaining_space);
842
	}
843
844
}

845
static void emit_string_initializer(const ir_initializer_t *initializer)
846
847
848
849
{
	size_t i, len;

	len = initializer->compound.n_initializers;
Matthias Braun's avatar
Matthias Braun committed
850
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
Matthias Braun's avatar
Matthias Braun committed
851
852
		be_emit_cstring("\t.ascii \"");
	} else {
853
854
855
856
		be_emit_cstring("\t.string \"");
		len -= 1;
	}

Michael Beck's avatar
Michael Beck committed
857
	for (i = 0; i < len; ++i) {
858
859
860
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
861
		tarval *tv = get_initializer_tarval(sub_initializer);
862
863
864
		int     c  = get_tarval_long(tv);

		switch (c) {
865
866
867
868
869
		case '"' : be_emit_cstring("\\\""); break;
		case '\n': be_emit_cstring("\\n"); break;
		case '\r': be_emit_cstring("\\r"); break;
		case '\t': be_emit_cstring("\\t"); break;
		case '\\': be_emit_cstring("\\\\"); break;
870
871
		default  :
			if (isprint(c))
872
				be_emit_char(c);
873
			else
874
				be_emit_irprintf("\\%o", c);
875
876
877
			break;
		}
	}
878
879
	be_emit_cstring("\"\n");
	be_emit_write_line();
880
881
}

882
883
enum normal_or_bitfield_kind {
	NORMAL = 0,
884
	TARVAL,
885
886
887
888
889
890
	BITFIELD
};

typedef struct {
	enum normal_or_bitfield_kind kind;
	union {
891
892
893
		ir_node       *value;
		tarval        *tarval;
		unsigned char  bf_val;
894
895
896
	} v;
} normal_or_bitfield;

897
898
899
900
901
902
903
904
905
906
static int is_type_variable_size(ir_type *type)
{
	(void) type;
	/* TODO */
	return 0;
}

static size_t get_initializer_size(const ir_initializer_t *initializer,
                                   ir_type *type)
{
Michael Beck's avatar
Michael Beck committed
907
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
908
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
909
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
910
911
912
913
		return get_type_size_bytes(type);
	case IR_INITIALIZER_CONST:
	case IR_INITIALIZER_NULL:
		return get_type_size_bytes(type);
Michael Beck's avatar
Michael Beck committed
914
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
915
		if (!is_type_variable_size(type)) {
916
917
918
919
920
921
			return get_type_size_bytes(type);
		} else {
			unsigned n_entries
				= get_initializer_compound_n_entries(initializer);
			unsigned i;
			unsigned initializer_size = get_type_size_bytes(type);
Michael Beck's avatar
Michael Beck committed
922
			for (i = 0; i < n_entries; ++i) {
923
924
925
926
927
928
929
930
931
				ir_entity *entity = get_compound_member(type, i);
				ir_type   *type   = get_entity_type(entity);

				const ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

				unsigned offset = get_entity_offset(entity);
				unsigned size   = get_initializer_size(sub_initializer, type);

Michael Beck's avatar
Michael Beck committed
932
				if (offset + size > initializer_size) {
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
					initializer_size = offset + size;
				}
			}
			return initializer_size;
		}
	}

	panic("found invalid initializer");
}

#ifndef NDEBUG
static normal_or_bitfield *glob_vals;
static size_t              max_vals;
#endif

948
static void emit_bitfield(normal_or_bitfield *vals, size_t offset_bits,
949
950
951
952
953
954
955
956
957
                          const ir_initializer_t *initializer, ir_type *type)
{
	unsigned char  last_bits = 0;
	ir_mode       *mode      = get_type_mode(type);
	tarval        *tv        = NULL;
	unsigned char  curr_bits;
	int            value_len;
	int            j;

Michael Beck's avatar
Michael Beck committed
958
	switch (get_initializer_kind(initializer)) {
959
960
961
962
963
964
965
	case IR_INITIALIZER_NULL:
		return;
	case IR_INITIALIZER_TARVAL:
		tv = get_initializer_tarval_value(initializer);
		break;
	case IR_INITIALIZER_CONST: {
		ir_node *node = get_initializer_const_value(initializer);
Michael Beck's avatar
Michael Beck committed
966
		if (!is_Const(node)) {
967
968
969
970
971
972
973
974
975
			panic("bitfield initializer not a Const node");
		}
		tv = get_Const_tarval(node);
		break;
	}
	case IR_INITIALIZER_COMPOUND:
		panic("bitfield initializer is compound");
	}
	if (tv == NULL) {
976
		panic("Couldn't get numeric value for bitfield initializer");
977
	}
978
	tv = tarval_convert_to(tv, get_type_mode(type));
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998

	/* normalize offset */
	vals        += offset_bits >> 3;
	offset_bits &= 7;
	value_len    = get_mode_size_bits(mode);

	/* combine bits with existing bits */
	for (j = 0; value_len + (int) offset_bits > 0; ++j) {
		assert((size_t) (vals - glob_vals) + j < max_vals);
		assert(vals[j].kind == BITFIELD ||
				(vals[j].kind == NORMAL && vals[j].v.value == NULL));
		vals[j].kind = BITFIELD;
		curr_bits    = get_tarval_sub_bits(tv, j);
		vals[j].v.bf_val
			|= (last_bits >> (8 - offset_bits)) | (curr_bits << offset_bits);
		value_len -= 8;
		last_bits = curr_bits;
	}
}

999
static void emit_ir_initializer(normal_or_bitfield *vals,
1000
1001
1002
1003
1004
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
	assert((size_t) (vals - glob_vals) < max_vals);

Michael Beck's avatar
Michael Beck committed
1005
	switch (get_initializer_kind(initializer)) {
1006
1007
1008
1009
1010
1011
1012
1013
1014
	case IR_INITIALIZER_NULL:
		return;
	case IR_INITIALIZER_TARVAL: {
		size_t i;

		assert(vals->kind != BITFIELD);
		vals->kind     = TARVAL;
		vals->v.tarval = get_initializer_tarval_value(initializer);
		assert(get_type_mode(type) == get_tarval_mode(vals->v.tarval));
Michael Beck's avatar
Michael Beck committed
1015
		for (i = 1; i < get_type_size_bytes(type); ++i) {
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
			vals[i].kind    = NORMAL;
			vals[i].v.value = NULL;
		}
		return;
	}
	case IR_INITIALIZER_CONST: {
		size_t i;

		assert(vals->kind != BITFIELD);
		vals->kind    = NORMAL;
		vals->v.value = get_initializer_const_value(initializer);
Michael Beck's avatar
Michael Beck committed
1027
		for (i = 1; i < get_type_size_bytes(type); ++i) {
1028
1029
1030
1031
1032
1033
1034
1035
1036
			vals[i].kind    = NORMAL;
			vals[i].v.value = NULL;
		}
		return;
	}
	case IR_INITIALIZER_COMPOUND: {
		size_t i = 0;
		size_t n = get_initializer_compound_n_entries(initializer);

Michael Beck's avatar
Michael Beck committed
1037
		if (is_Array_type(type)) {
1038
1039
1040
1041
			ir_type *element_type = get_array_element_type(type);
			size_t   skip         = get_type_size_bytes(element_type);
			size_t   alignment    = get_type_alignment_bytes(element_type);
			size_t   misalign     = skip % alignment;
Michael Beck's avatar
Michael Beck committed
1042
			if (misalign != 0) {
1043
1044
1045
				skip += alignment - misalign;
			}

Michael Beck's avatar
Michael Beck committed
1046
			for (i = 0; i < n; ++i) {
1047
1048
1049
				ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

1050
				emit_ir_initializer(vals, sub_initializer, element_type);
1051
1052
1053
1054

				vals += skip;
			}
		} else {
Michael Beck's avatar
Michael Beck committed
1055
			size_t n_members, i;
1056
			assert(is_compound_type(type));
Michael Beck's avatar
Michael Beck committed
1057
			n_members = get_compound_n_members(type);
Michael Beck's avatar
Michael Beck committed
1058
			for (i = 0; i < n_members; ++i) {
1059
1060
1061
1062
				ir_entity        *member    = get_compound_member(type, i);
				size_t            offset    = get_entity_offset(member);
				ir_type          *subtype   = get_entity_type(member);
				ir_mode          *mode      = get_type_mode(subtype);
1063
1064
1065
1066
1067
1068
				ir_initializer_t *sub_initializer;

				assert(i < get_initializer_compound_n_entries(initializer));
				sub_initializer
					= get_initializer_compound_value(initializer, i);

Michael Beck's avatar
Michael Beck committed
1069
				if (mode != NULL) {
1070
1071
1072
1073
					size_t offset_bits
						= get_entity_offset_bits_remainder(member);
					size_t value_len   = get_mode_size_bits(mode);

Michael Beck's avatar
Michael Beck committed
1074
					if (offset_bits != 0 ||
1075
1076
						(value_len != 8 && value_len != 16 && value_len != 32
						 && value_len != 64)) {
1077
						emit_bitfield(&vals[offset], offset_bits,
1078
1079
1080
1081
1082
						              sub_initializer, subtype);
						continue;
					}
				}

1083
				emit_ir_initializer(&vals[offset], sub_initializer, subtype);
1084
1085
1086
1087
1088
1089
			}
		}

		return;
	}
	}
1090
	panic("invalid ir_initializer kind found");
1091
1092
}

1093
static void emit_initializer(be_gas_decl_env_t *env, const ir_entity *entity)
1094
{
Matthias Braun's avatar
Matthias Braun committed
1095
	const ir_initializer_t *initializer = entity->initializer;
1096
1097
1098
1099
1100
	ir_type                *type;
	normal_or_bitfield     *vals;
	size_t                  size;
	size_t                  k;

Michael Beck's avatar
Michael Beck committed
1101
	if (initializer_is_string_const(initializer)) {
1102
		emit_string_initializer(initializer);
1103
1104
1105
1106
1107
1108
		return;
	}

	type = get_entity_type(entity);
	size = get_initializer_size(initializer, type);

Michael Beck's avatar
Michael Beck committed
1109
1110
1111
	if (size == 0)
		return;

1112
1113
1114
1115
	/*
	 * In the worst case, every initializer allocates one byte.
	 * Moreover, initializer might be big, do not allocate on stack.
	 */
1116
	vals = XMALLOCNZ(normal_or_bitfield, size);
1117
1118
1119
1120
1121
1122

#ifndef NDEBUG
	glob_vals = vals;
	max_vals  = size;
#endif

1123
	emit_ir_initializer(vals, initializer, type);
1124
1125
1126

	/* now write values sorted */
	for (k = 0; k < size; ) {
1127
1128
		int space     = 0;
		int elem_size = 1;
1129
		if (vals[k].kind == NORMAL) {
Michael Beck's avatar
Michael Beck committed
1130
			if (vals[k].v.value != NULL) {
1131
				emit_atomic_init(env, vals[k].v.value);
1132
				elem_size = get_mode_size_bytes(get_irn_mode(vals[k].v.value));
1133
	 		} else {
1134
	 			elem_size = 0;
1135
	 		}
Michael Beck's avatar
Michael Beck committed
1136
		} else if (vals[k].kind == TARVAL) {
1137
1138
1139
1140
1141
			tarval *tv   = vals[k].v.tarval;
			size_t  size = get_mode_size_bytes(get_tarval_mode(tv));

			assert(tv != NULL);

1142
			elem_size = size;
1143
1144
			emit_size_type(size);
			emit_arith_tarval(tv, size);
1145
1146
			be_emit_char('\n');
			be_emit_write_line();
1147
1148
		} else {
			assert(vals[k].kind == BITFIELD);
1149
1150
			be_emit_irprintf("\t.byte\t%d\n", vals[k].v.bf_val);
			be_emit_write_line();