irio.c 41.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * Copyright (C) 1995-2009 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * @file
 * @brief   Write textual representation of firm to file.
 * @author  Moritz Kroll
 * @version $Id$
 */
#include "config.h"

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

#include "irio.h"

35
#include "irnode_t.h"
36
37
38
39
40
41
42
43
44
#include "irprog.h"
#include "irgraph_t.h"
#include "ircons.h"
#include "irgmod.h"
#include "irflag_t.h"
#include "irgwalk.h"
#include "tv.h"
#include "array.h"
#include "error.h"
45
#include "typerep.h"
46
#include "adt/set.h"
47
#include "adt/obst.h"
48

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

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

typedef enum typetag_t
{
	tt_align,
	tt_allocation,
67
	tt_builtin,
68
	tt_cond_jmp_predicate,
69
70
	tt_initializer,
	tt_iro,
71
	tt_keyword,
72
	tt_mode_sort,
73
	tt_mode_arithmetic,
74
75
	tt_peculiarity,
	tt_pin_state,
76
	tt_tpo,
77
78
79
	tt_type_state,
	tt_variability,
	tt_visibility,
80
81
	tt_volatility,
	tt_segment
82
83
} typetag_t;

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

97
typedef struct symbol_t
98
{
99
100
101
102
	const char *str;      /**< The name of this symbol. */
	typetag_t   typetag;  /**< The type tag of this symbol. */
	unsigned    code;     /**< The value of this symbol. */
} symbol_t;
103
104
105
106
107
108
109

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

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

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

static int id_cmp(const void *elt, const void *key, size_t size)
{
	const id_entry *entry = (const id_entry *) elt;
	const id_entry *keyentry = (const id_entry *) key;
	(void) size;
	return entry->id - keyentry->id;
}

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
static void __attribute__((format(printf, 2, 3)))
parse_error(io_env_t *env, const char *fmt, ...)
{
	va_list ap;
	int     line = env->line;

	/* workaround read_c "feature" that a '\n' triggers the line++
	 * instead of the character after the '\n' */
	if (env->c == '\n') {
		line--;
	}

	fprintf(stderr, "%s:%d: error ", env->inputname, line);

	va_start(ap, fmt);
	vfprintf(stderr, fmt, ap);
	va_end(ap);
}

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

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

163
	symtbl = new_set(symbol_cmp, 256);
164

165
#define INSERT(tt, s, cod)                                       \
166
167
168
	key.str = (s);                                               \
	key.typetag = (tt);                                          \
	key.code = (cod);                                            \
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
	set_insert(symtbl, &key, sizeof(key), firm_fnv_hash_str(s) + tt * 17)

#define INSERTENUM(tt, e) INSERT(tt, #e, e)
#define INSERTKEYWORD(k) INSERT(tt_keyword, #k, kw_##k)

	INSERT(tt_tpo, "array", tpo_array);
	INSERT(tt_tpo, "class", tpo_class);
	INSERT(tt_tpo, "method", tpo_method);
	INSERT(tt_tpo, "pointer", tpo_pointer);
	INSERT(tt_tpo, "primitive", tpo_primitive);
	INSERT(tt_tpo, "struct", tpo_struct);
	INSERT(tt_tpo, "union", tpo_union);
	INSERT(tt_tpo, "Unknown", tpo_unknown);

	INSERT(tt_mode_sort, "auxiliary", irms_auxiliary);
	INSERT(tt_mode_sort, "control_flow", irms_control_flow);
	INSERT(tt_mode_sort, "memory", irms_memory);
	INSERT(tt_mode_sort, "internal_boolean", irms_internal_boolean);
	INSERT(tt_mode_sort, "reference", irms_reference);
	INSERT(tt_mode_sort, "int_number", irms_int_number);
	INSERT(tt_mode_sort, "float_number", irms_float_number);

	INSERT(tt_segment, "global", IR_SEGMENT_GLOBAL);
	INSERT(tt_segment, "thread_local", IR_SEGMENT_THREAD_LOCAL);
	INSERT(tt_segment, "constructors", IR_SEGMENT_CONSTRUCTORS);
	INSERT(tt_segment, "destructors", IR_SEGMENT_DESTRUCTORS);
195

196
197
198
	INSERTKEYWORD(constirg);
	INSERTKEYWORD(entity);
	INSERTKEYWORD(irg);
199
200
	INSERTKEYWORD(mode);
	INSERTKEYWORD(modes);
201
202
	INSERTKEYWORD(type);
	INSERTKEYWORD(typegraph);
203
204
	INSERTKEYWORD(program);
	INSERTKEYWORD(segment_type);
205

206
207
208
209
210
211
212
213
214
215
#include "gen_irio_lex.inl"

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

	INSERTENUM(tt_allocation, allocation_automatic);
	INSERTENUM(tt_allocation, allocation_parameter);
	INSERTENUM(tt_allocation, allocation_dynamic);
	INSERTENUM(tt_allocation, allocation_static);

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

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

248
249
250
251
	INSERTENUM(tt_peculiarity, peculiarity_description);
	INSERTENUM(tt_peculiarity, peculiarity_inherited);
	INSERTENUM(tt_peculiarity, peculiarity_existent);

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
	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_variability, variability_uninitialized);
	INSERTENUM(tt_variability, variability_initialized);
	INSERTENUM(tt_variability, variability_part_constant);
	INSERTENUM(tt_variability, variability_constant);

	INSERTENUM(tt_visibility, visibility_local);
	INSERTENUM(tt_visibility, visibility_external_visible);
	INSERTENUM(tt_visibility, visibility_external_allocated);

	INSERTENUM(tt_volatility, volatility_non_volatile);
	INSERTENUM(tt_volatility, volatility_is_volatile);

272
#undef INSERTKEYWORD
273
274
275
276
#undef INSERTENUM
#undef INSERT
}

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

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

	key.str = str;
294
	key.typetag = typetag;
295

296
	entry = set_find(symtbl, &key, sizeof(key), firm_fnv_hash_str(str) + typetag * 17);
297
	return entry ? entry->code : SYMERROR;
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
}

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

	entry = set_find(env->idset, &key, sizeof(key), (unsigned) id);
	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);
}

static void write_mode(io_env_t *env, ir_mode *mode)
{
	fputs(get_mode_name(mode), env->file);
	fputc(' ', env->file);
}

323
324
325
326
327
328
329
330
331
static void write_tarval(io_env_t *env, tarval *tv)
{
	char buf[1024];
	write_mode(env, get_tarval_mode(tv));
	tarval_snprintf(buf, sizeof(buf), tv);
	fputs(buf, env->file);
	fputc(' ', env->file);
}

332
333
334
335
static void write_align(io_env_t *env, ir_node *irn)
{
	ir_align align;

Michael Beck's avatar
Michael Beck committed
336
337
338
339
340
341
	if (is_Load(irn))
		align = get_Load_align(irn);
	else if (is_Store(irn))
		align = get_Store_align(irn);
	else
		panic("Invalid optype for write_align");
342
343
344
345
346

	fputs(get_align_name(align), env->file);
	fputc(' ', env->file);
}

347
348
349
350
351
352
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);
}

353
354
355
356
357
358
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);
}

359
360
361
362
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);
363

364
365
366
	fputs(get_initializer_kind_name(ini_kind), f);
	fputc(' ', f);

367
368
369
370
	switch (ini_kind) {
	case IR_INITIALIZER_CONST:
		fprintf(f, "%ld ", get_irn_node_nr(get_initializer_const_value(ini)));
		break;
371

372
373
374
	case IR_INITIALIZER_TARVAL:
		write_tarval(env, get_initializer_tarval_value(ini));
		break;
375

376
377
	case IR_INITIALIZER_NULL:
		break;
378

379
380
381
382
383
384
385
	case IR_INITIALIZER_COMPOUND: {
		unsigned i, n = get_initializer_compound_n_entries(ini);
		fprintf(f, "%d ", n);
		for (i = 0; i < n; i++)
			write_initializer(env, get_initializer_compound_value(ini, i));
		break;
	}
386

387
388
	default:
		panic("Unknown initializer kind");
389
390
391
	}
}

392
393
394
395
396
397
398
399
400
401
static void write_pin_state(io_env_t *env, ir_node *irn)
{
	fputs(get_op_pin_state_name(get_irn_pinned(irn)), env->file);
	fputc(' ', env->file);
}

static void write_volatility(io_env_t *env, ir_node *irn)
{
	ir_volatility vol;

Michael Beck's avatar
Michael Beck committed
402
403
404
405
406
407
	if (is_Load(irn))
		vol = get_Load_volatility(irn);
	else if (is_Store(irn))
		vol = get_Store_volatility(irn);
	else
		panic("Invalid optype for write_volatility");
408
409
410
411
412

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

413
static void export_type_common(io_env_t *env, ir_type *tp)
414
{
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
	fprintf(env->file, "\ttype %ld %s %u %u %s %s %d ",
	        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)),
	        get_visibility_name(get_type_visibility(tp)),
	        tp->flags);
}

static void export_compound_name(FILE *f, const ir_type *tp)
{
	ident *name = get_compound_ident(tp);
	if (name == NULL) {
		fputs("NULL ", f);
	} else {
		fprintf(f, "\"%s\" ", get_id_str(name));
	}
433
434
435
436
437
438
}

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

Michael Beck's avatar
Michael Beck committed
439
	/* skip types to be handled by post walker */
440
441
442
443
444
445
446
	switch (get_type_tpop_code(tp)) {
	case tpo_array:
	case tpo_method:
	case tpo_pointer:
		return;
	default:
		break;
447
448
449
450
	}

	export_type_common(env, tp);

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
	switch (get_type_tpop_code(tp)) {
	case tpo_uninitialized:
		panic("invalid type found");

	case tpo_class:
		export_compound_name(f, tp);
		break;

	case tpo_primitive:
		write_mode(env, get_type_mode(tp));
		break;

	case tpo_union:
	case tpo_struct:
	case tpo_enumeration:
		export_compound_name(f, tp);
		break;

	case tpo_array:
	case tpo_method:
	case tpo_pointer:
	case tpo_code:
	case tpo_none:
	case tpo_unknown:
		break;
476
477
478
479
480
481
482
	}
	fputc('\n', f);
}

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

Michael Beck's avatar
Michael Beck committed
485
	/* skip types already handled by pre walker */
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
	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;
501
502
503
	}

	export_type_common(env, tp);
504

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
	switch (get_type_tpop_code(tp)) {
	case tpo_array: {
		int n = get_array_n_dimensions(tp);
		fprintf(f, "%d %ld ", n, get_type_nr(get_array_element_type(tp)));
		for (i = 0; i < n; i++) {
			ir_node *lower = get_array_lower_bound(tp, i);
			ir_node *upper = get_array_upper_bound(tp, i);

			if (is_Const(lower))
				fprintf(f, "%ld ", get_tarval_long(get_Const_tarval(lower)));
			else
				panic("Lower array bound is not constant");

			if (is_Const(upper))
				fprintf(f, "%ld ", get_tarval_long(get_Const_tarval(upper)));
			else if (is_Unknown(upper))
				fputs("unknown ", f);
			else
				panic("Upper array bound is not constant");
		}
		break;
	}
527

528
529
530
531
532
533
534
535
536
537
538
539
	case tpo_method: {
		int nparams  = get_method_n_params(tp);
		int nresults = get_method_n_ress(tp);
		fprintf(f, "%u %u %d %d ", get_method_calling_convention(tp),
			get_method_additional_properties(tp), nparams, nresults);
		for (i = 0; i < nparams; i++)
			fprintf(f, "%ld ", get_type_nr(get_method_param_type(tp, i)));
		for (i = 0; i < nresults; i++)
			fprintf(f, "%ld ", get_type_nr(get_method_res_type(tp, i)));
		fprintf(f, "%d ", get_method_first_variadic_param_index(tp));
		break;
	}
540

541
542
543
544
	case tpo_pointer:
		write_mode(env, get_type_mode(tp));
		fprintf(f, "%ld ", get_type_nr(get_pointer_points_to_type(tp)));
		break;
545

546
547
548
549
550
551
552
553
	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;
554
555
556
557
558
559
560
	}
	fputc('\n', f);
}

static void export_entity(io_env_t *env, ir_entity *ent)
{
	ir_type *owner = get_entity_owner(ent);
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

	/* 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;

	fprintf(env->file, "\tentity %ld \"%s\" ",
	        get_entity_nr(ent), get_entity_name(ent));
	if (ent->ld_name != NULL) {
		fprintf(env->file, "\"%s\" ", get_entity_ld_name(ent));
	} else {
		fprintf(env->file, "NULL ");
	}

	fprintf(env->file, "%ld %ld %d %u %d %s %s %s %s %s ",
577
578
579
			get_type_nr(get_entity_type(ent)),
			get_type_nr(owner),
			get_entity_offset(ent),
580
			(unsigned) get_entity_offset_bits_remainder(ent),
581
			is_entity_compiler_generated(ent),
582
583
584
585
586
587
			get_allocation_name(get_entity_allocation(ent)),
			get_visibility_name(get_entity_visibility(ent)),
			get_variability_name(get_entity_variability(ent)),
			get_peculiarity_name(get_entity_peculiarity(ent)),
			get_volatility_name(get_entity_volatility(ent)));

Michael Beck's avatar
Michael Beck committed
588
589
	/* TODO: inheritance stuff for class entities not supported yet */
	if (is_Class_type(owner) && owner != get_glob_type())
590
		fprintf(stderr, "Inheritance of class entities not supported yet!\n");
591

Michael Beck's avatar
Michael Beck committed
592
593
	if (get_entity_variability(ent) != variability_uninitialized &&
	    get_entity_visibility(ent) != visibility_external_allocated)
594
	{
Michael Beck's avatar
Michael Beck committed
595
596
		if (is_compound_entity(ent)) {
			if (has_entity_initializer(ent)) {
597
598
				fputs("initializer ", env->file);
				write_initializer(env, get_entity_initializer(ent));
Michael Beck's avatar
Michael Beck committed
599
			} else {
600
				int i, n = get_compound_ent_n_values(ent);
601
				fputs("noninitializer ", env->file);
602
				fprintf(env->file, "%d ", n);
Michael Beck's avatar
Michael Beck committed
603
				for (i = 0; i < n; i++) {
604
605
606
607
					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));
				}
608
			}
Michael Beck's avatar
Michael Beck committed
609
		} else {
610
611
612
613
614
615
			ir_node *irn = get_atomic_ent_value(ent);
			fprintf(env->file, "%ld ", get_irn_node_nr(irn));
		}
	}

	fputc('\n', env->file);
616
617
}

618
619
620
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
621
	if (get_kind(tore.typ) == k_type)
622
623
624
625
		export_type_pre(env, tore.typ);
}

static void export_type_or_ent_post(type_or_ent tore, void *ctx)
626
627
628
{
	io_env_t *env = (io_env_t *) ctx;

629
630
631
632
	switch (get_kind(tore.ent)) {
	case k_entity:
		export_entity(env, tore.ent);
		break;
633

634
635
636
	case k_type:
		export_type_post(env, tore.typ);
		break;
637

638
639
640
	default:
		panic("export_type_or_ent_post: Unknown type or entity.");
		break;
641
642
643
	}
}

644
645
646
/**
 * Walker: exports every node.
 */
647
648
649
650
651
652
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
653
	if (env->ignoreblocks && opcode == iro_Block)
654
		return;
655

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

658
	n = get_irn_arity(irn);
Michael Beck's avatar
Michael Beck committed
659
	for (i = -1; i < n; i++) {
660
		ir_node *pred = get_irn_n(irn, i);
Michael Beck's avatar
Michael Beck committed
661
		if (pred == NULL) {
662
			/* Anchor node may have NULL predecessors */
663
			assert(is_Anchor(irn));
664
			fputs("-1 ", env->file);
665
		} else {
666
			fprintf(env->file, "%ld ", get_irn_node_nr(pred));
667
		}
668
669
670
671
	}

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

672
	switch (opcode)	{
673
	#include "gen_irio_export.inl"
674
	}
675
676
677
	fputs("}\n", env->file);
}

678
679
680
681
682
683
684
685
686
687
688
689
690
691
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");
}

692
693
694
695
696
697
static void export_modes(io_env_t *env)
{
	int i, n_modes = get_irp_n_modes();

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

Michael Beck's avatar
Michael Beck committed
698
	for (i = 0; i < n_modes; i++) {
699
		ir_mode *mode = get_irp_mode(i);
700
701
702
703
704
705
706
707
708
		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;
709
710
		}

711
712
713
714
715
716
		fprintf(env->file, "\tmode \"%s\" %s %d %d %s %d %d ",
		        get_mode_name(mode), get_mode_sort_name(get_mode_sort(mode)),
		        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
717
		if (mode_is_reference(mode)) {
718
719
720
721
722
723
			write_mode(env, get_reference_mode_signed_eq(mode));
			write_mode(env, get_reference_mode_unsigned_eq(mode));
		}
		fputc('\n', env->file);
	}

724
	fputs("}\n", env->file);
725
726
}

727
static void export_program(io_env_t *env)
728
{
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
	FILE         *f = env->file;
	ir_segment_t  s;

	fputs("\nprogram {\n", f);
	if (irp_prog_name_is_set()) {
		fprintf(f, "\tname \"%s\"\n", get_irp_name());
	}
	/* We need numbers for irgs... */
#if 0
	if (get_irp_main_irg() != NULL) {
		fprintf(f, "\tmain_irg %d\n", get_irp_main_irg
#endif

	for (s = 0; s <= IR_SEGMENT_LAST; ++s) {
		ir_type *segment_type = get_segment_type(s);
		fprintf(f, "\tsegment_type %s", get_segment_name(s));
		if (segment_type == NULL) {
			fputs(" NULL\n", f);
		} else {
			fprintf(f, " %ld\n", get_type_nr(segment_type));
		}
	}
	fputs("}\n", f);
}
753

754
755
756
757
void ir_export(const char *filename)
{
	FILE *file = fopen(filename, "wt");
	if (file == NULL) {
758
759
760
761
		perror(filename);
		return;
	}

762
763
764
	ir_export_file(file, filename);
	fclose(file);
}
765

766
767
768
769
770
771
772
773
774
775
/* Exports the whole irp to the given file in a textual form. */
void ir_export_file(FILE *file, const char *outputname)
{
	io_env_t env;
	int i, n_irgs = get_irp_n_irgs();

	(void) outputname;
	env.file = file;

	export_modes(&env);
776

777
	fputs("\ntypegraph {\n", env.file);
778
	type_walk_prog(export_type_or_ent_pre, export_type_or_ent_post, &env);
779
	fputs("}\n", env.file);
780

Michael Beck's avatar
Michael Beck committed
781
	for (i = 0; i < n_irgs; i++) {
782
783
		ir_graph *irg       = get_irp_irg(i);
		ir_type  *valuetype = get_irg_value_param_type(irg);
784

785
786
787
788
		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));
789
790
791
792
793
794

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

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

		fputs("}\n", env.file);
797
798
	}

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

801
802
803
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);

804
	export_program(&env);
805
806
}

807
/* Exports the given irg to the given file. */
808
void ir_export_irg(ir_graph *irg, FILE *file, const char *outputname)
809
810
811
{
	io_env_t env;

812
813
	(void) outputname;
	env.file = file;
814

815
816
	export_modes(&env);

817
818
	fputs("typegraph {\n", env.file);

819
	type_walk_irg(irg, export_type_or_ent_pre, export_type_or_ent_post, &env);
820

821
	fprintf(env.file, "}\n\nirg %ld {\n", get_entity_nr(get_irg_entity(irg)));
822
823
824
825
826
827
828

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

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

829
	/* TODO: Only output needed constants */
830
	fprintf(env.file, "}\n\nconstirg %ld {\n", get_irn_node_nr(get_const_code_irg()->current_block));
831
832
	walk_const_code(NULL, export_node, &env);
	fputs("}\n", env.file);
Moritz Kroll's avatar
Moritz Kroll committed
833
834
}

835
static void read_c(io_env_t *env)
Moritz Kroll's avatar
Moritz Kroll committed
836
{
837
838
839
840
	int c = fgetc(env->file);
	env->c = c;
	if (c == '\n')
		env->line++;
Moritz Kroll's avatar
Moritz Kroll committed
841
842
}

843
844
/** Returns the first non-whitespace character or EOF. **/
static void skip_ws(io_env_t *env)
845
{
846
847
848
	while (true) {
		switch (env->c) {
		case ' ':
849
850
		case '\t':
		case '\n':
851
852
853
		case '\r':
			read_c(env);
			continue;
854
855

		default:
856
			return;
857
858
859
860
861
862
		}
	}
}

static void skip_to(io_env_t *env, char to_ch)
{
863
864
865
	while (env->c != to_ch && env->c != EOF) {
		read_c(env);
	}
866
867
868
869
}

static int expect_char(io_env_t *env, char ch)
{
870
871
872
873
	skip_ws(env);
	if (env->c != ch) {
		parse_error(env, "Unexpected char '%c', expected '%c'\n",
		            env->c, ch);
874
875
		return 0;
	}
876
	read_c(env);
877
878
879
	return 1;
}

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

882
static char *read_word(io_env_t *env)
883
{
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
	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;
900
		}
901
		read_c(env);
902
	}
903

904
endofword:
905
906
	obstack_1grow(&env->obst, '\0');
	return obstack_finish(&env->obst);
907
908
}

909
static char *read_quoted_string(io_env_t *env)
910
{
911
912
913
914
915
916
	skip_ws(env);
	if (env->c != '\"') {
		parse_error(env, "Expected '\"', found '%c'\n", env->c);
		exit(1);
	}
	read_c(env);
917

918
919
920
	assert(obstack_object_size(&env->obst) == 0);
	while (true) {
		int ch = env->c;
Michael Beck's avatar
Michael Beck committed
921
		if (ch == EOF) {
922
			parse_error(env, "Unexpected end of quoted string!\n");
923
924
			exit(1);
		}
925
926
927
928
929
930
		if (ch == '\"') {
			read_c(env);
			break;
		}
		obstack_1grow(&env->obst, ch);
		read_c(env);
931
	}
932
933
934
	obstack_1grow(&env->obst, '\0');

	return obstack_finish(&env->obst);
935
936
}

937
static ident *read_ident(io_env_t *env)
938
{
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
	char  *str = read_quoted_string(env);
	ident *res = new_id_from_str(str);
	obstack_free(&env->obst, str);

	return res;
}

/*
 * reads a "quoted string" or alternatively the token NULL
 */
static char *read_quoted_string_null(io_env_t *env)
{
	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 == '"') {
		return read_quoted_string(env);
	}

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

966
static ident *read_ident_null(io_env_t *env)
967
{
968
969
970
971
972
973
974
975
	ident *res;
	char  *str = read_quoted_string_null(env);
	if (str == NULL)
		return NULL;

	res = new_id_from_str(str);
	obstack_free(&env->obst, str);
	return res;
976
977
978
979
}

static long read_long(io_env_t *env)
{
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
	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);
	} while(isdigit(env->c));
	obstack_1grow(&env->obst, 0);

	str = obstack_finish(&env->obst);
	result = atol(str);
	obstack_free(&env->obst, str);

	return result;
1001
1002
1003
1004
1005
}

static ir_node *get_node_or_null(io_env_t *env, long nodenr)
{
	ir_node *node = (ir_node *) get_id(env, nodenr);
1006
1007
1008
1009
	if (node && node->kind != k_ir_node) {
		panic("Irn ID %ld collides with something else in line %d\n",
		      nodenr, env->line);
	}
1010
1011
1012
1013
1014
1015
	return node;
}

static ir_node *get_node(io_env_t *env, long nodenr)
{
	ir_node *node = get_node_or_null(env, nodenr);
Michael Beck's avatar
Michael Beck committed
1016
	if (!node)
1017
		panic("Unknown node: %ld in line %d\n", nodenr, env->line);
1018
1019
1020
1021
1022
1023
1024

	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
1025
	if (node == NULL) {
1026
1027
1028
1029
1030
1031
1032
1033
1034
		node = new_Dummy(mode_X);
		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
1035
	if (type == NULL)
1036
		panic("unknown type: %ld in line %d\n", typenr, env->line);
Michael Beck's avatar
Michael Beck committed
1037
	else if (type->kind != k_type)
1038
1039
		panic("type ID %ld collides with something else in line %d\n",
		      typenr, env->line);
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
	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
1051
	if (entity == NULL) {
1052
		parse_error(env, "unknown entity: %ld\n", entnr);
1053
		exit(1);
1054
1055
1056
1057
1058
	} else if (entity->kind != k_entity) {
		panic("Entity ID %ld collides with something else in line %d\n",
		      entnr, env->line);
	}

1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
	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)
{
1069
	char *str = read_word(env);
1070
1071
1072
	int i, n;

	n = get_irp_n_modes();
Michael Beck's avatar
Michael Beck committed
1073
	for (i = 0; i < n; i++) {
1074
		ir_mode *mode = get_irp_mode(i);
1075
1076
		if (strcmp(str, get_mode_name(mode)) == 0) {
			obstack_free(&env->obst, str);
1077
			return mode;
1078
		}
1079
1080
	}

1081
1082
	parse_error(env, "unknown mode \"%s\"\n", str);
	exit(1);
1083
1084
1085
1086
}

static const char *get_typetag_name(typetag_t typetag)
{
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
	switch (typetag) {
	case tt_align:              return "align";
	case tt_allocation:         return "allocation";
	case tt_builtin:            return "builtin kind";
	case tt_initializer:        return "initializer kind";
	case tt_iro:                return "opcode";
	case tt_peculiarity:        return "peculiarity";
	case tt_pin_state:          return "pin state";
	case tt_tpo:                return "type";
	case tt_type_state:         return "type state";
	case tt_variability:        return "variability";
	case tt_visibility:         return "visibility";
	case tt_volatility:         return "volatility";
	case tt_cond_jmp_predicate: return "cond_jmp_predicate";
	case tt_keyword:            return "keyword";
	case tt_mode_sort:          return "mode_sort";
	case tt_mode_arithmetic:    return "mode_arithmetic";
	case tt_segment:            return "segment";
1105
	}
1106
	return "<UNKNOWN>";
1107
1108
}

1109
1110
1111
/**
 * Read and decode an enum constant.
 */
1112
1113
static unsigned read_enum(io_env_t *env, typetag_t typetag)
{
1114
1115
1116
1117
1118
	char     *str  = read_word(env);
	unsigned  code = symbol(str, typetag);

	if (code != SYMERROR) {
		obstack_free(&env->obst, str);
1119
		return code;
1120
	}
1121

1122
	parse_error(env, "invalid %s: \"%s\"\n", get_typetag_name(typetag), str);
1123
1124
1125
	return 0;
}

1126
1127
1128
1129
1130
#define read_align(env)              ((ir_align)              read_enum(env, tt_align))
#define read_allocation(env)         ((ir_allocation)         read_enum(env, tt_allocation))
#define read_builtin_kind(env)       ((ir_builtin_kind)       read_enum(env, tt_builtin))
#define read_cond_jmp_predicate(env) ((cond_jmp_predicate)    read_enum(env, tt_cond_jmp_predicate))
#define read_initializer_kind(env)   ((ir_initializer_kind_t) read_enum(env, tt_initializer))
1131
#define read_mode_arithmetic(env)    ((ir_mode_arithmetic)    read_enum(env, tt_mode_arithmetic))
1132
1133
1134
1135
1136
1137
#define read_peculiarity(env)        ((ir_peculiarity)        read_enum(env, tt_peculiarity))
#define read_pin_state(env)          ((op_pin_state)          read_enum(env, tt_pin_state))
#define read_type_state(env)         ((ir_type_state)         read_enum(env, tt_type_state))
#define read_variability(env)        ((ir_variability)        read_enum(env, tt_variability))
#define read_visibility(env)         ((ir_visibility)         read_enum(env, tt_visibility))
#define read_volatility(env)         ((ir_volatility)         read_enum(env, tt_volatility))
1138

1139
1140
1141
1142
1143
static ir_cons_flags get_cons_flags(io_env_t *env)
{
	ir_cons_flags flags = cons_none;

	op_pin_state pinstate = read_pin_state(env);
1144
1145
1146
1147
1148
1149
	switch (pinstate) {
	case op_pin_state_floats: flags |= cons_floats; break;
	case op_pin_state_pinned: break;
	default:
		panic("Error in %d: Invalid pinstate: %s", env->line,
		      get_op_pin_state_name(pinstate));
1150
1151
	}

Michael Beck's avatar
Michael Beck committed
1152
1153
1154
1155
	if (read_volatility(env) == volatility_is_volatile)
		flags |= cons_volatile;
	if (read_align(env) == align_non_aligned)
		flags |= cons_unaligned;
1156
1157
1158
1159

	return flags;
}

1160
1161
1162
static tarval *read_tv(io_env_t *env)
{
	ir_mode *tvmode = read_mode(env);
1163
1164
1165
1166
1167
	char    *str    = read_word(env);
	tarval  *tv     = new_tarval_from_str(str, strlen(str), tvmode);
	obstack_free(&env->obst, str);

	return tv;
1168
1169
}

1170
1171
1172
1173
static ir_initializer_t *read_initializer(io_env_t *env)
{
	ir_initializer_kind_t ini_kind = read_initializer_kind(env);

1174
1175
1176
1177
1178
	switch (ini_kind) {
	case IR_INITIALIZER_CONST: {
		ir_node *irn = get_node_or_dummy(env, read_long(env));
		return create_initializer_const(irn);
	}
1179

1180
1181
	case IR_INITIALIZER_TARVAL:
		return create_initializer_tarval(read_tv(env));
1182

1183
1184
	case IR_INITIALIZER_NULL:
		return get_initializer_null();
1185

1186
1187
1188
1189
1190
1191
	case IR_INITIALIZER_COMPOUND: {
		unsigned i, n = (unsigned) read_long(env);
		ir_initializer_t *ini = create_initializer_compound(n);
		for (i = 0; i < n; i++) {
			ir_initializer_t *curini = read_initializer(env);
			set_initializer_compound_value(ini, i, curini);
1192
		}
1193
1194
		return ini;
	}
1195

1196
1197
	default:
		panic("Unknown initializer kind");
1198
1199
1200
1201
	}
}


1202
/** Reads a type description and remembers it by its id. */
1203
static void import_type(io_env_t *env)
1204
1205
1206
1207
{
	int            i;
	ir_type       *type;
	long           typenr = read_long(env);
1208
	tp_opcode      tpop   = (tp_opcode) read_enum(env, tt_tpo);
1209
1210
1211
1212
	unsigned       size   = (unsigned) read_long(env);
	unsigned       align  = (unsigned) read_long(env);
	ir_type_state  state  = read_type_state(env);
	ir_visibility  vis    = read_visibility(env);
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
	unsigned       flags  = (unsigned) read_long(env);

	switch (tpop) {
	case tpo_array: {
		int ndims = (int) read_long(env);
		long elemtypenr = read_long(env);
		ir_type *elemtype = get_type(env, elemtypenr);

		type = new_type_array(ndims, elemtype);
		for (i = 0; i < ndims; i++) {
			char *str = read_word(env);
			if (strcmp(str, "unknown") != 0) {
				long lowerbound = atol(str);
				set_array_lower_bound_int(type, i, lowerbound);
			}
			obstack_free(&env->obst, str);
1229

1230
1231
1232
1233
1234
1235
			str = read_word(env);
			if (strcmp(str, "unknown") != 0) {
				long upperbound = atol(str);
				set_array_upper_bound_int(type, i, upperbound);
			}
			obstack_free(&env->obst, str);
1236
		}
1237
		set_type_size_bytes(type, size);
1238
1239
		break;
	}
1240

1241
1242
1243
	case tpo_class: {
		const char *name = read_quoted_string_null(env);
		ident      *id   = name != NULL ? new_id_from_str(name) : NULL;
1244

1245
1246
1247
1248
		if(typenr == (long) IR_SEGMENT_GLOBAL)
			type = get_glob_type();
		else
			type = new_type_class(id);
1249
		set_type_size_bytes(type, size);
1250
1251
		break;
	}
1252

1253
1254
1255
1256
1257
1258
	case tpo_method: {
		unsigned callingconv = (unsigned) read_long(env);
		unsigned addprops    = (unsigned) read_long(env);
		int nparams          = (int)      read_long(env);
		int nresults         = (int)      read_long(env);
		int variaindex;
1259

1260
		type = new_type_method(nparams, nresults);
1261

1262
1263
1264
		for (i = 0; i < nparams; i++) {
			long     typenr = read_long(env);
			ir_type *paramtype = get_type(env, typenr);
1265

1266
1267
1268
1269
1270
			set_method_param_type(type, i, paramtype);
		}
		for (i = 0; i < nresults; i++) {
			long typenr = read_long(env);
			ir_type *restype = get_type(env, typenr);
1271

1272
1273
			set_method_res_type(type, i, restype);
		}
Moritz Kroll's avatar
Moritz Kroll committed
1274

1275
1276
1277
1278
1279
1280
		variaindex = (int) read_long(env);
		if (variaindex != -1) {
			set_method_variadicity(type, variadicity_variadic);
			if (variaindex != nparams)
				set_method_first_variadic_param_index(type, variaindex);
		}
1281

1282
1283
1284
1285
		set_method_calling_convention(type, callingconv);
		set_method_additional_properties(type, addprops);
		break;
	}
1286

Matthias Braun's avatar