4 * Copyright: (c) Universitaet Karlsruhe
5 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
7 * Performs SSA-Destruction.
17 #include "iredges_t.h"
23 #include "bechordal_t.h"
26 #include "besched_t.h"
28 #define get_reg(irn) arch_get_irn_register(chordal_env->arch_env, irn, 0)
29 #define set_reg(irn, reg) arch_set_irn_register(chordal_env->arch_env, irn, 0, reg)
32 * Maps blocks to perm nodes inserted during phi destruction.
34 typedef struct _block2perm_t {
35 ir_node *block, *perm;
38 static int set_cmp_b2p(const void *x, const void *y, size_t size) {
39 const block2perm_t *b1 = x;
40 const block2perm_t *b2 = y;
41 return b1->block != b2->block;
44 #define is_Branch(irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_branch)
45 #define is_Perm(irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
46 #define get_reg_cls(irn) (arch_get_irn_reg_class(arch_env, irn, arch_pos_make_out(0)))
47 #define is_curr_reg_class(irn) (get_reg_cls(p) == chordal_env->cls)
49 static ir_node *get_or_insert_perm(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *block) {
50 block2perm_t find, *found;
52 set *b2p = chordal_env->data;
53 const arch_env_t *arch_env = chordal_env->arch_env;
55 /* iff needed insert perm node */
57 /* .if the perm is in the pset return it */
60 found = set_insert(b2p, &find, sizeof(find), HASH_PTR(find.block));
64 /* .else look for a perm of right register class in the schedule */
65 p = sched_last(find.block);
66 while (!is_Block(p) && (is_Branch(p) || (is_Perm(p) && !is_curr_reg_class(p))))
69 /* if we haven't found a perm of the right register class create a new one */
70 if (! (is_Perm(p) && is_curr_reg_class(p)))
71 p = insert_Perm_after(session, chordal_env->cls, p);
73 /* insert perm into pset */
78 #define is_pinned(irn) ((irn)->link)
79 #define get_pinning_block(irn) ((ir_node *)(irn)->link)
80 #define pin_irn(irn, lock) ((irn)->link = lock)
83 * Adjusts the register allocation for the phi-operands
84 * by inserting perm nodes, if necessary.
85 * @param phi The phi node to adjust operands for
87 static void adjust_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *phi) {
89 ir_node *arg, *phi_block, *arg_block;
90 const arch_register_t *phi_reg, *arg_reg;
91 const arch_register_class_t *cls;
93 assert(is_Phi(phi) && "Can only handle phi-destruction :)");
95 cls = arch_get_irn_reg_class(session->main_env->arch_env, phi, arch_pos_make_out(0));
96 phi_block = get_nodes_block(phi);
97 phi_reg = get_reg(phi);
98 /* all arguments of the phi */
99 for(i=0, max=get_irn_arity(phi); i<max; ++i) {
102 arg = get_irn_n(phi, i);
103 arg_block = get_nodes_block(arg);
104 arg_reg = get_reg(arg);
105 perm = get_Proj_pred(arg);
107 /* if registers don't match ...*/
108 if (phi_reg != arg_reg) {
110 /* First check if there is another phi in the same block
111 * having arg at the same pos in its arg-list */
112 if (!is_pinned(arg)) {
113 ir_node *other_phi = phi;
114 while ((other_phi = other_phi->link) != phi) {
115 assert(is_Phi(other_phi) && "link fields are screwed up");
116 if (get_irn_n(other_phi, i) == arg && get_reg(other_phi) == arg_reg)
117 pin_irn(arg, phi_block);
121 if (is_pinned(arg)) {
123 /* Arg is pinned. So another phi has locked it.
124 * Hence, a duplicate must be inserted */
125 assert(get_pinning_block(arg) == phi_block && "If arg is pinned it must be due to a phi in the same block");
126 dupl = new_Copy(session->main_env->node_factory, cls, session->irg, arg_block, arg);
127 set_irn_n(phi, i, dupl);
128 set_reg(dupl, phi_reg);
130 /* Add dupl to schedule */
131 tmp = sched_next(perm);
132 while (is_Proj(tmp) && sched_has_next(tmp))
133 tmp = sched_next(tmp);
134 sched_add_after(tmp, dupl);
136 /* Add dupl to chained list of duplicates. Ptrs starting at the Perm */
143 /* now the arg is the dupl */
146 /* Arg is not pinned. So set its color to the color of the phi.
147 * If the phi color is used by another proj of this perm
148 * one must NOT swap the colors. Proof: Critical edges removed,
149 * livein(PhiBl) = liveout(ArgBl), if all phis are processed then
150 * every color is used exactly once.
152 set_reg(arg, phi_reg);
155 /* Now the color of the arg and the phi-result are equal.
156 * Pin it, so everyone knows
157 * An arg never is a phi, because perms were inserted. So the link field is free */
158 pin_irn(arg, phi_block);
162 //static void collect_phis(ir_node *node, void *env) {
165 // pset_insert_ptr(phis, node);
168 void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
173 ir_node *first_phi, *recent_phi;
175 b2p = new_set(set_cmp_b2p, 32);
176 chordal_env->data = b2p;
179 // all_phis = pset_new_ptr_default();
180 // irg_walk_graph(session->irg, collect_phis, NULL, all_phis);
183 /* place perms in cf-preds of phis */
184 pmap_foreach(chordal_env->border_heads, pme) {
186 struct list_head *head = pme->value;
189 /* iterate over the first ops in the block until a non-phi is reached */
190 list_for_each_entry(border_t, curr, head, list) {
191 ir_node *phi = curr->irn;
192 if (curr->is_def && curr->is_real) {
197 /* chain of phis in a block */
198 if (first_phi == NULL)
201 recent_phi->link = phi;
205 for(i=0, max=get_irn_arity(phi); i<max; ++i) {
208 ir_printf("Placing perm for %+F \n", phi);
209 perm = get_or_insert_perm(session, chordal_env, get_Block_cfgpred_block(get_nodes_block(phi), i));
215 recent_phi->link = first_phi;
218 dump_ir_block_graph(session->irg, "-prems");
220 /* iterate over all blocks and correct color of arguments*/
221 pmap_foreach(chordal_env->border_heads, pme) {
223 struct list_head *head = pme->value;
225 /* iterate over the first ops in the block until a non-phi is reached */
226 list_for_each_entry(border_t, curr, head, list)
227 if (curr->is_def && curr->is_real) {
228 if (!is_Phi(curr->irn))
230 adjust_arguments(session, chordal_env, curr->irn);
235 dump_ir_block_graph_sched(session->irg, "-ssa-destr");
239 void be_ssa_destruction_check(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
243 /* iterate over all blocks */
244 pmap_foreach(chordal_env->border_heads, pme) {
246 struct list_head *head = pme->value;
248 /* iterate over the first ops in the block */
249 list_for_each_entry(border_t, curr, head, list)
250 if (curr->is_def && curr->is_real && is_Phi(curr->irn)) {
251 const arch_register_t *phi_reg, *arg_reg;
252 if (!is_Phi(curr->irn))
255 phi_reg = get_reg(curr->irn);
256 /* iterate over all args of phi */
257 for(i=0, max=get_irn_arity(curr->irn); i<max; ++i) {
258 ir_node *arg = get_irn_n(curr->irn, i);
259 arg_reg = get_reg(arg);
260 if(phi_reg != arg_reg)
261 ir_printf("register differ: %s %s\n", phi_reg->name, arg_reg->name);
263 ir_printf("Warning: Arg not pinned %n %N\n", arg, arg);