Remove the attribute const arch_env_t *arch_env from struct ia32_code_gen_t. We...
[libfirm] / ir / be / mips / mips_scheduler.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Mips implementation of list scheduler selector
23  * @author  Matthias Braun, Mehdi
24  * @version $Id$
25  */
26 #include "config.h"
27
28 #ifdef HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31
32 #include "mips_scheduler.h"
33
34 #include "../besched_t.h"
35 #include "be.h"
36 #include "../beabi.h"
37 #include "iredges.h"
38 #include "ircons.h"
39 #include "gen_mips_regalloc_if.h"
40
41 #include "mips_new_nodes.h"
42
43 list_sched_selector_t mips_sched_selector;
44
45 typedef struct {
46         const arch_env_t* arch_env;
47         pset *div_set;
48         /**
49          * This array holds an entry for each register that specifies how much cycles
50          * have to pass before we can access that register again
51          * (because mips will write the register value back in the WB phase of the pipeline)
52          */
53         int busy_registers[N_mips_gp_REGS];
54         /// current block
55         ir_node* block;
56         ir_node* last_nop;
57 } mips_sched_env_t;
58
59 /* Matze: deprecated and totally broken */
60 #if 0
61
62 static void *mips_scheduler_init_graph(const list_sched_selector_t *vtab, const arch_env_t *arch_env, ir_graph *irg)
63 {
64         mips_sched_env_t *sched_env = XMALLOCZ(mips_sched_env_t);
65
66         sched_env->arch_env = arch_env;
67         sched_env->div_set = new_pset(pset_default_ptr_cmp, 4);
68
69         return sched_env;
70 }
71
72 static void mips_scheduler_finish_graph(void* graph_env)
73 {
74         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
75         del_pset(sched_env->div_set);
76 }
77
78 static void *mips_scheduler_init_block(void *graph_env, ir_node *block)
79 {
80         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
81         assert(pset_count(sched_env->div_set) == 0);
82         srand(12234);
83         // TODO later we might have blocks that don't end in a jump
84         memset(&sched_env->busy_registers, 0, sizeof(sched_env->busy_registers));
85         sched_env->block = block;
86         sched_env->last_nop = NULL;
87         return sched_env;
88 }
89
90 static void mips_scheduler_finish_block(void* graph_env)
91 {
92         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
93         // attach last nop to end node (so that firm doesn't discard it)
94         if(sched_env->last_nop != NULL) {
95                 ir_node* end = get_irg_end(get_irn_irg(sched_env->block));
96                 (void) end;
97                 // TODO
98         }
99         sched_env->block = NULL;
100 }
101
102 static int mips_scheduler_to_appear_in_schedule(void *block_env, const ir_node *irn)
103 {
104         return is_mips_irn(irn) && !is_mips_zero(irn) && !is_mips_reinterpret_conv(irn) && !is_mips_fallthrough(irn);
105 }
106
107 static void mips_collect_mflohis(pset* set, ir_node* node) {
108         // construct a list of nodes that need to be scheduled before
109         // we are allowed to schedule another div or mul instruction
110         const ir_edge_t *edge, *edge2;
111
112         if(is_mips_div(node)) {
113                 foreach_out_edge(node, edge) {
114                         const ir_node* node2 = get_edge_src_irn(edge);
115
116                         assert(is_Proj(node2));
117                         foreach_out_edge(node2, edge2) {
118                                 const ir_node* node3 = get_edge_src_irn(edge2);
119                                 if(is_mips_mfhi(node3) || is_mips_mflo(node3))
120                                         pset_insert_ptr(set, node3);
121                         }
122                 }
123         } else if(is_mips_mult(node)) {
124                 foreach_out_edge(node, edge) {
125                         const ir_node* node2 = get_edge_src_irn(edge);
126
127                         if(is_mips_mfhi(node2) || is_mips_mflo(node2))
128                                 pset_insert_ptr(set, node2);
129                 }
130         }
131 }
132
133 static int mips_scheduler_node_allowed(mips_sched_env_t *sched_env, ir_node* node)
134 {
135         if(pset_count(sched_env->div_set) != 0 && (is_mips_div(node) || is_mips_mult(node))) {
136                 return 0;
137         }
138
139         return 1;
140 }
141
142 static ir_node *mips_scheduler_select(void *block_env, nodeset *ready_set, nodeset *live_set)
143 {
144         mips_sched_env_t *sched_env = (mips_sched_env_t*) block_env;
145         const arch_env_t *arch_env = (const arch_env_t*) sched_env->arch_env;
146         ir_node *node = NULL;
147         ir_node *block = sched_env->block;
148         ir_node *condjmp = NULL;
149         ir_graph *irg = get_irn_irg(block);
150         int have_non_branch_nodes = 0;
151
152         // test all nodes in the ready set and take the first non-branch that
153         // is allowed
154         for (node = nodeset_first(ready_set); node != NULL; node = nodeset_next(ready_set)) {
155                 if (arch_irn_class_is(arch_env, node, branch)) {
156                         if (is_irn_forking(node))
157                                 condjmp = node;
158                         continue;
159                 }
160
161                 have_non_branch_nodes = 1;
162
163                 if (mips_scheduler_node_allowed(sched_env, node))
164                 {
165                         nodeset_break(ready_set);
166
167                         // TODO update busy_registers
168
169                         if (is_mips_div(node) || is_mips_mult(node)) {
170                                 mips_collect_mflohis(sched_env->div_set, node);
171                         } else if(is_mips_mflo(node) || is_mips_mfhi(node)) {
172                                 pset_remove_ptr(sched_env->div_set, node);
173                         }
174
175                         return node;
176                 }
177         }
178
179         // if we arrive here no non-branch node was found that we can emit
180
181         // return a branch if there are just branches left
182         if(!have_non_branch_nodes) {
183                 // schedule conditional branches before non-conditional ones
184                 if(condjmp != NULL) {
185                         return condjmp;
186                 }
187                 node = nodeset_first(ready_set);
188                 assert(arch_irn_class_is(arch_env, node, branch));
189                 nodeset_break(ready_set);
190                 return node;
191         }
192
193         // emit a nop
194         node = new_rd_mips_nop(NULL, irg, block, mode_M);
195         keep_alive(node);
196         return node;
197 }
198
199 #endif
200
201 static
202 int mips_to_appear_in_schedule(void *block_env, const ir_node *node)
203 {
204         (void) block_env;
205
206         if(!is_mips_irn(node))
207                 return -1;
208         if(is_mips_zero(node) || is_mips_Immediate(node))
209                 return 0;
210
211         return 1;
212 }
213
214 list_sched_selector_t  mips_selector;
215
216 /**
217  * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
218  */
219 const list_sched_selector_t *mips_get_list_sched_selector(const void *self,
220                 list_sched_selector_t *selector)
221 {
222         (void) self;
223 #if 0
224         memset(&mips_sched_selector, 0, sizeof(mips_sched_selector));
225         mips_sched_selector.init_graph = mips_scheduler_init_graph;
226         mips_sched_selector.init_block = mips_scheduler_init_block;
227         mips_sched_selector.select = mips_scheduler_select;
228         mips_sched_selector.to_appear_in_schedule = mips_scheduler_to_appear_in_schedule;
229         mips_sched_selector.finish_block = mips_scheduler_finish_block;
230         mips_sched_selector.finish_graph = mips_scheduler_finish_graph;
231         //return &mips_sched_selector;
232 #endif
233         memcpy(&mips_selector, selector, sizeof(mips_selector));
234         mips_selector.to_appear_in_schedule = mips_to_appear_in_schedule;
235
236         return &mips_selector;
237 }
238
239 const ilp_sched_selector_t *mips_get_ilp_sched_selector(const void *self)
240 {
241         (void) self;
242         return NULL;
243 }