Remove redundant be_set_transformed_node() in transformer functions. They are vestig...
[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 #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 = XMALLOCZ(mips_sched_env_t);
67
68         sched_env->arch_env = arch_env;
69         sched_env->div_set = new_pset(pset_default_ptr_cmp, 4);
70
71         return sched_env;
72 }
73
74 static void mips_scheduler_finish_graph(void* graph_env)
75 {
76         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
77         del_pset(sched_env->div_set);
78 }
79
80 static void *mips_scheduler_init_block(void *graph_env, ir_node *block)
81 {
82         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
83         assert(pset_count(sched_env->div_set) == 0);
84         srand(12234);
85         // TODO later we might have blocks that don't end in a jump
86         memset(&sched_env->busy_registers, 0, sizeof(sched_env->busy_registers));
87         sched_env->block = block;
88         sched_env->last_nop = NULL;
89         return sched_env;
90 }
91
92 static void mips_scheduler_finish_block(void* graph_env)
93 {
94         mips_sched_env_t *sched_env = (mips_sched_env_t*) graph_env;
95         // attach last nop to end node (so that firm doesn't discard it)
96         if(sched_env->last_nop != NULL) {
97                 ir_node* end = get_irg_end(get_irn_irg(sched_env->block));
98                 (void) end;
99                 // TODO
100         }
101         sched_env->block = NULL;
102 }
103
104 static int mips_scheduler_to_appear_in_schedule(void *block_env, const ir_node *irn)
105 {
106         return is_mips_irn(irn) && !is_mips_zero(irn) && !is_mips_reinterpret_conv(irn) && !is_mips_fallthrough(irn);
107 }
108
109 static void mips_collect_mflohis(pset* set, ir_node* node) {
110         // construct a list of nodes that need to be scheduled before
111         // we are allowed to schedule another div or mul instruction
112         const ir_edge_t *edge, *edge2;
113
114         if(is_mips_div(node)) {
115                 foreach_out_edge(node, edge) {
116                         const ir_node* node2 = get_edge_src_irn(edge);
117
118                         assert(is_Proj(node2));
119                         foreach_out_edge(node2, edge2) {
120                                 const ir_node* node3 = get_edge_src_irn(edge2);
121                                 if(is_mips_mfhi(node3) || is_mips_mflo(node3))
122                                         pset_insert_ptr(set, node3);
123                         }
124                 }
125         } else if(is_mips_mult(node)) {
126                 foreach_out_edge(node, edge) {
127                         const ir_node* node2 = get_edge_src_irn(edge);
128
129                         if(is_mips_mfhi(node2) || is_mips_mflo(node2))
130                                 pset_insert_ptr(set, node2);
131                 }
132         }
133 }
134
135 static int mips_scheduler_node_allowed(mips_sched_env_t *sched_env, ir_node* node)
136 {
137         if(pset_count(sched_env->div_set) != 0 && (is_mips_div(node) || is_mips_mult(node))) {
138                 return 0;
139         }
140
141         return 1;
142 }
143
144 static ir_node *mips_scheduler_select(void *block_env, nodeset *ready_set, nodeset *live_set)
145 {
146         mips_sched_env_t *sched_env = (mips_sched_env_t*) block_env;
147         const arch_env_t *arch_env = (const arch_env_t*) sched_env->arch_env;
148         ir_node *node = NULL;
149         ir_node *block = sched_env->block;
150         ir_node *condjmp = NULL;
151         ir_graph *irg = get_irn_irg(block);
152         int have_non_branch_nodes = 0;
153
154         // test all nodes in the ready set and take the first non-branch that
155         // is allowed
156         for (node = nodeset_first(ready_set); node != NULL; node = nodeset_next(ready_set)) {
157                 if (arch_irn_class_is(arch_env, node, branch)) {
158                         if (is_irn_forking(node))
159                                 condjmp = node;
160                         continue;
161                 }
162
163                 have_non_branch_nodes = 1;
164
165                 if (mips_scheduler_node_allowed(sched_env, node))
166                 {
167                         nodeset_break(ready_set);
168
169                         // TODO update busy_registers
170
171                         if (is_mips_div(node) || is_mips_mult(node)) {
172                                 mips_collect_mflohis(sched_env->div_set, node);
173                         } else if(is_mips_mflo(node) || is_mips_mfhi(node)) {
174                                 pset_remove_ptr(sched_env->div_set, node);
175                         }
176
177                         return node;
178                 }
179         }
180
181         // if we arrive here no non-branch node was found that we can emit
182
183         // return a branch if there are just branches left
184         if(!have_non_branch_nodes) {
185                 // schedule conditional branches before non-conditional ones
186                 if(condjmp != NULL) {
187                         return condjmp;
188                 }
189                 node = nodeset_first(ready_set);
190                 assert(arch_irn_class_is(arch_env, node, branch));
191                 nodeset_break(ready_set);
192                 return node;
193         }
194
195         // emit a nop
196         node = new_rd_mips_nop(NULL, irg, block, mode_M);
197         keep_alive(node);
198         return node;
199 }
200
201 #endif
202
203 static
204 int mips_to_appear_in_schedule(void *block_env, const ir_node *node)
205 {
206         (void) block_env;
207
208         if(!is_mips_irn(node))
209                 return -1;
210         if(is_mips_zero(node) || is_mips_Immediate(node))
211                 return 0;
212
213         return 1;
214 }
215
216 list_sched_selector_t  mips_selector;
217
218 /**
219  * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
220  */
221 const list_sched_selector_t *mips_get_list_sched_selector(const void *self,
222                 list_sched_selector_t *selector)
223 {
224         (void) self;
225 #if 0
226         memset(&mips_sched_selector, 0, sizeof(mips_sched_selector));
227         mips_sched_selector.init_graph = mips_scheduler_init_graph;
228         mips_sched_selector.init_block = mips_scheduler_init_block;
229         mips_sched_selector.select = mips_scheduler_select;
230         mips_sched_selector.to_appear_in_schedule = mips_scheduler_to_appear_in_schedule;
231         mips_sched_selector.finish_block = mips_scheduler_finish_block;
232         mips_sched_selector.finish_graph = mips_scheduler_finish_graph;
233         //return &mips_sched_selector;
234 #endif
235         memcpy(&mips_selector, selector, sizeof(mips_selector));
236         mips_selector.to_appear_in_schedule = mips_to_appear_in_schedule;
237
238         return &mips_selector;
239 }
240
241 const ilp_sched_selector_t *mips_get_ilp_sched_selector(const void *self)
242 {
243         (void) self;
244         return NULL;
245 }