13
13
14
14
#include "../analysis/scope.h"
15
15
#include "../analysis/looptree.h"
16
+ #include "../analysis/free_variables.h"
16
17
17
18
#include <assert.h>
18
19
@@ -24,6 +25,7 @@ typedef struct Context_ {
24
25
Scope * fwd_scope ;
25
26
Scope * back_scope ;
26
27
LoopTree * current_looptree ;
28
+ struct Dict * scope_vars ;
27
29
} Context ;
28
30
29
31
static bool in_loop (LoopTree * lt , const Node * entry , const Node * block ) {
@@ -58,6 +60,30 @@ static void gather_exiting_nodes(LoopTree* lt, const CFNode* entry, const CFNode
58
60
}
59
61
}
60
62
63
+ static void find_unbound_vars (const Node * node , struct Dict * bound_set , struct Dict * free_set , struct List * leaking ) {
64
+ const Node * free_post ;
65
+ size_t i = 0 ;
66
+ while (dict_iter (free_set , & i , & free_post , NULL )) {
67
+ const Node * bound_pre ;
68
+ size_t j = 0 ;
69
+ while (dict_iter (bound_set , & j , & bound_pre , NULL )) {
70
+ if (bound_pre == free_post ) {
71
+ goto next ;
72
+ }
73
+ }
74
+
75
+ log_string (DEBUGVV , "Found variable used outside it's control scope: " );
76
+ log_node (DEBUGVV , free_post );
77
+ log_string (DEBUGVV , " (original:" );
78
+ log_node (DEBUGVV , node );
79
+ log_string (DEBUGVV , " )\n" );
80
+
81
+ append_list (const Node * , leaking , free_post );
82
+
83
+ next :;
84
+ }
85
+ }
86
+
61
87
static const Node * process_abstraction (Context * ctx , const Node * node ) {
62
88
assert (is_abstraction (node ));
63
89
Context new_context = * ctx ;
@@ -101,14 +127,34 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
101
127
Nodes nparams = recreate_variables (rewriter , get_abstraction_params (node ));
102
128
Nodes inner_yield_types = strip_qualifiers (arena , get_variables_types (arena , nparams ));
103
129
104
- LARRAY (Nodes , exit_allocas , exiting_nodes_count );
130
+ CFNode * cf_pre = scope_lookup (ctx -> fwd_scope , node );
131
+ // assert(cf_pre->idom && "cfg entry nodes can't be loop headers anyhow");
132
+ // cf_pre = cf_pre->idom;
133
+ CFNodeVariables * pre = * find_value_dict (CFNode * , CFNodeVariables * , ctx -> scope_vars , cf_pre );
134
+
135
+ LARRAY (Nodes , exit_param_allocas , exiting_nodes_count );
136
+ LARRAY (struct List * , leaking , exiting_nodes_count );
137
+ LARRAY (Nodes , exit_fwd_allocas , exiting_nodes_count );
105
138
for (size_t i = 0 ; i < exiting_nodes_count ; i ++ ) {
106
139
CFNode * exiting_node = read_list (CFNode * , exiting_nodes )[i ];
107
140
Nodes exit_param_types = rewrite_nodes (rewriter , get_variables_types (ctx -> rewriter .src_arena , get_abstraction_params (exiting_node -> node )));
108
- LARRAY (const Node * , allocas , exit_param_types .count );
141
+ LARRAY (const Node * , exit_param_allocas_tmp , exit_param_types .count );
109
142
for (size_t j = 0 ; j < exit_param_types .count ; j ++ )
110
- allocas [j ] = gen_primop_e (outer_bb , alloca_op , singleton (get_unqualified_type (exit_param_types .nodes [j ])), empty (arena ));
111
- exit_allocas [i ] = nodes (arena , exit_param_types .count , allocas );
143
+ exit_param_allocas_tmp [j ] = gen_primop_e (outer_bb , alloca_op , singleton (get_unqualified_type (exit_param_types .nodes [j ])), empty (arena ));
144
+ exit_param_allocas [i ] = nodes (arena , exit_param_types .count , exit_param_allocas_tmp );
145
+
146
+ // Search for what's required after the exit but not in scope at the loop header
147
+ // this is similar to the LCSSA constraint, but here it's because controls have hard scopes
148
+ CFNode * cf_post = scope_lookup (ctx -> fwd_scope , exiting_node -> node );
149
+ CFNodeVariables * post = * find_value_dict (CFNode * , CFNodeVariables * , ctx -> scope_vars , cf_post );
150
+ leaking [i ] = new_list (const Type * );
151
+ find_unbound_vars (exiting_node -> node , pre -> bound_set , post -> free_set , leaking [i ]);
152
+
153
+ size_t leaking_count = entries_count_list (leaking [i ]);
154
+ LARRAY (const Node * , exit_fwd_allocas_tmp , leaking_count );
155
+ for (size_t j = 0 ; j < leaking_count ; j ++ )
156
+ exit_fwd_allocas_tmp [j ] = gen_primop_e (outer_bb , alloca_op , singleton (rewrite_node (rewriter , get_unqualified_type (read_list (const Node * , leaking [i ])[j ]-> type ))), empty (arena ));
157
+ exit_fwd_allocas [i ] = nodes (arena , leaking_count , exit_fwd_allocas_tmp );
112
158
}
113
159
114
160
const Node * exit_destination_alloca = NULL ;
@@ -125,31 +171,24 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
125
171
.yield_types = inner_yield_types
126
172
}), true), "jp_continue" );
127
173
128
-
129
174
LARRAY (const Node * , exit_wrappers , exiting_nodes_count );
175
+ LARRAY (Node * , exit_helpers , exiting_nodes_count );
130
176
for (size_t i = 0 ; i < exiting_nodes_count ; i ++ ) {
177
+ exit_helpers [i ] = basic_block (arena , fn , empty (arena ), format_string_arena (arena -> arena , "exit_helper_%d" , i ));
178
+
131
179
CFNode * exiting_node = read_list (CFNode * , exiting_nodes )[i ];
132
180
assert (exiting_node -> node && exiting_node -> node -> tag != Function_TAG );
133
181
Nodes exit_wrapper_params = recreate_variables (& ctx -> rewriter , get_abstraction_params (exiting_node -> node ));
134
- BodyBuilder * exit_wrapper_bb = begin_body (arena );
135
-
136
- for (size_t j = 0 ; j < exit_allocas [i ].count ; j ++ )
137
- gen_store (exit_wrapper_bb , exit_allocas [i ].nodes [j ], exit_wrapper_params .nodes [j ]);
138
-
139
- const Node * exit_wrapper_body = finish_body (exit_wrapper_bb , join (arena , (Join ) {
140
- .join_point = join_token_exit ,
141
- .args = empty (arena )
142
- }));
143
182
144
183
switch (exiting_node -> node -> tag ) {
145
184
case BasicBlock_TAG : {
146
185
Node * pre_join_exit_bb = basic_block (arena , fn , exit_wrapper_params , format_string_arena (arena -> arena , "exit_wrapper_%d" , i ));
147
- pre_join_exit_bb -> payload .basic_block .body = exit_wrapper_body ;
186
+ pre_join_exit_bb -> payload .basic_block .body = jump_helper ( arena , exit_helpers [ i ], empty ( arena )) ;
148
187
exit_wrappers [i ] = pre_join_exit_bb ;
149
188
break ;
150
189
}
151
190
case Case_TAG :
152
- exit_wrappers [i ] = case_ (arena , exit_wrapper_params , exit_wrapper_body );
191
+ exit_wrappers [i ] = case_ (arena , exit_wrapper_params , jump_helper ( arena , exit_helpers [ i ], empty ( arena )) );
153
192
break ;
154
193
default :
155
194
assert (false);
@@ -196,10 +235,40 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
196
235
// assert(!search_processed(rewriter, old_params.nodes[i]));
197
236
// }
198
237
238
+ struct Dict * old_map = rewriter -> map ;
239
+ rewriter -> map = clone_dict (rewriter -> map );
199
240
Nodes inner_loop_params = recreate_variables (rewriter , get_abstraction_params (node ));
200
241
register_processed_list (rewriter , get_abstraction_params (node ), inner_loop_params );
201
242
const Node * loop_body = recreate_node_identity (rewriter , get_abstraction_body (node ));
202
243
244
+ // save the context
245
+ for (size_t i = 0 ; i < exiting_nodes_count ; i ++ ) {
246
+ CFNode * exiting_node = read_list (CFNode * , exiting_nodes )[i ];
247
+ assert (exiting_node -> node && exiting_node -> node -> tag != Function_TAG );
248
+ Nodes exit_wrapper_params = get_abstraction_params (exit_helpers [i ]);
249
+ BodyBuilder * exit_wrapper_bb = begin_body (arena );
250
+
251
+ for (size_t j = 0 ; j < exit_param_allocas [i ].count ; j ++ )
252
+ gen_store (exit_wrapper_bb , exit_param_allocas [i ].nodes [j ], exit_wrapper_params .nodes [j ]);
253
+ if (exiting_nodes_count > 1 )
254
+ gen_store (exit_wrapper_bb , exit_destination_alloca , int32_literal (arena , i ));
255
+
256
+ for (size_t j = 0 ; j < exit_fwd_allocas [i ].count ; j ++ ) {
257
+ gen_store (exit_wrapper_bb , exit_fwd_allocas [i ].nodes [j ], rewrite_node (rewriter , read_list (const Node * , leaking [i ])[j ]));
258
+ }
259
+
260
+ const Node * exit_wrapper_body = finish_body (exit_wrapper_bb , join (arena , (Join ) {
261
+ .join_point = join_token_exit ,
262
+ .args = empty (arena )
263
+ }));
264
+
265
+ exit_helpers [i ]-> payload .basic_block .body = exit_wrapper_body ;
266
+ }
267
+
268
+ destroy_dict (rewriter -> map );
269
+ rewriter -> map = old_map ;
270
+ register_processed_list (rewriter , get_abstraction_params (node ), nparams );
271
+
203
272
// restore the old context
204
273
for (size_t i = 0 ; i < exiting_nodes_count ; i ++ ) {
205
274
remove_dict (const Node * , rewriter -> map , read_list (CFNode * , exiting_nodes )[i ]-> node );
@@ -211,7 +280,7 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
211
280
register_processed (rewriter , node , cached_entry );
212
281
213
282
BodyBuilder * inner_bb = begin_body (arena );
214
- const Node * inner_control = control (arena , (Control ) {
283
+ const Node * inner_control = control (arena , (Control ) {
215
284
.inside = case_ (arena , singleton (join_token_continue ), loop_body ),
216
285
.yield_types = inner_yield_types
217
286
});
@@ -223,7 +292,7 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
223
292
.target = loop_outer ,
224
293
.args = inner_control_results
225
294
}));
226
- const Node * outer_control = control (arena , (Control ) {
295
+ const Node * outer_control = control (arena , (Control ) {
227
296
.inside = case_ (arena , singleton (join_token_exit ), jump (arena , (Jump ) {
228
297
.target = loop_outer ,
229
298
.args = nparams
@@ -233,34 +302,40 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
233
302
234
303
bind_instruction (outer_bb , outer_control );
235
304
236
- const Node * outer_body ;
237
-
238
305
LARRAY (const Node * , exit_numbers , exiting_nodes_count );
239
306
LARRAY (const Node * , exit_jumps , exiting_nodes_count );
240
307
for (size_t i = 0 ; i < exiting_nodes_count ; i ++ ) {
241
308
BodyBuilder * exit_recover_bb = begin_body (arena );
242
309
310
+ // recover the context
243
311
CFNode * exiting_node = read_list (CFNode * , exiting_nodes )[i ];
312
+ for (size_t j = 0 ; j < exit_fwd_allocas [i ].count ; j ++ ) {
313
+ const Node * recovered = gen_load (exit_recover_bb , exit_fwd_allocas [i ].nodes [j ]);
314
+ register_processed (rewriter , read_list (const Node * , leaking [i ])[j ], recovered );
315
+ }
316
+
244
317
const Node * recreated_exit = rewrite_node (rewriter , exiting_node -> node );
245
318
246
- LARRAY (const Node * , recovered_args , exit_allocas [i ].count );
247
- for (size_t j = 0 ; j < exit_allocas [i ].count ; j ++ )
248
- recovered_args [j ] = gen_load (exit_recover_bb , exit_allocas [i ].nodes [j ]);
319
+ LARRAY (const Node * , recovered_args , exit_param_allocas [i ].count );
320
+ for (size_t j = 0 ; j < exit_param_allocas [i ].count ; j ++ )
321
+ recovered_args [j ] = gen_load (exit_recover_bb , exit_param_allocas [i ].nodes [j ]);
249
322
250
323
exit_numbers [i ] = int32_literal (arena , i );
251
324
Node * exit_bb = basic_block (arena , fn , empty (arena ), format_string_arena (arena -> arena , "exit_recover_values_%s" , get_abstraction_name (exiting_node -> node )));
252
325
if (recreated_exit -> tag == BasicBlock_TAG ) {
253
326
exit_bb -> payload .basic_block .body = finish_body (exit_recover_bb , jump (arena , (Jump ) {
254
- .target = recreated_exit ,
255
- .args = nodes (arena , exit_allocas [i ].count , recovered_args ),
327
+ .target = recreated_exit ,
328
+ .args = nodes (arena , exit_param_allocas [i ].count , recovered_args ),
256
329
}));
257
330
} else {
258
331
assert (recreated_exit -> tag == Case_TAG );
259
- exit_bb -> payload .basic_block .body = finish_body (exit_recover_bb , let (arena , quote_helper (arena , nodes (arena , exit_allocas [i ].count , recovered_args )), recreated_exit ));
332
+ exit_bb -> payload .basic_block .body = finish_body (exit_recover_bb , let (arena , quote_helper (arena , nodes (arena , exit_param_allocas [i ].count , recovered_args )), recreated_exit ));
260
333
}
261
334
exit_jumps [i ] = jump_helper (arena , exit_bb , empty (arena ));
335
+ destroy_list (leaking [i ]);
262
336
}
263
337
338
+ const Node * outer_body ;
264
339
if (exiting_nodes_count == 1 )
265
340
outer_body = finish_body (outer_bb , exit_jumps [0 ]-> payload .jump .target -> payload .basic_block .body );
266
341
else {
@@ -311,12 +386,14 @@ static const Node* process_node(Context* ctx, const Node* node) {
311
386
ctx -> fwd_scope = new_scope (ctx -> current_fn );
312
387
ctx -> back_scope = new_scope_flipped (ctx -> current_fn );
313
388
ctx -> current_looptree = build_loop_tree (ctx -> fwd_scope );
389
+ ctx -> scope_vars = compute_scope_variables_map (ctx -> fwd_scope );
314
390
315
391
const Node * new = process_abstraction (ctx , node );;
316
392
317
393
destroy_scope (ctx -> fwd_scope );
318
394
destroy_scope (ctx -> back_scope );
319
395
destroy_loop_tree (ctx -> current_looptree );
396
+ destroy_scope_variables_map (ctx -> scope_vars );
320
397
return new ;
321
398
}
322
399
case Case_TAG :
@@ -360,7 +437,7 @@ static const Node* process_node(Context* ctx, const Node* node) {
360
437
idom = cfnode -> idom -> node ;
361
438
}
362
439
363
- if (!idom ) {
440
+ if (!idom ) {
364
441
break ;
365
442
}
366
443
0 commit comments