Repository navigation
Kilo/electric bear mdr - #20
Conversation
Introduces support for language-level pointers, including address-of operations, dereferencing, and pointer arithmetic. This change includes significant updates to the compiler, optimizer, and runtime to support a modern memory model. Key changes: - Added `PtrType` to the IR and compiler to track pointer types. - Implemented `ALLOCA`, `ADDR_LOCAL`, `ADDR_GLOBAL`, `PTR_LOAD`, and `PTR_STORE` instructions in the VM and IR. - Updated the optimizer with escape analysis support for pointers and new SSA optimization passes (block merging and unreachable block removal). - Enhanced the runtime with a segregated free-list allocator and support for reference-semantics structs and lists. - Added support for `__addr__` and `__deref__` built-in functions in the Python interpreter. - Updated documentation to reflect the new memory model and pointer operations.
…te specialization Introduce a more sophisticated optimization suite including interprocedural integer/boolean range analysis and branch-sensitive call-site specialization. This allows the compiler to specialize functions based on constant arguments and inferred value ranges, improving performance through reduced branching and better constant folding. Key changes include: - Added `src/optimizer/ranges.py` for range inference and folding. - Added `src/optimizer/puresim.py` for compile-time pure-function simulation. - Updated `CodeGen` to support lookup tables for specialized function paths. - Enhanced IR to track value ranges and argument constraints. - Added `OptimizerConfig` for tunable analysis budgets. refactor(runtime): implement deterministic scope-based reference counting Transition from a simple free-list allocator to a deterministic memory model using scope-based reference counting for managed objects (structs, lists, sets). Key changes include: - Implemented `FrObjHeader` to manage reference counts and scope tracking. - Added `runtime_scope_push` and `runtime_scope_pop` to manage allocation lifetimes. - Updated `fr_rt.c` to handle automatic cleanup of objects when their owning function scope exits. - Modified `CodeGen` to automatically emit scope management instructions for all user functions. - Updated documentation to reflect the new memory model and ownership semantics.
Introduces a new dictionary data type and a working HTTP/1.1 library (client and server) to the language. This change includes significant updates to the runtime, compiler, and optimizer. Key changes: - **Runtime**: Added `RuntimeDict` support, socket syscall wrappers (connect, accept, bind, listen, etc.), and improved value handling. - **Compiler**: Implemented dictionary bytecode operations, improved string equality handling, and enhanced struct field resolution. - **Optimizer**: Added type propagation for generic list types to refine element types at call sites, and implemented parallel move resolution in code generation to prevent register clobbering. - **Parser/Interpreter**: Added support for `elif` syntax, improved constant evaluation for booleans and bytes, and added `contains` builtin. - **Examples**: Added a complete HTTP library example suite.
…eephole Implement several new optimization passes and code generation improvements: - Add Loop-Invariant Code Motion (LICM) to hoist side-effect-free instructions out of loops. - Implement pure constant-call folding to evaluate pure functions at compile-time when arguments are constants. - Add an assembly peephole pass to remove redundant temporary copies and simplify identity operations (e.g., `mov r1, r1` or `add r1, 0`). - Implement comparison folding in codegen to fuse comparison instructions directly into conditional branches. - Improve type propagation for PHI nodes and struct field access. - Add support for trigonometric builtins (sin, cos, tan) and expanded filesystem operations. Additionally, add new benchmarks (nbody) and test cases for filesystem and math operations.
Update the optimizer to include heuristics for call-site specialization to prevent code bloat and refine the Loop Invariant Code Motion (LICM) pass to exclude constant operations. Additionally, update benchmarks to include a new memory benchmark and adjust the N-body benchmark. - optimizer: add check to ensure specialized clones are smaller or have fewer blocks than the original target - optimizer: exclude constant operations from LICM candidates - bench: add memory_bench.fr for RSS/allocation measurement - bench: update nbody_bench.fr to use dynamic body generation - docs: update bench/README.md with new benchmark descriptions and usage instructions
Add a new optimization pass in the native backend that recognizes simple list-reduction loops (integer sum, float sum, and float sum-of-squares) and emits AVX2 vectorized loops. The implementation includes: - Loop analysis to identify suitable reduction patterns. - Code generation for AVX2 loops with a scalar remainder. - Handling of edge cases like zero-length or non-multiple length lists. - Proper preservation of GPR/XMM state using `vzeroupper`. Also includes: - Redundant type conversion elimination in `passes.py`. - Updated documentation and new benchmarks for vector reductions.
Implement the Fr OS target for native compilation, allowing the emission of static userspace ELFs using the Fr OS syscall ABI and ISA profile. - Update `runtime/fr_rt.c` with Fr OS syscall definitions and logic for file I/O, sockets, and stat operations. - Add `--target fr-os` flag to `fr native` CLI for selecting the target. - Update `src/optimizer` to support target-specific code generation, including disabling AVX2 vectorization for Fr OS due to ISA restrictions. - Adjust C compiler flags for Fr OS to use `-ffreestanding` and disable PIE/PIC. - Refactor BSS and global variable emission in `codegen.py`. - Add documentation and examples for the Fr OS target.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Sorry @Omena0, your pull request is larger than the review limit of 150,000 diff characters |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
| int line) { | ||
| if (!list) return; | ||
| if (list->elem_type < 0 || list->elem_type == 0) list->elem_type = 4; | ||
| runtime_list_set_int_at(list, index, value, line); |
There was a problem hiding this comment.
[CRITICAL]: runtime_list_set_managed_at stores value without taking ownership
Unlike runtime_list_set_int (line 1158), this path neither calls runtime_retain/runtime_scope_forget on the new value nor releases the previous element. Because the list is marked elem_type = 4, runtime_release later releases every element, so this store leads to an over-release/double free, and the value can be freed at scope pop while the list still points at it (use-after-free).
|
|
||
| void runtime_dict_set(RuntimeDict* dict, int64_t key, int64_t value) { | ||
| if (!dict) return; | ||
| if (dict->key_type == -1) dict->key_type = key > 0x100000 ? 1 : 0; |
There was a problem hiding this comment.
[CRITICAL]: Integer dict keys above 0x100000 are treated as string pointers
key > 0x100000 is used to guess that the key is a string pointer, so a dict with integer keys such as 2000000 sets key_type = 1 and runtime_dict_key_eq then calls strcmp((const char*)a, (const char*)b) on the integer value, dereferencing an invalid address. The compiler only calls runtime_dict_set, so this heuristic is always used. Pass the element type explicitly instead of guessing from the value.
|
|
||
| void runtime_set_add(RuntimeSet* set, int64_t value) { | ||
| if (!set) return; | ||
| if (set->elem_type == -1) set->elem_type = value > 0x100000 ? 1 : 0; |
There was a problem hiding this comment.
[CRITICAL]: Large integer set elements are treated as string pointers
Same heuristic as the dict path: value > 0x100000 sets elem_type = 1, after which runtime_set_equal calls strcmp on the integer value. Any set of integers above 1,048,576 (for example s.add(2000000)) segfaults. runtime_set_add_typed exists but codegen always emits runtime_set_add (src/optimizer/codegen.py:2103), so the untyped heuristic is always used.
| strcpy(full, "["); | ||
| strcat(full, exc_type); | ||
| strcat(full, "] "); | ||
| strcat(full, message); |
There was a problem hiding this comment.
[WARNING]: Unbounded strcat into a 1024-byte stack buffer
runtime_exception_raise concatenates the user-controlled message (and exc_type) into char full[1024]. A raise message longer than about 1000 bytes overflows the stack. runtime_exception_raise_at has the same problem at lines 1631-1640. Use bounded snprintf or allocate the buffer.
| elif lst.startswith("["): | ||
| # dst doubles as the temporary list pointer: no scratch clobber. | ||
| self._emit_int_move(lst, dst) | ||
| self._emit(f" mov {dst}, [{dst} + 8]") |
There was a problem hiding this comment.
[WARNING]: Nested memory operand when the LIST_LEN result is spilled
When dst is a spill slot, _emit_int_move(lst, dst) loads the list pointer into [rbp-...], and this then emits mov [rbp-...], [[rbp-...] + 8], which x86 cannot encode. The heap/register path avoids this with a scratch register; the spilled path needs one too.
| if val_loc.startswith("xmm"): | ||
| self._emit(f" movsd [rbp - {stack_offset - offset}], {val_loc}") | ||
| else: | ||
| self._emit(f" mov [rbp - {stack_offset - offset}], {val_loc}") |
There was a problem hiding this comment.
[WARNING]: Memory-to-memory store for a spilled struct field
In the stack_alloc path, a spilled val_loc (starting with [) produces mov [rbp - off], [rbp - off2], which is not a valid x86 instruction; a spilled float would also need movsd. The heap path stages through r11; do the same here.
| # Assignments alias mutable objects, matching the native/C reference | ||
| # semantics. Fresh literals and struct constructors already produce a new | ||
| # object for every evaluation, so no defensive copy is needed here. | ||
| cell = _global_vars.get(node["name"]) if _global_vars else None |
There was a problem hiding this comment.
[WARNING]: Global lookup takes precedence over the local scope
_global_vars.get(node["name"]) is checked before creating a local, so inside a function a declaration or assignment whose name matches a module global (including a parameter with that name) writes the global cell and never creates the local. This breaks local shadowing. Check vars first, then fall back to the global.
| while (true) { | ||
| bytes chunk = sock.recv(4096) | ||
| if (len(chunk) == 0) { break } | ||
| raw = raw + chunk.decode() |
There was a problem hiding this comment.
[WARNING]: Decoding each recv chunk independently breaks multi-byte UTF-8
A UTF-8 sequence split across TCP segments makes chunk.decode() raise (or produce replacement characters), and binary bodies are always corrupted. Accumulate bytes and decode once after the full body is read.
| @@ -0,0 +1,83 @@ | |||
| // !true | |||
There was a problem hiding this comment.
[WARNING]: Expected output does not match the program
main prints energy(bodies) > 0.0. The total energy is dominated by the negative central-body potential term (39.47 * 0.037 / 4.98 ~= -0.293) which exceeds the positive kinetic energy (about 0.18), so the program prints false, not true. The test will fail unless the optimizer is masking a miscompile.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Files Reviewed (35 files)
Previous Review Summary (commit 071ebdb)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit 071ebdb)Status: 27 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)CRITICAL
WARNING
SUGGESTION
Files Reviewed (60 files)
Reviewed by free · Input: 113.3K · Output: 60.3K · Cached: 10.5M |
No description provided.