irio.c 44.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
 *
 * 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
 */
#include "config.h"

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

#include "irio.h"

34
#include "irnode_t.h"
35
36
#include "irprog.h"
#include "irgraph_t.h"
Michael Beck's avatar
Michael Beck committed
37
#include "irprintf.h"
38
39
40
41
42
43
44
#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_arithmetic,
74
	tt_pin_state,
75
	tt_tpo,
76
	tt_type_state,
77
	tt_volatility,
Matthias Braun's avatar
Matthias Braun committed
78
	tt_linkage,
79
80
	tt_segment,
	tt_visibility
81
82
} typetag_t;

83
84
85
86
87
typedef enum keyword_t
{
	kw_constirg,
	kw_entity,
	kw_irg,
88
89
90
	kw_int_mode,
	kw_reference_mode,
	kw_float_mode,
91
	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
	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_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);
188

Matthias Braun's avatar
Matthias Braun committed
189
190
191
192
193
194
	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);

195
196
197
	INSERT(tt_visibility, "local", ir_visibility_local);
	INSERT(tt_visibility, "external", ir_visibility_external);
	INSERT(tt_visibility, "default", ir_visibility_default);
198
	INSERT(tt_visibility, "private", ir_visibility_private);
199

200
201
202
	INSERTKEYWORD(constirg);
	INSERTKEYWORD(entity);
	INSERTKEYWORD(irg);
203
204
205
	INSERTKEYWORD(int_mode);
	INSERTKEYWORD(float_mode);
	INSERTKEYWORD(reference_mode);
206
	INSERTKEYWORD(modes);
207
208
	INSERTKEYWORD(type);
	INSERTKEYWORD(typegraph);
209
210
	INSERTKEYWORD(program);
	INSERTKEYWORD(segment_type);
211

212
213
214
215
216
#include "gen_irio_lex.inl"

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

217
218
219
	INSERTENUM(tt_builtin, ir_bk_trap);
	INSERTENUM(tt_builtin, ir_bk_debugbreak);
	INSERTENUM(tt_builtin, ir_bk_return_address);
220
	INSERTENUM(tt_builtin, ir_bk_frame_address);
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
	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);

241
242
243
244
245
	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);

246
247
248
249
250
251
252
253
254
255
256
	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);

257
#undef INSERTKEYWORD
258
259
260
261
#undef INSERTENUM
#undef INSERT
}

262
263
264
265
266
267
268
269
270
271
272
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";
}

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

284
285
/** 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)
286
{
287
	symbol_t key, *entry;
288
289

	key.str = str;
290
	key.typetag = typetag;
291

292
	entry = (symbol_t*)set_find(symtbl, &key, sizeof(key), firm_fnv_hash_str(str) + typetag * 17);
293
	return entry ? entry->code : SYMERROR;
294
295
296
297
298
299
300
}

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

301
	entry = (id_entry*)set_find(env->idset, &key, sizeof(key), (unsigned) id);
302
303
304
305
306
307
308
309
310
311
312
	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);
}

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
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
338
339
340
341
342
343
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
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);
	}
}

375
376
static void write_mode(io_env_t *env, ir_mode *mode)
{
377
	write_string(env, get_mode_name(mode));
378
379
380
	fputc(' ', env->file);
}

Matthias Braun's avatar
Matthias Braun committed
381
static void write_tarval(io_env_t *env, ir_tarval *tv)
382
383
384
385
386
387
388
389
{
	char buf[1024];
	write_mode(env, get_tarval_mode(tv));
	tarval_snprintf(buf, sizeof(buf), tv);
	fputs(buf, env->file);
	fputc(' ', env->file);
}

390
static void write_align(io_env_t *env, ir_align align)
391
392
393
394
395
{
	fputs(get_align_name(align), env->file);
	fputc(' ', env->file);
}

396
397
398
399
400
401
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);
}

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

408
409
410
411
412
413
414
415
416
417
static void write_list_begin(io_env_t *env)
{
	fputs("[", env->file);
}

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

418
419
420
421
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);
422

423
424
425
	fputs(get_initializer_kind_name(ini_kind), f);
	fputc(' ', f);

426
427
	switch (ini_kind) {
	case IR_INITIALIZER_CONST:
428
		write_long(env, get_irn_node_nr(get_initializer_const_value(ini)));
429
		break;
430

431
432
433
	case IR_INITIALIZER_TARVAL:
		write_tarval(env, get_initializer_tarval_value(ini));
		break;
434

435
436
	case IR_INITIALIZER_NULL:
		break;
437

438
	case IR_INITIALIZER_COMPOUND: {
Michael Beck's avatar
Michael Beck committed
439
440
441
		size_t i, n = get_initializer_compound_n_entries(ini);
		ir_fprintf(f, "%zu ", n);
		for (i = 0; i < n; ++i)
442
443
444
			write_initializer(env, get_initializer_compound_value(ini, i));
		break;
	}
445

446
447
	default:
		panic("Unknown initializer kind");
448
449
450
	}
}

451
452
453
454
455
456
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);
}

457
static void write_volatility(io_env_t *env, ir_volatility vol)
458
459
460
461
462
{
	fputs(get_volatility_name(vol), env->file);
	fputc(' ', env->file);
}

463
static void export_type_common(io_env_t *env, ir_type *tp)
464
{
465
	fprintf(env->file, "\ttype %ld %s %u %u %s %u ",
466
467
468
469
470
471
472
473
	        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);
}

474
475
476
477
static void export_type_pre(io_env_t *env, ir_type *tp)
{
	FILE *f = env->file;

Michael Beck's avatar
Michael Beck committed
478
	/* skip types to be handled by post walker */
479
480
481
482
483
484
485
	switch (get_type_tpop_code(tp)) {
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
		return;
	default:
		break;
486
487
488
489
	}

	export_type_common(env, tp);

490
491
492
493
494
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

	case tpo_class:
Matthias Braun's avatar
Matthias Braun committed
495
		write_ident_null(env, get_compound_ident(tp));
496
497
498
499
500
501
502
503
504
		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
505
		write_ident_null(env, get_compound_ident(tp));
506
507
508
509
510
511
512
513
514
		break;

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
515
516
517
518
519
520
521
	}
	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
522
	size_t i;
523

Michael Beck's avatar
Michael Beck committed
524
	/* skip types already handled by pre walker */
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	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;
540
541
542
	}

	export_type_common(env, tp);
543

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

			if (is_Const(upper))
558
				write_long(env, get_tarval_long(get_Const_tarval(upper)));
559
560
561
562
563
564
565
			else if (is_Unknown(upper))
				fputs("unknown ", f);
			else
				panic("Upper array bound is not constant");
		}
		break;
	}
566

567
	case tpo_method: {
Michael Beck's avatar
Michael Beck committed
568
569
570
		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),
571
572
			get_method_additional_properties(tp), nparams, nresults);
		for (i = 0; i < nparams; i++)
573
			write_long(env, get_type_nr(get_method_param_type(tp, i)));
574
		for (i = 0; i < nresults; i++)
575
			write_long(env, get_type_nr(get_method_res_type(tp, i)));
576
		ir_fprintf(f, "%u ", get_method_variadicity(tp));
577
578
		break;
	}
579

580
581
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
582
		write_long(env, get_type_nr(get_pointer_points_to_type(tp)));
583
		break;
584

585
586
587
588
589
590
591
592
	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;
593
594
595
596
597
598
	}
	fputc('\n', f);
}

static void export_entity(io_env_t *env, ir_entity *ent)
{
599
600
601
602
	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);
603
604
605
606
607
608
609

	/* 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
610
611
612
613
614
	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);
615
	} else {
Matthias Braun's avatar
Matthias Braun committed
616
		write_ident_null(env, get_entity_ld_ident(ent));
617
618
	}

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
	/* 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 ",
635
636
637
			get_type_nr(get_entity_type(ent)),
			get_type_nr(owner),
			get_entity_offset(ent),
638
			(unsigned) get_entity_offset_bits_remainder(ent),
639
			is_entity_compiler_generated(ent),
640
641
			get_volatility_name(get_entity_volatility(ent)));

Matthias Braun's avatar
Matthias Braun committed
642
643
644
645
	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
646
		size_t i, n = get_compound_ent_n_values(ent);
Matthias Braun's avatar
Matthias Braun committed
647
		fputs("compoundgraph ", env->file);
Michael Beck's avatar
Michael Beck committed
648
		ir_fprintf(env->file, "%zu ", n);
Matthias Braun's avatar
Matthias Braun committed
649
650
651
652
		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));
653
		}
Matthias Braun's avatar
Matthias Braun committed
654
655
	} else {
		fputs("none", env->file);
656
657
658
	}

	fputc('\n', env->file);
659
660
}

661
662
663
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
664
	if (get_kind(tore.typ) == k_type)
665
666
667
668
		export_type_pre(env, tore.typ);
}

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
669
670
671
{
	io_env_t *env = (io_env_t *) ctx;

672
673
674
675
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
676

677
678
679
	case k_type:
		export_type_post(env, tore.typ);
		break;
680

681
682
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
683
684
685
	}
}

Matthias Braun's avatar
Matthias Braun committed
686
687
688
689
690
691
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
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);
}

723
724
725
/**
 * Walker: exports every node.
 */
726
727
728
729
730
731
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
732
	if (env->ignoreblocks && opcode == iro_Block)
733
		return;
734

735
736
	fprintf(env->file, "\t%s ", get_irn_opname(irn));
	write_long(env, get_irn_node_nr(irn));
737

738
	write_list_begin(env);
739
	n = get_irn_arity(irn);
740
	if (!is_Block(irn)) {
741
742
		ir_node *block = get_nodes_block(irn);
		write_long(env, get_irn_node_nr(block));
743
744
745
	}

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

757
	fputs("{ ", env->file);
758

759
	switch (opcode) {
760
761
762
763
764
765
766
767
768
	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)));
769
		write_mode(env, get_irn_mode(irn));
770
771
772
773
774
		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
775
776
777
	case iro_ASM:
		export_ASM(env, irn);
		break;
778
#include "gen_irio_export.inl"
779
780
	default:
		panic("no export code for node %+F\n", irn);
781
	}
782
783
784
	fputs("}\n", env->file);
}

785
786
static void export_modes(io_env_t *env)
{
Michael Beck's avatar
Michael Beck committed
787
	size_t i, n_modes = get_irp_n_modes();
788
789
790

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

Michael Beck's avatar
Michael Beck committed
791
	for (i = 0; i < n_modes; i++) {
792
793
		ir_mode *mode = get_irp_mode(i);

794
795
796
797
798
799
800
801
802
803
804
805
806
807
		if (mode_is_int(mode)) {
			fprintf(env->file, "\tint_mode ");
			write_string(env, get_mode_name(mode));
			fprintf(env->file, "%s %u %d %u ",
			        get_mode_arithmetic_name(get_mode_arithmetic(mode)),
			        get_mode_size_bits(mode), get_mode_sign(mode),
			        get_mode_modulo_shift(mode));
		} else if (mode_is_reference(mode)) {
			fprintf(env->file, "\treference_mode ");
			write_string(env, get_mode_name(mode));
			fprintf(env->file, "%s %u %u ",
					get_mode_arithmetic_name(get_mode_arithmetic(mode)),
					get_mode_size_bits(mode),
					get_mode_modulo_shift(mode));
808
809
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
810
			write_int(env, (mode == mode_P ? 1 : 0));
811
812
813
814
815
816
817
818
819
		} else if (mode_is_float(mode)) {
			fprintf(env->file, "\tfloat_mode ");
			write_string(env, get_mode_name(mode));
			fprintf(env->file, "%s %u %u ",
			        get_mode_arithmetic_name(get_mode_arithmetic(mode)),
			        get_mode_exponent_size(mode),
			        get_mode_mantissa_size(mode));
		} else {
			/* skip "internal" modes */
820
821
822
823
		}
		fputc('\n', env->file);
	}

824
	fputs("}\n", env->file);
825
826
}

827
static void export_program(io_env_t *env)
828
{
829
830
831
832
833
	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
834
835
836
		fprintf(f, "\tname ");
		write_string(env, get_irp_name());
		fputc('\n', f);
837
838
	}

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

852
853
854
855
void ir_export(const char *filename)
{
	FILE *file = fopen(filename, "wt");
	if (file == NULL) {
856
857
858
859
		perror(filename);
		return;
	}

860
861
862
	ir_export_file(file, filename);
	fclose(file);
}
863

864
865
866
867
/* 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
868
	size_t i, n_irgs = get_irp_n_irgs();
869
870
871
872
873

	(void) outputname;
	env.file = file;

	export_modes(&env);
874

875
	fputs("\ntypegraph {\n", env.file);
876
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
877
	fputs("}\n", env.file);
878

Michael Beck's avatar
Michael Beck committed
879
	for (i = 0; i < n_irgs; i++) {
880
		ir_graph *irg       = get_irp_irg(i);
881

882
		fprintf(env.file, "\nirg %ld %ld {\n",
883
		        get_entity_nr(get_irg_entity(irg)),
884
		        get_type_nr(get_irg_frame_type(irg)));
885
886
887
888
889
890

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

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

		fputs("}\n", env.file);
893
894
	}

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

897
898
899
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

900
	export_program(&env);
901
902
}

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

908
909
	(void) outputname;
	env.file = file;
910

911
912
	export_modes(&env);

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

915
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
916

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

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

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

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

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

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

		default:
952
			return;
953
954
955
956
957
958
		}
	}
}

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

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

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

978
static char *read_word(io_env_t *env)
979
{
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
	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;
996
		}
997
		read_c(env);
998
	}
999

1000
endofword:
1001
	obstack_1grow(&env->obst, '\0');
1002
	return (char*)obstack_finish(&env->obst);
1003
1004
}

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

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

		if (env->c == '\\') {
1022
			read_c(env);
Matthias Braun's avatar
Matthias Braun committed
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
			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);
1037
1038
		}
		read_c(env);
1039
	}
Matthias Braun's avatar
Matthias Braun committed
1040
1041
	read_c(env);
	obstack_1grow(&env->obst, 0);
1042

1043
	return (char*)obstack_finish(&env->obst);
1044
1045
}

1046
static ident *read_ident(io_env_t *env)
1047
{
Matthias Braun's avatar
Matthias Braun committed
1048
	char  *str = read_string(env);
1049
1050
1051
1052
1053
1054
1055
1056
	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
1057
static char *read_string_null(io_env_t *env)
1058
1059
1060
1061
1062
1063
1064
1065
1066
{
	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
1067
		return read_string(env);
1068
1069
1070
1071
	}

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

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

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

static long read_long(io_env_t *env)
{
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
	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);
1101
	} while (isdigit(env->c));
1102
1103
	obstack_1grow(&env->obst, 0);

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

	return result;
1109
1110
}

1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
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
1121
1122
1123
1124
1125
1126
static size_t read_size_t(io_env_t *env)
{
	/* FIXME */
	return (size_t) read_unsigned(env);
}

1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
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;
}

1152
1153
1154
static ir_node *get_node_or_null(io_env_t *env, long nodenr)
{
	ir_node *node = (ir_node *) get_id(env, nodenr);
1155
1156
1157
1158
	if (node && node->kind != k_ir_node) {
		panic("Irn ID %ld collides with something else in line %d\n",
		      nodenr, env->line);
	}
1159
1160
1161
1162
1163
1164
	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
1165
	if (node == NULL) {
1166
		node = new_r_Dummy(env->irg, mode_X);
1167
1168
1169
1170
1171
1172
1173
1174
		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
1175
	if (type == NULL)
1176
		panic("unknown type: %ld in line %d\n", typenr, env->line);
Michael Beck's avatar
Michael Beck committed
1177
	else if (type->kind != k_type)
1178
1179
		panic("type ID %ld collides with something else in line %d\n",
		      typenr, env->line);
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
	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
1191
	if (entity == NULL) {
1192
		parse_error(env, "unknown entity: %ld\n", entnr);
1193
		exit(1);
1194
1195
1196
1197
1198
	} else if (entity->kind != k_entity) {
		panic("Entity ID %ld collides with something else in line %d\n",
		      entnr, env->line);
	}

1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
	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)
{
1209
	char *str = read_string(env);
Michael Beck's avatar
Michael Beck committed
1210
	size_t i, n;
1211
1212

	n = get_irp_n_modes();
Michael Beck's avatar
Michael Beck committed
1213
	for (i = 0; i < n; i++) {
1214
		ir_mode *mode = get_irp_mode(i);
1215
1216
		if (strcmp(str, get_mode_name(mode)) == 0) {
			obstack_free(&env->obst, str);
1217
			return mode;
1218