begnuas.c 44 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2011 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
#include "util.h"
43

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

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

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

Michael Beck's avatar
Michael Beck committed
55
/**
56
57
58
59
 * 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
60
 */
61
typedef struct be_gas_decl_env {
62
63
64
65
	be_gas_section_t     section;
	const be_main_env_t *main_env;
} be_gas_decl_env_t;

Matthias Braun's avatar
Matthias Braun committed
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
105
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);
	}
}

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
static void emit_section_sparc(be_gas_section_t section, const ir_entity *entity)
{
	be_gas_section_t base = section & GAS_SECTION_TYPE_MASK;
	be_gas_section_t flags = section & ~GAS_SECTION_TYPE_MASK;
	static const char *const basename[] = {
		"text", "data", "rodata", "bss", "ctors", "dtors"
	};

	if (current_section == section && !(section & GAS_SECTION_FLAG_COMDAT))
		return;
	current_section = section;

	be_emit_cstring("\t.section\t\".");

	/* Part1: section-name */
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('t');
123
	assert(base < (be_gas_section_t)ARRAY_SIZE(basename));
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
	be_emit_string(basename[base]);

	if (flags & GAS_SECTION_FLAG_COMDAT) {
		be_emit_char('.');
		be_gas_emit_entity(entity);
	}
	be_emit_char('"');

	/* for the simple sections we're done here */
	if (flags == 0)
		goto end;

	be_emit_cstring(",#alloc");

	switch (base) {
	case GAS_SECTION_TEXT: be_emit_cstring(",#execinstr"); break;
	case GAS_SECTION_DATA:
	case GAS_SECTION_BSS:  be_emit_cstring(",#write"); break;
	default:
		/* nothing */
		break;
	}
	if (flags & GAS_SECTION_FLAG_TLS) {
		be_emit_cstring(",#tls");
	}

end:
	be_emit_char('\n');
	be_emit_write_line();
}

155
static void emit_section(be_gas_section_t section, const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
156
{
157
158
	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
159
	static const char *const basename[] = {
160
161
		"text", "data", "rodata", "bss", "ctors", "dtors"
	};
Matthias Braun's avatar
Matthias Braun committed
162
	static const char *const type[] = {
Matthias Braun's avatar
Matthias Braun committed
163
		"progbits", "progbits", "progbits", "nobits", "init_array", "fini_array"
Matthias Braun's avatar
Matthias Braun committed
164
165
	};

Matthias Braun's avatar
Matthias Braun committed
166
167
168
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
		emit_section_macho(section);
		return;
169
170
171
	} else if(be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF_SPARC) {
		emit_section_sparc(section, entity);
		return;
Matthias Braun's avatar
Matthias Braun committed
172
173
	}

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
	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;
		}
	}

202
	assert(base < (be_gas_section_t) ARRAY_SIZE(basename));
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	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');
217
218
219
	if (base == GAS_SECTION_TEXT)
		be_emit_char('x');
	if (base != GAS_SECTION_RODATA && base != GAS_SECTION_TEXT)
220
221
222
223
224
		be_emit_char('w');
	if (flags & GAS_SECTION_FLAG_TLS)
		be_emit_char('T');
	if (flags & GAS_SECTION_FLAG_COMDAT)
		be_emit_char('G');
225
226
227
228
229
230
	/* section type */
	if (be_gas_object_file_format != OBJECT_FILE_FORMAT_COFF) {
		be_emit_cstring("\",");
		be_emit_char(be_gas_elf_type_char);
		be_emit_string(type[base]);
	}
231
232
233
234
235
236
237
238

	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
239
240
}

241
242


Matthias Braun's avatar
Matthias Braun committed
243
244
void be_gas_emit_switch_section(be_gas_section_t section)
{
245
246
247
248
249
250
251
	/* 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
252
static ir_tarval *get_initializer_tarval(const ir_initializer_t *initializer)
Matthias Braun's avatar
Matthias Braun committed
253
254
255
256
257
258
259
260
261
262
263
264
{
	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();
}

265
static bool initializer_is_string_const(const ir_initializer_t *initializer)
266
267
{
	size_t i, len;
268
	bool found_printable = false;
269
270

	if (initializer->kind != IR_INITIALIZER_COMPOUND)
271
		return false;
272
273
274

	len = initializer->compound.n_initializers;
	if (len < 1)
275
		return false;
276
277
	for (i = 0; i < len; ++i) {
		int               c;
Matthias Braun's avatar
Matthias Braun committed
278
		ir_tarval        *tv;
279
280
281
282
		ir_mode          *mode;
		ir_initializer_t *sub_initializer
			= initializer->compound.initializers[i];

Matthias Braun's avatar
Matthias Braun committed
283
284
		tv = get_initializer_tarval(sub_initializer);
		if (!tarval_is_constant(tv))
285
			return false;
286
287
288

		mode = get_tarval_mode(tv);
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
289
			return false;
290
291
292

		c = get_tarval_long(tv);
		if (isgraph(c) || isspace(c))
293
			found_printable = true;
294
		else if (c != 0)
295
			return false;
296
297

		if (i == len - 1 && c != '\0')
298
			return false;
299
300
301
302
303
304
305
306
307
308
309
	}

	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: {
Matthias Braun's avatar
Matthias Braun committed
310
		ir_tarval *tv = initializer->tarval.value;
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
		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;
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
	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 */
396
		return false;
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
	}
	/* 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;
	}

457
458
459
460
461
	/* the java frontend keeps some functions inside classes */
	if (is_Class_type(owner)) {
		return determine_basic_section(entity);
	}

462
463
464
465
466
467
468
469
470
471
472
	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);
473
474
	be_emit_char('\n');
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
475
476
}

477
static void emit_visibility(const ir_entity *entity)
Matthias Braun's avatar
Matthias Braun committed
478
{
479
480
	ir_linkage linkage = get_entity_linkage(entity);

481
	if (get_entity_linkage(entity) & IR_LINKAGE_WEAK) {
482
483
484
485
		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 ");
486
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
487
488
		be_emit_char('\n');
		be_emit_write_line();
489
490
491
	}

	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
492
493
			&& (linkage & IR_LINKAGE_HIDDEN_USER)
			&& get_entity_ld_name(entity)[0] != '\0') {
494
		be_emit_cstring("\t.no_dead_strip ");
495
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
496
497
498
499
500
		be_emit_char('\n');
		be_emit_write_line();
	}
}

501
void be_gas_emit_function_prolog(const ir_entity *entity, unsigned po2alignment)
502
{
503
504
	be_gas_section_t section = determine_section(NULL, entity);
	emit_section(section, entity);
505

Matthias Braun's avatar
Matthias Braun committed
506
507
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
508
509
	be_emit_write_line();
	be_emit_cstring("# -- Begin  ");
510
	be_gas_emit_entity(entity);
511
512
513
	be_emit_char('\n');
	be_emit_write_line();

514
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
515
516
517
518
519
520
		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
521
		be_emit_cstring("\t.p2align ");
522
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
523
524
		be_emit_write_line();
	}
525
	emit_visibility(entity);
526

Matthias Braun's avatar
Matthias Braun committed
527
528
	switch (be_gas_object_file_format) {
	case OBJECT_FILE_FORMAT_ELF:
529
	case OBJECT_FILE_FORMAT_ELF_SPARC:
530
		be_emit_cstring("\t.type\t");
531
		be_gas_emit_entity(entity);
532
533
534
		be_emit_cstring(", ");
		be_emit_char(be_gas_elf_type_char);
		be_emit_cstring("function\n");
535
536
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
537
	case OBJECT_FILE_FORMAT_COFF:
538
		be_emit_cstring("\t.def\t");
539
		be_gas_emit_entity(entity);
Matthias Braun's avatar
Matthias Braun committed
540
		be_emit_cstring(";");
541
		if (get_entity_visibility(entity) == ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
542
			be_emit_cstring("\t.scl\t3;");
543
		} else {
Matthias Braun's avatar
Matthias Braun committed
544
			be_emit_cstring("\t.scl\t2;");
545
		}
Matthias Braun's avatar
Matthias Braun committed
546
		be_emit_cstring("\t.type\t32;\t.endef\n");
547
548
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
549
	case OBJECT_FILE_FORMAT_MACH_O:
550
551
		break;
	}
552
	be_gas_emit_entity(entity);
553
554
555
556
	be_emit_cstring(":\n");
	be_emit_write_line();
}

557
void be_gas_emit_function_epilog(const ir_entity *entity)
558
{
Matthias Braun's avatar
Matthias Braun committed
559
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
560
		be_emit_cstring("\t.size\t");
561
		be_gas_emit_entity(entity);
562
		be_emit_cstring(", .-");
563
		be_gas_emit_entity(entity);
564
565
566
567
568
		be_emit_char('\n');
		be_emit_write_line();
	}

	be_emit_cstring("# -- End  ");
569
	be_gas_emit_entity(entity);
570
571
572
573
	be_emit_char('\n');
	be_emit_write_line();
}

Michael Beck's avatar
Michael Beck committed
574
/**
Michael Beck's avatar
Michael Beck committed
575
576
577
578
 * Output a tarval.
 *
 * @param tv     the tarval
 * @param bytes  the width of the tarvals value in bytes
Michael Beck's avatar
Michael Beck committed
579
 */
Matthias Braun's avatar
Matthias Braun committed
580
static void emit_arith_tarval(ir_tarval *tv, int bytes)
581
{
582
583
	switch (bytes) {
	case 1:
584
		be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
585
		return;
586
587

	case 2:
588
		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
589
		return;
590
591

	case 4:
592
		be_emit_irprintf("0x%02x%02x%02x%02x",
593
			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
594
		return;
595
596

	case 8:
597
		be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x",
598
599
			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
600
		return;
601
602

	case 12:
603
604
605
606
607
608
609
610
611
612
613
614
615
		/* 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
616
		return;
617

618
	case 16:
Matthias Braun's avatar
Matthias Braun committed
619
620
		/* Beware: Mixed endian output!  One little endian number emitted as
		 * three longs.  Each long initializer is written in big endian. */
621
		be_emit_irprintf(
Matthias Braun's avatar
Matthias Braun committed
622
623
624
625
626
627
			"\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),
628
629
			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
630
631
632
633
			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)
634
		);
Matthias Braun's avatar
Matthias Braun committed
635
		return;
636
	}
Matthias Braun's avatar
Matthias Braun committed
637

638
	panic("Can't dump a tarval with %d bytes", bytes);
639
640
}

641
642
643
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
644
645
const char *be_gas_insn_label_prefix(void)
{
646
647
648
	return ".LE";
}

649
650
/**
 * Return the tarval of an atomic initializer.
Michael Beck's avatar
Michael Beck committed
651
 *
Michael Beck's avatar
Michael Beck committed
652
 * @param init  a node representing the initializer (on the const code irg)
Michael Beck's avatar
Michael Beck committed
653
654
 *
 * @return the tarval
655
 */
Matthias Braun's avatar
Matthias Braun committed
656
static ir_tarval *get_atomic_init_tv(ir_node *init)
657
{
658
659
	for (;;) {
		ir_mode *mode = get_irn_mode(init);
660

661
		switch (get_irn_opcode(init)) {
662

663
664
665
		case iro_Cast:
			init = get_Cast_op(init);
			continue;
666

667
668
669
		case iro_Conv:
			init = get_Conv_op(init);
			continue;
670

671
672
		case iro_Const:
			return get_Const_tarval(init);
673

674
675
676
677
		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);
678

679
680
			case symconst_type_align:
				return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
681

Michael Beck's avatar
Michael Beck committed
682
683
684
			case symconst_ofs_ent:
				return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);

685
686
			case symconst_enum_const:
				return get_enumeration_value(get_SymConst_enum(init));
687

688
689
690
			default:
				return NULL;
			}
691
692
693

		default:
			return NULL;
694
		}
695
696
697
	}
}

698
/**
Michael Beck's avatar
Michael Beck committed
699
700
701
702
 * Dump an atomic value.
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
703
 */
704
static void do_emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
705
{
706
707
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
Matthias Braun's avatar
Matthias Braun committed
708
	ir_tarval *tv;
709
	ir_entity *ent;
710

711
712
	init = skip_Id(init);

713
714
	switch (get_irn_opcode(init)) {
	case iro_Cast:
715
		do_emit_atomic_init(env, get_Cast_op(init));
716
717
718
		return;

	case iro_Conv:
719
		do_emit_atomic_init(env, get_Conv_op(init));
720
721
722
723
724
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

725
		/* it's an arithmetic value */
726
		emit_arith_tarval(tv, bytes);
727
728
729
730
731
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_ent:
732
			ent = get_SymConst_entity(init);
733
			be_gas_emit_entity(ent);
734
735
			break;

736
		case symconst_ofs_ent:
737
			ent = get_SymConst_entity(init);
738
			be_emit_irprintf("%d", get_entity_offset(ent));
739
740
			break;

741
		case symconst_type_size:
742
			be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
743
744
			break;

745
		case symconst_type_align:
746
			be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
747
748
			break;

Michael Beck's avatar
Michael Beck committed
749
		case symconst_enum_const:
750
			tv = get_enumeration_value(get_SymConst_enum(init));
751
			emit_arith_tarval(tv, bytes);
Michael Beck's avatar
Michael Beck committed
752
753
			break;

754
		default:
755
			assert(!"emit_atomic_init(): don't know how to init from this SymConst");
756
757
758
		}
		return;

Michael Beck's avatar
Michael Beck committed
759
760
761
762
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '+' to work");
		}
763
		do_emit_atomic_init(env, get_Add_left(init));
Michael Beck's avatar
Michael Beck committed
764
		be_emit_cstring(" + ");
765
		do_emit_atomic_init(env, get_Add_right(init));
Michael Beck's avatar
Michael Beck committed
766
		return;
767

Michael Beck's avatar
Michael Beck committed
768
769
770
771
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '-' to work");
		}
772
		do_emit_atomic_init(env, get_Sub_left(init));
Michael Beck's avatar
Michael Beck committed
773
		be_emit_cstring(" - ");
774
		do_emit_atomic_init(env, get_Sub_right(init));
Michael Beck's avatar
Michael Beck committed
775
776
777
778
779
780
		return;

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

Olaf Liebe's avatar
Olaf Liebe committed
786
787
788
789
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
790
	default:
791
		panic("emit_atomic_init(): unsupported IR-node %+F", init);
792
	}
793
794
}

795
/**
Michael Beck's avatar
Michael Beck committed
796
797
798
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
799
 */
800
static void emit_size_type(size_t size)
801
{
Christian Würdig's avatar
Christian Würdig committed
802
	switch (size) {
803
	case 1:
804
		be_emit_cstring("\t.byte\t");
805
		break;
806

807
	case 2:
808
		be_emit_cstring("\t.short\t");
809
		break;
810

811
	case 4:
812
		be_emit_cstring("\t.long\t");
813
		break;
814

815
	case 8:
816
		be_emit_cstring("\t.quad\t");
817
		break;
818

819
820
	case 10:
	case 12:
Matthias Braun's avatar
Matthias Braun committed
821
	case 16: /* Note: .octa does not work on mac */
822
823
		/* handled in arith */
		break;
824

825
	default:
826
		panic("Try to dump a type with %u bytes", (unsigned)size);
827
	}
Christian Würdig's avatar
Christian Würdig committed
828
829
}

830
/**
831
 * Emit an atomic value.
Michael Beck's avatar
Michael Beck committed
832
833
834
 *
 * @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
835
 */
836
static void emit_atomic_init(be_gas_decl_env_t *env, ir_node *init)
Christian Würdig's avatar
Christian Würdig committed
837
838
839
{
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
840

841
842
	emit_size_type(bytes);
	do_emit_atomic_init(env, init);
843
844
	be_emit_char('\n');
	be_emit_write_line();
845
846
847
}

/**
Michael Beck's avatar
Michael Beck committed
848
 * Dump a string constant.
849
 * No checks are made!!
Michael Beck's avatar
Michael Beck committed
850
851
 *
 * @param ent  The entity to dump.
852
 */
853
static void emit_string_cst(const ir_entity *ent)
854
{
855
	int      i, len;
856
	int      output_len;
857
858
859
	ir_type *type;
	int      type_size;
	int      remaining_space;
860

861
862
	len        = get_compound_ent_n_values(ent);
	output_len = len;
Matthias Braun's avatar
Matthias Braun committed
863
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
864
865
866
		be_emit_cstring("\t.ascii \"");
	} else {
		be_emit_cstring("\t.string \"");
867
		output_len -= 1;
868
	}
869

870
	for (i = 0; i < output_len; ++i) {
871
872
873
874
875
876
877
		ir_node *irn;
		int c;

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

		switch (c) {
878
879
880
881
882
		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;
883
884
		default  :
			if (isprint(c))
885
				be_emit_char(c);
886
			else
887
				be_emit_irprintf("\\%o", c);
888
889
890
			break;
		}
	}
891
892
	be_emit_cstring("\"\n");
	be_emit_write_line();
893
894
895

	type            = get_entity_type(ent);
	type_size       = get_type_size_bytes(type);
896
	remaining_space = type_size - len;
897
	assert(remaining_space >= 0);
Michael Beck's avatar
Michael Beck committed
898
	if (remaining_space > 0) {
899
		be_emit_irprintf("\t.space\t%d, 0\n", remaining_space);
900
	}
901
902
}

903
static size_t emit_string_initializer(const ir_initializer_t *initializer)
904
905
906
907
{
	size_t i, len;

	len = initializer->compound.n_initializers;
Matthias Braun's avatar
Matthias Braun committed
908
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
Matthias Braun's avatar
Matthias Braun committed
909
910
		be_emit_cstring("\t.ascii \"");
	} else {
911
912
913
914
		be_emit_cstring("\t.string \"");
		len -= 1;
	}

Michael Beck's avatar
Michael Beck committed
915
	for (i = 0; i < len; ++i) {
916
917
918
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

Matthias Braun's avatar
Matthias Braun committed
919
920
		ir_tarval *tv = get_initializer_tarval(sub_initializer);
		int        c  = get_tarval_long(tv);
921
922

		switch (c) {
923
924
925
926
927
		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;
928
929
		default  :
			if (isprint(c))
930
				be_emit_char(c);
931
			else
932
				be_emit_irprintf("\\%o", c);
933
934
935
			break;
		}
	}
936
937
	be_emit_cstring("\"\n");
	be_emit_write_line();
938
939

	return initializer->compound.n_initializers;
940
941
}

942
typedef enum normal_or_bitfield_kind {
943
	NORMAL = 0,
944
	TARVAL,
945
	STRING,
946
	BITFIELD
947
} normal_or_bitfield_kind;
948
949

typedef struct {
950
	normal_or_bitfield_kind kind;
951
	union {
952
953
954
955
		ir_node                *value;
		ir_tarval              *tarval;
		unsigned char           bf_val;
		const ir_initializer_t *string;
956
957
958
	} v;
} normal_or_bitfield;

959
960
961
962
963
964
965
966
967
968
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
969
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
970
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
971
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
972
973
974
975
		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
976
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
977
		if (!is_type_variable_size(type)) {
978
979
			return get_type_size_bytes(type);
		} else {
Michael Beck's avatar
Michael Beck committed
980
			size_t n_entries
981
				= get_initializer_compound_n_entries(initializer);
Michael Beck's avatar
Michael Beck committed
982
			size_t i;
983
			unsigned initializer_size = get_type_size_bytes(type);
Michael Beck's avatar
Michael Beck committed
984
			for (i = 0; i < n_entries; ++i) {
985
986
987
988
989
990
991
992
993
				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
994
				if (offset + size > initializer_size) {
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
					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

1010
static void emit_bitfield(normal_or_bitfield *vals, size_t offset_bits,
1011
1012
                          const ir_initializer_t *initializer, ir_type *type)
{
1013
	static const size_t BITS_PER_BYTE = 8;
Matthias Braun's avatar
Matthias Braun committed
1014
1015
1016
1017
1018
1019
	ir_mode   *mode      = get_type_mode(type);
	ir_tarval *tv        = NULL;
	int        value_len;
	size_t     bit_offset;
	size_t     end;
	bool       big_endian = be_get_backend_param()->byte_order_big_endian;
1020

Michael Beck's avatar
Michael Beck committed
1021
	switch (get_initializer_kind(initializer)) {
1022
1023
1024
1025
1026
1027
1028
	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
1029
		if (!is_Const(node)) {
1030
1031
1032
1033
1034
1035
1036
1037
1038
			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) {
1039
		panic("Couldn't get numeric value for bitfield initializer");
1040
	}
1041
	tv = tarval_convert_to(tv, get_type_mode(type));
1042

1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
	value_len  = get_type_size_bytes(get_primitive_base_type(type));
	bit_offset = 0;
	end        = get_mode_size_bits(mode);
	while (bit_offset < end) {
		size_t        src_offset      = bit_offset / BITS_PER_BYTE;
		size_t        src_offset_bits = bit_offset % BITS_PER_BYTE;
		size_t        dst_offset      = (bit_offset+offset_bits) / BITS_PER_BYTE;
		size_t        dst_offset_bits = (bit_offset+offset_bits) % BITS_PER_BYTE;
		size_t        src_bits_len    = end-bit_offset;
		size_t        dst_bits_len    = BITS_PER_BYTE-dst_offset_bits;
		unsigned char curr_bits;
		normal_or_bitfield *val;
		if (src_bits_len > dst_bits_len)
			src_bits_len = dst_bits_len;

		if (big_endian) {
			val = &vals[value_len - dst_offset - 1];
		} else {
			val = &vals[dst_offset];
		}

		assert((val-glob_vals) < (ptrdiff_t) max_vals);
		assert(val->kind == BITFIELD ||
				(val->kind == NORMAL && val->v.value == NULL));
		val->kind  = BITFIELD;
		curr_bits  = get_tarval_sub_bits(tv, src_offset);
		curr_bits  = curr_bits >> src_offset_bits;
		if (src_offset_bits + src_bits_len > 8) {
			unsigned next_bits = get_tarval_sub_bits(tv, src_offset+1);
			curr_bits |= next_bits << (8 - src_offset_bits);
		}
		curr_bits &= (1 << src_bits_len) - 1;
		val->v.bf_val |= curr_bits << dst_offset_bits;

		bit_offset += dst_bits_len;
1078
1079
1080
	}
}

1081
static void emit_ir_initializer(normal_or_bitfield *vals,
1082
1083
1084
1085
1086
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
	assert((size_t) (vals - glob_vals) < max_vals);

1087
1088
1089
1090
1091
1092
1093
	if (initializer_is_string_const(initializer)) {
		assert(vals->kind != BITFIELD);
		vals->kind     = STRING;
		vals->v.string = initializer;
		return;
	}

Michael Beck's avatar
Michael Beck committed
1094
	switch (get_initializer_kind(initializer)) {
1095
1096
1097
1098
1099
1100
1101
1102
1103
	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
1104
		for (i = 1; i < get_type_size_bytes(type); ++i) {
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
			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
1116
		for (i = 1; i < get_type_size_bytes(type); ++i) {