From 47a9b594c07bbd8eb276856eff913557c326fded Mon Sep 17 00:00:00 2001 From: Ajay Brahmakshatriya Date: Wed, 20 Dec 2023 20:39:01 -0500 Subject: [PATCH] Fixed bug with dynamic variables escaping static scopes getting different names --- include/blocks/var_namer.h | 19 +++++++++- include/builder/array.h | 18 +++++++++ include/builder/dyn_var.h | 6 +-- include/util/tracer.h | 27 ++++++++++++++ samples/outputs.var_names/sample40 | 17 +++++---- samples/outputs.var_names/sample48 | 24 ++++++++++-- samples/outputs.var_names/sample52 | 49 +++++++++++++++++-------- samples/outputs.var_names/sample54 | 12 ++++++ samples/outputs/sample40 | 17 +++++---- samples/outputs/sample48 | 24 ++++++++++-- samples/outputs/sample52 | 49 +++++++++++++++++-------- samples/outputs/sample54 | 12 ++++++ samples/sample48.cpp | 2 + samples/sample53.cpp | 9 ++--- samples/sample54.cpp | 39 ++++++++++++++++++++ src/blocks/c_code_generator.cpp | 1 + src/blocks/var_namer.cpp | 39 +++++++++++++++++--- src/builder/builder.cpp | 4 +- src/builder/builder_context.cpp | 1 - src/builder/builder_context_support.cpp | 3 +- 20 files changed, 297 insertions(+), 75 deletions(-) create mode 100644 samples/outputs.var_names/sample54 create mode 100644 samples/outputs/sample54 create mode 100644 samples/sample54.cpp diff --git a/include/blocks/var_namer.h b/include/blocks/var_namer.h index 6ef24ef..7a1eb68 100644 --- a/include/blocks/var_namer.h +++ b/include/blocks/var_namer.h @@ -8,6 +8,14 @@ namespace block { +class var_gather_escapes : public block_visitor { +public: + using block_visitor::visit; + std::vector &escaping_tags; + var_gather_escapes(std::vector &e) : escaping_tags(e) {} + virtual void visit(decl_stmt::Ptr) override; +}; + class var_namer : public block_visitor { public: using block_visitor::visit; @@ -15,6 +23,9 @@ class var_namer : public block_visitor { std::map collected_decls; std::map decls_to_hoist; std::vector decl_tags_to_hoist; + + std::vector escaping_tags; + virtual void visit(decl_stmt::Ptr) override; static void name_vars(block::Ptr ast); @@ -24,7 +35,9 @@ class var_replacer : public block_visitor { public: using block_visitor::visit; std::map &collected_decls; - var_replacer(std::map &d) : collected_decls(d) {} + std::vector &escaping_tags; + var_replacer(std::map &d, std::vector &e) + : collected_decls(d), escaping_tags(e) {} virtual void visit(var_expr::Ptr) override; }; @@ -33,7 +46,9 @@ class var_hoister : public block_replacer { public: using block_replacer::visit; std::map &decls_to_hoist; - var_hoister(std::map &d) : decls_to_hoist(d) {} + std::vector &escaping_tags; + var_hoister(std::map &d, std::vector &e) + : decls_to_hoist(d), escaping_tags(e) {} virtual void visit(decl_stmt::Ptr) override; }; diff --git a/include/builder/array.h b/include/builder/array.h index 1c232a7..f235615 100644 --- a/include/builder/array.h +++ b/include/builder/array.h @@ -19,6 +19,15 @@ class dyn_arr { for (static_var i = 0; i < actual_size; i++) { new (m_arr + i) dyn_var(); } + // static tags for array nodes need to be adjusted + // so they are treated different from each other despite + // being declared at the same location. + // dyn_arr are special case of vars that escape their static scope but still + // shouldn't be treated together + // We do this by adding additional metadata on all of them + for (static_var i = 0; i < actual_size; i++) { + m_arr[i].block_var->template setMetadata("allow_escape_scope", 1); + } } } dyn_arr(const std::initializer_list &init) { @@ -34,6 +43,9 @@ class dyn_arr { else new (m_arr + i) dyn_var(); } + for (static_var i = 0; i < actual_size; i++) { + m_arr[i].block_var->template setMetadata("allow_escape_scope", 1); + } } void set_size(size_t new_size) { assert(size == 0 && "set_size should be only called for dyn_arr without size"); @@ -43,6 +55,9 @@ class dyn_arr { for (static_var i = 0; i < actual_size; i++) { new (m_arr + i) dyn_var(); } + for (static_var i = 0; i < actual_size; i++) { + m_arr[i].block_var->template setMetadata("allow_escape_scope", 1); + } } template @@ -59,6 +74,9 @@ class dyn_arr { else new (m_arr + i) dyn_var(); } + for (static_var i = 0; i < actual_size; i++) { + m_arr[i].block_var->template setMetadata("allow_escape_scope", 1); + } } dyn_arr(const dyn_arr &other) { diff --git a/include/builder/dyn_var.h b/include/builder/dyn_var.h index a09c30e..ee58214 100644 --- a/include/builder/dyn_var.h +++ b/include/builder/dyn_var.h @@ -234,12 +234,12 @@ class dyn_var_impl : public var { var_name = v.name; } - dyn_var_impl(const defer_init&) { + dyn_var_impl(const defer_init &) { // Do nothing here } - // The function to actually initialize a dyn_var, if it + // The function to actually initialize a dyn_var, if it // has been deferred. It is OKAY to call this even if defer_init - // is not used, but is not adviced. This can definitely be called multiple + // is not used, but is not adviced. This can definitely be called multiple // times and will produce the same dyn_var based on the static tag at the // time of this call // Currently we don't support init val, but can be added if needed diff --git a/include/util/tracer.h b/include/util/tracer.h index ec54a3c..5c4d758 100644 --- a/include/util/tracer.h +++ b/include/util/tracer.h @@ -58,6 +58,33 @@ class tag { return output_string; } + + std::string stringify_loc(void) { + std::string output_string = "["; + for (unsigned int i = 0; i < pointers.size(); i++) { + char temp[128]; + sprintf(temp, "%llx", pointers[i]); + output_string += temp; + if (i != pointers.size() - 1) + output_string += ", "; + } + output_string += "]:["; + output_string += "]"; + + return output_string; + } + std::string stringify_stat(void) { + std::string output_string = "["; + output_string += "]:["; + for (unsigned int i = 0; i < static_var_snapshots.size(); i++) { + output_string += static_var_snapshots[i]; + if (i != static_var_snapshots.size() - 1) + output_string += ", "; + } + output_string += "]"; + + return output_string; + } }; tag get_unique_tag(void); diff --git a/samples/outputs.var_names/sample40 b/samples/outputs.var_names/sample40 index c1363c1..b318865 100644 --- a/samples/outputs.var_names/sample40 +++ b/samples/outputs.var_names/sample40 @@ -1,7 +1,7 @@ #include int match_re (char* arg1) { int var3; - int var5; + int var4; int str_len_1 = strlen(arg1); int to_match_2 = 0; if (to_match_2 < str_len_1) { @@ -27,13 +27,14 @@ int match_re (char* arg1) { var3 = 0; return var3; } - return 1; + var4 = 1; + return var4; } var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } if (arg1[to_match_2] == 100) { goto label2; @@ -41,13 +42,13 @@ int match_re (char* arg1) { var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } diff --git a/samples/outputs.var_names/sample48 b/samples/outputs.var_names/sample48 index 927b316..d4713ab 100644 --- a/samples/outputs.var_names/sample48 +++ b/samples/outputs.var_names/sample48 @@ -5,22 +5,38 @@ FUNC_DECL SCALAR_TYPE (INT) VAR (x_0) NO_INITIALIZATION + DECL_STMT + SCALAR_TYPE (INT) + VAR (var1) + INT_CONST (0) + DECL_STMT + SCALAR_TYPE (INT) + VAR (var2) + INT_CONST (0) + EXPR_STMT + ASSIGN_EXPR + VAR_EXPR + VAR (var1) + INT_CONST (1) WHILE_STMT INT_CONST (1) STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (var1) + VAR (var3) INT_CONST (1) DECL_STMT SCALAR_TYPE (INT) - VAR (var2) + VAR (var4) INT_CONST (2) void my_bar (void) { int x_0; + int var1 = 0; + int var2 = 0; + var1 = 1; while (1) { - int var1 = 1; - int var2 = 2; + int var3 = 1; + int var4 = 2; } } diff --git a/samples/outputs.var_names/sample52 b/samples/outputs.var_names/sample52 index 009efe3..dfa1927 100644 --- a/samples/outputs.var_names/sample52 +++ b/samples/outputs.var_names/sample52 @@ -1,49 +1,66 @@ int isEven (int arg0) { + int var1; if (arg0 == 0) { - return 1; + var1 = 1; + return var1; } if (arg0 == 1) { - return 0; + var1 = 0; + return var1; } if (arg0 == 2) { - return 1; + var1 = 1; + return var1; } if (arg0 == 3) { - return 0; + var1 = 0; + return var1; } if (arg0 == 4) { - return 1; + var1 = 1; + return var1; } if (arg0 == 5) { - return 0; + var1 = 0; + return var1; } if (arg0 == 6) { - return 1; + var1 = 1; + return var1; } if (arg0 == 7) { - return 0; + var1 = 0; + return var1; } if (arg0 == 8) { - return 1; + var1 = 1; + return var1; } if (arg0 == 9) { - return 0; + var1 = 0; + return var1; } if (arg0 == 10) { - return 1; + var1 = 1; + return var1; } if (arg0 == 11) { - return 0; + var1 = 0; + return var1; } if (arg0 == 12) { - return 1; + var1 = 1; + return var1; } if (arg0 == 13) { - return 0; + var1 = 0; + return var1; } if (arg0 == 14) { - return 1; + var1 = 1; + return var1; } - return 0; + var1 = 0; + return var1; } diff --git a/samples/outputs.var_names/sample54 b/samples/outputs.var_names/sample54 new file mode 100644 index 0000000..bed524b --- /dev/null +++ b/samples/outputs.var_names/sample54 @@ -0,0 +1,12 @@ +void bar (void) { + int z_1; + int y_0 = 0; + if (y_0) { + z_1 = 1; + } else { + z_1 = 2; + } + int b_2; + int a_3 = z_1; +} + diff --git a/samples/outputs/sample40 b/samples/outputs/sample40 index 002d27f..28a80ac 100644 --- a/samples/outputs/sample40 +++ b/samples/outputs/sample40 @@ -1,7 +1,7 @@ #include int match_re (char* arg1) { int var3; - int var5; + int var4; int var1 = strlen(arg1); int var2 = 0; if (var2 < var1) { @@ -27,13 +27,14 @@ int match_re (char* arg1) { var3 = 0; return var3; } - return 1; + var4 = 1; + return var4; } var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } if (arg1[var2] == 100) { goto label2; @@ -41,13 +42,13 @@ int match_re (char* arg1) { var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } var3 = 0; return var3; } - var5 = 0; - return var5; + var4 = 0; + return var4; } diff --git a/samples/outputs/sample48 b/samples/outputs/sample48 index a6e5812..e299f04 100644 --- a/samples/outputs/sample48 +++ b/samples/outputs/sample48 @@ -5,22 +5,38 @@ FUNC_DECL SCALAR_TYPE (INT) VAR (var0) NO_INITIALIZATION + DECL_STMT + SCALAR_TYPE (INT) + VAR (var1) + INT_CONST (0) + DECL_STMT + SCALAR_TYPE (INT) + VAR (var2) + INT_CONST (0) + EXPR_STMT + ASSIGN_EXPR + VAR_EXPR + VAR (var1) + INT_CONST (1) WHILE_STMT INT_CONST (1) STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (var1) + VAR (var3) INT_CONST (1) DECL_STMT SCALAR_TYPE (INT) - VAR (var2) + VAR (var4) INT_CONST (2) void my_bar (void) { int var0; + int var1 = 0; + int var2 = 0; + var1 = 1; while (1) { - int var1 = 1; - int var2 = 2; + int var3 = 1; + int var4 = 2; } } diff --git a/samples/outputs/sample52 b/samples/outputs/sample52 index 009efe3..dfa1927 100644 --- a/samples/outputs/sample52 +++ b/samples/outputs/sample52 @@ -1,49 +1,66 @@ int isEven (int arg0) { + int var1; if (arg0 == 0) { - return 1; + var1 = 1; + return var1; } if (arg0 == 1) { - return 0; + var1 = 0; + return var1; } if (arg0 == 2) { - return 1; + var1 = 1; + return var1; } if (arg0 == 3) { - return 0; + var1 = 0; + return var1; } if (arg0 == 4) { - return 1; + var1 = 1; + return var1; } if (arg0 == 5) { - return 0; + var1 = 0; + return var1; } if (arg0 == 6) { - return 1; + var1 = 1; + return var1; } if (arg0 == 7) { - return 0; + var1 = 0; + return var1; } if (arg0 == 8) { - return 1; + var1 = 1; + return var1; } if (arg0 == 9) { - return 0; + var1 = 0; + return var1; } if (arg0 == 10) { - return 1; + var1 = 1; + return var1; } if (arg0 == 11) { - return 0; + var1 = 0; + return var1; } if (arg0 == 12) { - return 1; + var1 = 1; + return var1; } if (arg0 == 13) { - return 0; + var1 = 0; + return var1; } if (arg0 == 14) { - return 1; + var1 = 1; + return var1; } - return 0; + var1 = 0; + return var1; } diff --git a/samples/outputs/sample54 b/samples/outputs/sample54 new file mode 100644 index 0000000..ad6453d --- /dev/null +++ b/samples/outputs/sample54 @@ -0,0 +1,12 @@ +void bar (void) { + int var1; + int var0 = 0; + if (var0) { + var1 = 1; + } else { + var1 = 2; + } + int var2; + int var3 = var1; +} + diff --git a/samples/sample48.cpp b/samples/sample48.cpp index 0bd5c21..7a3bdf0 100644 --- a/samples/sample48.cpp +++ b/samples/sample48.cpp @@ -9,6 +9,8 @@ using builder::static_var; static void foo(void) { dyn_var x; + dyn_arr y = {0, 0}; + y[0] = 1; while (1) dyn_arr z = {1, 2}; } diff --git a/samples/sample53.cpp b/samples/sample53.cpp index 6bb8e3c..291d5e7 100644 --- a/samples/sample53.cpp +++ b/samples/sample53.cpp @@ -9,21 +9,20 @@ using builder::dyn_var; using builder::static_var; - struct external_object_t { dyn_var member = builder::defer_init(); }; -static void foo(external_object_t &obj) { +static void foo(external_object_t &obj) { // Init not obj.member.deferred_init(); - + dyn_var x = 0; if (x) { - obj.member = 1; + obj.member = 1; } else { obj.member = 2; - } + } } int main(int argc, char *argv[]) { diff --git a/samples/sample54.cpp b/samples/sample54.cpp new file mode 100644 index 0000000..d8a5a94 --- /dev/null +++ b/samples/sample54.cpp @@ -0,0 +1,39 @@ +// Include the headers +#include "blocks/c_code_generator.h" +#include "builder/dyn_var.h" +#include "builder/static_var.h" +#include + +// Include the BuildIt types +using builder::dyn_var; +using builder::static_var; + +static void bar(void) { + static_var x = 0; + + dyn_var y = 0; + + if (y) { + x = 1; + } else { + x = 2; + } + // When z is declared, x is in different states + dyn_var z = x; + + // Executions can now merge, but z is still in different states + x = 0; + + // this declaration forces executions to merge because static tags are the same + // merge is triggered by memoization + dyn_var b; + + // this statement now has issues because z has forked + dyn_var a = z; +} + +int main(int argc, char *argv[]) { + block::c_code_generator::generate_code(builder::builder_context().extract_function_ast(bar, "bar"), std::cout, + 0); + return 0; +} diff --git a/src/blocks/c_code_generator.cpp b/src/blocks/c_code_generator.cpp index 997298e..83921a1 100644 --- a/src/blocks/c_code_generator.cpp +++ b/src/blocks/c_code_generator.cpp @@ -306,6 +306,7 @@ void c_code_generator::visit(decl_stmt::Ptr a) { a->init_expr->accept(this); oss << ";"; } + // if (a->decl_var->hasMetadata("escapes_static_scope")) oss << " //" << "escapes_static_scope = 1"; } void c_code_generator::visit(if_stmt::Ptr a) { oss << "if ("; diff --git a/src/blocks/var_namer.cpp b/src/blocks/var_namer.cpp index 3bf694e..9b35039 100644 --- a/src/blocks/var_namer.cpp +++ b/src/blocks/var_namer.cpp @@ -2,8 +2,31 @@ #include namespace block { +void var_gather_escapes::visit(decl_stmt::Ptr stmt) { + if (stmt->decl_var->hasMetadata("escapes_static_scope") && + stmt->decl_var->getMetadata("escapes_static_scope")) { + + if (!stmt->decl_var->hasMetadata("allow_escape_scope") || + !stmt->decl_var->getMetadata("allow_escape_scope")) { + + std::string so_loc = stmt->decl_var->static_offset.stringify_loc(); + if (std::find(escaping_tags.begin(), escaping_tags.end(), so_loc) == escaping_tags.end()) + escaping_tags.push_back(so_loc); + } + } +} + +static std::string get_apt_tag(var::Ptr a, std::vector escaping_tags) { + std::string so_loc = a->static_offset.stringify_loc(); + if (std::find(escaping_tags.begin(), escaping_tags.end(), so_loc) != escaping_tags.end()) + return so_loc; + else + return a->static_offset.stringify(); +} + void var_namer::visit(decl_stmt::Ptr stmt) { - std::string so = stmt->decl_var->static_offset.stringify(); + std::string so = get_apt_tag(stmt->decl_var, escaping_tags); + if (collected_decls.find(so) != collected_decls.end()) { // This decl has been seen before, and needs to be marked for hoisting decls_to_hoist[so] = stmt; @@ -30,14 +53,15 @@ void var_namer::visit(decl_stmt::Ptr stmt) { } void var_replacer::visit(var_expr::Ptr a) { - std::string so = a->var1->static_offset.stringify(); + std::string so = get_apt_tag(a->var1, escaping_tags); + if (collected_decls.find(so) != collected_decls.end()) { a->var1 = collected_decls[so]; } } void var_hoister::visit(decl_stmt::Ptr a) { - std::string so = a->decl_var->static_offset.stringify(); + std::string so = get_apt_tag(a->decl_var, escaping_tags); if (decls_to_hoist.find(so) != decls_to_hoist.end()) { // This decl needs to be flattened into an assignment // but if it doesn't have an init_expr, just make a simple var_expr @@ -51,6 +75,7 @@ void var_hoister::visit(decl_stmt::Ptr a) { if (a->init_expr == nullptr) { estmt->expr1 = vexpr; + node = estmt; return; } else { assign_expr::Ptr assign = std::make_shared(); @@ -69,12 +94,16 @@ void var_hoister::visit(decl_stmt::Ptr a) { void var_namer::name_vars(block::Ptr a) { var_namer namer; + + var_gather_escapes gatherer(namer.escaping_tags); + a->accept(&gatherer); + a->accept(&namer); - var_replacer replacer(namer.collected_decls); + var_replacer replacer(namer.collected_decls, namer.escaping_tags); a->accept(&replacer); - var_hoister hoister(namer.decls_to_hoist); + var_hoister hoister(namer.decls_to_hoist, namer.escaping_tags); a->accept(&hoister); std::vector new_stmts; diff --git a/src/builder/builder.cpp b/src/builder/builder.cpp index 696d2fc..61a83b6 100644 --- a/src/builder/builder.cpp +++ b/src/builder/builder.cpp @@ -46,7 +46,6 @@ builder::builder(const var &a) { block_expr = nullptr; tracer::tag offset = get_offset_in_function(); - if (a.current_state == var::member_var) { assert(a.parent_var != nullptr); builder parent_expr_builder = (builder)(*a.parent_var); @@ -65,6 +64,9 @@ builder::builder(const var &a) { // It should be removed when it is used } else if (a.current_state == var::standalone_var) { assert(a.block_var != nullptr); + if (a.block_var->static_offset.stringify_stat() != offset.stringify_stat()) { + a.block_var->setMetadata("escapes_static_scope", 1); + } block::var_expr::Ptr var_expr = std::make_shared(); var_expr->static_offset = offset; diff --git a/src/builder/builder_context.cpp b/src/builder/builder_context.cpp index aacf40f..f6579d3 100644 --- a/src/builder/builder_context.cpp +++ b/src/builder/builder_context.cpp @@ -463,5 +463,4 @@ block::stmt::Ptr builder_context::extract_ast_from_function_internal(std::vector return ret_ast; } - } // namespace builder diff --git a/src/builder/builder_context_support.cpp b/src/builder/builder_context_support.cpp index d377d2d..e14bd67 100644 --- a/src/builder/builder_context_support.cpp +++ b/src/builder/builder_context_support.cpp @@ -13,10 +13,9 @@ void lambda_wrapper(std::function f) { } void lambda_wrapper_close(void) {} - void coroutine_wrapper(std::function f) { f(); - tail_call_guard +=1; + tail_call_guard += 1; } void coroutine_wrapper_close(void) {} } // namespace builder