irio.c 45 KB
Newer Older
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
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
 *
 * 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
#include "irprog.h"
#include "irgraph_t.h"
Michael Beck's avatar
Michael Beck committed
38
#include "irprintf.h"
39
40
41
42
43
44
45
#include "ircons.h"
#include "irgmod.h"
#include "irflag_t.h"
#include "irgwalk.h"
#include "tv.h"
#include "array.h"
#include "error.h"
46
#include "typerep.h"
47
#include "adt/set.h"
48
#include "adt/obst.h"
49

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

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

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

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

98
typedef struct symbol_t
99
{
100
101
102
103
	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;
104
105
106
107
108
109
110

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

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

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

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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);
}

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

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

164
	symtbl = new_set(symbol_cmp, 256);
165

166
#define INSERT(tt, s, cod)                                       \
167
168
169
	key.str = (s);                                               \
	key.typetag = (tt);                                          \
	key.code = (cod);                                            \
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
195
	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);
196

Matthias Braun's avatar
Matthias Braun committed
197
198
199
200
201
202
	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);

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

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

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

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

223
224
225
	INSERTENUM(tt_builtin, ir_bk_trap);
	INSERTENUM(tt_builtin, ir_bk_debugbreak);
	INSERTENUM(tt_builtin, ir_bk_return_address);
226
	INSERTENUM(tt_builtin, ir_bk_frame_address);
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
	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);

247
248
249
250
251
	INSERTENUM(tt_mode_arithmetic, irma_uninitialized);
	INSERTENUM(tt_mode_arithmetic, irma_none);
	INSERTENUM(tt_mode_arithmetic, irma_twos_complement);
	INSERTENUM(tt_mode_arithmetic, irma_ieee754);

252
253
254
255
256
257
258
259
260
261
262
	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);

263
#undef INSERTKEYWORD
264
265
266
267
#undef INSERTENUM
#undef INSERT
}

268
269
270
271
272
273
274
275
276
277
278
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";
}

279
280
281
282
283
284
285
286
287
288
289
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";
}

290
291
/** 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)
292
{
293
	symbol_t key, *entry;
294
295

	key.str = str;
296
	key.typetag = typetag;
297

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

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

307
	entry = (id_entry*)set_find(env->idset, &key, sizeof(key), (unsigned) id);
308
309
310
311
312
313
314
315
316
317
318
	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);
}

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
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);
	}
}

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

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

396
static void write_align(io_env_t *env, ir_align align)
397
398
399
400
401
{
	fputs(get_align_name(align), env->file);
	fputc(' ', env->file);
}

402
403
404
405
406
407
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);
}

408
409
410
411
412
413
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);
}

414
415
416
417
418
419
420
421
422
423
static void write_list_begin(io_env_t *env)
{
	fputs("[", env->file);
}

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

424
425
426
427
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);
428

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

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

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

441
442
	case IR_INITIALIZER_NULL:
		break;
443

444
	case IR_INITIALIZER_COMPOUND: {
Michael Beck's avatar
Michael Beck committed
445
446
447
		size_t i, n = get_initializer_compound_n_entries(ini);
		ir_fprintf(f, "%zu ", n);
		for (i = 0; i < n; ++i)
448
449
450
			write_initializer(env, get_initializer_compound_value(ini, i));
		break;
	}
451

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

457
458
459
460
461
462
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);
}

463
static void write_volatility(io_env_t *env, ir_volatility vol)
464
465
466
467
468
{
	fputs(get_volatility_name(vol), env->file);
	fputc(' ', env->file);
}

469
static void export_type_common(io_env_t *env, ir_type *tp)
470
{
471
	fprintf(env->file, "\ttype %ld %s %u %u %s %u ",
472
473
474
475
476
477
478
479
	        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);
}

480
481
482
483
static void export_type_pre(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;

Michael Beck's avatar
Michael Beck committed
484
	/* skip types to be handled by post walker */
485
486
487
488
489
490
491
	switch (get_type_tpop_code(tp)) {
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
		return;
	default:
		break;
492
493
494
495
	}

	export_type_common(env, tp);

496
497
498
499
500
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

	case tpo_class:
Matthias Braun's avatar
Matthias Braun committed
501
		write_ident_null(env, get_compound_ident(tp));
502
503
504
505
506
507
508
509
510
		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
511
		write_ident_null(env, get_compound_ident(tp));
512
513
514
515
516
517
518
519
520
		break;

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
521
522
523
524
525
526
527
	}
	fputc('\n', f);
}

static void export_type_post(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;
Michael Beck's avatar
Michael Beck committed
528
	size_t i;
529

Michael Beck's avatar
Michael Beck committed
530
	/* skip types already handled by pre walker */
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
	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;
546
547
548
	}

	export_type_common(env, tp);
549

550
551
	switch (get_type_tpop_code(tp)) {
	case tpo_array: {
Michael Beck's avatar
Michael Beck committed
552
553
		size_t n = get_array_n_dimensions(tp);
		ir_fprintf(f, "%zu %ld ", n, get_type_nr(get_array_element_type(tp)));
554
555
556
557
558
		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))
559
				write_long(env, get_tarval_long(get_Const_tarval(lower)));
560
561
562
563
			else
				panic("Lower array bound is not constant");

			if (is_Const(upper))
564
				write_long(env, get_tarval_long(get_Const_tarval(upper)));
565
566
567
568
569
570
571
			else if (is_Unknown(upper))
				fputs("unknown ", f);
			else
				panic("Upper array bound is not constant");
		}
		break;
	}
572

573
	case tpo_method: {
Michael Beck's avatar
Michael Beck committed
574
575
576
		size_t nparams  = get_method_n_params(tp);
		size_t nresults = get_method_n_ress(tp);
		ir_fprintf(f, "%u %u %zu %zu ", get_method_calling_convention(tp),
577
578
			get_method_additional_properties(tp), nparams, nresults);
		for (i = 0; i < nparams; i++)
579
			write_long(env, get_type_nr(get_method_param_type(tp, i)));
580
		for (i = 0; i < nresults; i++)
581
			write_long(env, get_type_nr(get_method_res_type(tp, i)));
582
		ir_fprintf(f, "%u ", get_method_variadicity(tp));
583
584
		break;
	}
585

586
587
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
588
		write_long(env, get_type_nr(get_pointer_points_to_type(tp)));
589
		break;
590

591
592
593
594
595
596
597
598
	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;
599
600
601
602
603
604
	}
	fputc('\n', f);
}

static void export_entity(io_env_t *env, ir_entity *ent)
{
605
606
607
608
	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);
609
610
611
612
613
614
615

	/* 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
616
617
618
619
620
	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);
621
	} else {
Matthias Braun's avatar
Matthias Braun committed
622
		write_ident_null(env, get_entity_ld_ident(ent));
623
624
	}

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
	/* 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 ",
641
642
643
			get_type_nr(get_entity_type(ent)),
			get_type_nr(owner),
			get_entity_offset(ent),
644
			(unsigned) get_entity_offset_bits_remainder(ent),
645
			is_entity_compiler_generated(ent),
646
647
			get_volatility_name(get_entity_volatility(ent)));

Matthias Braun's avatar
Matthias Braun committed
648
649
650
651
	if (ent->initializer != NULL) {
		fputs("initializer ", env->file);
		write_initializer(env, get_entity_initializer(ent));
	} else if (entity_has_compound_ent_values(ent)) {
Michael Beck's avatar
Michael Beck committed
652
		size_t i, n = get_compound_ent_n_values(ent);
Matthias Braun's avatar
Matthias Braun committed
653
		fputs("compoundgraph ", env->file);
Michael Beck's avatar
Michael Beck committed
654
		ir_fprintf(env->file, "%zu ", n);
Matthias Braun's avatar
Matthias Braun committed
655
656
657
658
		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));
659
		}
Matthias Braun's avatar
Matthias Braun committed
660
661
	} else {
		fputs("none", env->file);
662
663
664
	}

	fputc('\n', env->file);
665
666
}

667
668
669
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
670
	if (get_kind(tore.typ) == k_type)
671
672
673
674
		export_type_pre(env, tore.typ);
}

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
675
676
677
{
	io_env_t *env = (io_env_t *) ctx;

678
679
680
681
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
682

683
684
685
	case k_type:
		export_type_post(env, tore.typ);
		break;
686

687
688
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
689
690
691
	}
}

Matthias Braun's avatar
Matthias Braun committed
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
static void export_ASM(io_env_t *env, ir_node *node)
{
	ir_asm_constraint *input_constraints    = get_ASM_input_constraints(node);
	ir_asm_constraint *output_constraints   = get_ASM_output_constraints(node);
	ident            **clobbers             = get_ASM_clobbers(node);
	int                n_input_constraints  = get_ASM_n_input_constraints(node);
	int                n_output_constraints = get_ASM_n_output_constraints(node);
	int                n_clobbers           = get_ASM_n_clobbers(node);
	int i;

	write_ident(env, get_ASM_text(node));
	write_list_begin(env);
	for (i = 0; i < n_input_constraints; ++i) {
		const ir_asm_constraint *constraint = &input_constraints[i];
		write_unsigned(env, constraint->pos);
		write_ident(env, constraint->constraint);
		write_mode(env, constraint->mode);
	}
	write_list_end(env);

	write_list_begin(env);
	for (i = 0; i < n_output_constraints; ++i) {
		const ir_asm_constraint *constraint = &output_constraints[i];
		write_unsigned(env, constraint->pos);
		write_ident(env, constraint->constraint);
		write_mode(env, constraint->mode);
	}
	write_list_end(env);

	write_list_begin(env);
	for (i = 0; i < n_clobbers; ++i) {
		ident *clobber = clobbers[i];
		write_ident(env, clobber);
	}
	write_list_end(env);
}

729
730
731
/**
 * Walker: exports every node.
 */
732
733
734
735
736
737
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
738
	if (env->ignoreblocks && opcode == iro_Block)
739
		return;
740

741
742
	fprintf(env->file, "\t%s ", get_irn_opname(irn));
	write_long(env, get_irn_node_nr(irn));
743

744
	write_list_begin(env);
745
	n = get_irn_arity(irn);
746
	if (!is_Block(irn)) {
747
748
		ir_node *block = get_nodes_block(irn);
		write_long(env, get_irn_node_nr(block));
749
750
751
	}

	for (i = 0; i < n; i++) {
752
		ir_node *pred = get_irn_n(irn, i);
Michael Beck's avatar
Michael Beck committed
753
		if (pred == NULL) {
754
			/* Anchor node may have NULL predecessors */
755
			assert(is_Anchor(irn));
756
			fputs("-1 ", env->file);
757
		} else {
758
			write_long(env, get_irn_node_nr(pred));
759
		}
760
	}
761
	write_list_end(env);
762

763
	fputs("{ ", env->file);
764

765
	switch (opcode) {
766
767
768
769
770
771
772
773
774
	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)));
775
		write_mode(env, get_irn_mode(irn));
776
777
778
779
780
		break;
	case iro_Proj:
		write_mode(env, get_irn_mode(irn));
		fprintf(env->file, "%ld ", get_Proj_proj(irn));
		break;
Matthias Braun's avatar
Matthias Braun committed
781
782
783
	case iro_ASM:
		export_ASM(env, irn);
		break;
784
#include "gen_irio_export.inl"
785
786
	default:
		panic("no export code for node %+F\n", irn);
787
	}
788
789
790
	fputs("}\n", env->file);
}

791
792
793
794
795
796
797
798
799
800
801
802
803
804
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");
}

805
806
static void export_modes(io_env_t *env)
{
Michael Beck's avatar
Michael Beck committed
807
	size_t i, n_modes = get_irp_n_modes();
808
809
810

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

Michael Beck's avatar
Michael Beck committed
811
	for (i = 0; i < n_modes; i++) {
812
		ir_mode *mode = get_irp_mode(i);
813
814
815
816
817
818
819
820
821
		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;
822
823
		}

Matthias Braun's avatar
Matthias Braun committed
824
825
		fprintf(env->file, "\tmode ");
		write_string(env, get_mode_name(mode));
826
		fprintf(env->file, "%s %u %d %s %u ",
Matthias Braun's avatar
Matthias Braun committed
827
		        get_mode_sort_name(get_mode_sort(mode)),
828
829
		        get_mode_size_bits(mode), get_mode_sign(mode),
		        get_mode_arithmetic_name(get_mode_arithmetic(mode)),
830
		        get_mode_modulo_shift(mode));
Michael Beck's avatar
Michael Beck committed
831
		if (mode_is_reference(mode)) {
832
833
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
834
			write_int(env, (mode == mode_P ? 1 : 0));
835
836
837
838
		}
		fputc('\n', env->file);
	}

839
	fputs("}\n", env->file);
840
841
}

842
static void export_program(io_env_t *env)
843
{
844
845
846
847
848
	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
849
850
851
		fprintf(f, "\tname ");
		write_string(env, get_irp_name());
		fputc('\n', f);
852
853
	}

854
	for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
855
		ir_type *segment_type = get_segment_type(s);
Matthias Braun's avatar
Matthias Braun committed
856
		fprintf(f, "\tsegment_type %s ", get_segment_name(s));
857
858
859
		if (segment_type == NULL) {
			fputs(" NULL\n", f);
		} else {
Matthias Braun's avatar
Matthias Braun committed
860
861
			write_long(env, get_type_nr(segment_type));
			fputc('\n', f);
862
863
864
865
		}
	}
	fputs("}\n", f);
}
866

867
868
869
870
void ir_export(const char *filename)
{
	FILE *file = fopen(filename, "wt");
	if (file == NULL) {
871
872
873
874
		perror(filename);
		return;
	}

875
876
877
	ir_export_file(file, filename);
	fclose(file);
}
878

879
880
881
882
/* 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;
Michael Beck's avatar
Michael Beck committed
883
	size_t i, n_irgs = get_irp_n_irgs();
884
885
886
887
888

	(void) outputname;
	env.file = file;

	export_modes(&env);
889

890
	fputs("\ntypegraph {\n", env.file);
891
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
892
	fputs("}\n", env.file);
893

Michael Beck's avatar
Michael Beck committed
894
	for (i = 0; i < n_irgs; i++) {
895
		ir_graph *irg       = get_irp_irg(i);
896

897
		fprintf(env.file, "\nirg %ld %ld {\n",
898
		        get_entity_nr(get_irg_entity(irg)),
899
		        get_type_nr(get_irg_frame_type(irg)));
900
901
902
903
904
905

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

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

		fputs("}\n", env.file);
908
909
	}

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

912
913
914
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

915
	export_program(&env);
916
917
}

918
/* Exports the given irg to the given file. */
919
void ir_export_irg(ir_graph *irg, FILE *file, const char *outputname)
920
921
922
{
	io_env_t env;

923
924
	(void) outputname;
	env.file = file;
925

926
927
	export_modes(&env);

928
929
	fputs("typegraph {\n", env.file);

930
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
931

932
	fprintf(env.file, "}\n\nirg %ld {\n", get_entity_nr(get_irg_entity(irg)));
933
934
935
936
937
938
939

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

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

940
	/* TODO: Only output needed constants */
941
	fprintf(env.file, "}\n\nconstirg %ld {\n", get_irn_node_nr(get_const_code_irg()->current_block));
942
943
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);
Moritz Kroll's avatar
Moritz Kroll committed
944
945
}

946
static void read_c(io_env_t *env)
Moritz Kroll's avatar
Moritz Kroll committed
947
{
948
949
950
951
	int c = fgetc(env->file);
	env->c = c;
	if (c == '\n')
		env->line++;
Moritz Kroll's avatar
Moritz Kroll committed
952
953
}

954
955
/** Returns the first non-whitespace character or EOF. **/
static void skip_ws(io_env_t *env)
956
{
957
958
959
	while (true) {
		switch (env->c) {
		case ' ':
960
961
		case '\t':
		case '\n':
962
963
964
		case '\r':
			read_c(env);
			continue;
965
966

		default:
967
			return;
968
969
970
971
972
973
		}
	}
}

static void skip_to(io_env_t *env, char to_ch)
{
974
975
976
	while (env->c != to_ch && env->c != EOF) {
		read_c(env);
	}
977
978
979
980
}

static int expect_char(io_env_t *env, char ch)
{
981
982
983
984
	skip_ws(env);
	if (env->c != ch) {
		parse_error(env, "Unexpected char '%c', expected '%c'\n",
		            env->c, ch);
985
986
		return 0;
	}
987
	read_c(env);
988
989
990
	return 1;
}

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

993
static char *read_word(io_env_t *env)
994
{
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
	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;
1011
		}
1012
		read_c(env);
1013
	}
1014

1015
endofword:
1016
	obstack_1grow(&env->obst, '\0');
1017
	return (char*)obstack_finish(&env->obst);
1018
1019
}

Matthias Braun's avatar
Matthias Braun committed
1020
static char *read_string(io_env_t *env)
1021
{
1022
	skip_ws(env);
Matthias Braun's avatar
Matthias Braun committed
1023
1024
	if (env->c != '"') {
		parse_error(env, "Expected string, got '%c'\n", env->c);
1025
1026
1027
		exit(1);
	}
	read_c(env);
1028

1029
	assert(obstack_object_size(&env->obst) == 0);
Matthias Braun's avatar
Matthias Braun committed
1030
1031
1032
	while (env->c != '"') {
		if (env->c == EOF) {
			parse_error(env, "Unexpected EOF while parsing string\n");
1033
1034
			exit(1);
		}
Matthias Braun's avatar
Matthias Braun committed
1035
1036

		if (env->c == '\\') {
1037
			read_c(env);
Matthias Braun's avatar
Matthias Braun committed
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
			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);
			}
		} else {
			obstack_1grow(&env->obst, env->c);
1052
1053
		}
		read_c(env);
1054
	}
Matthias Braun's avatar
Matthias Braun committed
1055
1056
	read_c(env);
	obstack_1grow(&env->obst, 0);
1057

1058
	return (char*)obstack_finish(&env->obst);
1059
1060
}

1061
static ident *read_ident(io_env_t *env)
1062
{
Matthias Braun's avatar
Matthias Braun committed
1063
	char  *str = read_string(env);
1064
1065
1066
1067
1068
1069
1070
1071
	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
1072
static char *read_string_null(io_env_t *env)
1073
1074
1075
1076
1077
1078
1079
1080
1081
{
	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
1082
		return read_string(env);
1083
1084
1085
1086
	}

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

1089
static ident *read_ident_null(io_env_t *env)
1090
{
1091
	ident *res;
Matthias Braun's avatar
Matthias Braun committed
1092
	char  *str = read_string_null(env);
1093
1094
1095
1096
1097
1098
	if (str == NULL)
		return NULL;

	res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
1099
1100
1101
1102
}

static long read_long(io_env_t *env)
{
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
	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);
1116
	} while (isdigit(env->c));
1117
1118
	obstack_1grow(&env->obst, 0);

1119
	str = (char*)obstack_finish(&env->obst);
1120
1121
1122
1123
	result = atol(str);
	obstack_free(&env->obst, str);

	return result;
1124
1125
}

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
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);
}

Michael Beck's avatar
Michael Beck committed
1136
1137
1138
1139
1140
1141
static size_t read_size_t(io_env_t *env)
{
	/* FIXME */
	return (size_t) read_unsigned(env);
}

1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
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;
}

1167
1168
1169
static ir_node *get_node_or_null(io_env_t *env, long nodenr)
{
	ir_node *node = (ir_node *) get_id(env, nodenr);
1170
1171
1172
1173
	if (node && node->kind != k_ir_node) {
		panic("Irn ID %ld collides with something else in line %d\n",
		      nodenr, env->line);
	}
1174
1175
1176
1177
1178
1179
	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
1180
	if (node == NULL) {
1181
		node = new_r_Dummy(env->irg, mode_X);
1182
1183
1184
1185
1186
1187
1188
1189
		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
1190
	if (type == NULL)
1191
		panic("unknown type: %ld in line %d\n", typenr, env->line);
Michael Beck's avatar
Michael Beck committed
1192
	else if (type->kind != k_type)
1193
1194
		panic("type ID %ld collides with something else in line %d\n",
		      typenr, env->line);
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
	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
1206
	if (entity == NULL) {
1207
		parse_error(env, "unknown entity: %ld\n", entnr);
1208
		exit(1);
1209
1210
1211
1212
1213
	} else if (entity->kind != k_entity) {
		panic("Entity ID %ld collides with something else in line %d\n",
		      entnr, env->line);
	}

1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
	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)
{
1224
	char *str = read_string(env);
Michael Beck's avatar