summaryrefslogtreecommitdiffhomepage
path: root/ir/be/benode.h
blob: f1f582d5844f68b7423205f626e982a8c63f102d (plain)
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
29
30
31
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
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
96
97
98
99
100
101
102
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
131
132
133
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
 * This file is part of libFirm.
 * Copyright (C) 2012 University of Karlsruhe.
 */

/**
 * @file
 * @brief       Backend node support for generic backend nodes.
 * @author      Sebastian Hack
 * @date        17.05.2005
 *
 * Backend node support for generic backend nodes.
 * This file provides Perm, and Copy nodes.
 */
#ifndef FIRM_BE_BENODE_H
#define FIRM_BE_BENODE_H

#include "be_types.h"
#include "firm_types.h"
#include "irnode_t.h"

typedef enum be_opcode {
	beo_Asm,
	beo_first = beo_Asm,
	beo_Copy,
	beo_CopyKeep,
	beo_IncSP,
	beo_Keep,
	beo_MemPerm,
	beo_Perm,
	beo_Relocation,
	beo_Start,
	beo_Unknown,
	beo_last  = beo_Unknown
} be_opcode;

typedef struct be_asm_attr_t {
	except_attr exc;
	ident      *text;
	void       *operands;
} be_asm_attr_t;

typedef struct be_switch_attr_t {
	ir_switch_table const *table;
	ir_entity       const *table_entity;
} be_switch_attr_t;

extern ir_op *op_be_Asm;
extern ir_op *op_be_Copy;
extern ir_op *op_be_CopyKeep;
extern ir_op *op_be_IncSP;
extern ir_op *op_be_Keep;
extern ir_op *op_be_MemPerm;
extern ir_op *op_be_Perm;
extern ir_op *op_be_Relocation;
extern ir_op *op_be_Start;
extern ir_op *op_be_Unknown;

/**
 * Determines if irn is a be_node.
 */
bool is_be_node(const ir_node *irn);

/**
 * Create all BE specific opcodes.
 */
void be_init_op(void);

void be_finish_op(void);

/**
 * Position numbers for the be_Copy inputs.
 */
enum {
	n_be_Copy_op = 0
};

/**
 * Make a new Copy node.
 */
ir_node *be_new_d_Copy(dbg_info *dbgi, ir_node *block, ir_node *op);
ir_node *be_new_Copy(ir_node *block, ir_node *in);
/** Returns the Copy Argument. */
ir_node *be_get_Copy_op(const ir_node *cpy);

/**
 * Insert a Copy of @p val into @p reg before @p before.
 */
ir_node *be_new_Copy_before_reg(ir_node *val, ir_node *before, arch_register_t const *reg);

/**
 * Make a new Perm node.
 */
ir_node *be_new_Perm(ir_node *block, int n, ir_node *const *in);

/**
 * Create a new MemPerm node.
 * A MemPerm node exchanges the values of memory locations. (Typically entities
 * used as spillslots). MemPerm nodes perform this operation without modifying
 * any register values.
 */
ir_node *be_new_MemPerm(ir_node *block, int n, ir_node *const *in);

ir_node *be_new_Keep(ir_node *block, int arity, ir_node *const *in);
ir_node *be_new_Keep_one(ir_node *kept);

enum {
	n_be_IncSP_pred
};

/**
 * Make a stack pointer increase/decrease node.
 * @param block  The block to insert the node into.
 * @param old_sp The node defining the former stack pointer.
 * @param offset amount the stack should expand (positive offset) or shrink
 *               (negative offset). Note that the offset is independent of the
 *               natural stack direction of the architecture but just specifies
 *               abstract expanding/shrinking of the stack area.
 * @param no_align   Ignore SP alignment requirements.
 * @return       A new stack pointer increment/decrement node.
 * @note         This node sets a register constraint to the @p sp register on
 *               its output.
 */
ir_node *be_new_IncSP(ir_node *block, ir_node *old_sp, int offset, bool no_align);

/** Returns the previous node that computes the stack pointer. */
ir_node *be_get_IncSP_pred(ir_node *incsp);

/** Sets the previous node that computes the stack pointer. */
void be_set_IncSP_pred(ir_node *incsp, ir_node *pred);

/**
 * Sets a new offset to a IncSP node.
 * A positive offset means expanding the stack, a negative offset shrinking
 * an offset is == BE_STACK_FRAME_SIZE will be replaced by the real size of the
 * stackframe in the fix_stack_offsets phase.
 */
void be_set_IncSP_offset(ir_node *irn, int offset);

/** Gets the offset from a IncSP node. */
int be_get_IncSP_offset(const ir_node *irn);
bool be_get_IncSP_no_align(const ir_node *irn);

enum {
	n_be_CopyKeep_op,
	n_be_CopyKeep_max = n_be_CopyKeep_op
};
ir_node *be_new_CopyKeep(ir_node *block, ir_node *src, int n, ir_node *const *in_keep);

ir_node *be_get_CopyKeep_op(const ir_node *cpy);

void be_set_MemPerm_in_entity(const ir_node *irn, unsigned n, ir_entity* ent);
ir_entity *be_get_MemPerm_in_entity(const ir_node *irn, unsigned n);

void be_set_MemPerm_out_entity(const ir_node *irn, unsigned n, ir_entity* ent);
ir_entity *be_get_MemPerm_out_entity(const ir_node *irn, unsigned n);

void be_set_MemPerm_offset(ir_node *irn, int offset);
int be_get_MemPerm_offset(const ir_node *irn);

unsigned be_get_MemPerm_entity_arity(const ir_node *irn);

arch_register_req_t const **be_allocate_in_reqs(ir_graph *irg, unsigned n);

/**
 * Set the register requirements for a phi node.
 */
void be_set_phi_reg_req(ir_node *phi, const arch_register_req_t *req);

/**
 * Creates a new phi with associated backend informations
 */
ir_node *be_new_Phi(ir_node *block, int n_ins, ir_node **ins, arch_register_req_t const *req);

/**
 * Create a new Phi with backend info and without inputs.
 * Inputs are added later with @see be_complete_Phi().
 */
ir_node *be_new_Phi0(ir_node *block, arch_register_req_t const *req);

/**
 * Add inputs to a inputless Phi created by @see be_new_Phi0().
 */
ir_node *be_complete_Phi(ir_node *phi, unsigned n_ins, ir_node **ins);

enum {
	n_be_Asm_mem,
	n_be_Asm_first_in,
};

enum {
	pn_be_Asm_M,
	pn_be_Asm_X_regular,
	pn_be_Asm_first_out,
};

ir_node *be_new_Asm(dbg_info *dbgi, ir_node *block, int n_ins, ir_node **ins, arch_register_req_t const **in_reqs, int n_outs, ident *text, void *operands);

/**
 * Create a new Relocation node. The node returns the reference to an entity
 * with a specific linker relocation kind. The relocation kind is backend
 * specific. This node is meant to be used in preparation phases for position
 * independent code.
 */
ir_node *be_new_Relocation(dbg_info *dbgi, ir_graph *irg, unsigned kind, ir_entity *entity, ir_mode *mode);

ir_entity *be_get_Relocation_entity(ir_node const* node);

unsigned be_get_Relocation_kind(ir_node const* node);

typedef enum be_start_out {
	BE_START_NO,
	BE_START_REG,
	BE_START_IGNORE,
} be_start_out;

ir_node *be_new_Start(ir_graph *irg, be_start_out const *outs);

ir_node *be_get_Start_mem(ir_graph *irg);

/**
 * Get Proj of start node with a specific register.
 */
ir_node *be_get_Start_proj(ir_graph *irg, arch_register_t const *reg);

ir_node *be_new_Unknown(ir_node *block, arch_register_req_t const *req);

/**
 * Create a new Proj node.  Its mode is determined from the out requirement
 * @p pos of @p pred.
 */
ir_node *be_new_Proj(ir_node *pred, unsigned pos);

ir_node *be_new_Proj_reg(ir_node *pred, unsigned pos, arch_register_t const *reg);

/**
 * Gets the Proj with number pn from irn.
 * Creates the Proj, if it does not exist, yet.
 */
ir_node *be_get_or_make_Proj_for_pn(ir_node *irn, unsigned pn);

static inline bool be_is_Asm       (const ir_node *irn) { return get_irn_op(irn) == op_be_Asm       ; }
static inline bool be_is_Copy      (const ir_node *irn) { return get_irn_op(irn) == op_be_Copy      ; }
static inline bool be_is_CopyKeep  (const ir_node *irn) { return get_irn_op(irn) == op_be_CopyKeep  ; }
static inline bool be_is_Perm      (const ir_node *irn) { return get_irn_op(irn) == op_be_Perm      ; }
static inline bool be_is_MemPerm   (const ir_node *irn) { return get_irn_op(irn) == op_be_MemPerm   ; }
static inline bool be_is_Keep      (const ir_node *irn) { return get_irn_op(irn) == op_be_Keep      ; }
static inline bool be_is_IncSP     (const ir_node *irn) { return get_irn_op(irn) == op_be_IncSP     ; }
static inline bool be_is_Relocation(const ir_node *irn) { return get_irn_op(irn) == op_be_Relocation; }
static inline bool be_is_Start     (const ir_node *irn) { return get_irn_op(irn) == op_be_Start     ; }
static inline bool be_is_Unknown   (const ir_node *irn) { return get_irn_op(irn) == op_be_Unknown   ; }

static inline be_asm_attr_t const *get_be_asm_attr_const(ir_node const *const asmn)
{
	assert(be_is_Asm(asmn));
	return (be_asm_attr_t const*)get_irn_generic_attr_const(asmn);
}

/**
 * Copies the backend specific attributes from old node to new node.
 */
void be_copy_attr(ir_graph *irg, ir_node const *old_node, ir_node *new_node);

void be_switch_attr_init(ir_node *node, be_switch_attr_t *attr, ir_switch_table const *table, ir_entity const *table_entity);

static inline int be_switch_attrs_equal(be_switch_attr_t const *const a, be_switch_attr_t const *const b)
{
	return a->table == b->table && a->table_entity == b->table_entity;
}

#endif