begnuas.c 37.2 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
59
60
61
/**
 * Return the pseudo-instruction to be issued for a section switch
 * depending on the current flavour.
 *
 * @param section  the section to switch to
 *
 * @return  the pseudo-instruction
 */
Matthias Braun's avatar
Matthias Braun committed
62
63
64
65
static const char *get_section_name(be_gas_section_t section)
{
	static const char *text[OBJECT_FILE_FORMAT_LAST+1][GAS_SECTION_LAST+1] = {
		{ /* OBJECT_FILE_FORMAT_ELF */
Matthias Braun's avatar
Matthias Braun committed
66
67
68
69
			".section\t.text",
			".section\t.data",
			".section\t.rodata",
			".section\t.bss",
70
			".section\t.tdata,\"awT\",@progbits",
Matthias Braun's avatar
Matthias Braun committed
71
			".section\t.tbss,\"awT\",@nobits",
Matthias Braun's avatar
Matthias Braun committed
72
			".section\t.ctors,\"aw\",@progbits",
73
			".section\t.dtors,\"aw\",@progbits",
74
			NULL, /* no cstring section */
Matthias Braun's avatar
Matthias Braun committed
75
			NULL,
76
			NULL
Matthias Braun's avatar
Matthias Braun committed
77
		},
Matthias Braun's avatar
Matthias Braun committed
78
		{ /* OBJECT_FILE_FORMAT_COFF */
Matthias Braun's avatar
Matthias Braun committed
79
80
81
82
			".section\t.text",
			".section\t.data",
			".section .rdata,\"dr\"",
			".section\t.bss",
83
			".section\t.tdata,\"awT\",@progbits",
Matthias Braun's avatar
Matthias Braun committed
84
			".section\t.tbss,\"awT\",@nobits",
85
86
			".section\t.ctors,\"w\"",
			".section\t.dtors,\"w\"",
Matthias Braun's avatar
Matthias Braun committed
87
			NULL,
88
89
			NULL,
			NULL
90
		},
Matthias Braun's avatar
Matthias Braun committed
91
		{ /* OBJECT_FILE_FORMAT_MACH_O */
92
93
94
95
			".text",
			".data",
			".const",
			".data",
Matthias Braun's avatar
Matthias Braun committed
96
			NULL,             /* TLS is not supported on Mach-O */
97
			NULL,             /* TLS is not supported on Mach-O */
Matthias Braun's avatar
Matthias Braun committed
98
			".mod_init_func",
99
			".mod_term_func",
100
101
102
			".cstring",
			".section\t__IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5",
			".section\t__IMPORT,__pointers,non_lazy_symbol_pointers"
Matthias Braun's avatar
Matthias Braun committed
103
104
105
		}
	};

Matthias Braun's avatar
Matthias Braun committed
106
107
	assert((int) be_gas_object_file_format >= 0
			&& be_gas_object_file_format <= OBJECT_FILE_FORMAT_LAST);
108
	assert((int) section >= 0 && section <= GAS_SECTION_LAST);
Matthias Braun's avatar
Matthias Braun committed
109
	return text[be_gas_object_file_format][section];
Matthias Braun's avatar
Matthias Braun committed
110
111
}

Matthias Braun's avatar
Matthias Braun committed
112
113
void be_gas_emit_switch_section(be_gas_section_t section)
{
Michael Beck's avatar
Michael Beck committed
114
	if (current_section == section)
115
116
		return;

117
118
119
120
	be_emit_char('\t');
	be_emit_string(get_section_name(section));
	be_emit_char('\n');
	be_emit_write_line();
121
	current_section = section;
Matthias Braun's avatar
Matthias Braun committed
122
123
}

Matthias Braun's avatar
Matthias Braun committed
124
125
static void emit_entity_visibility(const ir_entity *entity)
{
126
127
	ir_visibility visibility = get_entity_visibility(entity);
	ir_linkage    linkage    = get_entity_linkage(entity);
Matthias Braun's avatar
Matthias Braun committed
128

129
	if (visibility != ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
		be_emit_cstring(".globl ");
		be_emit_ident(get_entity_ld_ident(entity));
		be_emit_char('\n');
		be_emit_write_line();
	}
	if (linkage & IR_LINKAGE_WEAK) {
		if (! (linkage & IR_LINKAGE_MERGE)) {
			panic("Weak symbols only supported in combination with IR_LINKAGE_MERGE on this architecture");
		}
		be_emit_cstring(".weak ");
		be_emit_ident(get_entity_ld_ident(entity));
		be_emit_char('\n');
		be_emit_write_line();
	}
}

146
void be_gas_emit_function_prolog(ir_entity *entity, unsigned po2alignment)
147
148
149
150
151
{
	const char *name = get_entity_ld_name(entity);

	be_gas_emit_switch_section(GAS_SECTION_TEXT);

Matthias Braun's avatar
Matthias Braun committed
152
153
	/* write the begin line (makes the life easier for scripts parsing the
	 * assembler) */
154
155
156
157
158
159
	be_emit_write_line();
	be_emit_cstring("# -- Begin  ");
	be_emit_string(name);
	be_emit_char('\n');
	be_emit_write_line();

160
	if (po2alignment > 0) {
Matthias Braun's avatar
Matthias Braun committed
161
162
163
164
165
166
		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
167
		be_emit_cstring("\t.p2align ");
168
		be_emit_irprintf("%u,%s,%u\n", po2alignment, fill_byte, maximum_skip);
Michael Beck's avatar
Michael Beck committed
169
170
		be_emit_write_line();
	}
Matthias Braun's avatar
Matthias Braun committed
171
	emit_entity_visibility(entity);
172

Matthias Braun's avatar
Matthias Braun committed
173
174
	switch (be_gas_object_file_format) {
	case OBJECT_FILE_FORMAT_ELF:
175
176
		be_emit_cstring("\t.type\t");
		be_emit_string(name);
177
178
179
		be_emit_cstring(", ");
		be_emit_char(be_gas_elf_type_char);
		be_emit_cstring("function\n");
180
181
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
182
	case OBJECT_FILE_FORMAT_COFF:
183
184
		be_emit_cstring("\t.def\t");
		be_emit_string(name);
Matthias Braun's avatar
Matthias Braun committed
185
		be_emit_cstring(";");
186
		if (get_entity_visibility(entity) == ir_visibility_local) {
Matthias Braun's avatar
Matthias Braun committed
187
			be_emit_cstring("\t.scl\t3;");
188
		} else {
Matthias Braun's avatar
Matthias Braun committed
189
			be_emit_cstring("\t.scl\t2;");
190
		}
Matthias Braun's avatar
Matthias Braun committed
191
		be_emit_cstring("\t.type\t32;\t.endef\n");
192
193
		be_emit_write_line();
		break;
Matthias Braun's avatar
Matthias Braun committed
194
	case OBJECT_FILE_FORMAT_MACH_O:
195
196
197
198
199
200
201
202
203
204
205
		break;
	}
	be_emit_string(name);
	be_emit_cstring(":\n");
	be_emit_write_line();
}

void be_gas_emit_function_epilog(ir_entity *entity)
{
	const char *name = get_entity_ld_name(entity);

Matthias Braun's avatar
Matthias Braun committed
206
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_ELF) {
207
208
209
210
211
212
213
214
215
216
217
218
219
220
		be_emit_cstring("\t.size\t");
		be_emit_string(name);
		be_emit_cstring(", .-");
		be_emit_string(name);
		be_emit_char('\n');
		be_emit_write_line();
	}

	be_emit_cstring("# -- End  ");
	be_emit_string(name);
	be_emit_char('\n');
	be_emit_write_line();
}

Michael Beck's avatar
Michael Beck committed
221
222
223
224
225
226
227
/**
 * 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.
 */
typedef struct _be_gas_decl_env {
228
	be_gas_section_t     section;
229
	const be_main_env_t *main_env;
Michael Beck's avatar
Michael Beck committed
230
} be_gas_decl_env_t;
Christian Würdig's avatar
Christian Würdig committed
231

232
233
/************************************************************************/

Michael Beck's avatar
Michael Beck committed
234
/**
Michael Beck's avatar
Michael Beck committed
235
236
237
238
 * Output a tarval.
 *
 * @param tv     the tarval
 * @param bytes  the width of the tarvals value in bytes
Michael Beck's avatar
Michael Beck committed
239
 */
240
static void dump_arith_tarval(tarval *tv, int bytes)
241
{
242
243
	switch (bytes) {
	case 1:
244
		be_emit_irprintf("0x%02x", get_tarval_sub_bits(tv, 0));
Matthias Braun's avatar
Matthias Braun committed
245
		return;
246
247

	case 2:
248
		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
249
		return;
250
251

	case 4:
252
		be_emit_irprintf("0x%02x%02x%02x%02x",
253
			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
254
		return;
255
256

	case 8:
257
		be_emit_irprintf("0x%02x%02x%02x%02x%02x%02x%02x%02x",
258
259
			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
260
		return;
261
262

	case 12:
263
264
265
266
267
268
269
270
271
272
273
274
275
		/* 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
276
		return;
277

278
	case 16:
Matthias Braun's avatar
Matthias Braun committed
279
280
		/* Beware: Mixed endian output!  One little endian number emitted as
		 * three longs.  Each long initializer is written in big endian. */
281
		be_emit_irprintf(
Matthias Braun's avatar
Matthias Braun committed
282
283
284
285
286
287
			"\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),
288
289
			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
290
291
292
293
			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)
294
		);
Matthias Braun's avatar
Matthias Braun committed
295
		return;
296
	}
Matthias Braun's avatar
Matthias Braun committed
297

298
	panic("Can't dump a tarval with %d bytes", bytes);
299
300
}

301
302
303
/**
 * Return the label prefix for labeled blocks.
 */
Matthias Braun's avatar
Matthias Braun committed
304
305
const char *be_gas_block_label_prefix(void)
{
Michael Beck's avatar
Michael Beck committed
306
307
308
	return ".LG";
}

309
310
311
/**
 * Return the label prefix for labeled instructions.
 */
Matthias Braun's avatar
Matthias Braun committed
312
313
const char *be_gas_insn_label_prefix(void)
{
314
315
316
	return ".LE";
}

317
318
319
320
321
322
323
324
325
void be_gas_emit_entity(ir_entity *entity)
{
	if (entity->type == firm_code_type) {
		ir_label_t label = get_entity_label(entity);
		be_emit_string(be_gas_block_label_prefix());
		be_emit_irprintf("%lu", label);
	} else {
		be_emit_ident(get_entity_ld_ident(entity));
	}
Michael Beck's avatar
Michael Beck committed
326
327
}

328
329
/**
 * Return the tarval of an atomic initializer.
Michael Beck's avatar
Michael Beck committed
330
 *
Michael Beck's avatar
Michael Beck committed
331
 * @param init  a node representing the initializer (on the const code irg)
Michael Beck's avatar
Michael Beck committed
332
333
 *
 * @return the tarval
334
 */
335
336
static tarval *get_atomic_init_tv(ir_node *init)
{
337
338
	for (;;) {
		ir_mode *mode = get_irn_mode(init);
339

340
		switch (get_irn_opcode(init)) {
341

342
343
344
		case iro_Cast:
			init = get_Cast_op(init);
			continue;
345

346
347
348
		case iro_Conv:
			init = get_Conv_op(init);
			continue;
349

350
351
		case iro_Const:
			return get_Const_tarval(init);
352

353
354
355
356
		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);
357

358
359
			case symconst_type_align:
				return new_tarval_from_long(get_type_alignment_bytes(get_SymConst_type(init)), mode);
360

Michael Beck's avatar
Michael Beck committed
361
362
363
			case symconst_ofs_ent:
				return new_tarval_from_long(get_entity_offset(get_SymConst_entity(init)), mode);

364
365
			case symconst_enum_const:
				return get_enumeration_value(get_SymConst_enum(init));
366

367
368
369
			default:
				return NULL;
			}
370
371
372

		default:
			return NULL;
373
		}
374
375
376
	}
}

377
/**
Michael Beck's avatar
Michael Beck committed
378
379
380
381
 * Dump an atomic value.
 *
 * @param env   the gas output environment
 * @param init  a node representing the atomic value (on the const code irg)
382
 */
383
static void do_dump_atomic_init(be_gas_decl_env_t *env, ir_node *init)
384
{
385
386
387
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
	tarval *tv;
388
	ir_entity *ent;
389

390
391
	init = skip_Id(init);

392
393
	switch (get_irn_opcode(init)) {
	case iro_Cast:
394
		do_dump_atomic_init(env, get_Cast_op(init));
395
396
397
		return;

	case iro_Conv:
398
		do_dump_atomic_init(env, get_Conv_op(init));
399
400
401
402
403
404
		return;

	case iro_Const:
		tv = get_Const_tarval(init);

		/* it's a arithmetic value */
405
		dump_arith_tarval(tv, bytes);
406
407
408
409
410
		return;

	case iro_SymConst:
		switch (get_SymConst_kind(init)) {
		case symconst_addr_name:
411
			be_emit_ident(get_SymConst_name(init));
412
413
414
			break;

		case symconst_addr_ent:
415
			ent = get_SymConst_entity(init);
416
			be_gas_emit_entity(ent);
417
418
			break;

419
		case symconst_ofs_ent:
420
			ent = get_SymConst_entity(init);
421
			be_emit_irprintf("%d", get_entity_offset(ent));
422
423
			break;

424
		case symconst_type_size:
425
			be_emit_irprintf("%u", get_type_size_bytes(get_SymConst_type(init)));
426
427
			break;

428
		case symconst_type_align:
429
			be_emit_irprintf("%u", get_type_alignment_bytes(get_SymConst_type(init)));
430
431
			break;

Michael Beck's avatar
Michael Beck committed
432
		case symconst_enum_const:
433
			tv = get_enumeration_value(get_SymConst_enum(init));
434
			dump_arith_tarval(tv, bytes);
Michael Beck's avatar
Michael Beck committed
435
436
			break;

437
		default:
438
			assert(!"dump_atomic_init(): don't know how to init from this SymConst");
439
440
441
		}
		return;

Michael Beck's avatar
Michael Beck committed
442
443
444
445
446
447
448
449
	case iro_Add:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '+' to work");
		}
		do_dump_atomic_init(env, get_Add_left(init));
		be_emit_cstring(" + ");
		do_dump_atomic_init(env, get_Add_right(init));
		return;
450

Michael Beck's avatar
Michael Beck committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
	case iro_Sub:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '-' to work");
		}
		do_dump_atomic_init(env, get_Sub_left(init));
		be_emit_cstring(" - ");
		do_dump_atomic_init(env, get_Sub_right(init));
		return;

	case iro_Mul:
		if (!mode_is_int(mode) && !mode_is_reference(mode)) {
			panic("Constant must be int or pointer for '*' to work");
		}
		do_dump_atomic_init(env, get_Mul_left(init));
		be_emit_cstring(" * ");
		do_dump_atomic_init(env, get_Mul_right(init));
		return;

Olaf Liebe's avatar
Olaf Liebe committed
469
470
471
472
	case iro_Unknown:
		be_emit_cstring("0");
		return;

Michael Beck's avatar
Michael Beck committed
473
474
	default:
		panic("dump_atomic_init(): unsupported IR-node %+F", init);
475
	}
476
477
}

478
/**
Michael Beck's avatar
Michael Beck committed
479
480
481
 * Dumps the type for given size (.byte, .long, ...)
 *
 * @param size  the size in bytes
482
 */
483
484
static void dump_size_type(size_t size)
{
Christian Würdig's avatar
Christian Würdig committed
485
	switch (size) {
486
	case 1:
487
		be_emit_cstring("\t.byte\t");
488
		break;
489

490
	case 2:
491
		be_emit_cstring("\t.short\t");
492
		break;
493

494
	case 4:
495
		be_emit_cstring("\t.long\t");
496
		break;
497

498
	case 8:
499
		be_emit_cstring("\t.quad\t");
500
		break;
501

502
503
	case 10:
	case 12:
Matthias Braun's avatar
Matthias Braun committed
504
	case 16: /* Note: .octa does not work on mac */
505
506
		/* handled in arith */
		break;
507

508
	default:
509
		panic("Try to dump a type with %u bytes", (unsigned)size);
510
	}
Christian Würdig's avatar
Christian Würdig committed
511
512
}

513
/**
514
 * Emit an atomic value.
Michael Beck's avatar
Michael Beck committed
515
516
517
 *
 * @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
518
 */
519
static void dump_atomic_init(be_gas_decl_env_t *env, ir_node *init)
Christian Würdig's avatar
Christian Würdig committed
520
521
522
{
	ir_mode *mode = get_irn_mode(init);
	int bytes     = get_mode_size_bytes(mode);
523

524
525
526
527
	dump_size_type(bytes);
	do_dump_atomic_init(env, init);
	be_emit_char('\n');
	be_emit_write_line();
528
529
530
531
532
533
}

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

534
535
536
static int initializer_is_string_const(const ir_initializer_t *initializer)
{
	size_t i, len;
Matthias Braun's avatar
Matthias Braun committed
537
	int found_printable = 0;
538

Michael Beck's avatar
Michael Beck committed
539
	if (initializer->kind != IR_INITIALIZER_COMPOUND)
540
541
542
		return 0;

	len = initializer->compound.n_initializers;
Michael Beck's avatar
Michael Beck committed
543
544
	if (len < 1)
		return 0;
Michael Beck's avatar
Michael Beck committed
545
	for (i = 0; i < len; ++i) {
546
547
548
549
550
551
		int               c;
		tarval           *tv;
		ir_mode          *mode;
		ir_initializer_t *sub_initializer
			= initializer->compound.initializers[i];

Michael Beck's avatar
Michael Beck committed
552
		if (sub_initializer->kind != IR_INITIALIZER_TARVAL)
553
554
555
556
557
			return 0;

		tv   = sub_initializer->tarval.value;
		mode = get_tarval_mode(tv);

Michael Beck's avatar
Michael Beck committed
558
		if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
559
560
561
			return 0;

		c = get_tarval_long(tv);
Matthias Braun's avatar
Matthias Braun committed
562
563
		if (isgraph(c) || isspace(c))
			found_printable = 1;
Michael Beck's avatar
Michael Beck committed
564
		else if (c != 0)
Matthias Braun's avatar
Matthias Braun committed
565
566
567
568
			return 0;

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

Matthias Braun's avatar
Matthias Braun committed
571
	return found_printable;
572
573
}

574
575
576
577
578
/**
 * Determine if an entity is a string constant
 * @param ent The entity
 * @return 1 if it is a string constant, 0 otherwise
 */
Matthias Braun's avatar
Matthias Braun committed
579
static int ent_is_string_const(const ir_entity *ent)
580
{
581
582
583
	ir_type *type, *element_type;
	ir_mode *mode;
	int i, c, n;
584

585
	type = get_entity_type(ent);
586
587

	/* if it's an array */
588
589
590
591
592
593
594
595
596
597
598
599
	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);
Michael Beck's avatar
Michael Beck committed
600
	if (!mode_is_int(mode) || get_mode_size_bits(mode) != 8)
601
602
		return 0;

Matthias Braun's avatar
Matthias Braun committed
603
604
605
606
	if (ent->initializer != NULL) {
		return initializer_is_string_const(ent->initializer);
	} else if (entity_has_compound_ent_values(ent)) {
		int found_printable = 0;
607
608
609
610
611
612
613
614
615
		/* 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));

Matthias Braun's avatar
Matthias Braun committed
616
617
			if (isgraph(c) || isspace(c))
				found_printable = 1;
Michael Beck's avatar
Michael Beck committed
618
			else if (c != 0)
Matthias Braun's avatar
Matthias Braun committed
619
620
621
				return 0;

			if (i == n - 1 && c != '\0')
622
623
				return 0;
		}
Matthias Braun's avatar
Matthias Braun committed
624
		return found_printable;
625
626
	}

Matthias Braun's avatar
Matthias Braun committed
627
	return 0;
628
629
}

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
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");
}

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;
}

671
/**
Michael Beck's avatar
Michael Beck committed
672
 * Dump a string constant.
673
 * No checks are made!!
Michael Beck's avatar
Michael Beck committed
674
675
 *
 * @param ent  The entity to dump.
676
 */
Matthias Braun's avatar
Matthias Braun committed
677
static void dump_string_cst(const ir_entity *ent)
678
{
679
	int      i, len;
680
	int      output_len;
681
682
683
	ir_type *type;
	int      type_size;
	int      remaining_space;
684

685
686
	len        = get_compound_ent_n_values(ent);
	output_len = len;
Matthias Braun's avatar
Matthias Braun committed
687
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
688
689
690
		be_emit_cstring("\t.ascii \"");
	} else {
		be_emit_cstring("\t.string \"");
691
		output_len -= 1;
692
	}
693

694
	for (i = 0; i < output_len; ++i) {
695
696
697
698
699
700
701
		ir_node *irn;
		int c;

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

		switch (c) {
702
703
704
705
706
		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;
707
708
		default  :
			if (isprint(c))
709
				be_emit_char(c);
710
			else
711
				be_emit_irprintf("\\%o", c);
712
713
714
			break;
		}
	}
715
716
	be_emit_cstring("\"\n");
	be_emit_write_line();
717
718
719

	type            = get_entity_type(ent);
	type_size       = get_type_size_bytes(type);
720
	remaining_space = type_size - len;
721
	assert(remaining_space >= 0);
Michael Beck's avatar
Michael Beck committed
722
	if (remaining_space > 0) {
723
		be_emit_irprintf("\t.zero\t%d\n", remaining_space);
724
	}
725
726
}

727
static void dump_string_initializer(const ir_initializer_t *initializer)
728
729
730
731
{
	size_t i, len;

	len = initializer->compound.n_initializers;
Matthias Braun's avatar
Matthias Braun committed
732
	if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O) {
Matthias Braun's avatar
Matthias Braun committed
733
734
		be_emit_cstring("\t.ascii \"");
	} else {
735
736
737
738
		be_emit_cstring("\t.string \"");
		len -= 1;
	}

Michael Beck's avatar
Michael Beck committed
739
	for (i = 0; i < len; ++i) {
740
741
742
743
744
745
746
		const ir_initializer_t *sub_initializer
			= get_initializer_compound_value(initializer, i);

		tarval *tv = get_initializer_tarval_value(sub_initializer);
		int     c  = get_tarval_long(tv);

		switch (c) {
747
748
749
750
751
		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;
752
753
		default  :
			if (isprint(c))
754
				be_emit_char(c);
755
			else
756
				be_emit_irprintf("\\%o", c);
757
758
759
			break;
		}
	}
760
761
	be_emit_cstring("\"\n");
	be_emit_write_line();
762
763
}

764
765
enum normal_or_bitfield_kind {
	NORMAL = 0,
766
	TARVAL,
767
768
769
770
771
772
	BITFIELD
};

typedef struct {
	enum normal_or_bitfield_kind kind;
	union {
773
774
775
		ir_node       *value;
		tarval        *tarval;
		unsigned char  bf_val;
776
777
778
	} v;
} normal_or_bitfield;

779
780
781
782
783
784
785
786
787
788
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
789
	switch (get_initializer_kind(initializer)) {
Michael Beck's avatar
Michael Beck committed
790
	case IR_INITIALIZER_TARVAL:
Matthias Braun's avatar
Matthias Braun committed
791
		assert(get_tarval_mode(get_initializer_tarval_value(initializer)) == get_type_mode(type));
792
793
794
795
		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
796
	case IR_INITIALIZER_COMPOUND:
Michael Beck's avatar
Michael Beck committed
797
		if (!is_type_variable_size(type)) {
798
799
800
801
802
803
			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
804
			for (i = 0; i < n_entries; ++i) {
805
806
807
808
809
810
811
812
813
				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
814
				if (offset + size > initializer_size) {
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
					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

830
831
832
833
834
835
836
837
838
839
static void dump_bitfield(normal_or_bitfield *vals, size_t offset_bits,
                          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
840
	switch (get_initializer_kind(initializer)) {
841
842
843
844
845
846
847
	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
848
		if (!is_Const(node)) {
849
850
851
852
853
854
855
856
857
			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) {
858
		panic("Couldn't get numeric value for bitfield initializer");
859
	}
860
	tv = tarval_convert_to(tv, get_type_mode(type));
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880

	/* 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;
	}
}

881
882
883
884
885
886
static void dump_ir_initializer(normal_or_bitfield *vals,
                                const ir_initializer_t *initializer,
                                ir_type *type)
{
	assert((size_t) (vals - glob_vals) < max_vals);

Michael Beck's avatar
Michael Beck committed
887
	switch (get_initializer_kind(initializer)) {
888
889
890
891
892
893
894
895
896
	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
897
		for (i = 1; i < get_type_size_bytes(type); ++i) {
898
899
900
901
902
903
904
905
906
907
908
			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
909
		for (i = 1; i < get_type_size_bytes(type); ++i) {
910
911
912
913
914
915
916
917
918
			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
919
		if (is_Array_type(type)) {
920
921
922
923
			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
924
			if (misalign != 0) {
925
926
927
				skip += alignment - misalign;
			}

Michael Beck's avatar
Michael Beck committed
928
			for (i = 0; i < n; ++i) {
929
930
931
932
933
934
935
936
				ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);

				dump_ir_initializer(vals, sub_initializer, element_type);

				vals += skip;
			}
		} else {
Michael Beck's avatar
Michael Beck committed
937
			size_t n_members, i;
938
			assert(is_compound_type(type));
Michael Beck's avatar
Michael Beck committed
939
			n_members = get_compound_n_members(type);
Michael Beck's avatar
Michael Beck committed
940
			for (i = 0; i < n_members; ++i) {
941
942
943
944
				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);
945
946
947
948
949
950
				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
951
				if (mode != NULL) {
952
953
954
955
					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
956
					if (offset_bits != 0 ||
957
958
959
960
961
962
963
964
						(value_len != 8 && value_len != 16 && value_len != 32
						 && value_len != 64)) {
						dump_bitfield(&vals[offset], offset_bits,
						              sub_initializer, subtype);
						continue;
					}
				}

965
966
967
968
969
970
971
				dump_ir_initializer(&vals[offset], sub_initializer, subtype);
			}
		}

		return;
	}
	}
972
	panic("invalid ir_initializer kind found");
973
974
}

Matthias Braun's avatar
Matthias Braun committed
975
static void dump_initializer(be_gas_decl_env_t *env, const ir_entity *entity)
976
{
Matthias Braun's avatar
Matthias Braun committed
977
	const ir_initializer_t *initializer = entity->initializer;
978
979
980
981
982
	ir_type                *type;
	normal_or_bitfield     *vals;
	size_t                  size;
	size_t                  k;

Michael Beck's avatar
Michael Beck committed
983
	if (initializer_is_string_const(initializer)) {
984
		dump_string_initializer(initializer);
985
986
987
988
989
990
		return;
	}

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

Michael Beck's avatar
Michael Beck committed
991
992
993
	if (size == 0)
		return;

994
995
996
997
	/*
	 * In the worst case, every initializer allocates one byte.
	 * Moreover, initializer might be big, do not allocate on stack.
	 */
998
	vals = XMALLOCNZ(normal_or_bitfield, size);
999
1000

#ifndef NDEBUG