feat: implement FBIP (Functional But In-Place) reuse analysis
When rc=1 at update sites, mutate in-place instead of allocating new: List.reverse: - Swap element pointers in-place instead of creating new list List.take: - Truncate list in-place, decref dropped elements List.drop: - Shift elements to front in-place, decref dropped elements List.map: - Mutate elements in-place, decref old values before storing new List.filter: - Filter in-place by shifting kept elements, decref filtered-out elements All operations check LUX_RC_HEADER(list)->rc == 1 at runtime and fall back to allocation when rc > 1 (list is shared). This completes Phase B performance optimizations: - B1: Last-use optimization (ownership transfer) ✅ - B2: Reuse analysis (FBIP) ✅ - B3: Drop specialization ✅ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1039,6 +1039,18 @@ impl CBackend {
|
||||
self.writeln("}");
|
||||
self.writeln("");
|
||||
self.writeln("static LuxList* lux_list_reverse(LuxList* list) {");
|
||||
self.writeln(" // FBIP: If rc=1, reverse in-place instead of copying");
|
||||
self.writeln(" if (LUX_RC_HEADER(list)->rc == 1) {");
|
||||
self.writeln(" // In-place reversal - just swap element pointers");
|
||||
self.writeln(" int64_t n = list->length;");
|
||||
self.writeln(" for (int64_t i = 0; i < n / 2; i++) {");
|
||||
self.writeln(" void* tmp = list->elements[i];");
|
||||
self.writeln(" list->elements[i] = list->elements[n - 1 - i];");
|
||||
self.writeln(" list->elements[n - 1 - i] = tmp;");
|
||||
self.writeln(" }");
|
||||
self.writeln(" return list; // Reuse same list");
|
||||
self.writeln(" }");
|
||||
self.writeln(" // rc > 1: Allocate new list (standard path)");
|
||||
self.writeln(" LuxList* result = lux_list_new(list->length);");
|
||||
self.writeln(" for (int64_t i = 0; i < list->length; i++) {");
|
||||
self.writeln(" lux_incref(list->elements[list->length - 1 - i]);");
|
||||
@@ -1050,7 +1062,20 @@ impl CBackend {
|
||||
self.writeln("");
|
||||
self.writeln("static LuxList* lux_list_take(LuxList* list, int64_t n) {");
|
||||
self.writeln(" if (n <= 0) return lux_list_new(0);");
|
||||
self.writeln(" if (n > list->length) n = list->length;");
|
||||
self.writeln(" if (n >= list->length) {");
|
||||
self.writeln(" lux_incref(list); // Return same list");
|
||||
self.writeln(" return list;");
|
||||
self.writeln(" }");
|
||||
self.writeln(" // FBIP: If rc=1, truncate in-place");
|
||||
self.writeln(" if (LUX_RC_HEADER(list)->rc == 1) {");
|
||||
self.writeln(" // Decref elements we're dropping");
|
||||
self.writeln(" for (int64_t i = n; i < list->length; i++) {");
|
||||
self.writeln(" lux_decref(list->elements[i]);");
|
||||
self.writeln(" }");
|
||||
self.writeln(" list->length = n;");
|
||||
self.writeln(" return list; // Reuse same list");
|
||||
self.writeln(" }");
|
||||
self.writeln(" // rc > 1: Allocate new list");
|
||||
self.writeln(" LuxList* result = lux_list_new(n);");
|
||||
self.writeln(" for (int64_t i = 0; i < n; i++) {");
|
||||
self.writeln(" lux_incref(list->elements[i]);");
|
||||
@@ -1067,6 +1092,20 @@ impl CBackend {
|
||||
self.writeln(" return list;");
|
||||
self.writeln(" }");
|
||||
self.writeln(" int64_t new_len = list->length - n;");
|
||||
self.writeln(" // FBIP: If rc=1, shift elements in-place");
|
||||
self.writeln(" if (LUX_RC_HEADER(list)->rc == 1) {");
|
||||
self.writeln(" // Decref elements we're dropping");
|
||||
self.writeln(" for (int64_t i = 0; i < n; i++) {");
|
||||
self.writeln(" lux_decref(list->elements[i]);");
|
||||
self.writeln(" }");
|
||||
self.writeln(" // Shift remaining elements to front");
|
||||
self.writeln(" for (int64_t i = 0; i < new_len; i++) {");
|
||||
self.writeln(" list->elements[i] = list->elements[n + i];");
|
||||
self.writeln(" }");
|
||||
self.writeln(" list->length = new_len;");
|
||||
self.writeln(" return list; // Reuse same list");
|
||||
self.writeln(" }");
|
||||
self.writeln(" // rc > 1: Allocate new list");
|
||||
self.writeln(" LuxList* result = lux_list_new(new_len);");
|
||||
self.writeln(" for (int64_t i = 0; i < new_len; i++) {");
|
||||
self.writeln(" lux_incref(list->elements[n + i]);");
|
||||
@@ -2432,7 +2471,26 @@ impl CBackend {
|
||||
let fn_var = format!("_fn_{}", id);
|
||||
let mapped_var = format!("_mapped_{}", id);
|
||||
|
||||
self.writeln(&format!("LuxList* {} = lux_list_new({}->length);", result_var, list));
|
||||
// FBIP: Check if we can reuse the list in-place
|
||||
self.writeln(&format!("LuxList* {};", result_var));
|
||||
self.writeln(&format!("if (LUX_RC_HEADER({})->rc == 1) {{", list));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("// FBIP: Reuse list in-place"));
|
||||
self.writeln(&format!("{} = {};", result_var, list));
|
||||
self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
|
||||
self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
|
||||
self.writeln(&format!("LuxInt {} = ((LuxInt(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", mapped_var, fn_var, fn_var, elem_var));
|
||||
self.writeln(&format!("lux_decref({}); // Decref old element", elem_var));
|
||||
self.writeln(&format!("{}->elements[{}] = lux_box_int({});", result_var, i_var, mapped_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.indent -= 1;
|
||||
self.writeln("} else {");
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("// Allocate new list"));
|
||||
self.writeln(&format!("{} = lux_list_new({}->length);", result_var, list));
|
||||
self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
|
||||
@@ -2442,6 +2500,8 @@ impl CBackend {
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.writeln(&format!("{}->length = {}->length;", result_var, list));
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref_closure({});", closure));
|
||||
@@ -2463,8 +2523,35 @@ impl CBackend {
|
||||
let fn_var = format!("_fn_{}", id);
|
||||
let keep_var = format!("_keep_{}", id);
|
||||
|
||||
self.writeln(&format!("LuxList* {} = lux_list_new({}->length);", result_var, list));
|
||||
// FBIP: Check if we can filter in-place
|
||||
self.writeln(&format!("LuxList* {};", result_var));
|
||||
self.writeln(&format!("int64_t {} = 0;", count_var));
|
||||
self.writeln(&format!("if (LUX_RC_HEADER({})->rc == 1) {{", list));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("// FBIP: Filter in-place"));
|
||||
self.writeln(&format!("{} = {};", result_var, list));
|
||||
self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
|
||||
self.writeln(&format!("LuxClosure* {} = (LuxClosure*){};", fn_var, closure));
|
||||
self.writeln(&format!("LuxBool {} = ((LuxBool(*)(void*, LuxInt)){}->fn_ptr)({}->env, lux_unbox_int({}));", keep_var, fn_var, fn_var, elem_var));
|
||||
self.writeln(&format!("if ({}) {{", keep_var));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("{}->elements[{}++] = {};", result_var, count_var, elem_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("} else {");
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("lux_decref({}); // Decref filtered-out element", elem_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.writeln(&format!("{}->length = {};", result_var, count_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("} else {");
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("// Allocate new list"));
|
||||
self.writeln(&format!("{} = lux_list_new({}->length);", result_var, list));
|
||||
self.writeln(&format!("for (int64_t {} = 0; {} < {}->length; {}++) {{", i_var, i_var, list, i_var));
|
||||
self.indent += 1;
|
||||
self.writeln(&format!("void* {} = {}->elements[{}];", elem_var, list, i_var));
|
||||
@@ -2480,6 +2567,8 @@ impl CBackend {
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
self.writeln(&format!("{}->length = {};", result_var, count_var));
|
||||
self.indent -= 1;
|
||||
self.writeln("}");
|
||||
// Decref the closure if it was a temporary (inline lambda)
|
||||
if closure.starts_with("_closure_") {
|
||||
self.writeln(&format!("lux_decref_closure({});", closure));
|
||||
|
||||
Reference in New Issue
Block a user