cleanup: Remove pointless assert(is_${NODE}(x)) just before get_${NODE}_${FOO}(x...
[libfirm] / ir / lower / lower_alloc.c
1 /*
2  * Copyright (C) 2011 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 (stack-) Alloc nodes to allocate an aligned number of bytes
23  * @author  Matthias Braun
24  */
25 #include "config.h"
26
27 #include "lower_alloc.h"
28 #include "irgwalk.h"
29 #include "irnode_t.h"
30 #include "ircons.h"
31 #include "error.h"
32 #include "irgmod.h"
33 #include "irnodeset.h"
34
35 static bool         lower_constant_sizes;
36 static unsigned     stack_alignment;
37 static long         addr_delta;
38 static ir_nodeset_t transformed;
39
40 /**
41  * Adjust the size of a node representing a stack alloc to a certain
42  * stack_alignment.
43  *
44  * @param size       the node containing the non-aligned size
45  * @param block      the block where new nodes are allocated on
46  * @return a node representing the aligned size
47  */
48 static ir_node *adjust_alloc_size(dbg_info *dbgi, ir_node *size, ir_node *block)
49 {
50         ir_mode   *mode;
51         ir_tarval *tv;
52         ir_node   *mask;
53         ir_graph  *irg;
54
55         if (stack_alignment <= 1)
56                 return size;
57         if (is_Const(size) && !lower_constant_sizes)
58                 return size;
59
60         mode = get_irn_mode(size);
61         tv   = new_tarval_from_long(stack_alignment-1, mode);
62         irg  = get_Block_irg(block);
63         mask = new_r_Const(irg, tv);
64         size = new_rd_Add(dbgi, block, size, mask, mode);
65
66         tv   = new_tarval_from_long(-(long)stack_alignment, mode);
67         mask = new_r_Const(irg, tv);
68         size = new_rd_And(dbgi, block, size, mask, mode);
69         return size;
70 }
71
72 static void transform_Proj_Alloc(ir_node *node)
73 {
74         ir_graph *irg;
75         dbg_info *dbgi;
76         ir_node *block;
77         ir_node *delta;
78         ir_node *add;
79         ir_node *dummy;
80         ir_node *alloc;
81         ir_node *new_proj;
82
83         /* we might need a result adjustment */
84         if (addr_delta == 0)
85                 return;
86         if (get_Proj_proj(node) != pn_Alloc_res)
87                 return;
88         if (ir_nodeset_contains(&transformed, node))
89                 return;
90
91         alloc = get_Proj_pred(node);
92         dbgi  = get_irn_dbg_info(alloc);
93         irg   = get_irn_irg(node);
94         block = get_nodes_block(node);
95         delta = new_r_Const_long(irg, mode_P, addr_delta);
96         dummy = new_r_Dummy(irg, mode_P);
97         add   = new_rd_Add(dbgi, block, dummy, delta, mode_P);
98
99         exchange(node, add);
100         new_proj = new_r_Proj(alloc, mode_P, pn_Alloc_res);
101         set_Add_left(add, new_proj);
102         ir_nodeset_insert(&transformed, new_proj);
103 }
104
105 /**
106  * lower Alloca nodes to allocate "bytes" instead of a certain type
107  */
108 static void lower_alloca_free(ir_node *node, void *data)
109 {
110         ir_type  *type;
111         unsigned  size;
112         ir_graph *irg;
113         ir_node  *count;
114         ir_mode  *mode;
115         ir_node  *szconst;
116         ir_node  *block;
117         ir_node  *mem;
118         ir_type  *new_type;
119         ir_node  *mul;
120         ir_node  *new_size;
121         dbg_info *dbgi;
122         ir_node  *new_node;
123         ir_where_alloc where;
124         (void) data;
125         if (is_Alloc(node)) {
126                 type = get_Alloc_type(node);
127         } else if (is_Free(node)) {
128                 type = get_Free_type(node);
129         } else if (is_Proj(node)) {
130                 ir_node *proj_pred = get_Proj_pred(node);
131                 if (is_Alloc(proj_pred)) {
132                         transform_Proj_Alloc(node);
133                 }
134                 return;
135         } else {
136                 return;
137         }
138         if (ir_nodeset_contains(&transformed, node))
139                 return;
140
141         ir_nodeset_insert(&transformed, node);
142         size = get_type_size_bytes(type);
143         if (is_unknown_type(type))
144                 size = 1;
145         if (size == 1 && stack_alignment <= 1)
146                 return;
147
148         if (is_Alloc(node)) {
149                 count     = get_Alloc_count(node);
150                 mem       = get_Alloc_mem(node);
151                 where     = get_Alloc_where(node);
152         } else {
153                 count = get_Free_count(node);
154                 mem   = get_Free_mem(node);
155                 where = get_Free_where(node);
156         }
157         mode      = get_irn_mode(count);
158         block     = get_nodes_block(node);
159         irg       = get_irn_irg(node);
160         szconst   = new_r_Const_long(irg, mode, (long)size);
161         mul       = new_r_Mul(block, count, szconst, mode);
162         dbgi      = get_irn_dbg_info(node);
163         new_size  = adjust_alloc_size(dbgi, mul, block);
164         new_type  = get_unknown_type();
165         if (is_Alloc(node)) {
166                 new_node = new_rd_Alloc(dbgi, block, mem, new_size, new_type, where);
167         } else {
168                 ir_node *ptr = get_Free_ptr(node);
169                 new_node
170                         = new_rd_Free(dbgi, block, mem, ptr, new_size, new_type, where);
171         }
172         ir_nodeset_insert(&transformed, new_node);
173
174         if (new_node != node)
175                 exchange(node, new_node);
176 }
177
178 void lower_alloc(ir_graph *irg, unsigned new_stack_alignment, bool lower_consts,
179                  long new_addr_delta)
180 {
181         if (!is_po2(stack_alignment))
182                 panic("stack alignment not a power of 2");
183         addr_delta           = new_addr_delta;
184         stack_alignment      = new_stack_alignment;
185         lower_constant_sizes = lower_consts;
186         ir_nodeset_init(&transformed);
187         irg_walk_graph(irg, lower_alloca_free, NULL, NULL);
188         ir_nodeset_destroy(&transformed);
189 }