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