Skip to content

Commit 1218aec

Browse files
committed
v3: fix ARM64 self-host (test_all.vsh step 4)
Make `v3 -selfhost -b arm64` produce a working arm64 compiler that can in turn compile programs with the native ARM64 backend. Fixes a series of ARM64-only SSA codegen bugs (plus one shared transformer fix) that caused the self-hosted binary to crash: - ssa: register `array_push_many_ptr` as its own synthetic (the C-macro name the transformer emits for `arr << ptr` / fixed-array appends). - ssa: synthesize `<Enum>__autostr` enum-to-string helpers (the C backend emits these; the SSA path had none). Flag enums get a flag-specific body that renders `Name{.a | .b}` (and `Name{}` for 0) via per-bit testing, matching the C backend. Enum field initializer expressions (`a = 1 << 3`, `a = -1`, ...) are evaluated via a port of cgen's `enum_field_expr_value`, shared by the autostr helpers and the `enum_values` table so both agree on the field's real value. - ssa: resolve a bare enum literal (`x = .member`, `return .member`) against the assignment/return target type, so a member name that is duplicated across enums is no longer built as 0. - ssa: fix the lvalue address of `(&Struct(rawptr)).field` (a pointer cast base was returning a null address). - ssa: re-classify `Type.method(args)` selector calls from the resolved signature's parameter count, so a cross-module static type-method (e.g. `token.Token.from_string_tinyv`) is not passed a phantom receiver that shifts its arguments. - ssa/arm64: give the `string` struct an `is_lit` field (offset 12, also taught to `block_struct_field_ptr`). `materialize_string` sets it to 1 for literals; `emit_make_string` now takes an explicit is_lit (1 for the `vstring_literal*` wrappers that borrow static C data, 0 for owned heap strings), so string.free aborts on neither static data nor a non-allocation-start pointer. Helpers that would otherwise return a view/interior pointer instead return an owned copy via `emit_make_owned_string` (matching V's substr/clone): `tos_clone`, strings.Builder `str`/`last_n`, `all_before_last`/`all_after_last`, the `trim_right` and string-slice fallbacks, and `int_str`/`format_int` (which shifts its backwards-written digits to the buffer start). - ssa: register a header-less synthetic `array__clone` and materialize slice rvalues (`a[lo..hi]`, tagged `value == "range"`) when their address is taken; transform: treat such range-index nodes as non-addressable so they materialize to a temp. - ssa: also stub the `v3.bench.*` rss helpers, matching the full import-path qualification that fn names now carry. The C-backend self-host chain still converges byte-for-byte and the v3 unit tests show no new failures.
1 parent 82e947b commit 1218aec

3 files changed

Lines changed: 517 additions & 59 deletions

File tree

vlib/v3/gen/arm64/gen.v

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,13 @@ fn (mut g Gen) materialize_string(val_id int, reg int) {
14111411
g.macho.add_reloc(g.macho.text_data.len, str_sym_idx, arm64_reloc_pageoff12, false)
14121412
g.emit32(asm_add_pageoff(Reg(reg)))
14131413

1414-
g.emit_mov_imm(10, i64(str_len))
1414+
// x10 holds the string struct's second 8-byte word: `len` in the low 32 bits and
1415+
// `is_lit` in the high 32 bits (matching `string{ str, len int, is_lit int }`).
1416+
// Every caller stores/moves x10 as that whole word, so set is_lit=1 here: string
1417+
// literals point at static data and must NOT be passed to free() (`string.free`
1418+
// returns early only when is_lit==1). Without this, freeing a literal (e.g. the
1419+
// `mut res := ''` in os.real_path) aborts with a libmalloc "pointer not allocated".
1420+
g.emit_mov_imm(10, i64(str_len) | (i64(1) << 32))
14151421
}
14161422

14171423
// ==================== Global access ====================

0 commit comments

Comments
 (0)