d376e4afd3d037e58f01e131b03e2aff40e064c0
[libfirm] / ir / be / ia32 / ia32_finish.c
1 /**
2  * This file implements functions to finalize the irg for emit.
3  * @author Christian Wuerdig
4  * $Id$
5  */
6
7 #include "irnode.h"
8 #include "ircons.h"
9 #include "irgmod.h"
10 #include "irgwalk.h"
11 #include "pdeq.h"
12
13 #include "../bearch.h"
14 #include "../besched_t.h"
15 #include "../benode_t.h"
16
17 #include "bearch_ia32_t.h"
18 #include "ia32_finish.h"
19 #include "ia32_new_nodes.h"
20 #include "ia32_map_regs.h"
21 #include "ia32_transform.h"
22 #include "ia32_dbg_stat.h"
23 #include "ia32_optimize.h"
24
25 /**
26  * Transforms a Sub or xSub into Neg--Add iff OUT_REG == SRC2_REG.
27  * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
28  */
29 static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) {
30         ia32_transform_env_t tenv;
31         ir_node *in1, *in2, *noreg, *nomem, *res;
32         const arch_register_t *in1_reg, *in2_reg, *out_reg, **slots;
33
34         /* Return if AM node or not a Sub or xSub */
35         if (get_ia32_op_type(irn) != ia32_Normal || !(is_ia32_Sub(irn) || is_ia32_xSub(irn)))
36                 return;
37
38         noreg   = ia32_new_NoReg_gp(cg);
39         nomem   = new_rd_NoMem(cg->irg);
40         in1     = get_irn_n(irn, 2);
41         in2     = get_irn_n(irn, 3);
42         in1_reg = arch_get_irn_register(cg->arch_env, in1);
43         in2_reg = arch_get_irn_register(cg->arch_env, in2);
44         out_reg = get_ia32_out_reg(irn, 0);
45
46         tenv.block    = get_nodes_block(irn);
47         tenv.dbg      = get_irn_dbg_info(irn);
48         tenv.irg      = cg->irg;
49         tenv.irn      = irn;
50         tenv.mode     = get_ia32_res_mode(irn);
51         tenv.cg       = cg;
52         DEBUG_ONLY(tenv.mod      = cg->mod;)
53
54         /* in case of sub and OUT == SRC2 we can transform the sequence into neg src2 -- add */
55         if (REGS_ARE_EQUAL(out_reg, in2_reg)) {
56                 /* generate the neg src2 */
57                 res = gen_Minus_ex(&tenv, in2);
58                 arch_set_irn_register(cg->arch_env, res, in2_reg);
59
60                 /* add to schedule */
61                 sched_add_before(irn, res);
62
63                 /* generate the add */
64                 if (mode_is_float(tenv.mode)) {
65                         res = new_rd_ia32_xAdd(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem);
66                         set_ia32_am_support(res, ia32_am_Source);
67                 }
68                 else {
69                         res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, res, in1, nomem);
70                         set_ia32_am_support(res, ia32_am_Full);
71                         set_ia32_commutative(res);
72                 }
73             set_ia32_res_mode(res, tenv.mode);
74
75                 SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(tenv.cg, irn));
76                 /* copy register */
77                 slots    = get_ia32_slots(res);
78                 slots[0] = in2_reg;
79
80                 /* add to schedule */
81                 sched_add_before(irn, res);
82
83                 /* remove the old sub */
84                 sched_remove(irn);
85
86                 DBG_OPT_SUB2NEGADD(irn, res);
87
88                 /* exchange the add and the sub */
89                 exchange(irn, res);
90         }
91 }
92
93 /**
94  * Transforms a LEA into an Add if possible
95  * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
96  */
97 static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) {
98         ia32_am_flavour_t am_flav;
99         int               imm = 0;
100         ir_node          *res = NULL;
101         ir_node          *nomem, *noreg, *base, *index, *op1, *op2;
102         char             *offs;
103         ia32_transform_env_t tenv;
104         const arch_register_t *out_reg, *base_reg, *index_reg;
105
106         /* must be a LEA */
107         if (! is_ia32_Lea(irn))
108                 return;
109
110         am_flav = get_ia32_am_flavour(irn);
111
112         if (get_ia32_am_sc(irn))
113                 return;
114
115         /* only some LEAs can be transformed to an Add */
116         if (am_flav != ia32_am_B && am_flav != ia32_am_OB && am_flav != ia32_am_OI && am_flav != ia32_am_BI)
117                 return;
118
119         noreg = ia32_new_NoReg_gp(cg);
120         nomem = new_rd_NoMem(cg->irg);
121         op1   = noreg;
122         op2   = noreg;
123         base  = get_irn_n(irn, 0);
124         index = get_irn_n(irn,1);
125
126         offs  = get_ia32_am_offs(irn);
127
128         /* offset has a explicit sign -> we need to skip + */
129         if (offs && offs[0] == '+')
130                 offs++;
131
132         out_reg   = arch_get_irn_register(cg->arch_env, irn);
133         base_reg  = arch_get_irn_register(cg->arch_env, base);
134         index_reg = arch_get_irn_register(cg->arch_env, index);
135
136         tenv.block = get_nodes_block(irn);
137         tenv.dbg   = get_irn_dbg_info(irn);
138         tenv.irg   = cg->irg;
139         tenv.irn   = irn;
140         DEBUG_ONLY(tenv.mod   = cg->mod;)
141         tenv.mode  = get_irn_mode(irn);
142         tenv.cg    = cg;
143
144         switch(get_ia32_am_flavour(irn)) {
145                 case ia32_am_B:
146                         /* out register must be same as base register */
147                         if (! REGS_ARE_EQUAL(out_reg, base_reg))
148                                 return;
149
150                         op1 = base;
151                         break;
152                 case ia32_am_OB:
153                         /* out register must be same as base register */
154                         if (! REGS_ARE_EQUAL(out_reg, base_reg))
155                                 return;
156
157                         op1 = base;
158                         imm = 1;
159                         break;
160                 case ia32_am_OI:
161                         /* out register must be same as index register */
162                         if (! REGS_ARE_EQUAL(out_reg, index_reg))
163                                 return;
164
165                         op1 = index;
166                         imm = 1;
167                         break;
168                 case ia32_am_BI:
169                         /* out register must be same as one in register */
170                         if (REGS_ARE_EQUAL(out_reg, base_reg)) {
171                                 op1 = base;
172                                 op2 = index;
173                         }
174                         else if (REGS_ARE_EQUAL(out_reg, index_reg)) {
175                                 op1 = index;
176                                 op2 = base;
177                         }
178                         else {
179                                 /* in registers a different from out -> no Add possible */
180                                 return;
181                         }
182                 default:
183                         break;
184         }
185
186         res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, op1, op2, nomem);
187         arch_set_irn_register(cg->arch_env, res, out_reg);
188         set_ia32_op_type(res, ia32_Normal);
189         set_ia32_commutative(res);
190         set_ia32_res_mode(res, tenv.mode);
191
192         if (imm) {
193                 set_ia32_cnst(res, offs);
194                 set_ia32_immop_type(res, ia32_ImmConst);
195         }
196
197         SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn));
198
199         /* add Add to schedule */
200         sched_add_before(irn, res);
201
202         DBG_OPT_LEA2ADD(irn, res);
203
204         res = new_rd_Proj(tenv.dbg, tenv.irg, tenv.block, res, tenv.mode, pn_ia32_Add_res);
205
206         /* add result Proj to schedule */
207         sched_add_before(irn, res);
208
209         /* remove the old LEA */
210         sched_remove(irn);
211
212         /* exchange the Add and the LEA */
213         exchange(irn, res);
214 }
215
216 static INLINE int need_constraint_copy(ir_node *irn) {
217         return \
218                 ! is_ia32_Lea(irn)          && \
219                 ! is_ia32_Conv_I2I(irn)     && \
220                 ! is_ia32_Conv_I2I8Bit(irn) && \
221                 ! is_ia32_CmpCMov(irn)      && \
222                 ! is_ia32_CmpSet(irn);
223 }
224
225 /**
226  * Insert copies for all ia32 nodes where the should_be_same requirement
227  * is not fulfilled.
228  * Transform Sub into Neg -- Add if IN2 == OUT
229  */
230 static void ia32_finish_node(ir_node *irn, void *env) {
231         ia32_code_gen_t            *cg = env;
232         const ia32_register_req_t **reqs;
233         const arch_register_t      *out_reg, *in_reg, *in2_reg;
234         int                         n_res, i;
235         ir_node                    *copy, *in_node, *block, *in2_node;
236         ia32_op_type_t              op_tp;
237
238         if (is_ia32_irn(irn)) {
239                 /* AM Dest nodes don't produce any values  */
240                 op_tp = get_ia32_op_type(irn);
241                 if (op_tp == ia32_AddrModeD)
242                         goto end;
243
244                 reqs  = get_ia32_out_req_all(irn);
245                 n_res = get_ia32_n_res(irn);
246                 block = get_nodes_block(irn);
247
248                 /* check all OUT requirements, if there is a should_be_same */
249                 if ((op_tp == ia32_Normal || op_tp == ia32_AddrModeS) && need_constraint_copy(irn))
250                 {
251                         for (i = 0; i < n_res; i++) {
252                                 if (arch_register_req_is(&(reqs[i]->req), should_be_same)) {
253                                         /* get in and out register */
254                                         out_reg  = get_ia32_out_reg(irn, i);
255                                         in_node  = get_irn_n(irn, reqs[i]->same_pos);
256                                         in_reg   = arch_get_irn_register(cg->arch_env, in_node);
257
258                                         /* don't copy ignore nodes */
259                                         if (arch_irn_is(cg->arch_env, in_node, ignore) && is_Proj(in_node))
260                                                 continue;
261
262                                         /* check if in and out register are equal */
263                                         if (! REGS_ARE_EQUAL(out_reg, in_reg)) {
264                                                 /* in case of a commutative op: just exchange the in's */
265                                                 /* beware: the current op could be everything, so test for ia32 */
266                                                 /*         commutativity first before getting the second in     */
267                                                 if (is_ia32_commutative(irn)) {
268                                                         in2_node = get_irn_n(irn, reqs[i]->same_pos ^ 1);
269                                                         in2_reg  = arch_get_irn_register(cg->arch_env, in2_node);
270
271                                                         if (REGS_ARE_EQUAL(out_reg, in2_reg)) {
272                                                                 set_irn_n(irn, reqs[i]->same_pos, in2_node);
273                                                                 set_irn_n(irn, reqs[i]->same_pos ^ 1, in_node);
274                                                         }
275                                                         else
276                                                                 goto insert_copy;
277                                                 }
278                                                 else {
279 insert_copy:
280                                                         DBG((cg->mod, LEVEL_1, "inserting copy for %+F in_pos %d\n", irn, reqs[i]->same_pos));
281                                                         /* create copy from in register */
282                                                         copy = be_new_Copy(arch_register_get_class(in_reg), cg->irg, block, in_node);
283
284                                                         DBG_OPT_2ADDRCPY(copy);
285
286                                                         /* destination is the out register */
287                                                         arch_set_irn_register(cg->arch_env, copy, out_reg);
288
289                                                         /* insert copy before the node into the schedule */
290                                                         sched_add_before(irn, copy);
291
292                                                         /* set copy as in */
293                                                         set_irn_n(irn, reqs[i]->same_pos, copy);
294                                                 }
295                                         }
296                                 }
297                         }
298                 }
299
300                 /* If we have a CondJmp/CmpSet/xCmpSet with immediate, we need to    */
301                 /* check if it's the right operand, otherwise we have */
302                 /* to change it, as CMP doesn't support immediate as  */
303                 /* left operands.                                     */
304                 if ((is_ia32_CondJmp(irn) || is_ia32_CmpSet(irn) || is_ia32_xCmpSet(irn)) &&
305                         (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn))                   &&
306                         op_tp == ia32_AddrModeS)
307                 {
308                         set_ia32_op_type(irn, ia32_AddrModeD);
309                         set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn)));
310                 }
311
312                 /* check if there is a sub which need to be transformed */
313                 ia32_transform_sub_to_neg_add(irn, cg);
314
315                 /* transform a LEA into an Add if possible */
316                 ia32_transform_lea_to_add(irn, cg);
317         }
318 end:
319
320         /* check for peephole optimization */
321         ia32_peephole_optimization(irn, cg);
322 }
323
324 static void ia32_finish_irg_walker(ir_node *block, void *env) {
325         ir_node *irn, *next;
326
327         for (irn = sched_first(block); ! sched_is_end(irn); irn = next) {
328                 next = sched_next(irn);
329                 ia32_finish_node(irn, env);
330         }
331 }
332
333 static void ia32_push_on_queue_walker(ir_node *block, void *env) {
334         waitq *wq = env;
335         waitq_put(wq, block);
336 }
337
338
339 /**
340  * Add Copy nodes for not fulfilled should_be_equal constraints
341  */
342 void ia32_finish_irg(ir_graph *irg, ia32_code_gen_t *cg) {
343         waitq *wq = new_waitq();
344
345         /* Push the blocks on the waitq because ia32_finish_irg_walker starts more walks ... */
346         irg_block_walk_graph(irg, NULL, ia32_push_on_queue_walker, wq);
347
348         while (! waitq_empty(wq)) {
349                 ir_node *block = waitq_get(wq);
350                 ia32_finish_irg_walker(block, cg);
351         }
352         del_waitq(wq);
353 }