irio.c 45.8 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
252
253
254
	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);

255
256
257
258
259
260
261
262
263
264
265
	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);

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

271
272
273
274
275
276
277
278
279
280
281
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";
}

282
283
284
285
286
287
288
289
290
291
292
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";
}

293
294
/** 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)
295
{
296
	symbol_t key, *entry;
297
298

	key.str = str;
299
	key.typetag = typetag;
300

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

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

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

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
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
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
383
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);
	}
}

384
385
386
387
388
389
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
390
static void write_tarval(io_env_t *env, ir_tarval *tv)
391
392
393
394
395
396
397
398
{
	char buf[1024];
	write_mode(env, get_tarval_mode(tv));
	tarval_snprintf(buf, sizeof(buf), tv);
	fputs(buf, env->file);
	fputc(' ', env->file);
}

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

405
406
407
408
409
410
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);
}

411
412
413
414
415
416
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);
}

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

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

427
428
429
430
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);
431

432
433
434
	fputs(get_initializer_kind_name(ini_kind), f);
	fputc(' ', f);

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

440
441
442
	case IR_INITIALIZER_TARVAL:
		write_tarval(env, get_initializer_tarval_value(ini));
		break;
443

444
445
	case IR_INITIALIZER_NULL:
		break;
446

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

455
456
	default:
		panic("Unknown initializer kind");
457
458
459
	}
}

460
461
462
463
464
465
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);
}

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

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

483
484
485
486
static void export_type_pre(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;

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

	export_type_common(env, tp);

499
500
501
502
503
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

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

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
524
525
526
527
528
529
530
	}
	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
531
	size_t i;
532

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

	export_type_common(env, tp);
552

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

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

576
	case tpo_method: {
Michael Beck's avatar
Michael Beck committed
577
578
579
		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),
580
581
			get_method_additional_properties(tp), nparams, nresults);
		for (i = 0; i < nparams; i++)
582
			write_long(env, get_type_nr(get_method_param_type(tp, i)));
583
		for (i = 0; i < nresults; i++)
584
			write_long(env, get_type_nr(get_method_res_type(tp, i)));
585
		ir_fprintf(f, "%u ", get_method_variadicity(tp));
586
587
		break;
	}
588

589
590
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
591
		write_long(env, get_type_nr(get_pointer_points_to_type(tp)));
592
		break;
593

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

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

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

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

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

	fputc('\n', env->file);
668
669
}

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

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
678
679
680
{
	io_env_t *env = (io_env_t *) ctx;

681
682
683
684
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
685

686
687
688
	case k_type:
		export_type_post(env, tore.typ);
		break;
689

690
691
692
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
		break;
693
694
695
	}
}

Matthias Braun's avatar
Matthias Braun committed
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
729
730
731
732
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);
}

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

745
746
	fprintf(env->file, "\t%s ", get_irn_opname(irn));
	write_long(env, get_irn_node_nr(irn));
747

748
	write_list_begin(env);
749
	n = get_irn_arity(irn);
750
	if (!is_Block(irn)) {
751
752
		ir_node *block = get_nodes_block(irn);
		write_long(env, get_irn_node_nr(block));
753
754
755
	}

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

767
	fputs("{ ", env->file);
768

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

794
795
796
797
798
799
800
801
802
803
804
805
806
807
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");
}

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

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

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

Matthias Braun's avatar
Matthias Braun committed
827
828
829
830
		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)),
831
832
833
834
		        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
835
		if (mode_is_reference(mode)) {
836
837
838
839
840
841
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
		}
		fputc('\n', env->file);
	}

842
	fputs("}\n", env->file);
843
844
}

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

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

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

878
879
880
	ir_export_file(file, filename);
	fclose(file);
}
881

882
883
884
885
/* 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
886
	size_t i, n_irgs = get_irp_n_irgs();
887
888
889
890
891

	(void) outputname;
	env.file = file;

	export_modes(&env);
892

893
	fputs("\ntypegraph {\n", env.file);
894
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
895
	fputs("}\n", env.file);
896

Michael Beck's avatar
Michael Beck committed
897
	for (i = 0; i < n_irgs; i++) {
898
899
		ir_graph *irg       = get_irp_irg(i);
		ir_type  *valuetype = get_irg_value_param_type(irg);
900

901
902
903
904
		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));
905
906
907
908
909
910

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

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

		fputs("}\n", env.file);
913
914
	}

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

917
918
919
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

920
	export_program(&env);
921
922
}

923
/* Exports the given irg to the given file. */
924
void ir_export_irg(ir_graph *irg, FILE *file, const char *outputname)
925
926
927
{
	io_env_t env;

928
929
	(void) outputname;
	env.file = file;
930

931
932
	export_modes(&env);

933
934
	fputs("typegraph {\n", env.file);

935
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
936

937
	fprintf(env.file, "}\n\nirg %ld {\n", get_entity_nr(get_irg_entity(irg)));
938
939
940
941
942
943
944

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

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

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

951
static void read_c(io_env_t *env)
Moritz Kroll's avatar
Moritz Kroll committed
952
{
953
954
955
956
	int c = fgetc(env->file);
	env->c = c;
	if (c == '\n')
		env->line++;
Moritz Kroll's avatar
Moritz Kroll committed
957
958
}

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

		default:
972
			return;
973
974
975
976
977
978
		}
	}
}

static void skip_to(io_env_t *env, char to_ch)
{
979
980
981
	while (env->c != to_ch && env->c != EOF) {
		read_c(env);
	}
982
983
984
985
}

static int expect_char(io_env_t *env, char ch)
{
986
987
988
989
	skip_ws(env);
	if (env->c != ch) {
		parse_error(env, "Unexpected char '%c', expected '%c'\n",
		            env->c, ch);
990
991
		return 0;
	}
992
	read_c(env);
993
994
995
	return 1;
}

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

998
static char *read_word(io_env_t *env)
999
{
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
	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;
1016
		}
1017
		read_c(env);
1018
	}
1019

1020
endofword:
1021
	obstack_1grow(&env->obst, '\0');
1022
	return (char*)obstack_finish(&env->obst);
1023
1024
}

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

1034
	assert(obstack_object_size(&env->obst) == 0);
Matthias Braun's avatar
Matthias Braun committed
1035
1036
1037
	while (env->c != '"') {
		if (env->c == EOF) {
			parse_error(env, "Unexpected EOF while parsing string\n");
1038
1039
			exit(1);
		}
Matthias Braun's avatar
Matthias Braun committed
1040
1041

		if (env->c == '\\') {
1042
			read_c(env);
Matthias Braun's avatar
Matthias Braun committed
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
			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);
1058
1059
		}
		read_c(env);
1060
	}
Matthias Braun's avatar
Matthias Braun committed
1061
1062
	read_c(env);
	obstack_1grow(&env->obst, 0);
1063

1064
	return (char*)obstack_finish(&env->obst);
1065
1066
}

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

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

1095
static ident *read_ident_null(io_env_t *env)
1096
{
1097
	ident *res;
Matthias Braun's avatar
Matthias Braun committed
1098
	char  *str = read_string_null(env);
1099
1100
1101
1102
1103
1104
	if (str == NULL)
		return NULL;

	res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
1105
1106
1107
1108
}

static long read_long(io_env_t *env)
{
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
	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);
1122
	} while (isdigit(env->c));
1123
1124
	obstack_1grow(&env->obst, 0);

1125
	str = (char*)obstack_finish(&env->obst);
1126
1127
1128
1129
	result = atol(str);
	obstack_free(&env->obst, str);

	return result;
1130
1131
}

1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
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
1142
1143
1144
1145
1146
1147
static size_t read_size_t(io_env_t *env)
{
	/* FIXME */
	return (size_t) read_unsigned(env);
}

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
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;
}

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

1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
	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)
{
1230
	char *str = read_word(env);
Michael Beck's avatar
Michael Beck committed
1231
	size_t i, n;
1232
1233

	n = get_irp_n_modes();
Michael Beck's avatar
Michael Beck committed
1234
	for (i = 0; i < n; i++) {
1235
		ir_mode *mode = get_irp_mode(i);
1236
1237
		if (strcmp(str, get_mode_name(mode)) == 0) {
			obstack_free(&env->obst, str);
1238
			return mode;