bearch.c 5.69 KB
Newer Older
1
2
3
4
5
6
7
/**
 * Processor architecture specification.
 * @author Sebastian Hack
 * @date 11.2.2005
 *
 * $Id$
 */
Sebastian Hack's avatar
Sebastian Hack committed
8

Michael Beck's avatar
Michael Beck committed
9
10
11
12
13
14
15
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
Daniel Grund's avatar
Daniel Grund committed
16

Michael Beck's avatar
Michael Beck committed
17
18
19
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
20

21
22
#include <string.h>

Michael Beck's avatar
Michael Beck committed
23
#include "bearch.h"
Sebastian Hack's avatar
Sebastian Hack committed
24
#include "ircons_t.h"
25

Sebastian Hack's avatar
Sebastian Hack committed
26
#include "bitset.h"
Sebastian Hack's avatar
Sebastian Hack committed
27
#include "pset.h"
28
29
#include "entity.h"

Sebastian Hack's avatar
Sebastian Hack committed
30
arch_env_t *arch_env_init(arch_env_t *env, const arch_isa_if_t *isa_if)
31
{
Sebastian Hack's avatar
Sebastian Hack committed
32
  memset(env, 0, sizeof(*env));
Sebastian Hack's avatar
Sebastian Hack committed
33
  env->isa = isa_if->init();
Sebastian Hack's avatar
Sebastian Hack committed
34
  return env;
Sebastian Hack's avatar
Sebastian Hack committed
35
36
}

Sebastian Hack's avatar
Sebastian Hack committed
37
38
arch_env_t *arch_env_add_irn_handler(arch_env_t *env,
    const arch_irn_handler_t *handler)
Sebastian Hack's avatar
Sebastian Hack committed
39
{
Sebastian Hack's avatar
Sebastian Hack committed
40
41
42
  assert(env->handlers_tos <= ARCH_MAX_HANDLERS);
  env->handlers[env->handlers_tos++] = handler;
  return env;
43
44
}

Sebastian Hack's avatar
Sebastian Hack committed
45
static const arch_irn_ops_t *fallback_irn_ops = NULL;
Sebastian Hack's avatar
Sebastian Hack committed
46

Sebastian Hack's avatar
Sebastian Hack committed
47
int arch_register_class_put(const arch_register_class_t *cls, bitset_t *bs)
48
{
Sebastian Hack's avatar
Sebastian Hack committed
49
50
51
52
53
  if(bs) {
    int i, n;
    for(i = 0, n = cls->n_regs; i < n; ++i)
      bitset_set(bs, i);
  }
54

Sebastian Hack's avatar
Sebastian Hack committed
55
  return cls->n_regs;
56
57
}

Sebastian Hack's avatar
Sebastian Hack committed
58
/**
Sebastian Hack's avatar
Sebastian Hack committed
59
60
61
62
 * Get the isa responsible for a node.
 * @param env The arch environment with the isa stack.
 * @param irn The node to get the responsible isa for.
 * @return The irn operations given by the responsible isa.
Sebastian Hack's avatar
Sebastian Hack committed
63
 */
Sebastian Hack's avatar
Sebastian Hack committed
64
65
static INLINE const arch_irn_ops_t *
get_irn_ops(const arch_env_t *env, const ir_node *irn)
66
{
Sebastian Hack's avatar
Sebastian Hack committed
67
  int i;
68

Sebastian Hack's avatar
Sebastian Hack committed
69
  for(i = env->handlers_tos - 1; i >= 0; --i) {
Sebastian Hack's avatar
Sebastian Hack committed
70
71
72
    const arch_irn_handler_t *handler = env->handlers[i];
    const arch_irn_ops_t *ops = handler->get_irn_ops(handler, irn);

Sebastian Hack's avatar
Sebastian Hack committed
73
74
75
    if(ops)
      return ops;
  }
Sebastian Hack's avatar
Sebastian Hack committed
76

Sebastian Hack's avatar
Sebastian Hack committed
77
  return fallback_irn_ops;
78
79
}

Sebastian Hack's avatar
Sebastian Hack committed
80
81
82
83
const arch_register_req_t *arch_get_register_req(const arch_env_t *env,
    arch_register_req_t *req, const ir_node *irn, int pos)
{
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
Sebastian Hack's avatar
Sebastian Hack committed
84
  req->type = arch_register_req_type_none;
85
  return ops->impl->get_irn_reg_req(ops, req, irn, pos);
Sebastian Hack's avatar
Sebastian Hack committed
86
87
}

Sebastian Hack's avatar
Sebastian Hack committed
88
89
90
91
92
93
void arch_set_stack_bias(const arch_env_t *env, ir_node *irn, int bias)
{
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
  ops->impl->set_stack_bias(ops, irn, bias);
}

94
95
96
97
98
99
entity *arch_get_frame_entity(const arch_env_t *env, ir_node *irn)
{
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
  return ops->impl->get_frame_entity(ops, irn);
}

Sebastian Hack's avatar
Sebastian Hack committed
100

Sebastian Hack's avatar
Sebastian Hack committed
101
int arch_get_allocatable_regs(const arch_env_t *env, const ir_node *irn, int pos, bitset_t *bs)
Sebastian Hack's avatar
Sebastian Hack committed
102
{
Sebastian Hack's avatar
Sebastian Hack committed
103
  arch_register_req_t local_req;
Sebastian Hack's avatar
Sebastian Hack committed
104
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
105
  const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos);
Sebastian Hack's avatar
Sebastian Hack committed
106

Sebastian Hack's avatar
Sebastian Hack committed
107
  if(req->type == arch_register_req_type_none) {
Sebastian Hack's avatar
Sebastian Hack committed
108
109
	  bitset_clear_all(bs);
	  return 0;
Sebastian Hack's avatar
Sebastian Hack committed
110
  }
Sebastian Hack's avatar
Sebastian Hack committed
111

Sebastian Hack's avatar
Sebastian Hack committed
112
  if(arch_register_req_is(req, limited)) {
Sebastian Hack's avatar
Sebastian Hack committed
113
	  req->limited(req->limited_env, bs);
Sebastian Hack's avatar
Sebastian Hack committed
114
115
	  return bitset_popcnt(bs);
  }
Sebastian Hack's avatar
Sebastian Hack committed
116
117
118

  arch_register_class_put(req->cls, bs);
  return req->cls->n_regs;
Sebastian Hack's avatar
Sebastian Hack committed
119
120
}

Sebastian Hack's avatar
Sebastian Hack committed
121
122
123
124
125
126
127
128
129
130
void arch_put_non_ignore_regs(const arch_env_t *env, const arch_register_class_t *cls, bitset_t *bs)
{
	int i;

	for(i = 0; i < cls->n_regs; ++i) {
		if(!arch_register_type_is(&cls->regs[i], ignore))
			bitset_set(bs, i);
	}
}

131
132
133
int arch_is_register_operand(const arch_env_t *env,
    const ir_node *irn, int pos)
{
Sebastian Hack's avatar
Sebastian Hack committed
134
135
	arch_register_req_t local_req;
	const arch_irn_ops_t *ops = get_irn_ops(env, irn);
136
	const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos);
Sebastian Hack's avatar
Sebastian Hack committed
137
	return req != NULL;
138
139
}

Sebastian Hack's avatar
Sebastian Hack committed
140
141
int arch_reg_is_allocatable(const arch_env_t *env, const ir_node *irn,
    int pos, const arch_register_t *reg)
Sebastian Hack's avatar
Sebastian Hack committed
142
{
143
144
145
	arch_register_req_t req;

	arch_get_register_req(env, &req, irn, pos);
Sebastian Hack's avatar
Sebastian Hack committed
146
147
148
149
150
151

	if(req.type == arch_register_req_type_none)
		return 0;

	if(arch_register_req_is(&req, limited)) {
		bitset_t *bs = bitset_alloca(req.cls->n_regs);
Sebastian Hack's avatar
Sebastian Hack committed
152
		req.limited(req.limited_env, bs);
Sebastian Hack's avatar
Sebastian Hack committed
153
		return bitset_is_set(bs, arch_register_get_index(reg));
154
155
	}

Sebastian Hack's avatar
Sebastian Hack committed
156
	return req.cls == reg->reg_class;
Sebastian Hack's avatar
Sebastian Hack committed
157
158
}

Sebastian Hack's avatar
Sebastian Hack committed
159
160
const arch_register_class_t *
arch_get_irn_reg_class(const arch_env_t *env, const ir_node *irn, int pos)
Sebastian Hack's avatar
Sebastian Hack committed
161
{
Sebastian Hack's avatar
Sebastian Hack committed
162
  arch_register_req_t local_req;
Sebastian Hack's avatar
Sebastian Hack committed
163
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
164
  const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos);
Sebastian Hack's avatar
Sebastian Hack committed
165
  return req ? req->cls : NULL;
Sebastian Hack's avatar
Sebastian Hack committed
166
167
}

Sebastian Hack's avatar
Sebastian Hack committed
168
extern const arch_register_t *
Sebastian Hack's avatar
Sebastian Hack committed
169
arch_get_irn_register(const arch_env_t *env, const ir_node *irn)
170
{
Sebastian Hack's avatar
Sebastian Hack committed
171
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
172
  return ops->impl->get_irn_reg(ops, irn);
173
}
174

Sebastian Hack's avatar
Sebastian Hack committed
175
extern void arch_set_irn_register(const arch_env_t *env,
Sebastian Hack's avatar
Sebastian Hack committed
176
    ir_node *irn, const arch_register_t *reg)
177
{
Sebastian Hack's avatar
Sebastian Hack committed
178
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
179
  ops->impl->set_irn_reg(ops, irn, reg);
180
}
181
182
183
184

extern arch_irn_class_t arch_irn_classify(const arch_env_t *env, const ir_node *irn)
{
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
185
  return ops->impl->classify(ops, irn);
186
}
Sebastian Hack's avatar
Sebastian Hack committed
187
188
189
190

extern arch_irn_flags_t arch_irn_get_flags(const arch_env_t *env, const ir_node *irn)
{
  const arch_irn_ops_t *ops = get_irn_ops(env, irn);
191
  return ops->impl->get_flags(ops, irn);
Sebastian Hack's avatar
Sebastian Hack committed
192
}
Sebastian Hack's avatar
Sebastian Hack committed
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234

extern const char *arch_irn_flag_str(arch_irn_flags_t fl)
{
	switch(fl) {
#define XXX(x) case arch_irn_flags_ ## x: return #x;
		XXX(dont_spill);
		XXX(ignore);
		XXX(rematerializable);
		XXX(none);
#undef XXX
	}
	return "n/a";
}

extern char *arch_register_req_format(char *buf, size_t len, const arch_register_req_t *req)
{
	char tmp[128];
	snprintf(buf, len, "class: %s", req->cls->name);

	if(arch_register_req_is(req, limited)) {
		bitset_pos_t elm;
		bitset_t *bs = bitset_alloca(req->cls->n_regs);
		req->limited(req->limited_env, bs);
		strncat(buf, " limited:", len);
		bitset_foreach(bs, elm) {
			strncat(buf, " ", len);
			strncat(buf, req->cls->regs[elm].name, len);
		}
	}

	if(arch_register_req_is(req, should_be_same)) {
		snprintf(tmp, sizeof(tmp), " same to: %+F", req->other_different);
		strncat(buf, tmp, len);
	}

	if(arch_register_req_is(req, should_be_different)) {
		snprintf(tmp, sizeof(tmp), " different to: %+F", req->other_different);
		strncat(buf, tmp, len);
	}

	return buf;
}