amd64_new_nodes.c 9.27 KB
Newer Older
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
4
5
6
7
8
9
10
11
12
 */

/**
 * @file
 * @brief   This file implements the creation of the achitecture specific firm
 *          opcodes and the coresponding node constructors for the amd64
 *          assembler irg.
 */
#include <stdlib.h>
Matthias Braun's avatar
Matthias Braun committed
13
#include <inttypes.h>
14

15
#include "error.h"
16
17
18
19
20
21
22
23
24
25
#include "irprog_t.h"
#include "irgraph_t.h"
#include "irnode_t.h"
#include "irmode_t.h"
#include "ircons_t.h"
#include "iropt_t.h"
#include "irop.h"
#include "irprintf.h"
#include "xmalloc.h"

26
#include "bearch.h"
27
28
29
30
31

#include "amd64_nodes_attr.h"
#include "amd64_new_nodes.h"
#include "gen_amd64_regalloc_if.h"

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
static const char *get_op_mode_string(amd64_op_mode_t mode)
{
	switch (mode) {
	case AMD64_OP_NONE:       return "none";
	case AMD64_OP_ADDR:       return "addr";
	case AMD64_OP_REG:        return "reg";
	case AMD64_OP_REG_REG:    return "reg+reg";
	case AMD64_OP_REG_IMM:    return "reg+imm";
	case AMD64_OP_IMM32:      return "imm32";
	case AMD64_OP_IMM64:      return "imm64";
	case AMD64_OP_ADDR_REG:   return "addr+reg";
	case AMD64_OP_ADDR_IMM:   return "addr+imm";
	case AMD64_OP_UNOP_REG:   return "unop_reg";
	case AMD64_OP_SHIFT_REG:  return "shift_reg";
	case AMD64_OP_SHIFT_IMM:  return "shift_imm";
	case AMD64_OP_CALL_ADDR:  return "call_addr";
	case AMD64_OP_CALL_IMM32: return "call_imm32";
	case AMD64_OP_RAX_REG:    return "rax_reg";
	case AMD64_OP_RAX_ADDR:   return "rax_addr";
	}
	panic("invalid op_mode");
}

static const char *get_insn_mode_string(amd64_insn_mode_t mode)
{
	switch (mode) {
	case INSN_MODE_8:  return "8";
	case INSN_MODE_16: return "16";
	case INSN_MODE_32: return "32";
	case INSN_MODE_64: return "64";
	}
	panic("invalid insn_mode");
}

66
67
68
/**
 * Dumper interface for dumping amd64 nodes in vcg.
 * @param F        the output file
69
 * @param n        the node to dump
70
71
 * @param reason   indicates which kind of information should be dumped
 */
72
static void amd64_dump_node(FILE *F, const ir_node *n, dump_reason_t reason)
73
74
75
76
77
78
79
{
	switch (reason) {
	case dump_node_opcode_txt:
		fprintf(F, "%s", get_irn_opname(n));
		break;

	case dump_node_mode_txt:
80
		fprintf(F, "[%s]", get_mode_name(get_irn_mode(n)));
81
82
83
84
85
86
87
		break;

	case dump_node_nodeattr_txt:
		break;

	case dump_node_info_txt:
		arch_dump_reqs_and_registers(F, n);
Matthias Braun's avatar
Matthias Braun committed
88
		const amd64_attr_t *attr = get_amd64_attr_const(n);
89
90
91
92
93
94
		fprintf(F, "mode = %s\n", get_op_mode_string(attr->op_mode));
		if (attr->op_mode == AMD64_OP_UNOP_REG) {
			const amd64_unop_attr_t *unop_attr = get_amd64_unop_attr_const(n);
			fprintf(F, "size = %s\n",
			        get_insn_mode_string(unop_attr->insn_mode));
		} else if (attr->op_mode == AMD64_OP_ADDR_REG) {
Matthias Braun's avatar
Matthias Braun committed
95
			const amd64_binop_addr_attr_t *binop_attr
96
				= get_amd64_binop_addr_attr_const(n);
Matthias Braun's avatar
Matthias Braun committed
97
98
99
			fprintf(F, "reg input: %d\n", binop_attr->u.reg_input);
		}
		if (attr->op_mode == AMD64_OP_ADDR_REG
100
		    || attr->op_mode == AMD64_OP_ADDR) {
Matthias Braun's avatar
Matthias Braun committed
101
			const amd64_addr_attr_t *addr_attr
102
103
104
				= get_amd64_addr_attr_const(n);
			fprintf(F, "size = %s\n",
			        get_insn_mode_string(addr_attr->insn_mode));
Matthias Braun's avatar
Matthias Braun committed
105
106
107
108
109
			fprintf(F, "base input: %d\n", addr_attr->addr.base_input);
			fprintf(F, "index input: %d\n", addr_attr->addr.index_input);
			ir_fprintf(F, "am imm: %+F%+" PRId32 "\n",
			           addr_attr->addr.immediate.entity,
					   addr_attr->addr.immediate.offset);
Matthias Braun's avatar
Matthias Braun committed
110
		}
111
112
113
114
		break;
	}
}

Matthias Braun's avatar
Matthias Braun committed
115
116
static void init_be_info(ir_node *node, arch_irn_flags_t flags,
                         const arch_register_req_t **in_reqs, int n_res)
117
{
118
119
120
121
122
123
124
	arch_set_irn_flags(node, flags);
	arch_set_irn_register_reqs_in(node, in_reqs);

	ir_graph       *irg  = get_irn_irg(node);
	struct obstack *obst = get_irg_obstack(irg);
	backend_info_t *info = be_get_info(node);
	info->out_infos = NEW_ARR_DZ(reg_out_info_t, obst, n_res);
125
126
}

Matthias Braun's avatar
Matthias Braun committed
127
128
129
static void init_amd64_attributes(ir_node *node, arch_irn_flags_t flags,
                                  const arch_register_req_t **in_reqs,
                                  int n_res, amd64_op_mode_t op_mode)
130
{
Matthias Braun's avatar
Matthias Braun committed
131
132
133
134
	init_be_info(node, flags, in_reqs, n_res);
	amd64_attr_t *attr = get_amd64_attr(node);
	attr->op_mode = op_mode;
}
135

Matthias Braun's avatar
Matthias Braun committed
136
137
138
139
static void init_amd64_switch_attributes(ir_node *node,
                                         const ir_switch_table *table,
                                         ir_entity *table_entity)
{
140
141
142
143
	amd64_switch_jmp_attr_t *attr = get_amd64_switch_jmp_attr(node);
	attr->table        = table;
	attr->table_entity = table_entity;

Matthias Braun's avatar
Matthias Braun committed
144
	for (unsigned o = 0, n_outs = arch_get_irn_n_outs(node); o < n_outs; o++) {
145
146
147
148
		arch_set_irn_register_req_out(node, o, arch_no_register_req);
	}
}

149
static void init_amd64_cc_attributes(ir_node *node, x86_condition_code_t cc)
150
{
151
	amd64_cc_attr_t *attr = get_amd64_cc_attr(node);
152
	attr->cc = cc;
153
154
}

Matthias Braun's avatar
Matthias Braun committed
155
156
157
static void init_amd64_movimm_attributes(ir_node *node,
                                         amd64_insn_mode_t insn_mode,
                                         ir_entity *entity, int64_t offset)
158
{
159
	amd64_movimm_attr_t *attr = get_amd64_movimm_attr(node);
Matthias Braun's avatar
Matthias Braun committed
160
161
162
	attr->insn_mode        = insn_mode;
	attr->immediate.entity = entity;
	attr->immediate.offset = offset;
163
164
}

Matthias Braun's avatar
Matthias Braun committed
165
166
static int cmp_imm32(const amd64_imm32_t *const imm0,
                     const amd64_imm32_t *const imm1)
Matthias Braun's avatar
Matthias Braun committed
167
{
Matthias Braun's avatar
Matthias Braun committed
168
169
170
171
172
173
174
175
176
177
178
179
180
	return imm0->offset != imm1->offset || imm0->entity != imm1->entity;
}

static int cmp_imm64(const amd64_imm64_t *const imm0,
                     const amd64_imm64_t *const imm1)
{
	return imm0->offset != imm1->offset || imm0->entity != imm1->entity;
}

static int cmp_addr(const amd64_addr_t *const am0,
                    const amd64_addr_t *const am1)
{
	return cmp_imm32(&am0->immediate, &am1->immediate)
Matthias Braun's avatar
Matthias Braun committed
181
182
183
184
185
186
	    || am0->base_input != am1->base_input
	    || am0->index_input != am1->index_input
	    || am0->log_scale != am1->log_scale
	    || am0->segment != am1->segment;
}

Michael Beck's avatar
Michael Beck committed
187
static int cmp_amd64_attr(const ir_node *a, const ir_node *b)
188
189
190
{
	const amd64_attr_t *attr_a = get_amd64_attr_const(a);
	const amd64_attr_t *attr_b = get_amd64_attr_const(b);
Matthias Braun's avatar
Matthias Braun committed
191
192
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
	return attr_a->op_mode != attr_b->op_mode;
}

static int cmp_amd64_addr_attr(const ir_node *a, const ir_node *b)
{
	const amd64_addr_attr_t *attr_a = get_amd64_addr_attr_const(a);
	const amd64_addr_attr_t *attr_b = get_amd64_addr_attr_const(b);
	return cmp_amd64_attr(a, b)
	    || cmp_addr(&attr_a->addr, &attr_b->addr)
	    || attr_a->insn_mode != attr_b->insn_mode
	    || attr_a->needs_frame_ent != attr_b->needs_frame_ent;
}

static int cmp_amd64_unop_attr(const ir_node *a, const ir_node *b)
{
	const amd64_unop_attr_t *attr_a = get_amd64_unop_attr_const(a);
	const amd64_unop_attr_t *attr_b = get_amd64_unop_attr_const(b);
	return cmp_amd64_attr(a, b)
	    || attr_a->insn_mode != attr_b->insn_mode;
}

static int cmp_amd64_binop_addr_attr(const ir_node *a,
                                     const ir_node *b)
{
	const amd64_binop_addr_attr_t *attr_a = get_amd64_binop_addr_attr_const(a);
	const amd64_binop_addr_attr_t *attr_b = get_amd64_binop_addr_attr_const(b);
	if (cmp_amd64_addr_attr(a, b))
		return 1;
	amd64_op_mode_t op_mode = attr_a->base.base.op_mode;
	if (op_mode == AMD64_OP_REG_IMM || op_mode == AMD64_OP_ADDR_IMM) {
		return cmp_imm32(&attr_a->u.immediate, &attr_b->u.immediate);
	} else {
		return attr_a->u.reg_input != attr_b->u.reg_input;
	}
225
226
227
228
229
230
231
}

static int cmp_amd64_movimm_attr(const ir_node *const a,
                                 const ir_node *const b)
{
	const amd64_movimm_attr_t *const attr_a = get_amd64_movimm_attr_const(a);
	const amd64_movimm_attr_t *const attr_b = get_amd64_movimm_attr_const(b);
Matthias Braun's avatar
Matthias Braun committed
232
233
234
235
236
237
238
239
240
241
242
243
244
	return cmp_amd64_attr(a, b)
	    || cmp_imm64(&attr_a->immediate, &attr_b->immediate)
	    || attr_a->insn_mode != attr_b->insn_mode;
}

static int cmp_amd64_shift_attr(const ir_node *const a,
                                const ir_node *const b)
{
	const amd64_shift_attr_t *const attr_a = get_amd64_shift_attr_const(a);
	const amd64_shift_attr_t *const attr_b = get_amd64_shift_attr_const(b);
	return cmp_amd64_attr(a, b)
	    || attr_a->immediate != attr_b->immediate
	    || attr_a->insn_mode != attr_b->insn_mode;
245
246
247
248
249
250
251
252
253
}

static int cmp_amd64_cc_attr(const ir_node *const a,
                             const ir_node *const b)
{
	if (cmp_amd64_attr(a, b))
		return true;
	const amd64_cc_attr_t *const attr_a = get_amd64_cc_attr_const(a);
	const amd64_cc_attr_t *const attr_b = get_amd64_cc_attr_const(b);
254
	return attr_a->cc != attr_b->cc;
255
256
257
258
259
260
261
262
263
264
265
266
}

static int cmp_amd64_switch_jmp_attr(const ir_node *const a,
                                    const ir_node *const b)
{
	if (cmp_amd64_attr(a, b))
		return true;
	const amd64_switch_jmp_attr_t *const attr_a
		= get_amd64_switch_jmp_attr_const(a);
	const amd64_switch_jmp_attr_t *const attr_b
		= get_amd64_switch_jmp_attr_const(b);
	return attr_a->table != attr_b->table;
267
268
}

269
static void amd64_copy_attr(ir_graph *irg, const ir_node *old_node,
270
                            ir_node *new_node)
271
272
273
274
275
276
277
278
279
280
281
{
	struct obstack   *obst       = get_irg_obstack(irg);
	const amd64_attr_t *attr_old = get_amd64_attr_const(old_node);
	amd64_attr_t     *attr_new   = get_amd64_attr(new_node);
	backend_info_t   *old_info   = be_get_info(old_node);
	backend_info_t   *new_info   = be_get_info(new_node);

	/* copy the attributes */
	memcpy(attr_new, attr_old, get_op_attr_size(get_irn_op(old_node)));

	/* copy out flags */
282
	new_info->flags = old_info->flags;
283
284
	new_info->out_infos =
		DUP_ARR_D(reg_out_info_t, obst, old_info->out_infos);
285
	new_info->in_reqs = old_info->in_reqs;
286
287
}

288
289
/* Include the generated constructor functions */
#include "gen_amd64_new_nodes.c.inl"