bearch.c 10.9 KB
Newer Older
1
2
3
4
5
6
7
/**
 * Processor architecture specification.
 * @author Sebastian Hack
 * @date 11.2.2005
 *
 * $Id$
 */
Michael Beck's avatar
Michael Beck committed
8
9
10
11
12
13
14
15
16
17
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
18

19
20
#include <string.h>

Michael Beck's avatar
Michael Beck committed
21
#include "bearch.h"
22

Sebastian Hack's avatar
Sebastian Hack committed
23
#include "pset.h"
24
25
26
27

#include "entity.h"
#include "ircons_t.h"

Sebastian Hack's avatar
Sebastian Hack committed
28
29
30
/* Needed for obstack copy */
#define bcopy(src,dst,n) memcpy(dst,src,n)

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#define INIT_HEADER(tgt, kind_suffix, a_isa, str) \
	do { \
		arch_header_t *h = (arch_header_t *) (tgt); \
		memset(tgt, 0, sizeof(*(tgt))); \
		h->kind = arch_kind_ ## kind_suffix; \
		h->name = new_id_from_str(str); \
		h->isa = a_isa; \
	} while(0)

static INLINE int hash_header(const arch_header_t *header)
{
	int res = HASH_PTR(header->isa);
	res = 37 * res + HASH_STR(header->name, strlen(header->name));
	res = 37 * res + header->kind;
	return res;
}

Sebastian Hack's avatar
Sebastian Hack committed
48
static int cmp_header(const void *a, const void *b)
49
50
51
52
{
	const arch_header_t *h1 = a;
	const arch_header_t *h2 = b;

Sebastian Hack's avatar
Sebastian Hack committed
53
	return !(h1->kind == h2->kind && h1->isa == h2->isa && strcmp(h1->name, h2->name) == 0);
54
55
}

Sebastian Hack's avatar
Sebastian Hack committed
56
57
58
59
60
61
62
/**
 * The obstack and pset where the arch data is stored.
 */
typedef struct _arch_data_t {
	struct obstack obst;			/**< Here is the data allocated. */
	pset *header_set;					/**< Here reside copies of the headers. */
} arch_data_t;
63

Sebastian Hack's avatar
Sebastian Hack committed
64
65
66
67
68
69
/**
 * Get the storage (obstack and pset) for the arch objects.
 * @return A struct containing both, the obst and pset where
 * the objects are allocated and their pointer are recorded.
 */
static INLINE arch_data_t *get_arch_data(void)
70
{
Sebastian Hack's avatar
Sebastian Hack committed
71
72
	static arch_data_t arch_data;
	static int inited = 0;
73

Sebastian Hack's avatar
Sebastian Hack committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	if(!inited) {
		obstack_init(&arch_data.obst);
		arch_data.header_set = new_pset(cmp_header, 512);
		inited = 1;
	}

	return &arch_data;
}

/**
 * Dump all arch objects in the arch_data collection.
 */
static void dump_arch_data(void)
{
	void *p;
	arch_data_t *d = get_arch_data();
	static const char *kind_names[] = {
#define ARCH_OBJ(name,in_list)	#name,
#include "bearch_obj.def"
#undef ARCH_OBJ
		""
	};

	printf("arch set:\n");
	for(p = pset_first(d->header_set); p; p = pset_next(d->header_set)) {
		arch_header_t *header = p;
		printf("%20s %10s %10s\n", kind_names[header->kind], header->name,
				header->isa ? header->isa->header.name : "");
	}
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
}

typedef struct _obj_info_t {
	const char *name;
	int listed_in_isa;
	size_t size;
} obj_info_t;

static const obj_info_t obj_info[] = {
#define ARCH_OBJ(name,listed_in_isa)		{ #name, listed_in_isa, sizeof(arch_ ## name ## _t) },
#include "bearch_obj.def"
#undef ARCH_OBJ
	{ 0 }
};

/**
 * Insert an arch object to the global arch obj storage.
 *
 * If the object has already been created there, nothing is done and
 * the old object is created.
 *
 * @param kind The kind of the arch object.
 * @param isa The isa the object belongs to or NULL if it is the isa
 * itself.
 * @param name The name of the object.
 * @return A pointer to the object.
 */
static INLINE void *_arch_data_insert(arch_kind_t kind, arch_isa_t *isa,
Sebastian Hack's avatar
Sebastian Hack committed
131
		const char *name, size_t size)
132
{
Sebastian Hack's avatar
Sebastian Hack committed
133
	arch_data_t *ad = get_arch_data();
134
	const obj_info_t *info = &obj_info[kind];
Sebastian Hack's avatar
Sebastian Hack committed
135
	arch_header_t *header = obstack_alloc(&ad->obst, size);
136
137
	arch_header_t *res = NULL;

Sebastian Hack's avatar
Sebastian Hack committed
138
139
140
141
142
143
144
	memset(header, 0, size);
	header->name = name;
	header->kind = kind;
	header->isa = isa;
	header->is_new = 1;

	res = pset_insert(ad->header_set, header, hash_header(header));
145
146

	/*
Sebastian Hack's avatar
Sebastian Hack committed
147
148
149
150
	 * If the object is newly created and thus not yet present
	 * in the set, add it to the isa
	 * The inserted object was no isa, list it in the isa if this is
	 * desired.
151
	 */
Sebastian Hack's avatar
Sebastian Hack committed
152
153
154
155
156
157
158
	if(res->is_new && isa && info->listed_in_isa) {
		list_add(&res->list, &isa->heads[kind]);
	}

	/* if it was in the set, remove it from the obstack */
	if(!res->is_new)
		obstack_free(&ad->obst, header);
159
160
161
162
163
164
165

	/* Mark the object as NOT new. */
	res->is_new = 0;

	return res;
}

Sebastian Hack's avatar
Sebastian Hack committed
166
167
#define arch_data_insert(type_suffix, isa, name) \
	_arch_data_insert(arch_kind_ ## type_suffix, isa, name, sizeof(arch_ ## type_suffix ## _t))
168
169
170
171
172
173
174
175
176

static INLINE void *_arch_data_find(arch_kind_t kind, const arch_isa_t *isa, const char *name)
{
	arch_header_t header;

	header.kind = kind;
	header.isa = (arch_isa_t *) isa;
	header.name = name;

Sebastian Hack's avatar
Sebastian Hack committed
177
	return pset_find(get_arch_data()->header_set, &header, hash_header(&header));
178
179
180
181
182
183
184
}

#define arch_data_find(type_suffix, isa, name) \
	_arch_data_find(arch_kind_ ## type_suffix, isa, name)

arch_isa_t *arch_add_isa(const char *name)
{
Sebastian Hack's avatar
Sebastian Hack committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
	arch_isa_t *isa;
	int i;

	isa = arch_data_insert(isa, NULL, name);
	for(i = 0; i < arch_kind_last; ++i)
		INIT_LIST_HEAD(&isa->heads[i]);

	return isa;
}

arch_register_set_t *arch_add_register_set(arch_isa_t *isa,
		const arch_register_class_t *cls, const char *name)
{
	arch_register_set_t *set =
		_arch_data_insert(arch_kind_register_set, isa, name,
				sizeof(arch_register_set_t) + cls->n_regs * sizeof(set->regs[0]));

	set->reg_class = cls;
	memset(set->regs, 0, sizeof(set->regs[0]) * cls->n_regs);

	return set;
206
207
208
209
}

arch_register_class_t *arch_add_register_class(arch_isa_t *isa, const char *name, int n_regs)
{
Sebastian Hack's avatar
Sebastian Hack committed
210
211
212
213
	char buf[64];
	char *set_name;
	int i, n;

214
215
	arch_register_class_t *cls =
		_arch_data_insert(arch_kind_register_class, isa, name,
Sebastian Hack's avatar
Sebastian Hack committed
216
217
218
219
220
				sizeof(arch_register_class_t) + n_regs * sizeof(arch_register_t *));

	/* Make a name for the set contianing all regs in this class. */
	n = snprintf(buf, sizeof(buf), "%s$set", name);
	set_name = obstack_copy(&get_arch_data()->obst, buf, n);
221
222
223

	cls->n_regs = n_regs;

Sebastian Hack's avatar
Sebastian Hack committed
224
225
226
227
228
229
230
	/* make the set of all registers in this class */
	cls->set = arch_add_register_set(isa, cls, name);

	/* Add each register in this class to the set */
	for(i = 0; i < n_regs; ++i)
		cls->set->regs[i] = 1;

231
232
233
	return cls;
}

Sebastian Hack's avatar
Sebastian Hack committed
234
235
236
237
238
239
void arch_register_set_add_register(arch_register_set_t *set, int index)
{
	assert(index >= 0 && index < set->reg_class->n_regs);
	set->regs[index] = 1;
}

240
241
242
243
244
245
arch_register_t *arch_add_register(arch_register_class_t *cls, int index, const char *name)
{
	arch_register_t *reg = NULL;

	assert(index >= 0 && index < cls->n_regs);
	reg = _arch_data_insert(arch_kind_register, arch_obj_get_isa(cls), name,
Sebastian Hack's avatar
Sebastian Hack committed
246
			sizeof(arch_register_t));
247
248
249
250
251
252
253
254
255
256
257
	cls->regs[index] = reg;

	reg->index = index;
	reg->reg_class = cls;
	reg->flags = arch_register_flag_none;

	return reg;
}

arch_immediate_t *arch_add_immediate(arch_isa_t *isa, const char *name, ir_mode *mode)
{
Sebastian Hack's avatar
Sebastian Hack committed
258
	arch_immediate_t *imm = arch_data_insert(immediate, isa, name);
259
260
261
262
	imm->mode = mode;
	return imm;
}

Sebastian Hack's avatar
Sebastian Hack committed
263
264
265
266
/*
 * Size of each operand type which should be allocated in an irn.
 * Keep this list up to date with the arch_operand_type_t enum.
 */
267
static const size_t operand_sizes[] = {
Sebastian Hack's avatar
Sebastian Hack committed
268
269
270
271
#define ARCH_OPERAND_TYPE(name,size_in_irn) size_in_irn,
#include "bearch_operand_types.def"
#undef ARCH_OPERAND_TYPE
	0
272
273
};

Sebastian Hack's avatar
Sebastian Hack committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/**
 * Determine the amount of bytes which has to be extra allocated when a
 * new ir node is made from a insn format.
 * This size depends on the operands specified in the insn format.
 * @param fmt The instruction format.
 * @return The number of bytes which the operands of an instruction
 * will need in an ir node.
 */
static INLINE int arch_get_operands_size(const arch_insn_format_t *fmt)
{
	int i, res = 0;

	for(i = 0; i < fmt->n_in + fmt->n_out; ++i) {
		arch_operand_type_t type = fmt->operands[i].type;

		assert(type > arch_operand_type_invalid && type < arch_operand_type_last);
		res += operand_sizes[type];
	}

	return res;
}

296
297
298
299
300
301
arch_insn_format_t *arch_add_insn_format(arch_isa_t *isa, const char *name, int n_in, int n_out)
{
	int i;

	arch_insn_format_t *fmt =
		_arch_data_insert(arch_kind_insn_format, isa, name,
Sebastian Hack's avatar
Sebastian Hack committed
302
				sizeof(arch_insn_format_t) + (n_in + n_out) * sizeof(arch_operand_t));
303
304
305
306

	fmt->n_in = n_in;
	fmt->n_out = n_out;

Sebastian Hack's avatar
Sebastian Hack committed
307
308
309
	/* initialize each operand with invalid. */
	for(i = 0; i < n_in + n_out; ++i)
		fmt->operands[i].type = arch_operand_type_invalid;
310
311
312
313
314
315

	return fmt;
}

arch_insn_t *arch_add_insn(arch_insn_format_t *fmt, const char *name)
{
Sebastian Hack's avatar
Sebastian Hack committed
316
317
318
	/* Get the size the operands will need in the irn. */
	int operands_size = arch_get_operands_size(fmt);

319
	/* Insert the insn into the isa. */
Sebastian Hack's avatar
Sebastian Hack committed
320
	arch_insn_t *insn = arch_data_insert(insn, arch_obj_get_isa(fmt), name);
321
322
323

	insn->format = fmt;
	insn->op = new_ir_op(get_next_ir_opcode(), name, op_pin_state_pinned, 0,
Sebastian Hack's avatar
Sebastian Hack committed
324
			oparity_dynamic, 0, sizeof(arch_irn_data_t) + operands_size);
325
326
327
328

	return insn;
}

329
arch_insn_format_t *arch_find_insn_format(const arch_isa_t *isa, const char *name)
330
331
332
333
334
335
336
337
338
{
	return arch_data_find(insn_format, isa, name);
}

arch_isa_t *arch_find_isa(const char *name)
{
	return arch_data_find(isa, NULL, name);
}

339
340
341
342
343
arch_insn_t *arch_find_insn(const arch_isa_t *isa, const char *name)
{
	return arch_data_find(insn, isa, name);
}

Sebastian Hack's avatar
Sebastian Hack committed
344
345
346
347
348
349
arch_immediate_t *arch_find_immediate(const arch_isa_t *isa, const char *name)
{
	return arch_data_find(immediate, isa, name);
}

arch_register_class_t *arch_find_register_class(const arch_isa_t *isa, const char *name)
350
351
352
353
{
	return arch_data_find(register_class, isa, name);
}

Sebastian Hack's avatar
Sebastian Hack committed
354
355
356
357
358
arch_register_set_t *arch_find_register_set(const arch_isa_t *isa, const char *name)
{
	return arch_data_find(register_set, isa, name);
}

359
360
361
362
363
arch_register_set_t *arch_get_register_set_for_class(arch_register_class_t *cls)
{
	return _arch_get_register_set_for_class(cls);
}

Sebastian Hack's avatar
Sebastian Hack committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
static INLINE arch_operand_t *_arch_set_operand(arch_insn_format_t *fmt, int pos,
		arch_operand_type_t type)
{
	arch_operand_t *operand;
	int ofs = arch_inout_to_index(fmt, pos);

	assert(ofs < fmt->n_in + fmt->n_out);

	operand = &fmt->operands[ofs];
	operand->type = type;
	return operand;
}

arch_operand_t *arch_set_operand_register_set(arch_insn_format_t *fmt,
		int pos, const arch_register_set_t *set)
{
	arch_operand_t *op = _arch_set_operand(fmt, pos, arch_operand_type_register_set);
	op->data.set = set;
	return op;
}

arch_operand_t *arch_set_operand_callback(arch_insn_format_t *fmt,
		int pos, arch_register_callback_t *cb)
{
	arch_operand_t *op = _arch_set_operand(fmt, pos, arch_operand_type_callback);
	op->data.callback = cb;
	return op;
}

arch_operand_t *arch_set_operand_immediate(arch_insn_format_t *fmt,
		int pos, const arch_immediate_t *imm)
{
	arch_operand_t *op = _arch_set_operand(fmt, pos, arch_operand_type_immediate);
	op->data.imm = imm;
	return op;
}

arch_operand_t *arch_set_operand_memory(arch_insn_format_t *fmt, int pos)
{
	arch_operand_t *op = _arch_set_operand(fmt, pos, arch_operand_type_memory);
	return op;
}

arch_operand_t *arch_set_operand_equals(arch_insn_format_t *fmt, int pos, int same_as_pos)
{
	arch_operand_t *op = _arch_set_operand(fmt, pos, arch_operand_type_equals);
	op->data.same_as_pos = same_as_pos;
	return op;
}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
ir_node *arch_new_node(const arch_insn_t *insn, ir_graph *irg, ir_node *block,
		ir_mode *mode, int arity, ir_node **in)
{
	ir_node *irn = new_ir_node(NULL, irg, block, insn->op, mode, arity, in);
	arch_irn_data_t *data = (void *) &irn->attr;

	data->magic = ARCH_IRN_FOURCC;
	data->insn = insn;

	return irn;
}

ir_node *arch_new_node_bare(const arch_insn_t *insn, ir_graph *irg, int arity)
{
	int i;
	ir_node **in = alloca(sizeof(in[0]) * arity);

	for(i = 0; i < arity; ++i)
		in[i] = new_Unknown(mode_Is);

	return arch_new_node(insn, irg, new_Unknown(mode_BB), mode_Is, arity, in);
}
436
437
438
439
440

ir_mode *arch_get_unknown_mode(void)
{
	return mode_Is;
}