irio.c 43.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * Copyright (C) 1995-2009 University of Karlsruhe.  All right reserved.
 *
 * 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.
 */

/**
 * @file
 * @brief   Write textual representation of firm to file.
 * @author  Moritz Kroll
 * @version $Id$
 */
#include "config.h"

#include <string.h>
29
30
31
#include <ctype.h>
#include <stdbool.h>
#include <stdarg.h>
32
33
34

#include "irio.h"

35
#include "irnode_t.h"
36
37
38
39
40
41
42
43
44
#include "irprog.h"
#include "irgraph_t.h"
#include "ircons.h"
#include "irgmod.h"
#include "irflag_t.h"
#include "irgwalk.h"
#include "tv.h"
#include "array.h"
#include "error.h"
45
#include "typerep.h"
46
#include "adt/set.h"
47
#include "adt/obst.h"
48

49
#define SYMERROR ((unsigned) ~0)
50

Moritz Kroll's avatar
Moritz Kroll committed
51
typedef struct io_env_t
52
{
53
	int c;                /**< currently read char */
54
	FILE *file;
55
	set *idset;           /**< id_entry set, which maps from file ids to new Firm elements */
56
	int ignoreblocks;
57
58
	const char *inputname;
	int line;
59
	ir_type **fixedtypes;
60
	struct obstack obst;
61
	ir_graph *irg;
62
63
64
65
66
67
} io_env_t;

typedef enum typetag_t
{
	tt_align,
	tt_allocation,
68
	tt_builtin,
69
	tt_cond_jmp_predicate,
70
71
	tt_initializer,
	tt_iro,
72
	tt_keyword,
73
	tt_mode_sort,
74
	tt_mode_arithmetic,
75
	tt_pin_state,
76
	tt_tpo,
77
	tt_type_state,
78
	tt_volatility,
Matthias Braun's avatar
Matthias Braun committed
79
	tt_linkage,
80
81
	tt_segment,
	tt_visibility
82
83
} typetag_t;

84
85
86
87
88
typedef enum keyword_t
{
	kw_constirg,
	kw_entity,
	kw_irg,
89
90
	kw_mode,
	kw_modes,
91
	kw_type,
92
93
94
	kw_typegraph,
	kw_program,
	kw_segment_type
95
96
} keyword_t;

97
typedef struct symbol_t
98
{
99
100
101
102
	const char *str;      /**< The name of this symbol. */
	typetag_t   typetag;  /**< The type tag of this symbol. */
	unsigned    code;     /**< The value of this symbol. */
} symbol_t;
103
104
105
106
107
108
109

typedef struct id_entry
{
	long id;
	void *elem;
} id_entry;

110
111
/** The symbol table, a set of symbol_t elements. */
static set *symtbl;
112

113
114
115
116
/**
 * Compare two symbol table entries.
 */
static int symbol_cmp(const void *elt, const void *key, size_t size)
117
{
118
	int res;
119
120
	const symbol_t *entry = (const symbol_t *) elt;
	const symbol_t *keyentry = (const symbol_t *) key;
121
	(void) size;
122
	res = entry->typetag - keyentry->typetag;
Michael Beck's avatar
Michael Beck committed
123
	if (res) return res;
124
125
126
127
128
129
130
131
132
133
134
	return strcmp(entry->str, keyentry->str);
}

static int id_cmp(const void *elt, const void *key, size_t size)
{
	const id_entry *entry = (const id_entry *) elt;
	const id_entry *keyentry = (const id_entry *) key;
	(void) size;
	return entry->id - keyentry->id;
}

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
static void __attribute__((format(printf, 2, 3)))
parse_error(io_env_t *env, const char *fmt, ...)
{
	va_list ap;
	int     line = env->line;

	/* workaround read_c "feature" that a '\n' triggers the line++
	 * instead of the character after the '\n' */
	if (env->c == '\n') {
		line--;
	}

	fprintf(stderr, "%s:%d: error ", env->inputname, line);

	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
}

154
155
/** Initializes the symbol table. May be called more than once without problems. */
static void symtbl_init(void)
156
{
157
	symbol_t key;
158
159

	/* Only initialize once */
Michael Beck's avatar
Michael Beck committed
160
	if (symtbl != NULL)
161
		return;
162

163
	symtbl = new_set(symbol_cmp, 256);
164

165
#define INSERT(tt, s, cod)                                       \
166
167
168
	key.str = (s);                                               \
	key.typetag = (tt);                                          \
	key.code = (cod);                                            \
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
	set_insert(symtbl, &key, sizeof(key), firm_fnv_hash_str(s) + tt * 17)

#define INSERTENUM(tt, e) INSERT(tt, #e, e)
#define INSERTKEYWORD(k) INSERT(tt_keyword, #k, kw_##k)

	INSERT(tt_tpo, "array", tpo_array);
	INSERT(tt_tpo, "class", tpo_class);
	INSERT(tt_tpo, "method", tpo_method);
	INSERT(tt_tpo, "pointer", tpo_pointer);
	INSERT(tt_tpo, "primitive", tpo_primitive);
	INSERT(tt_tpo, "struct", tpo_struct);
	INSERT(tt_tpo, "union", tpo_union);
	INSERT(tt_tpo, "Unknown", tpo_unknown);

	INSERT(tt_mode_sort, "auxiliary", irms_auxiliary);
	INSERT(tt_mode_sort, "control_flow", irms_control_flow);
	INSERT(tt_mode_sort, "memory", irms_memory);
	INSERT(tt_mode_sort, "internal_boolean", irms_internal_boolean);
	INSERT(tt_mode_sort, "reference", irms_reference);
	INSERT(tt_mode_sort, "int_number", irms_int_number);
	INSERT(tt_mode_sort, "float_number", irms_float_number);

	INSERT(tt_segment, "global", IR_SEGMENT_GLOBAL);
	INSERT(tt_segment, "thread_local", IR_SEGMENT_THREAD_LOCAL);
	INSERT(tt_segment, "constructors", IR_SEGMENT_CONSTRUCTORS);
	INSERT(tt_segment, "destructors", IR_SEGMENT_DESTRUCTORS);
195

Matthias Braun's avatar
Matthias Braun committed
196
197
198
199
200
201
	INSERT(tt_linkage, "constant", IR_LINKAGE_CONSTANT);
	INSERT(tt_linkage, "weak", IR_LINKAGE_WEAK);
	INSERT(tt_linkage, "garbage_collect", IR_LINKAGE_GARBAGE_COLLECT);
	INSERT(tt_linkage, "merge", IR_LINKAGE_MERGE);
	INSERT(tt_linkage, "hidden_user", IR_LINKAGE_HIDDEN_USER);

202
203
204
	INSERT(tt_visibility, "local", ir_visibility_local);
	INSERT(tt_visibility, "external", ir_visibility_external);
	INSERT(tt_visibility, "default", ir_visibility_default);
205
	INSERT(tt_visibility, "private", ir_visibility_private);
206

207
208
209
	INSERTKEYWORD(constirg);
	INSERTKEYWORD(entity);
	INSERTKEYWORD(irg);
210
211
	INSERTKEYWORD(mode);
	INSERTKEYWORD(modes);
212
213
	INSERTKEYWORD(type);
	INSERTKEYWORD(typegraph);
214
215
	INSERTKEYWORD(program);
	INSERTKEYWORD(segment_type);
216

217
218
219
220
221
#include "gen_irio_lex.inl"

	INSERTENUM(tt_align, align_non_aligned);
	INSERTENUM(tt_align, align_is_aligned);

222
223
224
	INSERTENUM(tt_builtin, ir_bk_trap);
	INSERTENUM(tt_builtin, ir_bk_debugbreak);
	INSERTENUM(tt_builtin, ir_bk_return_address);
225
	INSERTENUM(tt_builtin, ir_bk_frame_address);
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
	INSERTENUM(tt_builtin, ir_bk_prefetch);
	INSERTENUM(tt_builtin, ir_bk_ffs);
	INSERTENUM(tt_builtin, ir_bk_clz);
	INSERTENUM(tt_builtin, ir_bk_ctz);
	INSERTENUM(tt_builtin, ir_bk_popcount);
	INSERTENUM(tt_builtin, ir_bk_parity);
	INSERTENUM(tt_builtin, ir_bk_bswap);
	INSERTENUM(tt_builtin, ir_bk_inport);
	INSERTENUM(tt_builtin, ir_bk_outport);
	INSERTENUM(tt_builtin, ir_bk_inner_trampoline);

	INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_NONE);
	INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_TRUE);
	INSERTENUM(tt_cond_jmp_predicate, COND_JMP_PRED_FALSE);

	INSERTENUM(tt_initializer, IR_INITIALIZER_CONST);
	INSERTENUM(tt_initializer, IR_INITIALIZER_TARVAL);
	INSERTENUM(tt_initializer, IR_INITIALIZER_NULL);
	INSERTENUM(tt_initializer, IR_INITIALIZER_COMPOUND);

246
247
248
249
250
251
252
253
	INSERTENUM(tt_mode_arithmetic, irma_uninitialized);
	INSERTENUM(tt_mode_arithmetic, irma_none);
	INSERTENUM(tt_mode_arithmetic, irma_twos_complement);
	INSERTENUM(tt_mode_arithmetic, irma_ones_complement);
	INSERTENUM(tt_mode_arithmetic, irma_int_BCD);
	INSERTENUM(tt_mode_arithmetic, irma_ieee754);
	INSERTENUM(tt_mode_arithmetic, irma_float_BCD);

254
255
256
257
258
259
260
261
262
263
264
	INSERTENUM(tt_pin_state, op_pin_state_floats);
	INSERTENUM(tt_pin_state, op_pin_state_pinned);
	INSERTENUM(tt_pin_state, op_pin_state_exc_pinned);
	INSERTENUM(tt_pin_state, op_pin_state_mem_pinned);

	INSERTENUM(tt_type_state, layout_undefined);
	INSERTENUM(tt_type_state, layout_fixed);

	INSERTENUM(tt_volatility, volatility_non_volatile);
	INSERTENUM(tt_volatility, volatility_is_volatile);

265
#undef INSERTKEYWORD
266
267
268
269
#undef INSERTENUM
#undef INSERT
}

270
271
272
273
274
275
276
277
278
279
280
static const char *get_segment_name(ir_segment_t segment)
{
	switch (segment) {
	case IR_SEGMENT_GLOBAL:       return "global";
	case IR_SEGMENT_THREAD_LOCAL: return "thread_local";
	case IR_SEGMENT_CONSTRUCTORS: return "constructors";
	case IR_SEGMENT_DESTRUCTORS:  return "destructors";
	}
	return "INVALID_SEGMENT";
}

281
282
283
284
285
286
287
288
289
290
291
static const char *get_visibility_name(ir_visibility visibility)
{
	switch (visibility) {
	case ir_visibility_local:    return "local";
	case ir_visibility_external: return "external";
	case ir_visibility_default:  return "default";
	case ir_visibility_private:  return "private";
	}
	return "INVALID_VISIBILITY";
}

292
293
/** Returns the according symbol value for the given string and tag, or SYMERROR if none was found. */
static unsigned symbol(const char *str, typetag_t typetag)
294
{
295
	symbol_t key, *entry;
296
297

	key.str = str;
298
	key.typetag = typetag;
299

300
	entry = (symbol_t*)set_find(symtbl, &key, sizeof(key), firm_fnv_hash_str(str) + typetag * 17);
301
	return entry ? entry->code : SYMERROR;
302
303
304
305
306
307
308
}

static void *get_id(io_env_t *env, long id)
{
	id_entry key, *entry;
	key.id = id;

309
	entry = (id_entry*)set_find(env->idset, &key, sizeof(key), (unsigned) id);
310
311
312
313
314
315
316
317
318
319
320
	return entry ? entry->elem : NULL;
}

static void set_id(io_env_t *env, long id, void *elem)
{
	id_entry key;
	key.id = id;
	key.elem = elem;
	set_insert(env->idset, &key, sizeof(key), (unsigned) id);
}

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
static void write_long(io_env_t *env, long value)
{
	fprintf(env->file, "%ld ", value);
}

static void write_int(io_env_t *env, int value)
{
	fprintf(env->file, "%d ", value);
}

static void write_unsigned(io_env_t *env, unsigned value)
{
	fprintf(env->file, "%u ", value);
}

static void write_entity_ref(io_env_t *env, ir_entity *entity)
{
	write_long(env, get_entity_nr(entity));
}

static void write_type_ref(io_env_t *env, ir_type *type)
{
	write_long(env, get_type_nr(type));
}

Matthias Braun's avatar
Matthias Braun committed
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
static void write_string(io_env_t *env, const char *string)
{
	const char *c;
	fputc('"', env->file);
	for (c = string; *c != '\0'; ++c) {
		switch (*c) {
		case '\n':
			fputc('\\', env->file);
			fputc('n', env->file);
			break;
		case '"':
		case '\\':
			fputc('\\', env->file);
			/* FALLTHROUGH */
		default:
			fputc(*c, env->file);
			break;
		}
	}
	fputc('"', env->file);
}

static void write_ident(io_env_t *env, ident *id)
{
	write_string(env, get_id_str(id));
	fputc(' ', env->file);
}

static void write_ident_null(io_env_t *env, ident *id)
{
	if (id == NULL) {
		fputs("NULL ", env->file);
	} else {
		write_ident(env, id);
	}
}

383
384
385
386
387
388
static void write_mode(io_env_t *env, ir_mode *mode)
{
	fputs(get_mode_name(mode), env->file);
	fputc(' ', env->file);
}

Matthias Braun's avatar
Matthias Braun committed
389
static void write_tarval(io_env_t *env, ir_tarval *tv)
390
391
392
393
394
395
396
397
{
	char buf[1024];
	write_mode(env, get_tarval_mode(tv));
	tarval_snprintf(buf, sizeof(buf), tv);
	fputs(buf, env->file);
	fputc(' ', env->file);
}

398
399
400
401
static void write_align(io_env_t *env, ir_node *irn)
{
	ir_align align;

Michael Beck's avatar
Michael Beck committed
402
403
404
405
406
407
	if (is_Load(irn))
		align = get_Load_align(irn);
	else if (is_Store(irn))
		align = get_Store_align(irn);
	else
		panic("Invalid optype for write_align");
408
409
410
411
412

	fputs(get_align_name(align), env->file);
	fputc(' ', env->file);
}

413
414
415
416
417
418
static void write_builtin_kind(io_env_t *env, ir_node *irn)
{
	fputs(get_builtin_kind_name(get_Builtin_kind(irn)), env->file);
	fputc(' ', env->file);
}

419
420
421
422
423
424
static void write_cond_jmp_predicate(io_env_t *env, ir_node *irn)
{
	fputs(get_cond_jmp_predicate_name(get_Cond_jmp_pred(irn)), env->file);
	fputc(' ', env->file);
}

425
426
427
428
429
430
431
432
433
434
static void write_list_begin(io_env_t *env)
{
	fputs("[", env->file);
}

static void write_list_end(io_env_t *env)
{
	fputs("] ", env->file);
}

435
436
437
438
static void write_initializer(io_env_t *env, ir_initializer_t *ini)
{
	FILE *f = env->file;
	ir_initializer_kind_t ini_kind = get_initializer_kind(ini);
439

440
441
442
	fputs(get_initializer_kind_name(ini_kind), f);
	fputc(' ', f);

443
444
	switch (ini_kind) {
	case IR_INITIALIZER_CONST:
445
		write_long(env, get_irn_node_nr(get_initializer_const_value(ini)));
446
		break;
447

448
449
450
	case IR_INITIALIZER_TARVAL:
		write_tarval(env, get_initializer_tarval_value(ini));
		break;
451

452
453
	case IR_INITIALIZER_NULL:
		break;
454

455
456
	case IR_INITIALIZER_COMPOUND: {
		unsigned i, n = get_initializer_compound_n_entries(ini);
457
		fprintf(f, "%u ", n);
458
459
460
461
		for (i = 0; i < n; i++)
			write_initializer(env, get_initializer_compound_value(ini, i));
		break;
	}
462

463
464
	default:
		panic("Unknown initializer kind");
465
466
467
	}
}

468
469
470
471
472
473
474
475
476
477
static void write_pin_state(io_env_t *env, ir_node *irn)
{
	fputs(get_op_pin_state_name(get_irn_pinned(irn)), env->file);
	fputc(' ', env->file);
}

static void write_volatility(io_env_t *env, ir_node *irn)
{
	ir_volatility vol;

Michael Beck's avatar
Michael Beck committed
478
479
480
481
482
483
	if (is_Load(irn))
		vol = get_Load_volatility(irn);
	else if (is_Store(irn))
		vol = get_Store_volatility(irn);
	else
		panic("Invalid optype for write_volatility");
484
485
486
487
488

	fputs(get_volatility_name(vol), env->file);
	fputc(' ', env->file);
}

489
static void export_type_common(io_env_t *env, ir_type *tp)
490
{
491
	fprintf(env->file, "\ttype %ld %s %u %u %s %u ",
492
493
494
495
496
497
498
499
	        get_type_nr(tp),
	        get_type_tpop_name(tp),
	        get_type_size_bytes(tp),
	        get_type_alignment_bytes(tp),
	        get_type_state_name(get_type_state(tp)),
	        tp->flags);
}

500
501
502
503
static void export_type_pre(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;

Michael Beck's avatar
Michael Beck committed
504
	/* skip types to be handled by post walker */
505
506
507
508
509
510
511
	switch (get_type_tpop_code(tp)) {
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
		return;
	default:
		break;
512
513
514
515
	}

	export_type_common(env, tp);

516
517
518
519
520
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

	case tpo_class:
Matthias Braun's avatar
Matthias Braun committed
521
		write_ident_null(env, get_compound_ident(tp));
522
523
524
525
526
527
528
529
530
		break;

	case tpo_primitive:
		write_mode(env, get_type_mode(tp));
		break;

	case tpo_union:
	case tpo_struct:
	case tpo_enumeration:
Matthias Braun's avatar
Matthias Braun committed
531
		write_ident_null(env, get_compound_ident(tp));
532
533
534
535
536
537
538
539
540
		break;

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
541
542
543
544
545
546
547
	}
	fputc('\n', f);
}

static void export_type_post(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;
548
	int i;
549

Michael Beck's avatar
Michael Beck committed
550
	/* skip types already handled by pre walker */
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
	switch (get_type_tpop_code(tp)) {
	case tpo_class:
	case tpo_primitive:
	case tpo_struct:
	case tpo_union:
	case tpo_unknown:
	case tpo_uninitialized:
	case tpo_code:
	case tpo_none:
		return;
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_enumeration:
		break;
566
567
568
	}

	export_type_common(env, tp);
569

570
571
572
573
574
575
576
577
578
	switch (get_type_tpop_code(tp)) {
	case tpo_array: {
		int n = get_array_n_dimensions(tp);
		fprintf(f, "%d %ld ", n, get_type_nr(get_array_element_type(tp)));
		for (i = 0; i < n; i++) {
			ir_node *lower = get_array_lower_bound(tp, i);
			ir_node *upper = get_array_upper_bound(tp, i);

			if (is_Const(lower))
579
				write_long(env, get_tarval_long(get_Const_tarval(lower)));
580
581
582
583
			else
				panic("Lower array bound is not constant");

			if (is_Const(upper))
584
				write_long(env, get_tarval_long(get_Const_tarval(upper)));
585
586
587
588
589
590
591
			else if (is_Unknown(upper))
				fputs("unknown ", f);
			else
				panic("Upper array bound is not constant");
		}
		break;
	}
592

593
594
595
596
597
598
	case tpo_method: {
		int nparams  = get_method_n_params(tp);
		int nresults = get_method_n_ress(tp);
		fprintf(f, "%u %u %d %d ", get_method_calling_convention(tp),
			get_method_additional_properties(tp), nparams, nresults);
		for (i = 0; i < nparams; i++)
599
			write_long(env, get_type_nr(get_method_param_type(tp, i)));
600
		for (i = 0; i < nresults; i++)
601
			write_long(env, get_type_nr(get_method_res_type(tp, i)));
602
603
604
		fprintf(f, "%d ", get_method_first_variadic_param_index(tp));
		break;
	}
605

606
607
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
608
		write_long(env, get_type_nr(get_pointer_points_to_type(tp)));
609
		break;
610

611
612
613
614
615
616
617
618
	case tpo_enumeration:
		fprintf(stderr, "Enumeration type not handled yet by exporter\n");
		break;

	default:
		printf("export_type: Unknown type code \"%s\".\n",
		       get_type_tpop_name(tp));
		break;
619
620
621
622
623
624
	}
	fputc('\n', f);
}

static void export_entity(io_env_t *env, ir_entity *ent)
{
625
626
627
628
	FILE          *file       = env->file;
	ir_type       *owner      = get_entity_owner(ent);
	ir_visibility  visibility = get_entity_visibility(ent);
	ir_linkage     linkage    = get_entity_linkage(ent);
629
630
631
632
633
634
635

	/* we don't dump array_element_ent entities. They're a strange concept
	 * and lead to cycles in type_graph.
	 */
	if (is_Array_type(owner))
		return;

Matthias Braun's avatar
Matthias Braun committed
636
637
638
639
640
	fprintf(env->file, "\tentity ");
	write_long(env, get_entity_nr(ent));
	write_ident_null(env, get_entity_ident(ent));
	if (!entity_has_ld_ident(ent)) {
		write_ident_null(env, NULL);
641
	} else {
Matthias Braun's avatar
Matthias Braun committed
642
		write_ident_null(env, get_entity_ld_ident(ent));
643
644
	}

645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
	/* visibility + linkage */
	if (visibility != ir_visibility_default) {
		fprintf(file, "%s ", get_visibility_name(visibility));
	}
	if (linkage & IR_LINKAGE_CONSTANT)
		fputs("constant ", file);
	if (linkage & IR_LINKAGE_WEAK)
		fputs("weak ", file);
	if (linkage & IR_LINKAGE_GARBAGE_COLLECT)
		fputs("garbage_collect ", file);
	if (linkage & IR_LINKAGE_MERGE)
		fputs("merge ", file);
	if (linkage & IR_LINKAGE_HIDDEN_USER)
		fputs("hidden_user ", file);

	fprintf(file, "%ld %ld %d %u %d %s ",
661
662
663
			get_type_nr(get_entity_type(ent)),
			get_type_nr(owner),
			get_entity_offset(ent),
664
			(unsigned) get_entity_offset_bits_remainder(ent),
665
			is_entity_compiler_generated(ent),
666
667
			get_volatility_name(get_entity_volatility(ent)));

Matthias Braun's avatar
Matthias Braun committed
668
669
670
671
672
673
674
675
676
677
678
	if (ent->initializer != NULL) {
		fputs("initializer ", env->file);
		write_initializer(env, get_entity_initializer(ent));
	} else if (entity_has_compound_ent_values(ent)) {
		int i, n = get_compound_ent_n_values(ent);
		fputs("compoundgraph ", env->file);
		fprintf(env->file, "%d ", n);
		for (i = 0; i < n; i++) {
			ir_entity *member = get_compound_ent_value_member(ent, i);
			ir_node   *irn    = get_compound_ent_value(ent, i);
			fprintf(env->file, "%ld %ld ", get_entity_nr(member), get_irn_node_nr(irn));
679
		}
Matthias Braun's avatar
Matthias Braun committed
680
681
	} else {
		fputs("none", env->file);
682
683
684
	}

	fputc('\n', env->file);
685
686
}

687
688
689
static void export_type_or_ent_pre(type_or_ent tore, void *ctx)
{
	io_env_t *env = (io_env_t *) ctx;
Michael Beck's avatar
Michael Beck committed
690
	if (get_kind(tore.typ) == k_type)
691
692
693
694
		export_type_pre(env, tore.typ);
}

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
695
696
697
{
	io_env_t *env = (io_env_t *) ctx;

698
699
700
701
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
702

703
704
705
	case k_type:
		export_type_post(env, tore.typ);
		break;
706

707
708
709
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
		break;
710
711
712
	}
}

713
714
715
/**
 * Walker: exports every node.
 */
716
717
718
719
720
721
static void export_node(ir_node *irn, void *ctx)
{
	io_env_t *env = (io_env_t *) ctx;
	int i, n;
	unsigned opcode = get_irn_opcode(irn);

Michael Beck's avatar
Michael Beck committed
722
	if (env->ignoreblocks && opcode == iro_Block)
723
		return;
724

725
726
	fprintf(env->file, "\t%s ", get_irn_opname(irn));
	write_long(env, get_irn_node_nr(irn));
727

728
	write_list_begin(env);
729
	n = get_irn_arity(irn);
730
	if (!is_Block(irn)) {
731
732
		ir_node *block = get_nodes_block(irn);
		write_long(env, get_irn_node_nr(block));
733
734
735
	}

	for (i = 0; i < n; i++) {
736
		ir_node *pred = get_irn_n(irn, i);
Michael Beck's avatar
Michael Beck committed
737
		if (pred == NULL) {
738
			/* Anchor node may have NULL predecessors */
739
			assert(is_Anchor(irn));
740
			fputs("-1 ", env->file);
741
		} else {
742
			write_long(env, get_irn_node_nr(pred));
743
		}
744
	}
745
	write_list_end(env);
746

747
	fputs("{ ", env->file);
748

749
	switch (opcode) {
750
751
752
753
754
755
756
757
758
759
760
761
762
763
	case iro_Start:
	case iro_End:
	case iro_Block:
	case iro_Anchor:
		break;
	case iro_SymConst:
		/* TODO: only symconst_addr_ent implemented yet */
		assert(get_SymConst_kind(irn) == symconst_addr_ent);
		fprintf(env->file, "%ld ", get_entity_nr(get_SymConst_entity(irn)));
		break;
	case iro_Proj:
		write_mode(env, get_irn_mode(irn));
		fprintf(env->file, "%ld ", get_Proj_proj(irn));
		break;
764
#include "gen_irio_export.inl"
765
766
	default:
		panic("no export code for node %+F\n", irn);
767
	}
768
769
770
	fputs("}\n", env->file);
}

771
772
773
774
775
776
777
778
779
780
781
782
783
784
static const char *get_mode_sort_name(ir_mode_sort sort)
{
	switch (sort) {
	case irms_auxiliary:        return "auxiliary";
	case irms_control_flow:     return "control_flow";
	case irms_memory:           return "memory";
	case irms_internal_boolean: return "internal_boolean";
	case irms_reference:        return "reference";
	case irms_int_number:       return "int_number";
	case irms_float_number:     return "float_number";
	}
	panic("invalid mode sort found");
}

785
786
787
788
789
790
static void export_modes(io_env_t *env)
{
	int i, n_modes = get_irp_n_modes();

	fputs("modes {\n", env->file);

Michael Beck's avatar
Michael Beck committed
791
	for (i = 0; i < n_modes; i++) {
792
		ir_mode *mode = get_irp_mode(i);
793
794
795
796
797
798
799
800
801
		switch (get_mode_sort(mode)) {
		case irms_auxiliary:
		case irms_control_flow:
		case irms_memory:
		case irms_internal_boolean:
			/* skip "internal" modes, which may not be user defined */
			continue;
		default:
			break;
802
803
		}

Matthias Braun's avatar
Matthias Braun committed
804
805
806
807
		fprintf(env->file, "\tmode ");
		write_string(env, get_mode_name(mode));
		fprintf(env->file, "%s %u %d %s %u %u ",
		        get_mode_sort_name(get_mode_sort(mode)),
808
809
810
811
		        get_mode_size_bits(mode), get_mode_sign(mode),
		        get_mode_arithmetic_name(get_mode_arithmetic(mode)),
		        get_mode_modulo_shift(mode),
		        get_mode_n_vector_elems(mode));
Michael Beck's avatar
Michael Beck committed
812
		if (mode_is_reference(mode)) {
813
814
815
816
817
818
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
		}
		fputc('\n', env->file);
	}

819
	fputs("}\n", env->file);
820
821
}

822
static void export_program(io_env_t *env)
823
{
824
825
826
827
828
	FILE         *f = env->file;
	ir_segment_t  s;

	fputs("\nprogram {\n", f);
	if (irp_prog_name_is_set()) {
Matthias Braun's avatar
Matthias Braun committed
829
830
831
		fprintf(f, "\tname ");
		write_string(env, get_irp_name());
		fputc('\n', f);
832
833
	}

834
	for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
835
		ir_type *segment_type = get_segment_type(s);
Matthias Braun's avatar
Matthias Braun committed
836
		fprintf(f, "\tsegment_type %s ", get_segment_name(s));
837
838
839
		if (segment_type == NULL) {
			fputs(" NULL\n", f);
		} else {
Matthias Braun's avatar
Matthias Braun committed
840
841
			write_long(env, get_type_nr(segment_type));
			fputc('\n', f);
842
843
844
845
		}
	}
	fputs("}\n", f);
}
846

847
848
849
850
void ir_export(const char *filename)
{
	FILE *file = fopen(filename, "wt");
	if (file == NULL) {
851
852
853
854
		perror(filename);
		return;
	}

855
856
857
	ir_export_file(file, filename);
	fclose(file);
}
858

859
860
861
862
863
864
865
866
867
868
/* Exports the whole irp to the given file in a textual form. */
void ir_export_file(FILE *file, const char *outputname)
{
	io_env_t env;
	int i, n_irgs = get_irp_n_irgs();

	(void) outputname;
	env.file = file;

	export_modes(&env);
869

870
	fputs("\ntypegraph {\n", env.file);
871
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
872
	fputs("}\n", env.file);
873

Michael Beck's avatar
Michael Beck committed
874
	for (i = 0; i < n_irgs; i++) {
875
876
		ir_graph *irg       = get_irp_irg(i);
		ir_type  *valuetype = get_irg_value_param_type(irg);
877

878
879
880
881
		fprintf(env.file, "\nirg %ld %ld %ld {\n",
		        get_entity_nr(get_irg_entity(irg)),
		        get_type_nr(get_irg_frame_type(irg)),
		        valuetype == NULL ? -1 : get_type_nr(valuetype));
882
883
884
885
886
887

		env.ignoreblocks = 0;
		irg_block_walk_graph(irg, NULL, export_node, &env);

		env.ignoreblocks = 1;
		irg_walk_anchors(irg, NULL, export_node, &env);
888
889

		fputs("}\n", env.file);
890
891
	}

892
	fprintf(env.file, "\nconstirg %ld {\n", get_irn_node_nr(get_const_code_irg()->current_block));
893

894
895
896
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

897
	export_program(&env);
898
899
}

900
/* Exports the given irg to the given file. */
901
void ir_export_irg(ir_graph *irg, FILE *file, const char *outputname)
902
903
904
{
	io_env_t env;

905
906
	(void) outputname;
	env.file = file;
907

908
909
	export_modes(&env);

910
911
	fputs("typegraph {\n", env.file);

912
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
913

914
	fprintf(env.file, "}\n\nirg %ld {\n", get_entity_nr(get_irg_entity(irg)));
915
916
917
918
919
920
921

	env.ignoreblocks = 0;
	irg_block_walk_graph(irg, NULL, export_node, &env);

	env.ignoreblocks = 1;
	irg_walk_anchors(irg, NULL, export_node, &env);

922
	/* TODO: Only output needed constants */
923
	fprintf(env.file, "}\n\nconstirg %ld {\n", get_irn_node_nr(get_const_code_irg()->current_block));
924
925
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);
Moritz Kroll's avatar
Moritz Kroll committed
926
927
}

928
static void read_c(io_env_t *env)
Moritz Kroll's avatar
Moritz Kroll committed
929
{
930
931
932
933
	int c = fgetc(env->file);
	env->c = c;
	if (c == '\n')
		env->line++;
Moritz Kroll's avatar
Moritz Kroll committed
934
935
}

936
937
/** Returns the first non-whitespace character or EOF. **/
static void skip_ws(io_env_t *env)
938
{
939
940
941
	while (true) {
		switch (env->c) {
		case ' ':
942
943
		case '\t':
		case '\n':
944
945
946
		case '\r':
			read_c(env);
			continue;
947
948

		default:
949
			return;
950
951
952
953
954
955
		}
	}
}

static void skip_to(io_env_t *env, char to_ch)
{
956
957
958
	while (env->c != to_ch && env->c != EOF) {
		read_c(env);
	}
959
960
961
962
}

static int expect_char(io_env_t *env, char ch)
{
963
964
965
966
	skip_ws(env);
	if (env->c != ch) {
		parse_error(env, "Unexpected char '%c', expected '%c'\n",
		            env->c, ch);
967
968
		return 0;
	}
969
	read_c(env);
970
971
972
	return 1;
}

Michael Beck's avatar
Michael Beck committed
973
#define EXPECT(c) if (expect_char(env, (c))) {} else return 0
974

975
static char *read_word(io_env_t *env)
976
{
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
	skip_ws(env);

	assert(obstack_object_size(&env->obst) == 0);
	while (true) {
		int c = env->c;
		switch (c) {
		case EOF:
		case ' ':
		case '\t':
		case '\n':
		case '\r':
			goto endofword;

		default:
			obstack_1grow(&env->obst, c);
			break;
993
		}
994
		read_c(env);
995
	}
996

997
endofword:
998
	obstack_1grow(&env->obst, '\0');
999
	return (char*)obstack_finish(&env->obst);
1000
1001
}

Matthias Braun's avatar
Matthias Braun committed
1002
static char *read_string(io_env_t *env)
1003
{
1004
	skip_ws(env);
Matthias Braun's avatar
Matthias Braun committed
1005
1006
	if (env->c != '"') {
		parse_error(env, "Expected string, got '%c'\n", env->c);
1007
1008
1009
		exit(1);
	}
	read_c(env);
1010

1011
	assert(obstack_object_size(&env->obst) == 0);
Matthias Braun's avatar
Matthias Braun committed
1012
1013
1014
	while (env->c != '"') {
		if (env->c == EOF) {
			parse_error(env, "Unexpected EOF while parsing string\n");
1015
1016
			exit(1);
		}
Matthias Braun's avatar
Matthias Braun committed
1017
1018

		if (env->c == '\\') {
1019
			read_c(env);
Matthias Braun's avatar
Matthias Braun committed
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
			switch (env->c) {
			case 'n':
				obstack_1grow(&env->obst, '\n');
				break;
			case '"':
			case '\\':
				obstack_1grow(&env->obst, env->c);
				break;
			default:
				parse_error(env, "Unknown escape sequence '\\%c'\n", env->c);
				exit(1);
				break;
			}
		} else {
			obstack_1grow(&env->obst, env->c);
1035
1036
		}
		read_c(env);
1037
	}
Matthias Braun's avatar
Matthias Braun committed
1038
1039
	read_c(env);
	obstack_1grow(&env->obst, 0);
1040

1041
	return (char*)obstack_finish(&env->obst);
1042
1043
}

1044
static ident *read_ident(io_env_t *env)
1045
{
Matthias Braun's avatar
Matthias Braun committed
1046
	char  *str = read_string(env);
1047
1048
1049
1050
1051
1052
1053
1054
	ident *res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
}

/*
 * reads a "quoted string" or alternatively the token NULL
 */
Matthias Braun's avatar
Matthias Braun committed
1055
static char *read_string_null(io_env_t *env)
1056
1057
1058
1059
1060
1061
1062
1063
1064
{
	skip_ws(env);
	if (env->c == 'N') {
		char *str = read_word(env);
		if (strcmp(str, "NULL") == 0) {
			obstack_free(&env->obst, str);
			return NULL;
		}
	} else if (env->c == '"') {
Matthias Braun's avatar
Matthias Braun committed
1065
		return read_string(env);
1066
1067
1068
1069
	}

	parse_error(env, "Expected \"string\" or NULL\n");
	exit(1);
1070
1071
}

1072
static ident *read_ident_null(io_env_t *env)
1073
{
1074
	ident *res;
Matthias Braun's avatar
Matthias Braun committed
1075
	char  *str = read_string_null(env);
1076
1077
1078
1079
1080
1081
	if (str == NULL)
		return NULL;

	res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
1082
1083
1084
1085
}

static long read_long(io_env_t *env)
{
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
	long  result;
	char *str;

	skip_ws(env);
	if (!isdigit(env->c) && env->c != '-') {
		parse_error(env, "Expected number, got '%c'\n", env->c);
		exit(1);
	}

	assert(obstack_object_size(&env->obst) == 0);
	do {
		obstack_1grow(&env->obst, env->c);
		read_c(env);
1099
	} while (isdigit(env->c));
1100
1101
	obstack_1grow(&env->obst, 0);

1102
	str = (char*)obstack_finish(&env->obst);
1103
1104
1105
1106
	result = atol(str);
	obstack_free(&env->obst, str);

	return result;
1107
1108
}

1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
static int read_int(io_env_t *env)
{
	return (int) read_long(env);
}

static unsigned read_unsigned(io_env_t *env)
{
	return (unsigned) read_long(env);
}

1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
static void expect_list_begin(io_env_t *env)
{
	skip_ws(env);
	if (env->c != '[') {
		parse_error(env, "Expected list, got '%c'\n", env->c);
		exit(1);
	}
	read_c(env);
}

static bool list_has_next(io_env_t *env)
{
	if (feof(env->file)) {
		parse_error(env, "Unexpected EOF while reading list");
		exit(1);
	}
	skip_ws(env);
	if (env->c == ']') {
		read_c(env);
		return false;
	}

	return true;
}

1144
1145
1146
static ir_node *get_node_or_null(io_env_t *env, long nodenr)
{
	ir_node *node = (ir_node *) get_id(env, nodenr);
1147
1148
1149
1150
	if (node && node->kind != k_ir_node) {
		panic("Irn ID %ld collides with something else in line %d\n",
		      nodenr, env->line);
	}
1151
1152
1153
1154
1155
1156
	return node;
}

static ir_node *get_node_or_dummy(io_env_t *env, long nodenr)
{
	ir_node *node = get_node_or_null(env, nodenr);
Michael Beck's avatar
Michael Beck committed
1157
	if (node == NULL) {
1158
		node = new_r_Dummy(env->irg, mode_X);
1159
1160
1161
1162
1163
1164
1165
1166
		set_id(env, nodenr, node);
	}
	return node;
}

static ir_type *get_type(io_env_t *env, long typenr)
{
	ir_type *type = (ir_type *) get_id(env, typenr);
Michael Beck's avatar
Michael Beck committed
1167
	if (type == NULL)
1168
		panic("unknown type: %ld in line %d\n", typenr, env->line);
Michael Beck's avatar
Michael Beck committed
1169
	else if (type->kind != k_type)
1170
1171
		panic("type ID %ld collides with something else in line %d\n",
		      typenr, env->line);
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
	return type;
}

static ir_type *read_type(io_env_t *env)
{
	return get_type(env, read_long(env));
}

static ir_entity *get_entity(io_env_t *env, long entnr)
{
	ir_entity *entity = (ir_entity *) get_id(env, entnr);
Michael Beck's avatar
Michael Beck committed
1183
	if (entity == NULL) {
1184
		parse_error(env, "unknown entity: %ld\n", entnr);
1185
		exit(1);
1186
1187
1188
1189
1190
	} else if (entity->kind != k_entity) {
		panic("Entity ID %ld collides with something else in line %d\n",
		      entnr, env->line);
	}

1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
	return entity;
}

static ir_entity *read_entity(io_env_t *env)
{
	return get_entity(env, read_long(env));
}

static ir_mode *read_mode(io_env_t *env)
{
1201
	char *str = read_word(env);
1202
1203
1204
	int i, n;

	n = get_irp_n_modes();
Michael Beck's avatar
Michael Beck committed
1205
	for (i = 0; i < n; i++) {
1206
		ir_mode *mode = get_irp_mode(i);
1207
1208
		if (strcmp(str, get_mode_name(mode)) == 0) {
			obstack_free(&env->obst, str);
1209
			return mode;
1210
		}
1211
1212
	}

1213
1214
	parse_error(env, "unknown mode \"%s\"\n", str);
	exit(1);
1215
1216
1217
1218
}

static const char *get_typetag_name(typetag_t typetag)
{
1219
1220
1221
1222
	switch (typetag) {
	case tt_align:              return "align";
	case tt_allocation:         return "allocation";
	case tt_builtin:            return "builtin kind";
Matthias Braun's avatar
Matthias Braun committed
1223
	case tt_cond_jmp_predicate: return "cond_jmp_predicate";
1224
1225
	case tt_initializer:        return "initializer kind";
	case tt_iro:                return "opcode";
Matthias Braun's avatar
Matthias Braun committed
1226
1227
1228
1229
	case tt_keyword:            return "keyword";
	case tt_linkage:            return "linkage";
	case tt_mode_arithmetic:    return "mode_arithmetic";
	case tt_mode_sort:          return "mode_sort";
1230
	case tt_pin_state:          return "pin state";
Matthias Braun's avatar
Matthias Braun committed
1231
	case tt_segment:            return "segment";
1232
1233
1234
	case tt_tpo:                return "type";
	case tt_type_state:         return "type state";
	case tt_volatility:         return "volatility";
1235
	case tt_visibility:         return "visibility";
1236
	}
1237
	return "<UNKNOWN>";
1238
1239
}

1240
1241
1242
/**
 * Read and decode an enum constant.
 */
1243
1244
static unsigned read_enum(io_env_t *env, typetag_t typetag)
{
1245
1246
1247
1248
1249
	char     *str  = read_word(env);
	unsigned  code = symbol(str, typetag);

	if (code != SYMERROR) {
		obstack_free(&env->obst, str);
1250
		return code;