begnuas.c 41.1 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[] = {
113
		"", "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 blocks.
 */
Matthias Braun's avatar
Matthias Braun committed
578
579
const char *be_gas_block_label_prefix(void)
{
Michael Beck's avatar
Michael Beck committed
580
581
582
	return ".LG";
}

583
584
585
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
586
587
const char *be_gas_insn_label_prefix(void)
{
588
589
590
	return ".LE";
}

591
592
/**
 * Return the tarval of an atomic initializer.
Michael Beck's avatar
Michael Beck committed
593
 *
Michael Beck's avatar
Michael Beck committed
594
 * @param init  a node representing the initializer (on the const code irg)
Michael Beck's avatar
Michael Beck committed
595
596
 *
 * @return the tarval
597
 */
598
599
static tarval *get_atomic_init_tv(ir_node *init)
{
600
601
	for (;;) {
		ir_mode *mode = get_irn_mode(init);
602

603
		switch (get_irn_opcode(init)) {
604

605
606
607
		case iro_Cast:
			init = get_Cast_op(init);
			continue;
608

609
610
611
		case iro_Conv:
			init = get_Conv_op(init);
			continue;
612

613
614
		case iro_Const:
			return get_Const_tarval(init);
615

616
617
618
619
		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);
620

621
622
			case symconst_type_align:
				return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
623

Michael Beck's avatar
Michael Beck committed
624
625
626
			case symconst_ofs_ent:
				return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);

627
628
			case symconst_enum_const:
				return get_enumeration_value(get_SymConst_enum(init));
629

630
631
632
			default:
				return NULL;
			}
633
634
635

		default:
			return NULL;
636
		}
637
638
639
	}
}

640
/**
Michael Beck's avatar
Michael Beck committed
641
642
643
644
 * Dump an atomic value.
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
645
 */
646
static void do_emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
647
{
648
649
650
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
	tarval *tv;
651
	ir_entity *ent;
652

653
654
	init = skip_Id(init);

655
656
	switch (get_irn_opcode(init)) {
	case iro_Cast:
657
		do_emit_atomic_init(env, get_Cast_op(init));
658
659
660
		return;

	case iro_Conv:
661
		do_emit_atomic_init(env, get_Conv_op(init));
662
663
664
665
666
667
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

		/* it's a arithmetic value */
668
		emit_arith_tarval(tv, bytes);
669
670
671
672
673
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_name:
674
			be_emit_ident(get_SymConst_name(init));
675
676
677
			break;

		case symconst_addr_ent:
678
			ent = get_SymConst_entity(init);
679
			be_gas_emit_entity(ent);
680
681
			break;

682
		case symconst_ofs_ent:
683
			ent = get_SymConst_entity(init);
684
			be_emit_irprintf("%d", get_entity_offset(ent));
685
686
			break;

687
		case symconst_type_size:
688
			be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
689
690
			break;

691
		case symconst_type_align:
692
			be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
693
694
			break;

Michael Beck's avatar
Michael Beck committed
695
		case symconst_enum_const:
696
			tv = get_enumeration_value(get_SymConst_enum(init));
697
			emit_arith_tarval(tv, bytes);
Michael Beck's avatar
Michael Beck committed
698
699
			break;

700
		default:
701
			assert(!"emit_atomic_init(): don't know how to init from this SymConst");
702
703
704
		}
		return;

Michael Beck's avatar
Michael Beck committed
705
706
707
708
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '+' to work");
		}
709
		do_emit_atomic_init(env, get_Add_left(init));
Michael Beck's avatar
Michael Beck committed
710
		be_emit_cstring(" + ");
711
		do_emit_atomic_init(env, get_Add_right(init));
Michael Beck's avatar
Michael Beck committed
712
		return;
713

Michael Beck's avatar
Michael Beck committed
714
715
716
717
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '-' to work");
		}
718
		do_emit_atomic_init(env, get_Sub_left(init));
Michael Beck's avatar
Michael Beck committed
719
		be_emit_cstring(" - ");
720
		do_emit_atomic_init(env, get_Sub_right(init));
Michael Beck's avatar
Michael Beck committed
721
722
723
724
725
726
		return;

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

Olaf Liebe's avatar
Olaf Liebe committed
732
733
734
735
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
736
	default:
737
		panic("emit_atomic_init(): unsupported IR-node %+F", init);
738
	}
739
740
}

741
/**
Michael Beck's avatar
Michael Beck committed
742
743
744
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
745
 */
746
static void emit_size_type(size_t size)
747
{
Christian Würdig's avatar
Christian Würdig committed
748
	switch (size) {
749
	case 1:
750
		be_emit_cstring("\t.byte\t");
751
		break;
752

753
	case 2:
754
		be_emit_cstring("\t.short\t");
755
		break;
756

757
	case 4:
758
		be_emit_cstring("\t.long\t");
759
		break;
760

761
	case 8:
762
		be_emit_cstring("\t.quad\t");
763
		break;
764

765
766
	case 10:
	case 12:
Matthias Braun's avatar
Matthias Braun committed
767
	case 16: /* Note: .octa does not work on mac */
768
769
		/* handled in arith */
		break;
770

771
	default:
772
		panic("Try to dump a type with %u bytes", (unsigned)size);
773
	}
Christian Würdig's avatar
Christian Würdig committed
774
775
}

776
/**
777
 * Emit an atomic value.
Michael Beck's avatar
Michael Beck committed
778
779
780
 *
 * @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
781
 */
782
static void emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
Christian Würdig's avatar
Christian Würdig committed
783
784
785
{
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
786

787
788
	emit_size_type(bytes);
	do_emit_atomic_init(env, init);
789
790
	be_emit_char('\n');
	be_emit_write_line();
791
792
793
794
795
796
797
}

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

/**
Michael Beck's avatar
Michael Beck committed
798
 * Dump a string constant.
799
 * No checks are made!!
Michael Beck's avatar
Michael Beck committed
800
801
 *
 * @param ent  The entity to dump.
802
 */
803
static void emit_string_cst(const ir_entity *ent)
804
{
805
	int      i, len;
806
	int      output_len;
807
808
809
	ir_type *type;
	int      type_size;
	int      remaining_space;
810

811
812
	len        = get_compound_ent_n_values(ent);
	output_len = len;
Matthias Braun's avatar
Matthias Braun committed
813
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
814
815
816
		be_emit_cstring("\t.ascii \"");
	} else {
		be_emit_cstring("\t.string \"");
817
		output_len -= 1;
818
	}
819

820
	for (i = 0; i < output_len; ++i) {
821
822
823
824
825
826
827
		ir_node *irn;
		int c;

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

		switch (c) {
828
829
830
831
832
		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;
833
834
		default  :
			if (isprint(c))
835
				be_emit_char(c);
836
			else
837
				be_emit_irprintf("\\%o", c);
838
839
840
			break;
		}
	}
841
842
	be_emit_cstring("\"\n");
	be_emit_write_line();
843
844
845

	type            = get_entity_type(ent);
	type_size       = get_type_size_bytes(type);
846
	remaining_space = type_size - len;
847
	assert(remaining_space >= 0);
Michael Beck's avatar
Michael Beck committed
848
	if (remaining_space > 0) {
849
		be_emit_irprintf("\t.zero\t%d\n", remaining_space);
850
	}
851
852
}

853
static void emit_string_initializer(const ir_initializer_t *initializer)
854
855
856
857
{
	size_t i, len;

	len = initializer->compound.n_initializers;
Matthias Braun's avatar
Matthias Braun committed
858
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
Matthias Braun's avatar
Matthias Braun committed
859
860
		be_emit_cstring("\t.ascii \"");
	} else {
861
862
863
864
		be_emit_cstring("\t.string \"");
		len -= 1;
	}

Michael Beck's avatar
Michael Beck committed
865
	for (i = 0; i < len; ++i) {
866
867
868
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
869
		tarval *tv = get_initializer_tarval(sub_initializer);
870
871
872
		int     c  = get_tarval_long(tv);

		switch (c) {
873
874
875
876
877
		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;
878
879
		default  :
			if (isprint(c))
880
				be_emit_char(c);
881
			else
882
				be_emit_irprintf("\\%o", c);
883
884
885
			break;
		}
	}
886
887
	be_emit_cstring("\"\n");
	be_emit_write_line();
888
889
}

890
891
enum normal_or_bitfield_kind {
	NORMAL = 0,
892
	TARVAL,
893
894
895
896
897
898
	BITFIELD
};

typedef struct {
	enum normal_or_bitfield_kind kind;
	union {
899
900
901
		ir_node       *value;
		tarval        *tarval;
		unsigned char  bf_val;
902
903
904
	} v;
} normal_or_bitfield;

905
906
907
908
909
910
911
912
913
914
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
915
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
916
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
917
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
918
919
920
921
		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
922
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
923
		if (!is_type_variable_size(type)) {
924
925
926
927
928
929
			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
930
			for (i = 0; i < n_entries; ++i) {
931
932
933
934
935
936
937
938
939
				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
940
				if (offset + size > initializer_size) {
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
					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

956
static void emit_bitfield(normal_or_bitfield *vals, size_t offset_bits,
957
958
959
960
961
962
963
964
965
                          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
966
	switch (get_initializer_kind(initializer)) {
967
968
969
970
971
972
973
	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
974
		if (!is_Const(node)) {
975
976
977
978
979
980
981
982
983
			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) {
984
		panic("Couldn't get numeric value for bitfield initializer");
985
	}
986
	tv = tarval_convert_to(tv, get_type_mode(type));
987
988
989
990
991
992
993
994
995
996
997
998
999
1000

	/* 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
For faster browsing, not all history is shown. View entire blame