code refactoring for full addressmode support and more architecture independence
[libfirm] / ir / be / ia32 / ia32_map_regs.c
1 /**
2  * Register mapping for firm nodes. Stolen from bearch_firm :)
3  * $Id$
4  */
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif
8
9 #include <stdlib.h>
10
11 #include "ia32_map_regs.h"
12 #include "ia32_new_nodes.h"
13 #include "gen_ia32_regalloc_if.h"
14
15 static int maxnum_gpreg_args = 3;   /* maximum number of int arguments passed in registers; default 3 */
16 static int maxnum_fpreg_args = 5;   /* maximum number of float arguments passed in registers; default 5 */
17
18 /* this is the order of the assigned registers usesd for parameter passing */
19
20 const ia32_register_req_t *gpreg_param_req_std[] = {
21         &ia32_default_req_ia32_gp_eax,
22         &ia32_default_req_ia32_gp_ecx,
23         &ia32_default_req_ia32_gp_edx,
24         &ia32_default_req_ia32_gp_ebx,
25         &ia32_default_req_ia32_gp_edi,
26         &ia32_default_req_ia32_gp_esi
27 };
28
29 const ia32_register_req_t *gpreg_param_req_this[] = {
30         &ia32_default_req_ia32_gp_ecx,
31         &ia32_default_req_ia32_gp_eax,
32         &ia32_default_req_ia32_gp_edx,
33         &ia32_default_req_ia32_gp_ebx,
34         &ia32_default_req_ia32_gp_edi,
35         &ia32_default_req_ia32_gp_esi
36 };
37
38 const ia32_register_req_t *fpreg_param_req_std[] = {
39         &ia32_default_req_ia32_fp_xmm0,
40         &ia32_default_req_ia32_fp_xmm1,
41         &ia32_default_req_ia32_fp_xmm2,
42         &ia32_default_req_ia32_fp_xmm3,
43         &ia32_default_req_ia32_fp_xmm4,
44         &ia32_default_req_ia32_fp_xmm5,
45         &ia32_default_req_ia32_fp_xmm6,
46         &ia32_default_req_ia32_fp_xmm7
47 };
48
49 const ia32_register_req_t *fpreg_param_req_this[] = {
50         NULL,  /* in case of a "this" pointer, the first parameter must not be a float */
51         &ia32_default_req_ia32_fp_xmm0,
52         &ia32_default_req_ia32_fp_xmm1,
53         &ia32_default_req_ia32_fp_xmm2,
54         &ia32_default_req_ia32_fp_xmm3,
55         &ia32_default_req_ia32_fp_xmm4,
56         &ia32_default_req_ia32_fp_xmm5,
57         &ia32_default_req_ia32_fp_xmm6,
58         &ia32_default_req_ia32_fp_xmm7
59 };
60
61
62
63 /* Mapping to store registers in firm nodes */
64
65 struct ia32_irn_reg_assoc {
66         const ir_node *irn;
67         const arch_register_t *reg;
68 };
69
70 int ia32_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
71         const struct ia32_irn_reg_assoc *x = a;
72         const struct ia32_irn_reg_assoc *y = b;
73
74         return x->irn != y->irn;
75 }
76
77 static struct ia32_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
78         struct ia32_irn_reg_assoc templ;
79         unsigned int hash;
80
81         templ.irn = irn;
82         templ.reg = NULL;
83         hash = HASH_PTR(irn);
84
85         return set_insert(reg_set, &templ, sizeof(templ), hash);
86 }
87
88 void ia32_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
89         struct ia32_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
90         assoc->reg = reg;
91 }
92
93 const arch_register_t *ia32_get_firm_reg(const ir_node *irn, set *reg_set) {
94         struct ia32_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
95         return assoc->reg;
96 }
97
98
99
100 /* Mapping to store proj numbers for registers */
101
102 struct ia32_reg_projnum_assoc {
103         const arch_register_t *reg;
104         long                   proj_num;
105 };
106
107 int ia32_cmp_reg_projnum_assoc(const void *a, const void *b, size_t len) {
108         const struct ia32_reg_projnum_assoc *x = a;
109         const struct ia32_reg_projnum_assoc *y = b;
110
111         return !(x->reg == y->reg);
112 }
113
114 static struct ia32_reg_projnum_assoc *get_reg_projnum_assoc(const arch_register_t *reg, set *reg_set) {
115         struct ia32_reg_projnum_assoc templ;
116         unsigned int hash;
117
118         templ.reg      = reg;
119         templ.proj_num = -1;
120         hash = HASH_PTR(reg);
121
122         return set_insert(reg_set, &templ, sizeof(templ), hash);
123 }
124
125 void ia32_set_reg_projnum(const arch_register_t *reg, long proj_num, set *reg_set) {
126         struct ia32_reg_projnum_assoc *assoc = get_reg_projnum_assoc(reg, reg_set);
127         assoc->proj_num = proj_num;
128 }
129
130 long ia32_get_reg_projnum(const arch_register_t *reg, set *reg_set) {
131         struct ia32_reg_projnum_assoc *assoc = get_reg_projnum_assoc(reg, reg_set);
132         return assoc->proj_num;
133 }
134
135
136
137 /**
138  * Check all parameters and determine the maximum number of parameters
139  * to pass in gp regs resp. in fp regs.
140  *
141  * @param n       The number of parameters
142  * @param modes   The parameter list
143  * @param n_int   Holds the number of int parameters to be passed in regs after the call
144  * @param n_float Holds the number of float parameters to be passed in regs after the call
145  * @return        The number of the last parameter to be passed in register
146  */
147 int ia32_get_n_regparam_class(int n, ir_node **params, int *n_int, int *n_float) {
148         int i, finished = 0;
149
150         for (i = 0; i < n && !finished; i++) {
151                 if (mode_is_int(get_irn_mode(params[i]))) {
152                         *n_int = *n_int + 1;
153                 }
154                 else if (mode_is_float(get_irn_mode(params[i]))) {
155                         *n_float = *n_float + 1;
156                 }
157                 else {
158                         finished = 1;
159                 }
160
161                 /* test for maximum */
162                 if (*n_int == maxnum_gpreg_args || *n_float == maxnum_fpreg_args) {
163                         finished = 1;
164                 }
165         }
166
167         return i - 1;
168 }
169
170
171 /**
172  * Returns the register requirements for parameter nr.
173  *
174  * @param n     The number of parameters
175  * @param modes The parameter list
176  * @param nr    The number of the parameter to return the requirements for
177  * @param cc    The calling convention
178  * @return      The register requirements
179  */
180 const ia32_register_req_t *ia32_get_RegParam_req(int n, ir_node **params, long nr, unsigned cc) {
181         const ia32_register_req_t **current_gpreg_param_req;
182         const ia32_register_req_t **current_fpreg_param_req;
183         const ia32_register_req_t  *param_req = NULL;
184         int n_gpregparam = 0;
185         int n_fpregparam = 0;
186         int i, done      = 0;
187         int cur_gp_idx   = 0;
188         int cur_fp_idx   = 0;
189         int biggest_n    = ia32_get_n_regparam_class(n, params, &n_gpregparam, &n_fpregparam);
190
191         /* Check if parameter #nr is in range for passing in register */
192         if (nr <= biggest_n) {
193                 current_gpreg_param_req = gpreg_param_req_std;
194                 current_fpreg_param_req = fpreg_param_req_std;
195
196                 if (cc & cc_this_call) {
197                         current_gpreg_param_req = gpreg_param_req_this;
198                         current_fpreg_param_req = fpreg_param_req_this;
199                 }
200
201                 /* loop over all parameters and determine whether its a int or float register parameter */
202                 for (i = 0; i < nr && !done && (cc & cc_reg_param); i++) {
203                         if (mode_is_int(get_irn_mode(params[i])) && cur_gp_idx < maxnum_gpreg_args) {
204                                 /* param can be passed in general purpose register and we have some registers left */
205                                 cur_gp_idx++;
206                         }
207                         else if (mode_is_float(get_irn_mode(params[i])) && cur_fp_idx < maxnum_fpreg_args) {
208                                 /* param can be passed in floating point register and we have some registers left */
209                                 assert(current_gpreg_param_req[cur_fp_idx] && "'this' pointer cannot be passed as float");
210                                 cur_fp_idx++;
211                         }
212                 }
213
214                 /* now: i == nr, that's the parameter requirement we want */
215                 if (mode_is_int(get_irn_mode(params[i])) && cur_gp_idx < maxnum_gpreg_args) {
216                         /* parameter #nr can be passed in general purpose register */
217                         param_req = current_gpreg_param_req[i];
218                 }
219                 else if (mode_is_float(get_irn_mode(params[i])) && cur_fp_idx < maxnum_fpreg_args) {
220                         /* parameter #nr can be passed in floating point register */
221                         param_req = current_fpreg_param_req[i];
222                 }
223                 else {
224                         assert(0 && "This should not happen!");
225                 }
226         }
227
228         return param_req;
229 }
230
231
232
233 /**
234  * Translates the projnum into a "real" argument position for register
235  * requirements dependend on the predecessor.
236  */
237 long ia32_translate_proj_pos(const ir_node *proj) {
238         ir_node *first;
239         ir_node *pred = get_Proj_pred(proj);
240         long nr       = get_Proj_proj(proj);
241
242         if (is_ia32_Load(pred)) {
243                 if (nr == pn_Load_res)
244                         return 0;
245                 assert(0 && "unsupported Proj(Load) number");
246         }
247         else if (is_ia32_Store(pred)) {
248                 return 0;
249         }
250         else if (is_ia32_CondJmp(pred)) {
251                 return 0;
252         }
253         else if (is_ia32_SwitchJmp(pred)) {
254                 return 0;
255         }
256         else if (is_ia32_Cdq(pred) || is_ia32_Mulh(pred)) {
257                 if (nr == pn_EAX)
258                         return 0;
259                 if (nr == pn_EDX)
260                         return 1;
261         }
262         else if (is_ia32_DivMod(pred)) {
263                 if (nr == pn_DivMod_res_div || pn_Div_res)
264                         return 0;
265                 if (nr == pn_DivMod_res_mod || pn_Mod_res)
266                         return 1;
267         }
268         else if (is_ia32_fDiv(pred)) {
269                 if (nr == pn_Quot_res)
270                         return 0;
271                 else
272                         assert(0 && "there should be no more Projs for a fDiv");
273         }
274         else if (is_ia32_Call(pred)) {
275                 return 0;
276         }
277         else if (get_irn_mode(proj) == mode_X && nr == pn_Start_X_initial_exec) {
278                 return 0;
279         }
280         else if (is_Proj(pred)) {
281                 first = get_Proj_pred(pred);
282
283                 if (is_ia32_Call(first))
284                         return 0;
285
286                 assert(0 && "unsupported proj-pos translation Proj(Proj)");
287                 return -1;
288         }
289         else if (get_irn_opcode(pred) == iro_Start) {
290                 return nr;
291         }
292
293 //      assert(0 && "unsupported Proj(X)");
294         return nr;
295 }