b4b1d44a9b656ca7b32bbe632c478ccc49c80716
[libfirm] / ir / be / bessadestr.c
1 /**
2  * Author:      Daniel Grund
3  * Date:                25.05.2005
4  * Copyright:   (c) Universitaet Karlsruhe
5  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  *
7  * Performs SSA-Destruction.
8  */
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "debug.h"
14 #include "set.h"
15 #include "pmap.h"
16 #include "irnode.h"
17 #include "iredges_t.h"
18 #include "be_t.h"
19 #include "bechordal_t.h"
20 #include "bearch.h"
21 #include "benode_t.h"
22 #include "besched_t.h"
23
24 #define get_reg(irn) arch_get_irn_register(chordal_env->arch_env, irn, 0)
25 #define set_reg(irn, reg) arch_set_irn_register(chordal_env->arch_env, irn, 0, reg)
26
27 /**
28  * Maps blocks to perm nodes inserted during phi destruction.
29  */
30 typedef struct _block2perm_t {
31         ir_node *block, *perm;
32 } block2perm_t;
33
34 static int set_cmp_b2p(const void *x, const void *y, size_t size) {
35         const block2perm_t *b1 = x;
36         const block2perm_t *b2 = y;
37         return b1->block != b2->block;
38 }
39
40 #define is_Branch(irn)          (arch_irn_classify(arch_env, irn) == arch_irn_class_branch)
41 #define is_Perm(irn)            (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
42 #define get_reg_cls(irn)        (arch_get_irn_reg_class(arch_env, irn, arch_pos_make_out(0)))
43 #define is_curr_reg_class(irn)  (get_reg_cls(p) == chordal_env->cls)
44
45 static ir_node *get_perm(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *block) {
46         block2perm_t find, *found;
47         ir_node *p;
48         set *b2p = chordal_env->data;
49         const arch_env_t *arch_env = chordal_env->arch_env;
50
51         /* iff needed insert perm node */
52
53         /* .if the perm is in the pset return it */
54         find.block = block;
55         find.perm = NULL;
56         found = set_insert(b2p, &find, sizeof(find), HASH_PTR(find.block));
57         if (found->perm)
58                 return found->perm;
59
60         /* .else look for a perm of right register class in the schedule */
61         p = sched_last(find.block);
62         while (!is_Block(p) && (is_Branch(p) || (is_Perm(p) && !is_curr_reg_class(p))))
63                 p = sched_prev(p);
64
65         /* if we haven't found a perm of the right register class create a new one */
66         if (! (is_Perm(p) && is_curr_reg_class(p)))
67                 p = insert_Perm_after(session, chordal_env->cls, p);
68
69         /* insert perm into pset */
70         found->perm = p;
71         return p;
72 }
73
74 /**
75  * Adjusts the register allocation for the phi-operands
76  * by inserting perm nodes, if necessary.
77  * @param phi The phi node to adjust operands for
78  */
79 static void adjust_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, const ir_node *phi) {
80         int i, max;
81         ir_node *arg, *perm, *proj;
82         const arch_register_t *phi_reg, *arg_reg, *proj_reg;
83         const ir_edge_t *edge;
84
85         assert(is_Phi(phi) && "Can only handle phi-destruction :)");
86
87         phi_reg = get_reg(phi);
88         /* all arguments of the phi */
89         for(i=0, max=get_irn_arity(phi); i<max; ++i) {
90                 arg = get_irn_n(phi, i);
91                 arg_reg = get_reg(arg);
92                 /* if registers don't match ...*/
93                 if (phi_reg != arg_reg) {
94                         perm = get_perm(session, chordal_env, get_nodes_block(arg));
95                         /* adjust assigned registers for the projs */
96                         foreach_out_edge(perm, edge) {
97                                 proj = get_edge_src_irn(edge);
98                                 proj_reg = get_reg(proj);
99                                 if (proj_reg == arg_reg)
100                                         set_reg(proj, phi_reg);
101                                 else if (proj_reg == phi_reg)
102                                         set_reg(proj, arg_reg);
103                         }
104                 }
105         }
106 }
107
108 static void checker(be_chordal_env_t *chordal_env) {
109         pmap_entry *pme;
110         int i, max;
111
112         /* iterate over all blocks */
113         pmap_foreach(chordal_env->border_heads, pme) {
114                 border_t *curr;
115                 struct list_head *head = pme->value;
116
117                 /* iterate over the first ops in the block */
118                 list_for_each_entry_reverse(border_t, curr, head, list)
119                         if (curr->is_def && curr->is_real && is_Phi(curr->irn)) {
120                                 const arch_register_t *phi_reg, *arg_reg;
121                                 if (!is_Phi(curr->irn))
122                                         break;
123
124                                 phi_reg = get_reg(curr->irn);
125                                 /* iterate over all args of phi */
126                                 for(i=0, max=get_irn_arity(curr->irn); i<max; ++i) {
127                                         arg_reg = get_reg(get_irn_n(curr->irn, i));
128                                         assert(phi_reg == arg_reg && "WTF? You can do it better!?");
129                                 }
130                         }
131         }
132 }
133
134 void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
135         pmap_entry *pme;
136         set *b2p;
137
138         b2p = new_set(set_cmp_b2p, 32);
139         chordal_env->data = b2p;
140         /* iterate over all blocks */
141         pmap_foreach(chordal_env->border_heads, pme) {
142                 border_t *curr;
143                 struct list_head *head = pme->value;
144
145                 /* iterate over the first ops in the block until a non-phi is reached */
146                 list_for_each_entry_reverse(border_t, curr, head, list)
147                         if (curr->is_def && curr->is_real) {
148                                 if (!is_Phi(curr->irn))
149                                         break;
150                                 adjust_arguments(session, chordal_env, curr->irn);
151                         }
152         }
153         del_set(b2p);
154         checker(chordal_env);
155 }