irio.c 44.9 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_arithmetic,
75
	tt_pin_state,
76
	tt_tpo,
77
	tt_type_state,
78
	tt_volatility,
Matthias Braun's avatar
Matthias Braun committed
79
	tt_linkage,
80
81
	tt_segment,
	tt_visibility
82
83
} typetag_t;

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

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

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

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

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

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

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

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

165
	symtbl = new_set(symbol_cmp, 256);
166

167
#define INSERT(tt, s, cod)                                       \
168
169
170
	key.str = (s);                                               \
	key.typetag = (tt);                                          \
	key.code = (cod);                                            \
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
	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);
189

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

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

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

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

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

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

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

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

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

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

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

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

	key.str = str;
291
	key.typetag = typetag;
292

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

436
437
	case IR_INITIALIZER_NULL:
		break;
438

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

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

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

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

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

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

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

	export_type_common(env, tp);

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

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

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

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

	export_type_common(env, tp);
544

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Matthias Braun's avatar
Matthias Braun committed
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
723
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);
}

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

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

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

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

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

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

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

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

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

795
796
797
798
799
800
801
802
803
804
805
806
807
808
		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));
809
810
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
811
			write_int(env, (mode == mode_P ? 1 : 0));
812
813
814
815
816
817
818
819
820
		} 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 */
821
822
823
824
		}
		fputc('\n', env->file);
	}

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

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

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

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

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

865
866
867
868
/* Exports the whole irp to the given file in a textual form. */
void ir_export_file(FILE *file, const char *outputname)
{
	io_env_t env;
Michael Beck's avatar
Michael Beck committed
869
	size_t i, n_irgs = get_irp_n_irgs();
870
871
872
873
874

	(void) outputname;
	env.file = file;

	export_modes(&env);
875

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

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

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

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

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

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

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

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

901
	export_program(&env);
902
903
}

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

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

912
913
	export_modes(&env);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return result;
1110
1111
}

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

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

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

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

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