edfd9a7a56bc4b1187227957061cca13f9bd20ee
[libfirm] / ir / lower / lower_copyb.c
1 /*
2  * Copyright (C) 1995-2007 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   Lower small CopyB nodes into a series of Load/store
23  * @author  Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "ircons.h"
31 #include "lowering.h"
32 #include "irprog_t.h"
33 #include "irnode_t.h"
34 #include "type_t.h"
35 #include "irtools.h"
36
37 typedef struct copyb_env {
38         ir_node *next;      /**< link to the next one */
39 } copyb_env;
40
41
42 typedef struct walker_env {
43         struct obstack obst;      /**< temporary space */
44         int            max_size;
45         ir_node        *list;     /**< list of CopyB nodes. */
46 } walker_env;
47
48 /**
49  * Build a graph that copies an entity of type tp from src to tgt
50  */
51 static ir_node *build_copy_graph(dbg_info *dbg, ir_node *blk, ir_node *mem, ir_node *src, ir_node *tgt, ir_type *tp) {
52         int i, n;
53
54         if (is_Array_type(tp)) {
55                 assert(0);
56         } else {
57                 for (i = 0, n = get_compound_n_members(tp); i < n; ++i) {
58                         ir_entity *ent  = get_compound_member(tp, i);
59                         ir_node *s      = new_d_simpleSel(dbg, mem, src, ent);
60                         ir_node *d      = new_d_simpleSel(dbg, mem, tgt, ent);
61                         ir_type *ent_tp = get_entity_type(ent);
62
63                         if (is_atomic_type(ent_tp)) {
64                                 ir_mode *mode = get_type_mode(ent_tp);
65                                 ir_node *irn  = new_rd_Load(dbg, current_ir_graph, blk, mem, s, mode);
66                                 ir_node *res  = new_r_Proj(current_ir_graph, blk, irn, mode, pn_Load_res);
67
68                                 mem = new_r_Proj(current_ir_graph, blk, irn, mode_M, pn_Load_M);
69                                 irn = new_rd_Store(dbg, current_ir_graph, blk, mem, d, res);
70                                 mem = new_r_Proj(current_ir_graph, blk, irn, mode_M, pn_Store_M);
71                         } else {
72                                 mem = build_copy_graph(dbg, blk, mem, s, d, ent_tp);
73                         }
74                 }
75         }
76         return mem;
77 }
78
79 /**
80  * Walker: lower small CopyB nodes.
81  */
82 static void lower_copyb_nodes(ir_node *irn, void *ctx) {
83         ir_type    *tp;
84         int        size;
85         walker_env *env = ctx;
86
87         if (! is_CopyB(irn))
88                 return;
89
90         tp = get_CopyB_type(irn);
91         if (get_type_state(tp) != layout_fixed)
92                 return;
93
94         size = get_type_size_bytes(tp);
95         if (size > env->max_size)
96                 return;
97
98         /* for now, we can only handle Struct's */
99         if (is_Struct_type(tp)) {
100                 irn = build_copy_graph(get_irn_dbg_info(irn), get_nodes_block(irn), get_CopyB_mem(irn), get_CopyB_src(irn), get_CopyB_dst(irn), tp);
101         }
102 }
103
104 /**
105  * Lower CopyB nodes of size smaller that max_size into Loads/Stores
106  */
107 void lower_CopyB(int max_size) {
108         walker_env env;
109         int        i;
110
111         obstack_init(&env.obst);
112         env.max_size = max_size;
113         env.list     = NULL;
114         for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
115                 irg_walk_graph(get_irp_irg(i), firm_clear_link, lower_copyb_nodes, NULL);
116         }
117 }