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