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

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

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

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

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

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

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

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

Michael Beck's avatar
Michael Beck committed
54
55
56
57
58
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
static void dump_size_type(size_t size) {
Christian Würdig's avatar
Christian Würdig committed
484
	switch (size) {
485
	case 1:
486
		be_emit_cstring("\t.byte\t");
487
		break;
488

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

573
574
575
576
577
/**
 * 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
578
static int ent_is_string_const(const ir_entity *ent)
579
{
580
581
582
	ir_type *type, *element_type;
	ir_mode *mode;
	int i, c, n;
583

584
	type = get_entity_type(ent);
585
586

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

Matthias Braun's avatar
Matthias Braun committed
602
603
604
605
	if (ent->initializer != NULL) {
		return initializer_is_string_const(ent->initializer);
	} else if (entity_has_compound_ent_values(ent)) {
		int found_printable = 0;
606
607
608
609
610
611
612
613
614
		/* 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
615
616
			if (isgraph(c) || isspace(c))
				found_printable = 1;
Michael Beck's avatar
Michael Beck committed
617
			else if (c != 0)
Matthias Braun's avatar
Matthias Braun committed
618
619
620
				return 0;

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

Matthias Braun's avatar
Matthias Braun committed
626
	return 0;
627
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
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;
}

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

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

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

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

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

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

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

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

Michael Beck's avatar
Michael Beck committed
738
	for (i = 0; i < len; ++i) {
739
740
741
742
743
744
745
		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) {
746
747
748
749
750
		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;
751
752
		default  :
			if (isprint(c))
753
				be_emit_char(c);
754
			else
755
				be_emit_irprintf("\\%o", c);
756
757
758
			break;
		}
	}
759
760
	be_emit_cstring("\"\n");
	be_emit_write_line();
761
762
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#ifndef NDEBUG
	glob_vals = vals;
For faster browsing, not all history is shown. View entire blame