Skip to content

Commit 91c317f

Browse files
committed
fix scoping issues with reconvergence heuristics
1 parent a66815a commit 91c317f

File tree

3 files changed

+108
-30
lines changed

3 files changed

+108
-30
lines changed

samples/aobench/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
if (TARGET vcc)
22
add_executable(aobench_host ao_host.c ao_main.c)
3-
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ao.comp.c.ll COMMAND vcc ARGS ${CMAKE_CURRENT_SOURCE_DIR}/ao.comp.cpp --only-run-clang -o ${CMAKE_CURRENT_BINARY_DIR}/ao.comp.c.ll COMMENT ao.comp.c.ll DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ao.comp.cpp)
3+
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ao.comp.c.ll COMMAND vcc ARGS ${CMAKE_CURRENT_SOURCE_DIR}/ao.comp.cpp --only-run-clang -O3 -o ${CMAKE_CURRENT_BINARY_DIR}/ao.comp.c.ll COMMENT ao.comp.c.ll DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ao.comp.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ao.c)
44

55
set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/ao_main.c APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ao.comp.c.ll)
66
add_custom_command(TARGET aobench_host POST_BUILD

src/shady/analysis/free_variables.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ static CFNodeVariables* visit_domtree(Context* ctx, CFNode* cfnode, int depth, C
128128
// Unbind parameters
129129
for (size_t j = 0; j < params.count; j++) {
130130
const Node* param = params.nodes[j];
131-
bool r = remove_dict(const Node*, ctx->current_scope->bound_set, param);
132-
assert(r);
131+
assert(find_key_dict(const Node*, ctx->current_scope->bound_set, param));
132+
//bool r = remove_dict(const Node*, ctx->current_scope->bound_set, param);
133+
//assert(r);
133134
}
134135

135136
return ctx->current_scope;

src/shady/passes/reconvergence_heuristics.c

Lines changed: 104 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "../analysis/scope.h"
1515
#include "../analysis/looptree.h"
16+
#include "../analysis/free_variables.h"
1617

1718
#include <assert.h>
1819

@@ -24,6 +25,7 @@ typedef struct Context_ {
2425
Scope* fwd_scope;
2526
Scope* back_scope;
2627
LoopTree* current_looptree;
28+
struct Dict* scope_vars;
2729
} Context;
2830

2931
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
5860
}
5961
}
6062

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+
6187
static const Node* process_abstraction(Context* ctx, const Node* node) {
6288
assert(is_abstraction(node));
6389
Context new_context = *ctx;
@@ -101,14 +127,34 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
101127
Nodes nparams = recreate_variables(rewriter, get_abstraction_params(node));
102128
Nodes inner_yield_types = strip_qualifiers(arena, get_variables_types(arena, nparams));
103129

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);
105138
for (size_t i = 0; i < exiting_nodes_count; i++) {
106139
CFNode* exiting_node = read_list(CFNode*, exiting_nodes)[i];
107140
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);
109142
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);
112158
}
113159

114160
const Node* exit_destination_alloca = NULL;
@@ -125,31 +171,24 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
125171
.yield_types = inner_yield_types
126172
}), true), "jp_continue");
127173

128-
129174
LARRAY(const Node*, exit_wrappers, exiting_nodes_count);
175+
LARRAY(Node*, exit_helpers, exiting_nodes_count);
130176
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+
131179
CFNode* exiting_node = read_list(CFNode*, exiting_nodes)[i];
132180
assert(exiting_node->node && exiting_node->node->tag != Function_TAG);
133181
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-
}));
143182

144183
switch (exiting_node->node->tag) {
145184
case BasicBlock_TAG: {
146185
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));
148187
exit_wrappers[i] = pre_join_exit_bb;
149188
break;
150189
}
151190
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)));
153192
break;
154193
default:
155194
assert(false);
@@ -196,10 +235,40 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
196235
// assert(!search_processed(rewriter, old_params.nodes[i]));
197236
// }
198237

238+
struct Dict* old_map = rewriter->map;
239+
rewriter->map = clone_dict(rewriter->map);
199240
Nodes inner_loop_params = recreate_variables(rewriter, get_abstraction_params(node));
200241
register_processed_list(rewriter, get_abstraction_params(node), inner_loop_params);
201242
const Node* loop_body = recreate_node_identity(rewriter, get_abstraction_body(node));
202243

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+
203272
// restore the old context
204273
for (size_t i = 0; i < exiting_nodes_count; i++) {
205274
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) {
211280
register_processed(rewriter, node, cached_entry);
212281

213282
BodyBuilder* inner_bb = begin_body(arena);
214-
const Node* inner_control = control (arena, (Control) {
283+
const Node* inner_control = control(arena, (Control) {
215284
.inside = case_(arena, singleton(join_token_continue), loop_body),
216285
.yield_types = inner_yield_types
217286
});
@@ -223,7 +292,7 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
223292
.target = loop_outer,
224293
.args = inner_control_results
225294
}));
226-
const Node* outer_control = control (arena, (Control) {
295+
const Node* outer_control = control(arena, (Control) {
227296
.inside = case_(arena, singleton(join_token_exit), jump(arena, (Jump) {
228297
.target = loop_outer,
229298
.args = nparams
@@ -233,34 +302,40 @@ static const Node* process_abstraction(Context* ctx, const Node* node) {
233302

234303
bind_instruction(outer_bb, outer_control);
235304

236-
const Node* outer_body;
237-
238305
LARRAY(const Node*, exit_numbers, exiting_nodes_count);
239306
LARRAY(const Node*, exit_jumps, exiting_nodes_count);
240307
for (size_t i = 0; i < exiting_nodes_count; i++) {
241308
BodyBuilder* exit_recover_bb = begin_body(arena);
242309

310+
// recover the context
243311
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+
244317
const Node* recreated_exit = rewrite_node(rewriter, exiting_node->node);
245318

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]);
249322

250323
exit_numbers[i] = int32_literal(arena, i);
251324
Node* exit_bb = basic_block(arena, fn, empty(arena), format_string_arena(arena->arena, "exit_recover_values_%s", get_abstraction_name(exiting_node->node)));
252325
if (recreated_exit->tag == BasicBlock_TAG) {
253326
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),
256329
}));
257330
} else {
258331
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));
260333
}
261334
exit_jumps[i] = jump_helper(arena, exit_bb, empty(arena));
335+
destroy_list(leaking[i]);
262336
}
263337

338+
const Node* outer_body;
264339
if (exiting_nodes_count == 1)
265340
outer_body = finish_body(outer_bb, exit_jumps[0]->payload.jump.target->payload.basic_block.body);
266341
else {
@@ -311,12 +386,14 @@ static const Node* process_node(Context* ctx, const Node* node) {
311386
ctx->fwd_scope = new_scope(ctx->current_fn);
312387
ctx->back_scope = new_scope_flipped(ctx->current_fn);
313388
ctx->current_looptree = build_loop_tree(ctx->fwd_scope);
389+
ctx->scope_vars = compute_scope_variables_map(ctx->fwd_scope);
314390

315391
const Node* new = process_abstraction(ctx, node);;
316392

317393
destroy_scope(ctx->fwd_scope);
318394
destroy_scope(ctx->back_scope);
319395
destroy_loop_tree(ctx->current_looptree);
396+
destroy_scope_variables_map(ctx->scope_vars);
320397
return new;
321398
}
322399
case Case_TAG:
@@ -360,7 +437,7 @@ static const Node* process_node(Context* ctx, const Node* node) {
360437
idom = cfnode->idom->node;
361438
}
362439

363-
if(!idom) {
440+
if (!idom) {
364441
break;
365442
}
366443

0 commit comments

Comments
 (0)