diff --git a/include/builder/dyn_var.h b/include/builder/dyn_var.h index 7b6560d..84e30ea 100644 --- a/include/builder/dyn_var.h +++ b/include/builder/dyn_var.h @@ -133,6 +133,8 @@ class dyn_var_impl : public var { block::var::Ptr dyn_var = std::make_shared(); dyn_var->var_type = create_block_type(); tracer::tag offset = tracer::get_offset_in_function(); + // push this tag into the live_dyn_vars set + get_run_state()->insert_live_dyn_var(offset); dyn_var->preferred_name = utils::find_variable_name_cached(this, offset); block_var = dyn_var; dyn_var->static_offset = offset; @@ -325,7 +327,11 @@ class dyn_var_impl : public var { from_builder_vector(a); } - virtual ~dyn_var_impl() = default; + virtual ~dyn_var_impl() { + if (block_var && is_under_run()) { + get_run_state()->remove_live_dyn_var(block_var->static_offset); + } + } // Assume that _impl objects will never be created // Thus addr can always cast the address to dyn_var @@ -410,6 +416,9 @@ class dyn_var : public dyn_var_impl, public dyn_var_parent_selector, // constructors so define them here dyn_var(const dyn_var &t) : dyn_var_impl((builder)t) {} + // Since we are also defining a destructor, we should define a move constructor + dyn_var(dyn_var &&t): dyn_var_impl((builder)t) {} + // Unfortunately because we are changing the return type, // the implicitly defined copy assignment will always // shadow the version the parent defines diff --git a/include/builder/live_dyn_var.h b/include/builder/live_dyn_var.h new file mode 100644 index 0000000..c665143 --- /dev/null +++ b/include/builder/live_dyn_var.h @@ -0,0 +1,33 @@ +#ifndef BUILDER_LIVE_DYN_VAR_H +#define BUILDER_LIVE_DYN_VAR_H + +#include "util/tracer.h" +#include + +namespace builder { + +class live_tag_set { + std::unordered_set live_set; + size_t computed_hash = 0; +public: + // Default empty set + live_tag_set() {} + + live_tag_set(std::unordered_set &live_set): live_set(live_set) { + // Now update the hash + for (auto s: live_set) { + computed_hash = tracer::hash_combine(computed_hash, s.hash()); + } + } + + bool operator==(const live_tag_set& other) { + if (this == &other) return true; + if (computed_hash != other.computed_hash) return false; + return live_set == other.live_set; + } +}; + + +} + +#endif diff --git a/include/builder/run_states.h b/include/builder/run_states.h index 3c977a8..69254eb 100644 --- a/include/builder/run_states.h +++ b/include/builder/run_states.h @@ -10,6 +10,7 @@ #include #include #include "blocks/stmt.h" +#include "builder/tag_factory.h" namespace builder { @@ -61,6 +62,9 @@ class run_state { // Annotations to be attached to the next statement std::set current_annotations; + // Set of dyn_variables that are live + std::vector live_dyn_vars; + /* Tracing and re-execution related members */ // Vector of bools to return on branching @@ -103,6 +107,9 @@ class run_state { current_annotations.clear(); return to_ret; } + + void insert_live_dyn_var(const tracer::tag& new_tag); + void remove_live_dyn_var(const tracer::tag& new_tag); friend class execution_state; friend class invocation_state; @@ -143,6 +150,9 @@ class invocation_state { /* ND_VAR state */ std::unordered_map> nd_state_map; + // Tag factory state + tag_factory tag_factory_instance; + // Main invocation function std::function invocation_function; diff --git a/include/builder/tag_factory.h b/include/builder/tag_factory.h new file mode 100644 index 0000000..cc9aebe --- /dev/null +++ b/include/builder/tag_factory.h @@ -0,0 +1,24 @@ +#ifndef BUILDER_TAG_FACTORY_H +#define BUILDER_TAG_FACTORY_H + +#include "util/tracer.h" + +namespace builder { + +class tag_factory { + std::unordered_map internal_map; + tracer::tag_id next_id = 1; +public: + tracer::tag_id create_tag_id (const tracer::tag& t) { + auto it = internal_map.find(t); + if (it != internal_map.end()) + return it->second; + internal_map[t] = next_id++; + return next_id - 1; + } +}; + +} + + +#endif diff --git a/include/util/tracer.h b/include/util/tracer.h index 76af0c8..b01bc37 100644 --- a/include/util/tracer.h +++ b/include/util/tracer.h @@ -14,11 +14,15 @@ class builder_context; namespace tracer { +using tag_id = size_t; + class tag { public: std::vector pointers; std::vector> static_var_snapshots; std::vector> static_var_key_values; + std::vector live_dyn_vars; + std::string cached_string; mutable size_t cached_hash = 0; @@ -33,6 +37,7 @@ class tag { void clear(void) { pointers.clear(); static_var_snapshots.clear(); + live_dyn_vars.clear(); } // A function to create another tag @@ -82,6 +87,13 @@ class tag { for (unsigned i = 0; i < static_var_snapshots.size(); i++) { h = hash_combine(h, static_var_snapshots[i]->computed_hash); } + + // Finally combine the hash of the live_dyn_vars + + for (unsigned i = 0; i < live_dyn_vars.size(); i++) { + h = hash_combine(h, (size_t) live_dyn_vars[i]); + } + cached_hash = h; return cached_hash; } diff --git a/samples/outputs.var_names/sample23 b/samples/outputs.var_names/sample23 index a3cd254..83493aa 100644 --- a/samples/outputs.var_names/sample23 +++ b/samples/outputs.var_names/sample23 @@ -1,4 +1,8 @@ STMT_BLOCK + DECL_STMT + SCALAR_TYPE (INT) + VAR (t_2) + NO_INITIALIZATION DECL_STMT SCALAR_TYPE (INT) VAR (x_0) @@ -8,49 +12,35 @@ STMT_BLOCK VAR (var1) VAR_EXPR VAR (x_0) - DECL_STMT - SCALAR_TYPE (INT) - VAR (var2) - NO_INITIALIZATION IF_STMT GT_EXPR VAR_EXPR VAR (var1) INT_CONST (10) STMT_BLOCK - DECL_STMT - SCALAR_TYPE (INT) - VAR (t_3) - INT_CONST (9) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (var2) - VAR_EXPR - VAR (t_3) + VAR (t_2) + INT_CONST (9) STMT_BLOCK - DECL_STMT - SCALAR_TYPE (INT) - VAR (t_4) - INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (var2) - VAR_EXPR - VAR (t_4) + VAR (t_2) + INT_CONST (0) IF_STMT VAR_EXPR - VAR (var2) + VAR (t_2) STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (k_5) + VAR (k_3) INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (k_5) + VAR (k_3) INT_CONST (0) STMT_BLOCK IF_STMT @@ -59,31 +49,29 @@ STMT_BLOCK STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (k_6) + VAR (k_4) INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (k_6) + VAR (k_4) INT_CONST (0) STMT_BLOCK { + int t_2; int x_0; int var1 = x_0; - int var2; if (var1 > 10) { - int t_3 = 9; - var2 = t_3; + t_2 = 9; } else { - int t_4 = 0; - var2 = t_4; + t_2 = 0; } - if (var2) { - int k_5 = 0; - k_5 = 0; + if (t_2) { + int k_3 = 0; + k_3 = 0; } if (x_0) { - int k_6 = 0; - k_6 = 0; + int k_4 = 0; + k_4 = 0; } } diff --git a/samples/outputs.var_names/sample54 b/samples/outputs.var_names/sample54 index 52f3f00..4619aa8 100644 --- a/samples/outputs.var_names/sample54 +++ b/samples/outputs.var_names/sample54 @@ -1,18 +1,20 @@ void bar (void) { - int z_3; - int* k_4; int y_0 = 0; int m_1; int n_2; if (y_0) { - z_3 = 1; - k_4 = (&(m_1)); + int z_3 = 1; + int& k_4 = m_1; + int b_5; + int a_6 = z_3; + z_3 = z_3 + k_4; } else { - z_3 = 2; - k_4 = (&(m_1)); + int z_7 = 2; + int& k_8 = m_1; + int b_9; + int a_10 = z_7; + z_7 = z_7 + k_8; } - int b_5; - int a_6 = z_3; - z_3 = z_3 + k_4[0]; + m_1 = m_1 + 3; } diff --git a/samples/outputs/sample23 b/samples/outputs/sample23 index 8c3ca97..5afdacf 100644 --- a/samples/outputs/sample23 +++ b/samples/outputs/sample23 @@ -1,4 +1,8 @@ STMT_BLOCK + DECL_STMT + SCALAR_TYPE (INT) + VAR (var2) + NO_INITIALIZATION DECL_STMT SCALAR_TYPE (INT) VAR (var0) @@ -8,49 +12,35 @@ STMT_BLOCK VAR (var1) VAR_EXPR VAR (var0) - DECL_STMT - SCALAR_TYPE (INT) - VAR (var2) - NO_INITIALIZATION IF_STMT GT_EXPR VAR_EXPR VAR (var1) INT_CONST (10) STMT_BLOCK - DECL_STMT - SCALAR_TYPE (INT) - VAR (var3) - INT_CONST (9) EXPR_STMT ASSIGN_EXPR VAR_EXPR VAR (var2) - VAR_EXPR - VAR (var3) + INT_CONST (9) STMT_BLOCK - DECL_STMT - SCALAR_TYPE (INT) - VAR (var4) - INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR VAR (var2) - VAR_EXPR - VAR (var4) + INT_CONST (0) IF_STMT VAR_EXPR VAR (var2) STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (var5) + VAR (var3) INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (var5) + VAR (var3) INT_CONST (0) STMT_BLOCK IF_STMT @@ -59,31 +49,29 @@ STMT_BLOCK STMT_BLOCK DECL_STMT SCALAR_TYPE (INT) - VAR (var6) + VAR (var4) INT_CONST (0) EXPR_STMT ASSIGN_EXPR VAR_EXPR - VAR (var6) + VAR (var4) INT_CONST (0) STMT_BLOCK { + int var2; int var0; int var1 = var0; - int var2; if (var1 > 10) { - int var3 = 9; - var2 = var3; + var2 = 9; } else { - int var4 = 0; - var2 = var4; + var2 = 0; } if (var2) { - int var5 = 0; - var5 = 0; + int var3 = 0; + var3 = 0; } if (var0) { - int var6 = 0; - var6 = 0; + int var4 = 0; + var4 = 0; } } diff --git a/samples/outputs/sample54 b/samples/outputs/sample54 index 2e900f1..395c25c 100644 --- a/samples/outputs/sample54 +++ b/samples/outputs/sample54 @@ -1,18 +1,20 @@ void bar (void) { - int var3; - int* var4; int var0 = 0; int var1; int var2; if (var0) { - var3 = 1; - var4 = (&(var1)); + int var3 = 1; + int& var4 = var1; + int var5; + int var6 = var3; + var3 = var3 + var4; } else { - var3 = 2; - var4 = (&(var1)); + int var7 = 2; + int& var8 = var1; + int var9; + int var10 = var7; + var7 = var7 + var8; } - int var5; - int var6 = var3; - var3 = var3 + var4[0]; + var1 = var1 + 3; } diff --git a/samples/sample23.cpp b/samples/sample23.cpp index 13c19ba..0349106 100644 --- a/samples/sample23.cpp +++ b/samples/sample23.cpp @@ -8,10 +8,12 @@ using builder::dyn_var; using builder::static_var; static dyn_var foo(dyn_var x) { + int t; if (x > 10) - return 9; + t = 9; else - return 0; + t = 0; + return t; } static void bar(void) { diff --git a/samples/sample53.cpp b/samples/sample53.cpp index 64d03aa..8890e7a 100644 --- a/samples/sample53.cpp +++ b/samples/sample53.cpp @@ -18,6 +18,7 @@ static void foo(external_object_t &obj) { // Init not obj.member.deferred_init(builder::with_name("member_var", true)); obj.counter.deferred_init(); + obj.counter = 0; dyn_var x = 0; if (x) { diff --git a/samples/sample54.cpp b/samples/sample54.cpp index 7a57b07..52c63cd 100644 --- a/samples/sample54.cpp +++ b/samples/sample54.cpp @@ -1,5 +1,3 @@ -/*NO_TEST*/ -/* This feature has been disabled for now. TODO: Enable this test after selective path merging implementation */ // Include the headers #include "blocks/c_code_generator.h" #include "builder/dyn_var.h" @@ -21,21 +19,27 @@ static void bar(void) { } else { x = 2; } - // When z is declared, x is in different states - dyn_var z = x; - dyn_var k = m; - // Executions can now merge, but z is still in different states - x = 0; + { + // When z is declared, x is in different states + dyn_var z = x; + dyn_var k = m; - // this declaration forces executions to merge because static tags are the same - // merge is triggered by memoization - dyn_var b; + // Executions can now merge, but z is still in different states + x = 0; - // this statement now has issues because z has forked - dyn_var a = z; + // this declaration forces executions to merge because static tags are the same + // merge is triggered by memoization + dyn_var b; - z = z + k; + // this statement now has issues because z has forked + dyn_var a = z; + + z = z + k; + } + + // This statement should be merged since z's lifetime has ended + m = m + 3; } int main(int argc, char *argv[]) { diff --git a/src/builder/builder_context.cpp b/src/builder/builder_context.cpp index 322da36..fc54566 100644 --- a/src/builder/builder_context.cpp +++ b/src/builder/builder_context.cpp @@ -226,6 +226,7 @@ void builder_context::extract_function_ast_impl(invocation_state* i_state) { block::sub_expr_cleanup cleaner; ast->accept(&cleaner); + if (!feature_unstructured) { block::basic_block::cfg_block BBs = generate_basic_blocks(block::to(ast)); @@ -234,15 +235,15 @@ void builder_context::extract_function_ast_impl(invocation_state* i_state) { finder.ast = ast; ast->accept(&finder); + block::if_switcher switcher; + ast->accept(&switcher); + block::for_loop_finder for_finder; for_finder.ast = ast; ast->accept(&for_finder); } - block::if_switcher switcher; - ast->accept(&switcher); - // Run RCE after loop finder // since RCE does rely on loops being detected // If labels are still kept around, RCE cannot be as aggressive diff --git a/src/builder/run_states.cpp b/src/builder/run_states.cpp index 91a84c9..73c7d41 100644 --- a/src/builder/run_states.cpp +++ b/src/builder/run_states.cpp @@ -112,4 +112,25 @@ bool run_state::get_next_bool(block::expr::Ptr expr) { return ret_val; } +void run_state::insert_live_dyn_var(const tracer::tag& t) { + // First convert the tag to tag_id using the invocation's tag factory + tracer::tag_id tid = i_state->tag_factory_instance.create_tag_id(t); + // Insert it into the live set and sort + live_dyn_vars.push_back(tid); + std::sort(live_dyn_vars.begin(), live_dyn_vars.end()); +} +void run_state::remove_live_dyn_var(const tracer::tag& t) { + // First convert the tag to tag_id using the invocation's tag factory + tracer::tag_id tid = i_state->tag_factory_instance.create_tag_id(t); + + // Search using binary search, might not be exact + auto it = std::lower_bound(live_dyn_vars.begin(), live_dyn_vars.end(), tid); + + // Check if we actually found the value + if (it != live_dyn_vars.end() && *it == tid) { + // Erase it. This shifts all subsequent elements left. + live_dyn_vars.erase(it); + } +} + } diff --git a/src/util/tracer.cpp b/src/util/tracer.cpp index 73e26df..df850e5 100644 --- a/src/util/tracer.cpp +++ b/src/util/tracer.cpp @@ -55,6 +55,10 @@ tag get_offset_in_function(void) { new_tag.static_var_key_values.push_back({tuple->var_name, tuple->serialize()}); } } + + // Finally add the live_dyn_var set + new_tag.live_dyn_vars = builder::get_run_state()->live_dyn_vars; + return new_tag; } @@ -95,6 +99,10 @@ tag get_offset_in_function(void) { new_tag.static_var_key_values.push_back({tuple->var_name, tuple->serialize()}); } } + + // Finally add the live_dyn_var set + new_tag.live_dyn_vars = builder::get_run_state()->live_dyn_vars; + return new_tag; } #endif @@ -129,7 +137,15 @@ bool tag::operator==(const tag &other) const { // Now compare the actual snapshots if (!(static_var_snapshots[i]->operator == (other.static_var_snapshots[i]))) return false; + } + + // Finally compare the live_dyn_vars + if (live_dyn_vars.size() != other.live_dyn_vars.size()) + return false; + for (unsigned int i = 0; i < live_dyn_vars.size(); i++) + if (!(live_dyn_vars[i] == other.live_dyn_vars[i])) + return false; return true; } @@ -155,7 +171,15 @@ std::string tag::stringify(void) { if (i != static_var_snapshots.size() - 1) output_string += ", "; } + output_string += "]:["; + + for (unsigned int i = 0; i < live_dyn_vars.size(); i++) { + output_string += std::to_string(live_dyn_vars[i]); + if (i != live_dyn_vars.size() - 1) + output_string += ", "; + } output_string += "]"; + cached_string = output_string; return output_string; } @@ -172,7 +196,7 @@ std::string tag::stringify_stat(void) { if (i != static_var_snapshots.size() - 1) output_string += ", "; } - output_string += "]"; + output_string += "]:[]"; return output_string; }