c989af90e5c337c91b0a907f90e41ebced9d717d
[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 "irdump.h"
19 #include "irprintf.h"
20
21 #include "be_t.h"
22 #include "beutil.h"
23 #include "bechordal_t.h"
24 #include "bearch.h"
25 #include "benode_t.h"
26 #include "besched_t.h"
27
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)
30
31 /**
32  * Maps blocks to perm nodes inserted during phi destruction.
33  */
34 typedef struct _block2perm_t {
35   ir_node *block, *perm;
36 } block2perm_t;
37
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;
42 }
43
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)
48
49 static ir_node *get_perm(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *block) {
50   block2perm_t find, *found;
51   ir_node *p;
52   set *b2p = chordal_env->data;
53   const arch_env_t *arch_env = chordal_env->arch_env;
54
55   /* iff needed insert perm node */
56
57   /* .if the perm is in the pset return it */
58   find.block = block;
59   find.perm = NULL;
60   found = set_insert(b2p, &find, sizeof(find), HASH_PTR(find.block));
61   if (found->perm)
62     return found->perm;
63
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))))
67     p = sched_prev(p);
68
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);
72
73         /* insert perm into pset */
74         found->perm = p;
75         return p;
76 }
77
78 /**
79  * Adjusts the register allocation for the phi-operands
80  * by inserting perm nodes, if necessary.
81  * @param phi The phi node to adjust operands for
82  */
83 static void adjust_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, const ir_node *phi) {
84         int i, max;
85         ir_node *arg;
86         const arch_register_t *phi_reg, *arg_reg, *proj_reg;
87         const ir_edge_t *edge;
88   ir_node *phi_block = get_nodes_block(phi);
89
90         assert(is_Phi(phi) && "Can only handle phi-destruction :)");
91
92         phi_reg = get_reg(phi);
93         /* all arguments of the phi */
94         for(i=0, max=get_irn_arity(phi); i<max; ++i) {
95                 arg = get_irn_n(phi, i);
96                 arg_reg = get_reg(arg);
97                 /* if registers don't match ...*/
98                 if (phi_reg != arg_reg) {
99       ir_node *perm;
100
101                         perm = get_perm(session, chordal_env, get_nodes_block(get_irn_n(phi_block, i)));
102
103                         /*
104        * Look at the projs of the perm.
105        * Find the one which corresponds to the phi argument
106        * This is done via the proj number: If
107        * the i-th argument of the perm is the old Phi
108        * argument, then the Proj with number i is the
109        * one we want.
110        */
111                         foreach_out_edge(perm, edge) {
112                                 ir_node *proj = get_edge_src_irn(edge);
113         int proj_nr = get_Proj_proj(proj);
114
115         if(get_irn_n(perm, proj_nr) == arg) {
116           assert(get_reg(proj) == NULL);
117           set_reg(proj, phi_reg);
118         }
119                         }
120                 }
121         }
122 }
123
124 static void checker(be_chordal_env_t *chordal_env) {
125   pmap_entry *pme;
126   int i, max;
127
128   /* iterate over all blocks */
129   pmap_foreach(chordal_env->border_heads, pme) {
130     border_t *curr;
131     struct list_head *head = pme->value;
132
133     /* iterate over the first ops in the block */
134     list_for_each_entry_reverse(border_t, curr, head, list)
135       if (curr->is_def && curr->is_real && is_Phi(curr->irn)) {
136         const arch_register_t *phi_reg, *arg_reg;
137         if (!is_Phi(curr->irn))
138           break;
139
140         phi_reg = get_reg(curr->irn);
141         /* iterate over all args of phi */
142         for(i=0, max=get_irn_arity(curr->irn); i<max; ++i) {
143           arg_reg = get_reg(get_irn_n(curr->irn, i));
144           if(phi_reg != arg_reg)
145             ir_printf("register differ: %s %s\n", phi_reg->name, arg_reg->name);
146         }
147       }
148   }
149 }
150
151 void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
152         pmap_entry *pme;
153         set *b2p;
154
155         b2p = new_set(set_cmp_b2p, 32);
156         chordal_env->data = b2p;
157         /* iterate over all blocks */
158         pmap_foreach(chordal_env->border_heads, pme) {
159                 border_t *curr;
160                 struct list_head *head = pme->value;
161
162                 /* iterate over the first ops in the block until a non-phi is reached */
163                 list_for_each_entry_reverse(border_t, curr, head, list)
164                         if (curr->is_def && curr->is_real) {
165                                 if (!is_Phi(curr->irn))
166                                         break;
167                                 adjust_arguments(session, chordal_env, curr->irn);
168                         }
169         }
170     dump_ir_block_graph_sched(session->irg, "-ssa-destr");
171         del_set(b2p);
172         checker(chordal_env);
173 }