2 * Storage - associate pseudos with "storage" that keeps them alive
3 * between basic blocks. The aim is to be able to turn as much of
4 * the global storage allocation problem as possible into a local
7 * Copyright (C) 2004 Linus Torvalds
14 #include "expression.h"
15 #include "linearize.h"
18 ALLOCATOR(storage
, "storages");
19 ALLOCATOR(storage_hash
, "storage hash");
21 #define MAX_STORAGE_HASH 64
22 static struct storage_hash_list
*storage_hash_table
[MAX_STORAGE_HASH
];
24 static inline unsigned int storage_hash(struct basic_block
*bb
, pseudo_t pseudo
, enum inout_enum inout
)
26 unsigned hash
= hashval(bb
) + hashval(pseudo
) + hashval(inout
);
27 hash
+= hash
/ MAX_STORAGE_HASH
;
28 return hash
& (MAX_STORAGE_HASH
-1);
31 static int hash_list_cmp(const void *_a
, const void *_b
)
33 const struct storage_hash
*a
= _a
;
34 const struct storage_hash
*b
= _b
;
35 if (a
->pseudo
!= b
->pseudo
)
36 return a
->pseudo
< b
->pseudo
? -1 : 1;
40 static void sort_hash_list(struct storage_hash_list
**listp
)
42 sort_list((struct ptr_list
**)listp
, hash_list_cmp
);
45 struct storage_hash_list
*gather_storage(struct basic_block
*bb
, enum inout_enum inout
)
48 struct storage_hash
*entry
, *prev
;
49 struct storage_hash_list
*list
= NULL
;
51 for (i
= 0; i
< MAX_STORAGE_HASH
; i
++) {
52 struct storage_hash
*hash
;
53 FOR_EACH_PTR(storage_hash_table
[i
], hash
) {
54 if (hash
->bb
== bb
&& hash
->inout
== inout
)
55 add_ptr_list(&list
, hash
);
56 } END_FOR_EACH_PTR(hash
);
58 sort_hash_list(&list
);
61 FOR_EACH_PTR(list
, entry
) {
62 if (prev
&& entry
->pseudo
== prev
->pseudo
) {
63 assert(entry
== prev
);
64 DELETE_CURRENT_PTR(entry
);
67 } END_FOR_EACH_PTR(entry
);
72 static void name_storage(void)
77 for (i
= 0; i
< MAX_STORAGE_HASH
; i
++) {
78 struct storage_hash
*hash
;
79 FOR_EACH_PTR(storage_hash_table
[i
], hash
) {
80 struct storage
*storage
= hash
->storage
;
83 storage
->name
= ++name
;
84 } END_FOR_EACH_PTR(hash
);
88 struct storage
*lookup_storage(struct basic_block
*bb
, pseudo_t pseudo
, enum inout_enum inout
)
90 struct storage_hash_list
*list
= storage_hash_table
[storage_hash(bb
,pseudo
,inout
)];
91 struct storage_hash
*hash
;
93 FOR_EACH_PTR(list
, hash
) {
94 if (hash
->bb
== bb
&& hash
->pseudo
== pseudo
&& hash
->inout
== inout
)
96 } END_FOR_EACH_PTR(hash
);
100 void add_storage(struct storage
*storage
, struct basic_block
*bb
, pseudo_t pseudo
, enum inout_enum inout
)
102 struct storage_hash_list
**listp
= storage_hash_table
+ storage_hash(bb
,pseudo
,inout
);
103 struct storage_hash
*hash
= alloc_storage_hash(storage
);
106 hash
->pseudo
= pseudo
;
109 add_ptr_list(listp
, hash
);
113 static int storage_hash_cmp(const void *_a
, const void *_b
)
115 const struct storage_hash
*a
= _a
;
116 const struct storage_hash
*b
= _b
;
117 struct storage
*aa
= a
->storage
;
118 struct storage
*bb
= b
->storage
;
121 return a
->bb
< b
->bb
? -1 : 1;
122 if (a
->inout
!= b
->inout
)
123 return a
->inout
< b
->inout
? -1 : 1;
124 if (aa
->type
!= bb
->type
)
125 return aa
->type
< bb
->type
? -1 : 1;
126 if (aa
->regno
!= bb
->regno
)
127 return aa
->regno
< bb
->regno
? -1 : 1;
131 static void vrfy_storage(struct storage_hash_list
**listp
)
133 struct storage_hash
*entry
, *last
;
135 sort_list((struct ptr_list
**)listp
, storage_hash_cmp
);
137 FOR_EACH_PTR(*listp
, entry
) {
139 struct storage
*a
= last
->storage
;
140 struct storage
*b
= entry
->storage
;
143 if (last
->bb
== entry
->bb
144 && last
->inout
== entry
->inout
145 && a
->type
!= REG_UDEF
146 && a
->type
== b
->type
147 && a
->regno
== b
->regno
) {
148 printf("\t BAD: same storage as %s in %p: %s (%s and %s)\n",
149 last
->inout
== STOR_IN
? "input" : "output",
152 show_pseudo(last
->pseudo
),
153 show_pseudo(entry
->pseudo
));
157 } END_FOR_EACH_PTR(entry
);
160 void free_storage(void)
164 for (i
= 0; i
< MAX_STORAGE_HASH
; i
++) {
165 vrfy_storage(storage_hash_table
+ i
);
166 free_ptr_list(storage_hash_table
+ i
);
170 const char *show_storage(struct storage
*s
)
172 static char buffer
[1024];
177 sprintf(buffer
, "reg%d (%d)", s
->regno
, s
->name
);
180 sprintf(buffer
, "%d(SP) (%d)", s
->offset
, s
->name
);
183 sprintf(buffer
, "ARG%d (%d)", s
->regno
, s
->name
);
186 sprintf(buffer
, "%d:%d (%d)", s
->type
, s
->regno
, s
->name
);
193 * Combine two storage allocations into one.
195 * We just randomly pick one over the other, and replace
198 static struct storage
* combine_storage(struct storage
*src
, struct storage
*dst
)
200 struct storage
**usep
;
202 /* Remove uses of "src_storage", replace with "dst" */
203 FOR_EACH_PTR(src
->users
, usep
) {
204 assert(*usep
== src
);
206 add_ptr_list(&dst
->users
, usep
);
207 } END_FOR_EACH_PTR(usep
);
215 static void set_up_bb_storage(struct basic_block
*bb
)
217 struct basic_block
*child
;
219 FOR_EACH_PTR(bb
->children
, child
) {
221 FOR_EACH_PTR(child
->needs
, pseudo
) {
222 struct storage
*child_in
, *parent_out
;
224 parent_out
= lookup_storage(bb
, pseudo
, STOR_OUT
);
225 child_in
= lookup_storage(child
, pseudo
, STOR_IN
);
229 add_storage(parent_out
, child
, pseudo
, STOR_IN
);
232 if (parent_out
== child_in
)
234 combine_storage(parent_out
, child_in
);
238 add_storage(child_in
, bb
, pseudo
, STOR_OUT
);
241 parent_out
= alloc_storage();
242 add_storage(parent_out
, bb
, pseudo
, STOR_OUT
);
243 add_storage(parent_out
, child
, pseudo
, STOR_IN
);
244 } END_FOR_EACH_PTR(pseudo
);
245 } END_FOR_EACH_PTR(child
);
248 static void set_up_argument_storage(struct entrypoint
*ep
, struct basic_block
*bb
)
252 FOR_EACH_PTR(bb
->needs
, arg
) {
253 struct storage
*storage
= alloc_storage();
255 /* FIXME! Totally made-up argument passing conventions */
256 if (arg
->type
== PSEUDO_ARG
) {
257 storage
->type
= REG_ARG
;
258 storage
->regno
= arg
->nr
;
260 add_storage(storage
, bb
, arg
, STOR_IN
);
261 } END_FOR_EACH_PTR(arg
);
265 * One phi-source may feed multiple phi nodes. If so, combine
266 * the storage output for this bb into one entry to reduce
269 static void combine_phi_storage(struct basic_block
*bb
)
271 struct instruction
*insn
;
272 FOR_EACH_PTR(bb
->insns
, insn
) {
273 struct instruction
*phi
;
274 struct storage
*last
;
276 if (!insn
->bb
|| insn
->opcode
!= OP_PHISOURCE
)
279 FOR_EACH_PTR(insn
->phi_users
, phi
) {
280 struct storage
*storage
= lookup_storage(bb
, phi
->target
, STOR_OUT
);
282 DELETE_CURRENT_PTR(phi
);
285 if (last
&& storage
!= last
)
286 storage
= combine_storage(storage
, last
);
288 } END_FOR_EACH_PTR(phi
);
289 PACK_PTR_LIST(&insn
->phi_users
);
290 } END_FOR_EACH_PTR(insn
);
293 void set_up_storage(struct entrypoint
*ep
)
295 struct basic_block
*bb
;
297 /* First set up storage for the incoming arguments */
298 set_up_argument_storage(ep
, ep
->entry
->bb
);
300 /* Then do a list of all the inter-bb storage */
301 FOR_EACH_PTR(ep
->bbs
, bb
) {
302 set_up_bb_storage(bb
);
303 combine_phi_storage(bb
);
304 } END_FOR_EACH_PTR(bb
);