bearch_firm.c 11.5 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
3
4
5
6
7
8

/**
 * ISA implementation for Firm IR nodes.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

Sebastian Hack's avatar
Sebastian Hack committed
9
10
11
12
#ifdef WITH_LIBCORE
#include <libcore/lc_opts.h>
#endif

Christian Würdig's avatar
Christian Würdig committed
13
14
15
16
17
#include "bitset.h"
#include "obst.h"

#include "irmode_t.h"
#include "irnode_t.h"
Sebastian Hack's avatar
Sebastian Hack committed
18
#include "iredges_t.h"
Christian Würdig's avatar
Christian Würdig committed
19
20
21
22
23
24
#include "irgmod.h"
#include "ircons_t.h"
#include "irgwalk.h"
#include "type.h"

#include "../bearch.h"
Sebastian Hack's avatar
Sebastian Hack committed
25
#include "../besched.h"
Christian Würdig's avatar
Christian Würdig committed
26
27
28
29
30
31
32
#include "../beutil.h"

#define N_REGS 3

typedef struct {
  enum  { imm_Const, imm_SymConst } tp;
  union {
Sebastian Hack's avatar
Sebastian Hack committed
33
34
    const_attr    cnst_attr;
    symconst_attr symc_attr;
Christian Würdig's avatar
Christian Würdig committed
35
36
37
38
39
40
41
42
43
44
45
46
  } data;
} imm_attr_t;

static arch_register_t datab_regs[N_REGS];

static arch_register_class_t reg_classes[] = {
  { "datab", N_REGS, datab_regs },
};

static ir_op *op_push;
static ir_op *op_imm;

Sebastian Hack's avatar
Sebastian Hack committed
47
48
const arch_isa_if_t firm_isa;

Christian Würdig's avatar
Christian Würdig committed
49
50
51
52
53
54
55
#define N_CLASSES \
  (sizeof(reg_classes) / sizeof(reg_classes[0]))

#define CLS_DATAB 0

tarval *get_Imm_tv(ir_node *n) {
  imm_attr_t *attr = (imm_attr_t *)get_irn_generic_attr(n);
Sebastian Hack's avatar
Sebastian Hack committed
56
  return attr->tp == imm_Const ? attr->data.cnst_attr.tv : NULL;
Christian Würdig's avatar
Christian Würdig committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
}

int is_Imm(const ir_node *irn) {
  return get_irn_op(irn) == op_imm;
}

static int dump_node_Imm(ir_node *n, FILE *F, dump_reason_t reason) {
  ir_mode    *mode;
  int        bad = 0;
  char       buf[1024];
  tarval     *tv;
  imm_attr_t *attr;

  switch (reason) {
    case dump_node_opcode_txt:
      tv = get_Imm_tv(n);

      if (tv) {
        tarval_snprintf(buf, sizeof(buf), tv);
        fprintf(F, "%s", buf);
      }
      else {
        fprintf(F, "immSymC");
      }
      break;

    case dump_node_mode_txt:
      mode = get_irn_mode(n);

      if (mode && mode != mode_BB && mode != mode_ANY && mode != mode_BAD && mode != mode_T) {
        fprintf(F, "[%s]", get_mode_name(mode));
      }
      break;

    case dump_node_nodeattr_txt:
      attr = (imm_attr_t *)get_irn_generic_attr(n);

      if (is_Imm(n) && attr->tp == imm_SymConst) {
        const char *name    = NULL;
Sebastian Hack's avatar
Sebastian Hack committed
96
        symconst_attr *sc_attr = &attr->data.symc_attr;
Christian Würdig's avatar
Christian Würdig committed
97

Sebastian Hack's avatar
Sebastian Hack committed
98
        switch (sc_attr->num) {
Christian Würdig's avatar
Christian Würdig committed
99
          case symconst_addr_name:
Sebastian Hack's avatar
Sebastian Hack committed
100
            name = get_id_str(sc_attr->sym.ident_p);
Christian Würdig's avatar
Christian Würdig committed
101
102
103
            break;

          case symconst_addr_ent:
Sebastian Hack's avatar
Sebastian Hack committed
104
            name = get_entity_ld_name(sc_attr->sym.entity_p);
Christian Würdig's avatar
Christian Würdig committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
            break;

          default:
            assert(!"Unsupported SymConst");
        }

        fprintf(F, "&%s ", name);
      }

      break;

    case dump_node_info_txt:
      break;
  }

  return bad;
}

Sebastian Hack's avatar
Sebastian Hack committed
123
static void *firm_init(void)
Christian Würdig's avatar
Christian Würdig committed
124
125
126
{
  static struct obstack obst;
  static int inited = 0;
Sebastian Hack's avatar
Sebastian Hack committed
127
	arch_isa_t *isa = malloc(sizeof(*isa));
Christian Würdig's avatar
Christian Würdig committed
128
129
  int k;

Sebastian Hack's avatar
Sebastian Hack committed
130
131
	isa->impl = &firm_isa;

Christian Würdig's avatar
Christian Würdig committed
132
  if(inited)
Sebastian Hack's avatar
Sebastian Hack committed
133
    return NULL;
Christian Würdig's avatar
Christian Würdig committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

  inited = 1;
  obstack_init(&obst);

  for(k = 0; k < N_CLASSES; ++k) {
    const arch_register_class_t *cls = &reg_classes[k];
    int i;

    for(i = 0; i < cls->n_regs; ++i) {
      int n;
      char buf[8];
      char *name;
      arch_register_t *reg = (arch_register_t *) &cls->regs[i];

      n = snprintf(buf, sizeof(buf), "r%d", i);
      name = obstack_copy0(&obst, buf, n);

      reg->name = name;
      reg->reg_class = cls;
      reg->index = i;
      reg->type = 0;
    }
  }

	/*
	 * Create some opcodes and types to let firm look a little
	 * bit more like real machines.
	 */
	if(!op_push) {
		int push_opc = get_next_ir_opcode();

		op_push = new_ir_op(push_opc, "Push",
				op_pin_state_pinned, 0, oparity_binary, 0, 0, NULL);
	}

	if(!op_imm) {
		int imm_opc = get_next_ir_opcode();
Sebastian Hack's avatar
Sebastian Hack committed
171
		ir_op_ops ops;
Christian Würdig's avatar
Christian Würdig committed
172

Sebastian Hack's avatar
Sebastian Hack committed
173
174
		memset(&ops, 0, sizeof(ops));
		ops.dump_node = dump_node_Imm;
Christian Würdig's avatar
Christian Würdig committed
175
176
177
178

		op_imm = new_ir_op(imm_opc, "Imm",
				op_pin_state_pinned, 0, oparity_zero, 0, sizeof(imm_attr_t), &ops);
	}
Sebastian Hack's avatar
Sebastian Hack committed
179
180
181
182
183
184
185

	return isa;
}

static void firm_done(void *self)
{
	free(self);
Christian Würdig's avatar
Christian Würdig committed
186
187
}

Sebastian Hack's avatar
Sebastian Hack committed
188
static int firm_get_n_reg_class(const void *self)
Christian Würdig's avatar
Christian Würdig committed
189
190
191
192
{
  return N_CLASSES;
}

Sebastian Hack's avatar
Sebastian Hack committed
193
static const arch_register_class_t *firm_get_reg_class(const void *self, int i)
Christian Würdig's avatar
Christian Würdig committed
194
195
196
197
198
199
200
201
{
  assert(i >= 0 && i < N_CLASSES);
  return &reg_classes[i];
}

static const arch_register_req_t firm_std_reg_req = {
  arch_register_req_type_normal,
  &reg_classes[CLS_DATAB],
202
  NULL,
Sebastian Hack's avatar
Sebastian Hack committed
203
  NULL
Christian Würdig's avatar
Christian Würdig committed
204
205
206
};

static const arch_register_req_t *
207
firm_get_irn_reg_req(const void *self,
Christian Würdig's avatar
Christian Würdig committed
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    arch_register_req_t *req, const ir_node *irn, int pos)
{
  if(is_firm_be_mode(get_irn_mode(irn)))
    memcpy(req, &firm_std_reg_req, sizeof(*req));
  else
    req = NULL;

  return req;
}

struct irn_reg_assoc {
  const ir_node *irn;
  const arch_register_t *reg;
};

static int cmp_irn_reg_assoc(const void *a, const void *b, size_t len)
{
  const struct irn_reg_assoc *x = a;
  const struct irn_reg_assoc *y = b;

Sebastian Hack's avatar
Sebastian Hack committed
228
  return x->irn != y->irn;
Christian Würdig's avatar
Christian Würdig committed
229
230
}

Sebastian Hack's avatar
Sebastian Hack committed
231
static struct irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn)
Christian Würdig's avatar
Christian Würdig committed
232
233
234
235
236
237
238
239
240
241
{
  static set *reg_set = NULL;
  struct irn_reg_assoc templ;

  if(!reg_set)
    reg_set = new_set(cmp_irn_reg_assoc, 1024);

  templ.irn = irn;
  templ.reg = NULL;

Sebastian Hack's avatar
Sebastian Hack committed
242
  return set_insert(reg_set, &templ, sizeof(templ), HASH_PTR(irn));
Christian Würdig's avatar
Christian Würdig committed
243
244
}

245
static void firm_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg)
Christian Würdig's avatar
Christian Würdig committed
246
{
Sebastian Hack's avatar
Sebastian Hack committed
247
  struct irn_reg_assoc *assoc = get_irn_reg_assoc(irn);
Christian Würdig's avatar
Christian Würdig committed
248
249
250
  assoc->reg = reg;
}

251
static const arch_register_t *firm_get_irn_reg(const void *self, const ir_node *irn)
Christian Würdig's avatar
Christian Würdig committed
252
{
Sebastian Hack's avatar
Sebastian Hack committed
253
  struct irn_reg_assoc *assoc = get_irn_reg_assoc(irn);
Christian Würdig's avatar
Christian Würdig committed
254
255
256
  return assoc->reg;
}

257
static arch_irn_class_t firm_classify(const void *self, const ir_node *irn)
Christian Würdig's avatar
Christian Würdig committed
258
259
260
261
262
263
264
265
{
    arch_irn_class_t res;

    switch(get_irn_opcode(irn)) {
        case iro_Cond:
        case iro_Jmp:
            res = arch_irn_class_branch;
            break;
Christian Würdig's avatar
Christian Würdig committed
266
267
268
		case iro_Call:
			res = arch_irn_class_call;
			break;
Christian Würdig's avatar
Christian Würdig committed
269
270
271
272
273
274
275
        default:
            res = arch_irn_class_normal;
    }

	return res;
}

276
static arch_irn_flags_t firm_get_flags(const void *self, const ir_node *irn)
Christian Würdig's avatar
Christian Würdig committed
277
{
Sebastian Hack's avatar
Sebastian Hack committed
278
	arch_irn_flags_t res = 0;
Christian Würdig's avatar
Christian Würdig committed
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

	if(get_irn_op(irn) == op_imm)
		res |= arch_irn_flags_rematerializable;

	switch(get_irn_opcode(irn)) {
		case iro_Add:
		case iro_Sub:
		case iro_Shl:
		case iro_Shr:
		case iro_Shrs:
		case iro_And:
		case iro_Or:
		case iro_Eor:
		case iro_Not:
			res |= arch_irn_flags_rematerializable;
		default:
			res = res;
	}

	return res;
}

301
302
303
304
305
static const arch_irn_ops_if_t firm_irn_ops_if = {
	firm_get_irn_reg_req,
	firm_set_irn_reg,
	firm_get_irn_reg,
	firm_classify,
Christian Würdig's avatar
Christian Würdig committed
306
307
308
	firm_get_flags
};

309
310
311
312
313
314
static const arch_irn_ops_t firm_irn_ops = {
	&firm_irn_ops_if
};

static const void *firm_get_irn_ops(const arch_irn_handler_t *self,
	const ir_node *irn)
Christian Würdig's avatar
Christian Würdig committed
315
{
316
	return &firm_irn_ops;
Christian Würdig's avatar
Christian Würdig committed
317
318
319
}

const arch_irn_handler_t firm_irn_handler = {
320
	firm_get_irn_ops,
Christian Würdig's avatar
Christian Würdig committed
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
};

static ir_node *new_Push(ir_graph *irg, ir_node *bl, ir_node *push, ir_node *arg)
{
	ir_node *ins[2];
	ins[0] = push;
	ins[1] = arg;
	return new_ir_node(NULL, irg, bl, op_push, mode_M, 2, ins);
}

/**
 * Creates an op_Imm node from an op_Const.
 */
static ir_node *new_Imm(ir_graph *irg, ir_node *bl, ir_node *cnst) {
  ir_node    *ins[1];
  ir_node    *res;
  imm_attr_t *attr;

  res = new_ir_node(NULL, irg, bl, op_imm, get_irn_mode(cnst), 0, ins);
  attr = (imm_attr_t *) &res->attr;

  switch (get_irn_opcode(cnst)) {
    case iro_Const:
      attr->tp      = imm_Const;
Sebastian Hack's avatar
Sebastian Hack committed
345
      attr->data.cnst_attr = get_irn_const_attr(cnst);
Christian Würdig's avatar
Christian Würdig committed
346
347
      break;
    case iro_SymConst:
Sebastian Hack's avatar
Sebastian Hack committed
348
349
      attr->tp             = imm_SymConst;
      attr->data.symc_attr = get_irn_symconst_attr(cnst);
Christian Würdig's avatar
Christian Würdig committed
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
      break;
    case iro_Unknown:
      break;
    default:
      assert(0 && "Cannot create Imm for this opcode");
  }

  return res;
}

static void prepare_walker(ir_node *irn, void *data)
{
	opcode opc = get_irn_opcode(irn);

	/* A replacement for this node has already been computed. */
	if(get_irn_link(irn))
		return;

	if(opc == iro_Call) {
		ir_node *bl   = get_nodes_block(irn);
		ir_graph *irg = get_irn_irg(bl);

		ir_node *store   = get_Call_mem(irn);
		ir_node *ptr     = get_Call_ptr(irn);
374
		ir_type *ct      = get_Call_type(irn);
Christian Würdig's avatar
Christian Würdig committed
375
376
377
378
379
380
381
		int np           = get_Call_n_params(irn) > 0 ? 1 : 0;

		if(np > 0) {
			ir_node *ins[1];
			char buf[128];
			ir_node *nc;
			int i, n = get_Call_n_params(irn);
382
			ir_type *nt;
Christian Würdig's avatar
Christian Würdig committed
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
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
      unsigned cc = get_method_calling_convention(get_Call_type(irn));

      if (cc & cc_last_on_top) {
			  store = new_Push(irg, bl, store, get_Call_param(irn, 0));

			  for (i = 1; i < n; ++i)
				  store = new_Push(irg, bl, store, get_Call_param(irn, i));
      }
      else {
        store = new_Push(irg, bl, store, get_Call_param(irn, n - 1));

        for (i = n - 2; i >= 0; --i)
          store = new_Push(irg, bl, store, get_Call_param(irn, i));
      }

			snprintf(buf, sizeof(buf), "push_%s", get_type_name(ct));

			n = get_method_n_ress(ct);
			nt = new_type_method(new_id_from_str(buf), 0, n);
			for(i = 0; i < n; ++i)
				set_method_res_type(nt, i, get_method_res_type(ct, i));

			nc = new_r_Call(irg, bl, store, ptr, 0, ins, nt);
			exchange(irn, nc);
			set_irn_link(nc, nc);
		}
	}
}

static void localize_const_walker(ir_node *irn, void *data)
{
	if(!is_Block(irn)) {
		int i, n;
		ir_node *bl = get_nodes_block(irn);

		for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
			ir_node *op    = get_irn_n(irn, i);
			opcode opc     = get_irn_opcode(op);

			if(opc == iro_Const
			|| opc == iro_Unknown
			|| (opc == iro_SymConst /*&& get_SymConst_kind(op) == symconst_addr_ent*/)) {
				ir_graph *irg   = get_irn_irg(bl);
				ir_node *imm_bl = is_Phi(irn) ? get_Block_cfgpred_block(bl, i) : bl;

				ir_node *imm = new_Imm(irg, imm_bl, op);
				set_irn_n(irn, i, imm);
			}
		}
	}
}

Sebastian Hack's avatar
Sebastian Hack committed
435
436
437
438
439
440
441
442
443
444
445
static const arch_irn_handler_t *firm_get_irn_handler(const void *self)
{
	return &firm_irn_handler;
}

typedef struct _firm_code_gen_t {
	const arch_code_generator_if_t *impl;
	ir_graph *irg;
} firm_code_gen_t;


Christian Würdig's avatar
Christian Würdig committed
446
447
448
449
450
static void clear_link(ir_node *irn, void *data)
{
	set_irn_link(irn, NULL);
}

Sebastian Hack's avatar
Sebastian Hack committed
451
452
453
454
455
456
457
458
459
static void firm_prepare_graph(void *self)
{
	firm_code_gen_t *cg = self;

	irg_walk_graph(cg->irg, clear_link, localize_const_walker, NULL);
	irg_walk_graph(cg->irg, NULL, prepare_walker, NULL);
}

static void firm_before_sched(void *self)
Christian Würdig's avatar
Christian Würdig committed
460
461
462
{
}

Sebastian Hack's avatar
Sebastian Hack committed
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
static void imm_scheduler(ir_node *irn, void *env) {
	if(is_Imm(irn)) {
		const ir_edge_t *e;
		ir_node *user, *user_block, *before, *tgt_block;

		if (1 != get_irn_n_edges(irn)) {
			printf("Out edges: %d\n", get_irn_n_edges(irn));
			assert(1 == get_irn_n_edges(irn));
		}

		e = get_irn_out_edge_first(irn);
		user = e->src;
		user_block = get_nodes_block(user);
		if (is_Phi(user)) {
			before = get_Block_cfgpred_block(user_block, e->pos);
			tgt_block = before;
		} else {
			before = user;
			tgt_block = user_block;
		}

		sched_remove(irn);
		set_nodes_block(irn, tgt_block);
		sched_add_before(before, irn);
	}
}

static void firm_before_ra(void *self)
{
	firm_code_gen_t *cg = self;
	irg_walk_graph(cg->irg, imm_scheduler, NULL, NULL);
}

static void firm_codegen_done(void *self)
{
	free(self);
}

Sebastian Hack's avatar
Sebastian Hack committed
501
502
static void *firm_cg_init(FILE *file_handle, ir_graph *irg, const arch_env_t *env);

503
static const arch_code_generator_if_t firm_code_gen_if = {
Sebastian Hack's avatar
Sebastian Hack committed
504
	firm_cg_init,
Sebastian Hack's avatar
Sebastian Hack committed
505
506
507
	firm_prepare_graph,
	firm_before_sched,
	firm_before_ra,
508
509
	NULL,  /* lower spill */
	NULL,  /* lower reload */
Sebastian Hack's avatar
Sebastian Hack committed
510
511
512
	firm_codegen_done
};

Sebastian Hack's avatar
Sebastian Hack committed
513
static void *firm_cg_init(FILE *file_handle, ir_graph *irg, const arch_env_t *env)
Sebastian Hack's avatar
Sebastian Hack committed
514
{
515
	firm_code_gen_t *cg = xmalloc(sizeof(*cg));
516
	cg->impl = &firm_code_gen_if;
Sebastian Hack's avatar
Sebastian Hack committed
517
	cg->irg  = irg;
Sebastian Hack's avatar
Sebastian Hack committed
518
	return cg;
Sebastian Hack's avatar
Sebastian Hack committed
519
520
521
}


522
static const arch_code_generator_if_t *firm_get_code_generator_if(void *self)
Sebastian Hack's avatar
Sebastian Hack committed
523
{
524
	return &firm_code_gen_if;
Sebastian Hack's avatar
Sebastian Hack committed
525
526
}

Sebastian Hack's avatar
Sebastian Hack committed
527
528
529
530
531
532
533
534
535
536
static const list_sched_selector_t *firm_get_list_sched_selector(const void *self) {
	return trivial_selector;
}

#ifdef WITH_LIBCORE
static void firm_register_options(lc_opt_entry_t *ent)
{
}
#endif

Christian Würdig's avatar
Christian Würdig committed
537
const arch_isa_if_t firm_isa = {
Sebastian Hack's avatar
Sebastian Hack committed
538
539
540
#ifdef WITH_LIBCORE
	firm_register_options,
#endif
Christian Würdig's avatar
Christian Würdig committed
541
	firm_init,
Sebastian Hack's avatar
Sebastian Hack committed
542
	firm_done,
Christian Würdig's avatar
Christian Würdig committed
543
544
	firm_get_n_reg_class,
	firm_get_reg_class,
Sebastian Hack's avatar
Sebastian Hack committed
545
	firm_get_irn_handler,
546
	firm_get_code_generator_if,
Sebastian Hack's avatar
Sebastian Hack committed
547
	firm_get_list_sched_selector
Christian Würdig's avatar
Christian Würdig committed
548
};