bearch: Disallow passing Projs to get_irn_ops().
[libfirm] / ir / be / bearch.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief       Processor architecture specification.
9  * @author      Sebastian Hack
10  */
11 #include "config.h"
12
13 #include <string.h>
14
15 #include "bearch.h"
16 #include "benode.h"
17 #include "beinfo.h"
18 #include "ircons_t.h"
19 #include "irnode_t.h"
20 #include "irop_t.h"
21
22 #include "bitset.h"
23 #include "pset.h"
24 #include "raw_bitset.h"
25
26 #include "irprintf.h"
27
28 arch_register_req_t const arch_no_requirement = {
29         arch_register_req_type_none,
30         NULL,
31         NULL,
32         0,
33         0,
34         0
35 };
36
37 /**
38  * Get the isa responsible for a node.
39  * @param irn The node to get the responsible isa for.
40  * @return The irn operations given by the responsible isa.
41  */
42 static const arch_irn_ops_t *get_irn_ops(const ir_node *irn)
43 {
44         ir_op          const *const op     = get_irn_op(irn);
45         arch_irn_ops_t const *const be_ops = get_op_ops(op)->be_ops;
46         assert(be_ops);
47         return be_ops;
48 }
49
50 void arch_set_frame_offset(ir_node *irn, int offset)
51 {
52         const arch_irn_ops_t *ops = get_irn_ops(irn);
53         ops->set_frame_offset(irn, offset);
54 }
55
56 ir_entity *arch_get_frame_entity(const ir_node *irn)
57 {
58         const arch_irn_ops_t *ops = get_irn_ops(irn);
59         return ops->get_frame_entity(irn);
60 }
61
62 int arch_get_sp_bias(ir_node *irn)
63 {
64         const arch_irn_ops_t *ops = get_irn_ops(irn);
65         return ops->get_sp_bias(irn);
66 }
67
68 int arch_possible_memory_operand(const ir_node *irn, unsigned int i)
69 {
70         const arch_irn_ops_t *ops = get_irn_ops(irn);
71
72         if (ops->possible_memory_operand) {
73                 return ops->possible_memory_operand(irn, i);
74         } else {
75                 return 0;
76         }
77 }
78
79 void arch_perform_memory_operand(ir_node *irn, ir_node *spill, unsigned int i)
80 {
81         const arch_irn_ops_t *ops = get_irn_ops(irn);
82         ops->perform_memory_operand(irn, spill, i);
83 }
84
85 int arch_get_op_estimated_cost(const ir_node *irn)
86 {
87         const arch_irn_ops_t *ops = get_irn_ops(irn);
88
89         if (ops->get_op_estimated_cost) {
90                 return ops->get_op_estimated_cost(irn);
91         } else {
92                 return 1;
93         }
94 }
95
96 static reg_out_info_t *get_out_info_n(const ir_node *node, unsigned pos)
97 {
98         const backend_info_t *info = be_get_info(node);
99         assert(pos < (unsigned)ARR_LEN(info->out_infos));
100         return &info->out_infos[pos];
101 }
102
103
104 const arch_register_t *arch_get_irn_register(const ir_node *node)
105 {
106         const reg_out_info_t *out = get_out_info(node);
107         return out->reg;
108 }
109
110 const arch_register_t *arch_get_irn_register_out(const ir_node *node,
111                                                  unsigned pos)
112 {
113         const reg_out_info_t *out = get_out_info_n(node, pos);
114         return out->reg;
115 }
116
117 const arch_register_t *arch_get_irn_register_in(const ir_node *node, int pos)
118 {
119         ir_node *op = get_irn_n(node, pos);
120         return arch_get_irn_register(op);
121 }
122
123 void arch_set_irn_register_out(ir_node *node, unsigned pos,
124                                const arch_register_t *reg)
125 {
126         reg_out_info_t *out = get_out_info_n(node, pos);
127         out->reg            = reg;
128 }
129
130 void arch_set_irn_register(ir_node *node, const arch_register_t *reg)
131 {
132         reg_out_info_t *out = get_out_info(node);
133         out->reg = reg;
134 }
135
136 void arch_set_irn_flags(ir_node *node, arch_irn_flags_t flags)
137 {
138         backend_info_t *const info = be_get_info(node);
139         info->flags = flags;
140 }
141
142 void arch_add_irn_flags(ir_node *node, arch_irn_flags_t flags)
143 {
144         backend_info_t *const info = be_get_info(node);
145         info->flags |= flags;
146 }
147
148 bool arch_reg_is_allocatable(const arch_register_req_t *req,
149                              const arch_register_t *reg)
150 {
151         assert(req->type != arch_register_req_type_none);
152         if (req->cls != reg->reg_class)
153                 return false;
154         if (reg->type & arch_register_type_virtual)
155                 return true;
156         if (arch_register_req_is(req, limited))
157                 return rbitset_is_set(req->limited, reg->index);
158         return true;
159 }
160
161 /**
162  * Print information about a register requirement in human readable form
163  * @param F   output stream/file
164  * @param req The requirements structure to format.
165  */
166 static void arch_dump_register_req(FILE *F, const arch_register_req_t *req,
167                             const ir_node *node)
168 {
169         if (req == NULL || req->type == arch_register_req_type_none) {
170                 fprintf(F, "n/a");
171                 return;
172         }
173
174         fprintf(F, "%s", req->cls->name);
175
176         if (arch_register_req_is(req, limited)) {
177                 unsigned n_regs = req->cls->n_regs;
178                 unsigned i;
179
180                 fprintf(F, " limited to");
181                 for (i = 0; i < n_regs; ++i) {
182                         if (rbitset_is_set(req->limited, i)) {
183                                 const arch_register_t *reg = &req->cls->regs[i];
184                                 fprintf(F, " %s", reg->name);
185                         }
186                 }
187         }
188
189         if (arch_register_req_is(req, should_be_same)) {
190                 const unsigned other = req->other_same;
191                 int i;
192
193                 fprintf(F, " same as");
194                 for (i = 0; 1U << i <= other; ++i) {
195                         if (other & (1U << i)) {
196                                 ir_fprintf(F, " #%d (%+F)", i, get_irn_n(skip_Proj_const(node), i));
197                         }
198                 }
199         }
200
201         if (arch_register_req_is(req, must_be_different)) {
202                 const unsigned other = req->other_different;
203                 int i;
204
205                 fprintf(F, " different from");
206                 for (i = 0; 1U << i <= other; ++i) {
207                         if (other & (1U << i)) {
208                                 ir_fprintf(F, " #%d (%+F)", i, get_irn_n(skip_Proj_const(node), i));
209                         }
210                 }
211         }
212
213         if (req->width != 1) {
214                 fprintf(F, " width:%d", req->width);
215         }
216         if (arch_register_req_is(req, aligned)) {
217                 fprintf(F, " aligned");
218         }
219         if (arch_register_req_is(req, ignore)) {
220                 fprintf(F, " ignore");
221         }
222         if (arch_register_req_is(req, produces_sp)) {
223                 fprintf(F, " produces_sp");
224         }
225 }
226
227 void arch_dump_reqs_and_registers(FILE *F, const ir_node *node)
228 {
229         backend_info_t *const info  = be_get_info(node);
230         int             const n_ins = get_irn_arity(node);
231         /* don't fail on invalid graphs */
232         if (!info || (!info->in_reqs && n_ins != 0) || !info->out_infos) {
233                 fprintf(F, "invalid register requirements!!!\n");
234                 return;
235         }
236
237         for (int i = 0; i < n_ins; ++i) {
238                 const arch_register_req_t *req = arch_get_irn_register_req_in(node, i);
239                 fprintf(F, "inreq #%d = ", i);
240                 arch_dump_register_req(F, req, node);
241                 fputs("\n", F);
242         }
243         be_foreach_out(node, o) {
244                 const arch_register_req_t *req = arch_get_irn_register_req_out(node, o);
245                 fprintf(F, "outreq #%u = ", o);
246                 arch_dump_register_req(F, req, node);
247                 const arch_register_t *reg = arch_get_irn_register_out(node, o);
248                 fprintf(F, " [%s]\n", reg != NULL ? reg->name : "n/a");
249         }
250
251         fprintf(F, "flags =");
252         arch_irn_flags_t flags = arch_get_irn_flags(node);
253         if (flags == arch_irn_flags_none) {
254                 fprintf(F, " none");
255         } else {
256                 if (flags & arch_irn_flags_dont_spill) {
257                         fprintf(F, " unspillable");
258                 }
259                 if (flags & arch_irn_flags_rematerializable) {
260                         fprintf(F, " remat");
261                 }
262                 if (flags & arch_irn_flags_modify_flags) {
263                         fprintf(F, " modify_flags");
264                 }
265                 if (flags & arch_irn_flags_simple_jump) {
266                         fprintf(F, " simple_jump");
267                 }
268                 if (flags & arch_irn_flags_not_scheduled) {
269                         fprintf(F, " not_scheduled");
270                 }
271         }
272         fprintf(F, " (0x%x)\n", (unsigned)flags);
273 }