irio.c 42.9 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
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);
429

430
431
432
	fputs(get_initializer_kind_name(ini_kind), f);
	fputc(' ', f);

433
434
	switch (ini_kind) {
	case IR_INITIALIZER_CONST:
435
		write_long(env, get_irn_node_nr(get_initializer_const_value(ini)));
436
		break;
437

438
439
440
	case IR_INITIALIZER_TARVAL:
		write_tarval(env, get_initializer_tarval_value(ini));
		break;
441

442
443
	case IR_INITIALIZER_NULL:
		break;
444

445
446
	case IR_INITIALIZER_COMPOUND: {
		unsigned i, n = get_initializer_compound_n_entries(ini);
447
		fprintf(f, "%u ", n);
448
449
450
451
		for (i = 0; i < n; i++)
			write_initializer(env, get_initializer_compound_value(ini, i));
		break;
	}
452

453
454
	default:
		panic("Unknown initializer kind");
455
456
457
	}
}

458
459
460
461
462
463
464
465
466
467
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
468
469
470
471
472
473
	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");
474
475
476
477
478

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

479
static void export_type_common(io_env_t *env, ir_type *tp)
480
{
481
	fprintf(env->file, "\ttype %ld %s %u %u %s %u ",
482
483
484
485
486
487
488
489
	        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);
}

490
491
492
493
static void export_type_pre(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;

Michael Beck's avatar
Michael Beck committed
494
	/* skip types to be handled by post walker */
495
496
497
498
499
500
501
	switch (get_type_tpop_code(tp)) {
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
		return;
	default:
		break;
502
503
504
505
	}

	export_type_common(env, tp);

506
507
508
509
510
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

	case tpo_class:
Matthias Braun's avatar
Matthias Braun committed
511
		write_ident_null(env, get_compound_ident(tp));
512
513
514
515
516
517
518
519
520
		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
521
		write_ident_null(env, get_compound_ident(tp));
522
523
524
525
526
527
528
529
530
		break;

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
531
532
533
534
535
536
537
	}
	fputc('\n', f);
}

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

Michael Beck's avatar
Michael Beck committed
540
	/* skip types already handled by pre walker */
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
	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;
556
557
558
	}

	export_type_common(env, tp);
559

560
561
562
563
564
565
566
567
568
	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))
569
				write_long(env, get_tarval_long(get_Const_tarval(lower)));
570
571
572
573
			else
				panic("Lower array bound is not constant");

			if (is_Const(upper))
574
				write_long(env, get_tarval_long(get_Const_tarval(upper)));
575
576
577
578
579
580
581
			else if (is_Unknown(upper))
				fputs("unknown ", f);
			else
				panic("Upper array bound is not constant");
		}
		break;
	}
582

583
584
585
586
587
588
	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++)
589
			write_long(env, get_type_nr(get_method_param_type(tp, i)));
590
		for (i = 0; i < nresults; i++)
591
			write_long(env, get_type_nr(get_method_res_type(tp, i)));
592
593
594
		fprintf(f, "%d ", get_method_first_variadic_param_index(tp));
		break;
	}
595

596
597
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
598
		write_long(env, get_type_nr(get_pointer_points_to_type(tp)));
599
		break;
600

601
602
603
604
605
606
607
608
	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;
609
610
611
612
613
614
	}
	fputc('\n', f);
}

static void export_entity(io_env_t *env, ir_entity *ent)
{
615
616
617
618
	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);
619
620
621
622
623
624
625

	/* 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
626
627
628
629
630
	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);
631
	} else {
Matthias Braun's avatar
Matthias Braun committed
632
		write_ident_null(env, get_entity_ld_ident(ent));
633
634
	}

635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
	/* 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 ",
651
652
653
			get_type_nr(get_entity_type(ent)),
			get_type_nr(owner),
			get_entity_offset(ent),
654
			(unsigned) get_entity_offset_bits_remainder(ent),
655
			is_entity_compiler_generated(ent),
656
657
			get_volatility_name(get_entity_volatility(ent)));

Matthias Braun's avatar
Matthias Braun committed
658
659
660
661
662
663
664
665
666
667
668
	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));
669
		}
Matthias Braun's avatar
Matthias Braun committed
670
671
	} else {
		fputs("none", env->file);
672
673
674
	}

	fputc('\n', env->file);
675
676
}

677
678
679
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
680
	if (get_kind(tore.typ) == k_type)
681
682
683
684
		export_type_pre(env, tore.typ);
}

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
685
686
687
{
	io_env_t *env = (io_env_t *) ctx;

688
689
690
691
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
692

693
694
695
	case k_type:
		export_type_post(env, tore.typ);
		break;
696

697
698
699
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
		break;
700
701
702
	}
}

703
704
705
/**
 * Walker: exports every node.
 */
706
707
708
709
710
711
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
712
	if (env->ignoreblocks && opcode == iro_Block)
713
		return;
714

715
	fprintf(env->file, "\t%s %ld [ ", get_irn_opname(irn), get_irn_node_nr(irn));
716

717
	n = get_irn_arity(irn);
718
719
720
721
722
	if (!is_Block(irn)) {
		fprintf(env->file, "%ld ", get_irn_node_nr(get_nodes_block(irn)));
	}

	for (i = 0; i < n; i++) {
723
		ir_node *pred = get_irn_n(irn, i);
Michael Beck's avatar
Michael Beck committed
724
		if (pred == NULL) {
725
			/* Anchor node may have NULL predecessors */
726
			assert(is_Anchor(irn));
727
			fputs("-1 ", env->file);
728
		} else {
729
			write_long(env, get_irn_node_nr(pred));
730
		}
731
732
733
734
	}

	fprintf(env->file, "] { ");

735
	switch (opcode) {
736
737
738
739
740
741
742
743
744
745
746
747
748
749
	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;
750
#include "gen_irio_export.inl"
751
752
	default:
		panic("no export code for node %+F\n", irn);
753
	}
754
755
756
	fputs("}\n", env->file);
}

757
758
759
760
761
762
763
764
765
766
767
768
769
770
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");
}

771
772
773
774
775
776
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
777
	for (i = 0; i < n_modes; i++) {
778
		ir_mode *mode = get_irp_mode(i);
779
780
781
782
783
784
785
786
787
		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;
788
789
		}

Matthias Braun's avatar
Matthias Braun committed
790
791
792
793
		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)),
794
795
796
797
		        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
798
		if (mode_is_reference(mode)) {
799
800
801
802
803
804
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
		}
		fputc('\n', env->file);
	}

805
	fputs("}\n", env->file);
806
807
}

808
static void export_program(io_env_t *env)
809
{
810
811
812
813
814
	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
815
816
817
		fprintf(f, "\tname ");
		write_string(env, get_irp_name());
		fputc('\n', f);
818
819
	}

820
	for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
821
		ir_type *segment_type = get_segment_type(s);
Matthias Braun's avatar
Matthias Braun committed
822
		fprintf(f, "\tsegment_type %s ", get_segment_name(s));
823
824
825
		if (segment_type == NULL) {
			fputs(" NULL\n", f);
		} else {
Matthias Braun's avatar
Matthias Braun committed
826
827
			write_long(env, get_type_nr(segment_type));
			fputc('\n', f);
828
829
830
831
		}
	}
	fputs("}\n", f);
}
832

833
834
835
836
void ir_export(const char *filename)
{
	FILE *file = fopen(filename, "wt");
	if (file == NULL) {
837
838
839
840
		perror(filename);
		return;
	}

841
842
843
	ir_export_file(file, filename);
	fclose(file);
}
844

845
846
847
848
849
850
851
852
853
854
/* 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);
855

856
	fputs("\ntypegraph {\n", env.file);
857
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
858
	fputs("}\n", env.file);
859

Michael Beck's avatar
Michael Beck committed
860
	for (i = 0; i < n_irgs; i++) {
861
862
		ir_graph *irg       = get_irp_irg(i);
		ir_type  *valuetype = get_irg_value_param_type(irg);
863

864
865
866
867
		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));
868
869
870
871
872
873

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

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

		fputs("}\n", env.file);
876
877
	}

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

880
881
882
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

883
	export_program(&env);
884
885
}

886
/* Exports the given irg to the given file. */
887
void ir_export_irg(ir_graph *irg, FILE *file, const char *outputname)
888
889
890
{
	io_env_t env;

891
892
	(void) outputname;
	env.file = file;
893

894
895
	export_modes(&env);

896
897
	fputs("typegraph {\n", env.file);

898
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
899

900
	fprintf(env.file, "}\n\nirg %ld {\n", get_entity_nr(get_irg_entity(irg)));
901
902
903
904
905
906
907

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

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

908
	/* TODO: Only output needed constants */
909
	fprintf(env.file, "}\n\nconstirg %ld {\n", get_irn_node_nr(get_const_code_irg()->current_block));
910
911
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);
Moritz Kroll's avatar
Moritz Kroll committed
912
913
}

914
static void read_c(io_env_t *env)
Moritz Kroll's avatar
Moritz Kroll committed
915
{
916
917
918
919
	int c = fgetc(env->file);
	env->c = c;
	if (c == '\n')
		env->line++;
Moritz Kroll's avatar
Moritz Kroll committed
920
921
}

922
923
/** Returns the first non-whitespace character or EOF. **/
static void skip_ws(io_env_t *env)
924
{
925
926
927
	while (true) {
		switch (env->c) {
		case ' ':
928
929
		case '\t':
		case '\n':
930
931
932
		case '\r':
			read_c(env);
			continue;
933
934

		default:
935
			return;
936
937
938
939
940
941
		}
	}
}

static void skip_to(io_env_t *env, char to_ch)
{
942
943
944
	while (env->c != to_ch && env->c != EOF) {
		read_c(env);
	}
945
946
947
948
}

static int expect_char(io_env_t *env, char ch)
{
949
950
951
952
	skip_ws(env);
	if (env->c != ch) {
		parse_error(env, "Unexpected char '%c', expected '%c'\n",
		            env->c, ch);
953
954
		return 0;
	}
955
	read_c(env);
956
957
958
	return 1;
}

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

961
static char *read_word(io_env_t *env)
962
{
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
	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;
979
		}
980
		read_c(env);
981
	}
982

983
endofword:
984
	obstack_1grow(&env->obst, '\0');
985
	return (char*)obstack_finish(&env->obst);
986
987
}

Matthias Braun's avatar
Matthias Braun committed
988
static char *read_string(io_env_t *env)
989
{
990
	skip_ws(env);
Matthias Braun's avatar
Matthias Braun committed
991
992
	if (env->c != '"') {
		parse_error(env, "Expected string, got '%c'\n", env->c);
993
994
995
		exit(1);
	}
	read_c(env);
996

997
	assert(obstack_object_size(&env->obst) == 0);
Matthias Braun's avatar
Matthias Braun committed
998
999
1000
	while (env->c != '"') {
		if (env->c == EOF) {
			parse_error(env, "Unexpected EOF while parsing string\n");
1001
1002
			exit(1);
		}
Matthias Braun's avatar
Matthias Braun committed
1003
1004

		if (env->c == '\\') {
1005
			read_c(env);
Matthias Braun's avatar
Matthias Braun committed
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
			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);
1021
1022
		}
		read_c(env);
1023
	}
Matthias Braun's avatar
Matthias Braun committed
1024
1025
	read_c(env);
	obstack_1grow(&env->obst, 0);
1026

1027
	return (char*)obstack_finish(&env->obst);
1028
1029
}

1030
static ident *read_ident(io_env_t *env)
1031
{
Matthias Braun's avatar
Matthias Braun committed
1032
	char  *str = read_string(env);
1033
1034
1035
1036
1037
1038
1039
1040
	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
1041
static char *read_string_null(io_env_t *env)
1042
1043
1044
1045
1046
1047
1048
1049
1050
{
	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
1051
		return read_string(env);
1052
1053
1054
1055
	}

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

1058
static ident *read_ident_null(io_env_t *env)
1059
{
1060
	ident *res;
Matthias Braun's avatar
Matthias Braun committed
1061
	char  *str = read_string_null(env);
1062
1063
1064
1065
1066
1067
	if (str == NULL)
		return NULL;

	res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
1068
1069
1070
1071
}

static long read_long(io_env_t *env)
{
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
	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);
1085
	} while (isdigit(env->c));
1086
1087
	obstack_1grow(&env->obst, 0);

1088
	str = (char*)obstack_finish(&env->obst);
1089
1090
1091
1092
	result = atol(str);
	obstack_free(&env->obst, str);

	return result;
1093
1094
}

1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
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);
}

1105
1106
1107
static ir_node *get_node_or_null(io_env_t *env, long nodenr)
{
	ir_node *node = (ir_node *) get_id(env, nodenr);
1108
1109
1110
1111
	if (node && node->kind != k_ir_node) {
		panic("Irn ID %ld collides with something else in line %d\n",
		      nodenr, env->line);
	}
1112
1113
1114
1115
1116
1117
	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
1118
	if (node == NULL) {
1119
		node = new_r_Dummy(env->irg, mode_X);
1120
1121
1122
1123
1124
1125
1126
1127
		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
1128
	if (type == NULL)
1129
		panic("unknown type: %ld in line %d\n", typenr, env->line);
Michael Beck's avatar
Michael Beck committed
1130
	else if (type->kind != k_type)
1131
1132
		panic("type ID %ld collides with something else in line %d\n",
		      typenr, env->line);
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
	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
1144
	if (entity == NULL) {
1145
		parse_error(env, "unknown entity: %ld\n", entnr);
1146
		exit(1);
1147
1148
1149
1150
1151
	} else if (entity->kind != k_entity) {
		panic("Entity ID %ld collides with something else in line %d\n",
		      entnr, env->line);
	}

1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
	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)
{
1162
	char *str = read_word(env);
1163
1164
1165
	int i, n;

	n = get_irp_n_modes();
Michael Beck's avatar
Michael Beck committed
1166
	for (i = 0; i < n; i++) {
1167
		ir_mode *mode = get_irp_mode(i);
1168
1169
		if (strcmp(str, get_mode_name(mode)) == 0) {
			obstack_free(&env->obst, str);
1170
			return mode;
1171
		}
1172
1173
	}

1174
1175
	parse_error(env, "unknown mode \"%s\"\n", str);
	exit(1);
1176
1177
1178
1179
}

static const char *get_typetag_name(typetag_t typetag)
{
1180
1181
1182
1183
	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
1184
	case tt_cond_jmp_predicate: return "cond_jmp_predicate";
1185
1186
	case tt_initializer:        return "initializer kind";
	case tt_iro:                return "opcode";
Matthias Braun's avatar
Matthias Braun committed
1187
1188
1189
1190
	case tt_keyword:            return "keyword";
	case tt_linkage:            return "linkage";
	case tt_mode_arithmetic:    return "mode_arithmetic";
	case tt_mode_sort:          return "mode_sort";
1191
	case tt_pin_state:          return "pin state";
Matthias Braun's avatar
Matthias Braun committed
1192
	case tt_segment:            return "segment";
1193
1194
1195
	case tt_tpo:                return "type";
	case tt_type_state:         return "type state";
	case tt_volatility:         return "volatility";
1196
	case tt_visibility:         return "visibility";
1197
	}
1198
	return "<UNKNOWN>";
1199
1200
}

1201
1202
1203
/**
 * Read and decode an enum constant.
 */
1204
1205
static unsigned read_enum(io_env_t *env, typetag_t typetag)
{
1206
1207
1208
1209
1210
	char     *str  = read_word(env);
	unsigned  code = symbol(str, typetag);

	if (code != SYMERROR) {
		obstack_free(&env->obst, str);
1211
		return code;
1212
	}
1213

1214
	parse_error(env, "invalid %s: \"%s\"\n", get_typetag_name(typetag), str);
1215
1216
1217
	return 0;
}

1218
1219
1220
1221
1222
#define read_align(env)              ((ir_align)              read_enum(env, tt_align))
#define read_allocation(env)         ((ir_allocation)         read_enum(env, tt_allocation))
#define read_builtin_kind(env)       ((ir_builtin_kind)       read_enum(env, tt_builtin))
#define read_cond_jmp_predicate(env) ((cond_jmp_predicate)    read_enum(env, tt_cond_jmp_predicate))
#define read_initializer_kind(env)   ((ir_initializer_kind_t) read_enum(env, tt_initializer))
1223
#define read_mode_arithmetic(env)    ((ir_mode_arithmetic)    read_enum(env, tt_mode_arithmetic))
1224
1225
1226
1227
1228
#define read_peculiarity(env)        ((ir_peculiarity)        read_enum(env, tt_peculiarity))
#define read_pin_state(env)          ((op_pin_state)          read_enum(env, tt_pin_state))
#define read_type_state(env)         ((ir_type_state)         read_enum(env, tt_type_state))
#define read_variability(env)        ((ir_variability)        read_enum(env, tt_variability))
#define read_volatility(env)         ((ir_volatility)         read_enum(env, tt_volatility))
1229

1230
1231
1232
1233
1234
static ir_cons_flags get_cons_flags(io_env_t *env)
{
	ir_cons_flags flags = cons_none;

	op_pin_state pinstate = read_pin_state(env);
1235
1236
1237
1238
1239
1240
	switch (pinstate) {
	case op_pin_state_floats: flags |= cons_floats; break;
	case op_pin_state_pinned: break;
	default:
		panic("Error in %d: Invalid pinstate: %s", env->line,
		      get_op_pin_state_name(pinstate));
1241
1242
	}