From 74cc35d48879e0a50d4903d49d7426f1999de735 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Thu, 25 Jun 2026 01:32:32 +0900 Subject: [PATCH] test: migrate Fam4 static-init/DATA-emit value tests to @test (#30) Continues the test-arch tower past Fam8-13. 11 module-level static-init / DATA-emit value drivers move from test/wcc/*_run.c into @test row- tables under test/lang/; every classification empirically re-probed at HEAD (refuting two stale worklist tags). - value rows -> test/lang/*_test.ww (11 files) - reject rows -> runww //ww:error carriers (3, dual-stage non-vacuous; 947 const-divzero confirmed a both-stage compile-reject, not run-exit) - 840_zeroinit, 944_array_zeroinit, 989_arrlit_tail_zero kept as byte-id .c pins (zero-over-dirtied-frame / DATAW-length is byte-id-blind to a runtime @test; #263), mutation-gated - repoint two stale comment refs to deleted test names (719, 989_structlocal_frame) Migrated static-init @test ride the cs==ww T2 byte-id gate, preserving DATA-emit byte-id. 2D global-struct array-field read (#137/#150) confirmed cs==ww + correct at HEAD. Coverage parity verified row-by-row; two-round reviewed. Floor ratchet follows. --- Makefile | 82 +--- test/lang/arr_u16_store_test.ww | 41 ++ test/lang/array_static_init_test.ww | 99 +++++ test/lang/const_slice_aggregate_test.ww | 62 +++ test/lang/def_float_lit_test.ww | 62 +++ test/lang/inferred_scalar_global_test.ww | 33 ++ test/lang/nestfield_test.ww | 38 ++ test/lang/signed_data_emit_test.ww | 66 ++++ test/lang/strarray_static_test.ww | 44 +++ test/lang/struct_composite_init_test.ww | 66 ++++ test/lang/structlit_arrfield_test.ww | 34 ++ test/lang/valstruct_subsize_test.ww | 70 ++++ test/wcc/719_signed_data_emit.c | 5 +- test/wcc/914_arr_u16_store_run.c | 217 ----------- test/wcc/917_def_float_lit_run.c | 231 ------------ test/wcc/918_struct_composite_init_run.c | 241 ------------ test/wcc/919_array_static_init_run.c | 354 ------------------ test/wcc/919_strarray_static_run.c | 204 ---------- test/wcc/923_signed_data_emit_run.c | 221 ----------- test/wcc/946_const_slice_aggregate_run.c | 303 --------------- test/wcc/947_inferred_scalar_global_run.c | 276 -------------- test/wcc/949_structlit_arrfield_run.c | 206 ---------- test/wcc/949_valstruct_subsize_run.c | 251 ------------- test/wcc/989_nestfield_run.c | 202 ---------- test/wcc/989_structlocal_frame.c | 6 +- .../data/arr_nested_ellipsis_reject/case.ww | 7 + test/wcc/data/const_divzero_reject/case.ww | 8 + test/wcc/data/slice_of_str_reject/case.ww | 8 + 28 files changed, 647 insertions(+), 2790 deletions(-) create mode 100644 test/lang/arr_u16_store_test.ww create mode 100644 test/lang/array_static_init_test.ww create mode 100644 test/lang/const_slice_aggregate_test.ww create mode 100644 test/lang/def_float_lit_test.ww create mode 100644 test/lang/inferred_scalar_global_test.ww create mode 100644 test/lang/nestfield_test.ww create mode 100644 test/lang/signed_data_emit_test.ww create mode 100644 test/lang/strarray_static_test.ww create mode 100644 test/lang/struct_composite_init_test.ww create mode 100644 test/lang/structlit_arrfield_test.ww create mode 100644 test/lang/valstruct_subsize_test.ww delete mode 100644 test/wcc/914_arr_u16_store_run.c delete mode 100644 test/wcc/917_def_float_lit_run.c delete mode 100644 test/wcc/918_struct_composite_init_run.c delete mode 100644 test/wcc/919_array_static_init_run.c delete mode 100644 test/wcc/919_strarray_static_run.c delete mode 100644 test/wcc/923_signed_data_emit_run.c delete mode 100644 test/wcc/946_const_slice_aggregate_run.c delete mode 100644 test/wcc/947_inferred_scalar_global_run.c delete mode 100644 test/wcc/949_structlit_arrfield_run.c delete mode 100644 test/wcc/949_valstruct_subsize_run.c delete mode 100644 test/wcc/989_nestfield_run.c create mode 100644 test/wcc/data/arr_nested_ellipsis_reject/case.ww create mode 100644 test/wcc/data/const_divzero_reject/case.ww create mode 100644 test/wcc/data/slice_of_str_reject/case.ww diff --git a/Makefile b/Makefile index 87afd144..5e8e6e20 100644 --- a/Makefile +++ b/Makefile @@ -274,7 +274,6 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \ $(BIN)/test_m1mangle_sym \ $(BIN)/test_m1usehint_run \ $(BIN)/test_m1union_run \ - $(BIN)/test_nestfield_run \ $(BIN)/test_structlocal_frame \ $(BIN)/test_arrlit_tail_zero_run \ $(BIN)/test_allocalias_run \ @@ -345,7 +344,6 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \ $(BIN)/test_struct_byval_param \ $(BIN)/test_struct_multi_return_scratch \ $(BIN)/test_signed_data_emit \ - $(BIN)/test_signed_data_emit_run \ $(BIN)/test_tagged_call_arg \ $(BIN)/test_sret_struct_return \ $(BIN)/test_tagged_sret_run \ @@ -361,7 +359,6 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \ $(BIN)/test_alias_emit_b7_run \ $(BIN)/test_variant_chain_b95_run \ $(BIN)/test_peellint_gate \ - $(BIN)/test_const_slice_aggregate_run \ $(BIN)/test_xmod_fnptr_const_run \ $(BIN)/test_errtype_compare \ $(BIN)/test_intbinop_mismatch \ @@ -505,18 +502,10 @@ TESTS = $(BIN)/test_smoke $(BIN)/test_lex $(BIN)/test_parse $(BIN)/test_check \ $(BIN)/test_coloimport_sep \ $(BIN)/test_depmain_sep \ $(BIN)/test_checked_run \ - $(BIN)/test_inferred_scalar_global_run \ - $(BIN)/test_structlit_arrfield_run \ $(BIN)/test_defdim_struct_run \ $(BIN)/test_arrlit_slice_run \ - $(BIN)/test_valstruct_subsize_run \ $(BIN)/test_def_mangle_run \ - $(BIN)/test_arr_u16_store_run \ $(BIN)/test_arr_module_index_run \ - $(BIN)/test_def_float_lit_run \ - $(BIN)/test_struct_composite_init_run \ - $(BIN)/test_array_static_init_run \ - $(BIN)/test_strarray_static_run \ $(BIN)/test_array_init_acceptiffits_run \ $(BIN)/test_amp_def_global_run \ $(BIN)/test_f64crossmod_run \ @@ -778,28 +767,15 @@ $(BIN)/test_m1union_run: test/wcc/989_m1union_run.c \ $(LIB)/libwwrt.a | $(BIN) $(CC) $(CFLAGS) -o $@ $< -# 989_nestfield_run (#44/#55): a struct with a nested sub-8 composite field -# (inner{x:u8,y:u8}, slotsize 8 != size 2) plus a successor must address -# every field at the checker's NATURAL offset on BOTH the write -# (construction) and read (field-access) paths. wwstage's registerstruct -# rebuilt fi.foff slot-padded for the write while the read used tfield -# natural — gate-blind (the shape is corpus-absent). Builds+runs on BOTH -# driver twins (rule-10), pinning the absolute 0 (all fields read back). -$(BIN)/test_nestfield_run: test/wcc/989_nestfield_run.c \ - $(BIN)/ww $(BIN)/ww_ww \ - $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ - $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - # 989_structlocal_frame (#75): a sub-8 nested-composite struct LOCAL must # reserve its frame slot at the struct's NATURAL size (round8(ti.size)), # not the slot-padded ti.slotsize. wwstage's slotsize() TY_STRUCT arm # over-reserved, so outer{a:u8,p:inner{x:u8,y:u8},z:i64} emitted frame $32 # / -24(BP) vs cstage's $16 / -16(BP) — runtime-invisible (both exit 0) # but a cs!=ww .s divergence (rule 10) and a latent byte-id landmine. The -# FRAME-ABSOLUTE twin of the RUNTIME 989_nestfield_run: emits .s via w6c -# and w6c_ww and byte-diffs (no link, no run). +# FRAME-ABSOLUTE twin of the runtime nestfield rows (migrated to +# test/lang/nestfield_test.ww): emits .s via w6c and w6c_ww and byte-diffs +# (no link, no run). $(BIN)/test_structlocal_frame: test/wcc/989_structlocal_frame.c \ $(BIN)/w6c $(BIN)/w6c_ww | $(BIN) $(CC) $(CFLAGS) -o $@ $< @@ -1914,12 +1890,6 @@ $(BIN)/test_signed_data_emit: test/wcc/719_signed_data_emit.c \ $(BIN)/w6c $(BIN)/w6c_ww | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_signed_data_emit_run: test/wcc/923_signed_data_emit_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ - $(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_tagged_call_arg: test/wcc/720_tagged_call_arg.c \ $(BIN)/w6c $(BIN)/w6c_ww | $(BIN) $(CC) $(CFLAGS) -o $@ $< @@ -2005,12 +1975,6 @@ $(BIN)/test_variant_chain_b95_run: test/wcc/944_variant_chain_b95_run.c \ $(BIN)/test_peellint_gate: test/wcc/944_peellint_gate.c tools/peellint | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_const_slice_aggregate_run: test/wcc/946_const_slice_aggregate_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ - $(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_xmod_fnptr_const_run: test/wcc/949_xmod_fnptr_const_run.c \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \ @@ -2651,16 +2615,6 @@ $(BIN)/test_checked_run: test/wcc/969_checked_run.c $(BIN)/ww $(BIN)/w6c \ $(BIN)/w6a $(BIN)/w6l $(LIB)/libwwrt.a | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_inferred_scalar_global_run: test/wcc/947_inferred_scalar_global_run.c $(BIN)/ww \ - $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - -$(BIN)/test_structlit_arrfield_run: test/wcc/949_structlit_arrfield_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_defdim_struct_run: test/wcc/951_defdim_struct_run.c \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \ $(BIN)/ww_ww $(BIN)/w6c_ww $(BIN)/w6a_ww $(BIN)/w6l_ww \ @@ -2673,46 +2627,16 @@ $(BIN)/test_arrlit_slice_run: test/wcc/953_arrlit_slice_run.c \ $(LIB)/libwwrt.a | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_valstruct_subsize_run: test/wcc/949_valstruct_subsize_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_def_mangle_run: test/wcc/913_def_mangle_run.c $(BIN)/ww \ $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ $(LIB)/libwwrt.a | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_arr_u16_store_run: test/wcc/914_arr_u16_store_run.c $(BIN)/ww \ - $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_arr_module_index_run: test/wcc/915_arr_module_index_run.c $(BIN)/ww \ $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ $(LIB)/libwwrt.a | $(BIN) $(CC) $(CFLAGS) -o $@ $< -$(BIN)/test_def_float_lit_run: test/wcc/917_def_float_lit_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - -$(BIN)/test_struct_composite_init_run: test/wcc/918_struct_composite_init_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - -$(BIN)/test_array_static_init_run: test/wcc/919_array_static_init_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - -$(BIN)/test_strarray_static_run: test/wcc/919_strarray_static_run.c \ - $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ - $(LIB)/libwwrt.a | $(BIN) - $(CC) $(CFLAGS) -o $@ $< - $(BIN)/test_array_init_acceptiffits_run: test/wcc/920_array_init_acceptiffits_run.c \ $(BIN)/ww $(BIN)/w6c $(BIN)/w6c_ww $(BIN)/w6a $(BIN)/w6l \ $(LIB)/libwwrt.a | $(BIN) diff --git a/test/lang/arr_u16_store_test.ww b/test/lang/arr_u16_store_test.ww new file mode 100644 index 00000000..6a004d6b --- /dev/null +++ b/test/lang/arr_u16_store_test.ww @@ -0,0 +1,41 @@ +// arr_u16_store_test — [N]u16/[N]i16 array-literal init stores MOVW per slot. +// Migrated from test/wcc/914_arr_u16_store_run.c. Pre-fix a [4]u16 init emitted +// overlapping MOVQ stores (accident-corrected for some values); the fix dispatches +// a proper MOVW per 2-byte slot (op chosen by esz, not signedness). cstage +// build+run was T1; cs==ww .s byte-id rides T2 (test-lang-byteid). The full_init +// row asserts each element to catch any value drift; the [4]u8 control pins the +// MOVB path is unchanged; i16_signed pins the dispatch is not signedness-gated. + +package arr_u16_store_test; + +@test fn u16_full_init() void = { + let a: [4]u16 = [0xABCDu16, 0xBEEFu16, 0xC0DEu16, 0xDEADu16]; + assert(a[0] == 0xABCDu16); + assert(a[1] == 0xBEEFu16); + assert(a[2] == 0xC0DEu16); + assert(a[3] == 0xDEADu16); +}; + +@test fn u16_small_values() void = { + let a: [4]u16 = [10u16, 20u16, 30u16, 40u16]; + let s: i32 = 0; + s += a[0]: i32; s += a[1]: i32; + s += a[2]: i32; s += a[3]: i32; + assert(s == 100); +}; + +@test fn u8_control() void = { + let a: [4]u8 = [10u8, 20u8, 30u8, 40u8]; + let s: i32 = 0; + s += a[0]: i32; s += a[1]: i32; + s += a[2]: i32; s += a[3]: i32; + assert(s == 100); +}; + +@test fn i16_signed() void = { + let a: [4]i16 = [10i16, 20i16, 30i16, -5i16]; + let s: i32 = 0; + s += a[0]: i32; s += a[1]: i32; + s += a[2]: i32; s += a[3]: i32; + assert(s == 55); +}; diff --git a/test/lang/array_static_init_test.ww b/test/lang/array_static_init_test.ww new file mode 100644 index 00000000..a9307ce0 --- /dev/null +++ b/test/lang/array_static_init_test.ww @@ -0,0 +1,99 @@ +// array_static_init_test — module-level 1D/2D/3D array static-init, element +// read. Migrated from test/wcc/919_array_static_init_run.c (#129 Phase A.3, +// #156). emit_array_lit_bytes recurses on a TY_ARRAY element (esz=etype->size, +// rule 13); cgindex leaves the sub-array ADDRESS for an array element so the +// outer index dereferences the right cell (#135 sister). cstage build+run was +// T1; cs==ww .s byte-id rides T2 (test-lang-byteid). The nested-array `...` +// repeat reject is the runww carrier test/wcc/data/arr_nested_ellipsis_reject. +// +// Float-element rows assert bit-exact incl negative elements (drew: exercise the +// sign-XOR byte-loop per element). The struct-with-array-field rows read the +// array-field elements directly (D1.buf[k], D2.m[i][j]): the old #137/#150 cs≠ww +// global-struct-field-base bug is CLOSED at HEAD, so the read is now cs==ww IDENT +// — the original deferred this to byte-id only because the bug was then open. + +package array_static_init_test; + +let A_U8: [4]u8 = [1u8, 2u8, 3u8, 4u8]; +let A_U32: [4]u32 = [1u32, 2u32, 3u32, 4u32]; +let A_U64: [2]u64 = [1u64, 2u64]; +let A_INEG: [4]i32 = [-1, -2, -3, -4]; +let A_F64: [4]f64 = [1.5, -2.5, 3.5, -4.5]; +let A_F32: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32]; +def DA_U32: [4]u32 = [11u32, 22u32, 33u32, 44u32]; +def DA_F64: [4]f64 = [1.5, 2.5, 3.5, 4.5]; +let A_UZ: [4]u8 = [0u8, 0u8, 0u8, 0u8]; +let A_U1: [1]u8 = [7u8]; +let A2D: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]]; +def DA2D: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]]; +let A2V: [3][2]u64 = [[10u64,11u64],[20u64,21u64],[30u64,31u64]]; +let A28: [2][1]u32 = [[7u32],[9u32]]; +let A2W: [2][2]u64 = [[1u64,2u64],[3u64,4u64]]; +let A3D: [2][2][2]u8 = [[[1u8,2u8],[3u8,4u8]],[[5u8,6u8],[7u8,8u8]]]; + +type dt1 = struct { tag: i32, buf: [4]u8 }; +let D1: dt1 = dt1{tag=42, buf=[1u8, 2u8, 3u8, 4u8]}; +type dt2 = struct { tag: i32, m: [2][2]u64 }; +let D2: dt2 = dt2{tag=42, m=[[1u64,2u64],[3u64,4u64]]}; + +fn bits64(v: f64) u64 = { + let x: f64 = v; + let p: *u64 = (&x): *u64; + return *p; +}; + +fn bits32(v: f32) u32 = { + let x: f32 = v; + let p: *u32 = (&x): *u32; + return *p; +}; + +fn at(i: i32, j: i32) u64 = { return A2V[i][j]; }; + +@test fn let_u8_arr() void = { assert(A_U8[0]: i32 == 1); }; +@test fn let_u32_arr() void = { assert(A_U32[0]: i32 == 1); }; +@test fn let_u64_arr() void = { assert(A_U64[0]: i32 == 1); }; +@test fn let_i32_neg_arr() void = { assert(A_INEG[0] == -1); }; + +@test fn let_f64_arr() void = { + assert(bits64(A_F64[0]) == 0x3FF8000000000000u64); + assert(bits64(A_F64[1]) == 0xC004000000000000u64); + assert(bits64(A_F64[3]) == 0xC012000000000000u64); +}; + +@test fn let_f32_arr() void = { + assert(bits32(A_F32[0]) == 0x3FC00000u32); + assert(bits32(A_F32[1]) == 0xC0200000u32); + assert(bits32(A_F32[3]) == 0xC0900000u32); +}; + +@test fn def_u32_arr() void = { assert(DA_U32[0]: i32 == 11); }; + +@test fn def_f64_arr() void = { + assert(bits64(DA_F64[0]) == 0x3FF8000000000000u64); + assert(bits64(DA_F64[3]) == 0x4012000000000000u64); +}; + +@test fn let_struct_with_arr_field() void = { + assert(D1.tag == 42); + assert(D1.buf[0]: i32 == 1); + assert(D1.buf[3]: i32 == 4); +}; +@test fn let_u8_zero_arr() void = { assert(A_UZ[0]: i32 == 0); }; +@test fn let_u8_single() void = { assert(A_U1[0]: i32 == 7); }; +@test fn let_2d_u64() void = { assert(A2D[1][0]: i32 == 3); }; +@test fn def_2d_u64() void = { assert(DA2D[2][1]: i32 == 6); }; +@test fn let_2d_varidx() void = { assert((at(1, 1) + at(2, 0)): i32 == 51); }; +@test fn let_2d_u32_8byte() void = { assert(A28[1][0]: i32 == 9); }; + +@test fn let_2d_write() void = { + A2W[1][0] = 99u64; + assert((A2W[0][0] + A2W[0][1] + A2W[1][0] + A2W[1][1]): i32 == 106); +}; + +@test fn let_struct_2d_field() void = { + assert(D2.tag == 42); + assert(D2.m[1][0]: i32 == 3); + assert(D2.m[1][1]: i32 == 4); +}; +@test fn let_3d_u8() void = { assert(A3D[1][1][0]: i32 == 7); }; diff --git a/test/lang/const_slice_aggregate_test.ww b/test/lang/const_slice_aggregate_test.ww new file mode 100644 index 00000000..624bd126 --- /dev/null +++ b/test/lang/const_slice_aggregate_test.ww @@ -0,0 +1,62 @@ +// const_slice_aggregate_test — module-level const slice of (str,*fn) tuple rows +// + scalar &fn globals, DATA emit with element relocations. Migrated from +// test/wcc/946_const_slice_aggregate_run.c (#117/#119). cstage build+run was T1; +// cs==ww .s byte-id rides T2 (test-lang-byteid). The loud non-tuple-aggregate +// reject is the runww carrier test/wcc/data/slice_of_str_reject. +// +// drew: CALL THROUGH the *fn reloc — a scalar-only / len-only assert is +// reloc-blind. Each row calls each distinct fn back so a wrong/swapped reloc is +// caught; the str-element relocs + per-row backing stride ride the T2 byte-id. +// Whole-element word0 is the only correctly-loaded backing word (#121 read +// constraint), so the fn-first / scalar-first orderings put the read target at +// word0. + +package const_slice_aggregate_test; + +fn fa(c: rune) bool = { return c == 'a'; }; +fn fz(c: rune) bool = { return c == 'z'; }; + +const TBL_FN: [](*fn(c: rune) bool, str) = [(&fa, "aa"), (&fz, "zzz")]; +const TBL_SF: [](str, *fn(c: rune) bool) = [("aa", &fa), ("zzz", &fz)]; +const TBL_3: [](str, *fn(c: rune) bool) = + [("a", &fa), ("bb", &fa), ("ccc", &fa)]; +const TSCAL: [](i64, str) = [(10i64, "a"), (20i64, "bb")]; +let PF: *fn(c: rune) bool = &fa; +let PG: *fn(c: rune) bool = &fz; + +@test fn fnfirst_reloc() void = { + let e0 = TBL_FN[0]; + let e1 = TBL_FN[1]; + let f0 = e0.0; + let f1 = e1.0; + assert((*f0)('a')); + assert(!(*f0)('z')); + assert((*f1)('z')); + assert(!(*f1)('a')); + assert(len(TBL_FN) == 2); +}; + +@test fn consumer_str_fn() void = { + assert(len(TBL_SF) == 2); +}; + +@test fn consumer_3row() void = { + assert(len(TBL_3) == 3); +}; + +@test fn scalar_tuple_slice() void = { + let e0 = TSCAL[0]; + let e1 = TSCAL[1]; + let v0 = e0.0; + let v1 = e1.0; + assert(v0 == 10); + assert(v1 == 20); + assert(len(TSCAL) == 2); +}; + +@test fn scalar_fnptr() void = { + assert((*PF)('a')); + assert(!(*PF)('z')); + assert((*PG)('z')); + assert(!(*PG)('a')); +}; diff --git a/test/lang/def_float_lit_test.ww b/test/lang/def_float_lit_test.ww new file mode 100644 index 00000000..637f061d --- /dev/null +++ b/test/lang/def_float_lit_test.ww @@ -0,0 +1,62 @@ +// def_float_lit_test — module-level `def`/`let` f64/f32 literal (incl negation) +// emits DATA, read back from a fn. Migrated from test/wcc/917_def_float_lit_run.c +// (#129 Phase A.1). Pre-fix `def K: f64 = lit;` fell through emit_defs's int-only +// fold gate so no DATAW landed (link: `undefined reference to main.K`); emit_lets's +// float arm never peeled N_UN(MINUS/PLUS, N_FLOATLIT) so `let g: f64 = -1.5;` +// silently zero-emitted. Fix = shared emit_floatlit_data helper (negation via +// IEEE-754 sign-bit XOR). cstage build+run was T1; cs==ww .s byte-id rides T2 +// (test-lang-byteid). +// +// drew: assert BIT-EXACT incl sign — the bits()-reinterpret reads the full IEEE +// pattern, so a sign-bit or mantissa drift fails (a truncating `: i32` read would +// alias 1.5 and 1.9). The negative rows pin the sign-XOR byte path. + +package def_float_lit_test; + +def KDPOS: f64 = 1.5; +def KDNEG: f64 = -1.5; +def KFPOS: f32 = 1.5f32; +def KFNEG: f32 = -1.5f32; +let GDNEG: f64 = -1.5; +let GDPOS: f64 = 1.5; +let GFPOS: f32 = 1.5f32; + +fn bits64(v: f64) u64 = { + let x: f64 = v; + let p: *u64 = (&x): *u64; + return *p; +}; + +fn bits32(v: f32) u32 = { + let x: f32 = v; + let p: *u32 = (&x): *u32; + return *p; +}; + +@test fn def_f64_pos() void = { + assert(bits64(KDPOS) == 0x3FF8000000000000u64); +}; + +@test fn def_f64_neg() void = { + assert(bits64(KDNEG) == 0xBFF8000000000000u64); +}; + +@test fn def_f32_pos() void = { + assert(bits32(KFPOS) == 0x3FC00000u32); +}; + +@test fn def_f32_neg() void = { + assert(bits32(KFNEG) == 0xBFC00000u32); +}; + +@test fn let_f64_neg() void = { + assert(bits64(GDNEG) == 0xBFF8000000000000u64); +}; + +@test fn let_f64_pos() void = { + assert(bits64(GDPOS) == 0x3FF8000000000000u64); +}; + +@test fn let_f32_pos() void = { + assert(bits32(GFPOS) == 0x3FC00000u32); +}; diff --git a/test/lang/inferred_scalar_global_test.ww b/test/lang/inferred_scalar_global_test.ww new file mode 100644 index 00000000..ce704a6f --- /dev/null +++ b/test/lang/inferred_scalar_global_test.ww @@ -0,0 +1,33 @@ +// inferred_scalar_global_test — module-level inferred/const-expr scalar global +// emit + read. Migrated from test/wcc/947_inferred_scalar_global_run.c +// (#66 b-i, #134 neg, #133 const-expr). An inferred / unary / const-expr int +// global once emitted no DATAW on wwstage (MOVSXD on stale AX) and link-failed +// on cstage; the let pass-2 arm now const-folds the rhs and stamps an N_INTLIT +// so cgen's literal DATA emitter fires in BOTH stages. cstage build+run was T1; +// cs==ww .s byte-id rides T2 (test-lang-byteid). The div-by-zero const-expr +// reject is the runww carrier test/wcc/data/const_divzero_reject. +// +// The typed controls (typed_ctrl/neg_typed_ctrl/const_typed) lock the +// construction proof: the inferred decl's emitted .s equals the typed decl's +// after defaulting. + +package inferred_scalar_global_test; + +let SI = 42; +let STC: i64 = 42; +let SNI = -42; +let SNT: int = -42; +let SCI = 7 * 6; +let SCT: i64 = 7 * 6; +def KD: int = 6; +let SDR = KD * 7; +let SUB = -(2 * 3); + +@test fn inferred() void = { assert(SI: i64 == 42); }; +@test fn typed_ctrl() void = { assert(STC == 42); }; +@test fn neg_inferred() void = { assert(SNI: i64 == -42); }; +@test fn neg_typed_ctrl() void = { assert(SNT == -42); }; +@test fn const_inferred() void = { assert(SCI: i64 == 42); }; +@test fn const_typed() void = { assert(SCT == 42); }; +@test fn const_defref() void = { assert(SDR: i64 == 42); }; +@test fn const_unary_binop() void = { assert(SUB: i64 == -6); }; diff --git a/test/lang/nestfield_test.ww b/test/lang/nestfield_test.ww new file mode 100644 index 00000000..bf47dd91 --- /dev/null +++ b/test/lang/nestfield_test.ww @@ -0,0 +1,38 @@ +// nestfield_test — nested sub-8 composite struct field at natural offsets. +// Migrated from test/wcc/989_nestfield_run.c (#44/#55). For outer{a:u8, p:inner} +// the natural offset of p is 1, but a pre-fix slot-padded layout put it at 8, so +// construction (write) and field-access (read) disagreed and o.p.x / o.p.y read +// wrong. cstage build+run was T1; the original cat-A invariant (cs==ww exit) +// now rides the stronger T2 .s byte-id (test-lang-byteid). +// +// nested3's z proves post-composite accumulation stays natural (z follows the +// 1-byte-padded inner, not the 8-byte-padded one). flat_ctl is the no-sub-8-field +// control where natural and slot-padded layouts coincide. + +package nestfield_test; + +type inr = struct { x: u8, y: u8 }; +type ot2 = struct { a: u8, p: inr }; +type ot3 = struct { a: u8, p: inr, z: i64 }; +type flt = struct { a: u8, b: i64 }; + +@test fn nested2() void = { + let o: ot2 = ot2 { a = 5, p = inr { x = 6, y = 7 } }; + assert(o.a: int == 5); + assert(o.p.x: int == 6); + assert(o.p.y: int == 7); +}; + +@test fn nested3() void = { + let o: ot3 = ot3 { a = 1, p = inr { x = 2, y = 3 }, z = 0x44444444i64 }; + assert(o.a: int == 1); + assert(o.p.x: int == 2); + assert(o.p.y: int == 3); + assert(o.z == 0x44444444i64); +}; + +@test fn flat_ctl() void = { + let o: flt = flt { a = 9, b = 0x33333333i64 }; + assert(o.a: int == 9); + assert(o.b == 0x33333333i64); +}; diff --git a/test/lang/signed_data_emit_test.ww b/test/lang/signed_data_emit_test.ww new file mode 100644 index 00000000..06759591 --- /dev/null +++ b/test/lang/signed_data_emit_test.ww @@ -0,0 +1,66 @@ +// signed_data_emit_test — module-level signed i8..i64 scalar + 1D-array DATA +// emit, self-asserting the sign survives exactly. Migrated from +// test/wcc/923_signed_data_emit_run.c. Pre-fix wwstage silently zeroed negative +// array entries; cstage emitted nothing (link failed). cstage build+run was T1; +// cs==ww .s byte-id rides T2 (test-lang-byteid). +// +// drew: assert SIGN survives exactly — every row compares against the signed +// typed literal, so a sign-extension or zero-fill drift fails. i64_tilde pins +// the N_UN(TK_TILDE) fold (~0u64 == -1i64). The arrays mirror the utf8 DFA shape. + +package signed_data_emit_test; + +let X_I8N: i8 = -1i8; +let X_I8P: i8 = 42i8; +let X_I16N: i16 = -2i16; +let X_I16P: i16 = 1000i16; +let X_I32N: i32 = -100i32; +let X_I32P: i32 = 100000i32; +let X_I64N: i64 = -1000i64; +let X_I64P: i64 = 1000000i64; +let X_TILDE: i64 = (~0u64): i64; + +let DFA: [8]i8 = [0i8, -1i8, 1i8, 2i8, 0i8, 0i8, -1i8, -1i8]; +let A16: [4]i16 = [1i16, -2i16, 3i16, -4i16]; +let A32: [4]i32 = [10i32, -20i32, 30i32, -40i32]; +let A64: [4]i64 = [100i64, -200i64, 300i64, -400i64]; + +@test fn i8_neg_scalar() void = { assert(X_I8N == -1i8); }; +@test fn i8_pos_scalar() void = { assert(X_I8P == 42i8); }; +@test fn i16_neg_scalar() void = { assert(X_I16N == -2i16); }; +@test fn i16_pos_scalar() void = { assert(X_I16P == 1000i16); }; +@test fn i32_neg_scalar() void = { assert(X_I32N == -100i32); }; +@test fn i32_pos_scalar() void = { assert(X_I32P == 100000i32); }; +@test fn i64_neg_scalar() void = { assert(X_I64N == -1000i64); }; +@test fn i64_pos_scalar() void = { assert(X_I64P == 1000000i64); }; +@test fn i64_tilde_scalar() void = { assert(X_TILDE == -1i64); }; + +@test fn i8_arr_dfa() void = { + assert(DFA[0] == 0i8); + assert(DFA[1] == -1i8); + assert(DFA[2] == 1i8); + assert(DFA[3] == 2i8); + assert(DFA[6] == -1i8); + assert(DFA[7] == -1i8); +}; + +@test fn i16_arr_mixed() void = { + assert(A16[0] == 1i16); + assert(A16[1] == -2i16); + assert(A16[2] == 3i16); + assert(A16[3] == -4i16); +}; + +@test fn i32_arr_mixed() void = { + assert(A32[0] == 10i32); + assert(A32[1] == -20i32); + assert(A32[2] == 30i32); + assert(A32[3] == -40i32); +}; + +@test fn i64_arr_mixed() void = { + assert(A64[0] == 100i64); + assert(A64[1] == -200i64); + assert(A64[2] == 300i64); + assert(A64[3] == -400i64); +}; diff --git a/test/lang/strarray_static_test.ww b/test/lang/strarray_static_test.ww new file mode 100644 index 00000000..5bdd802c --- /dev/null +++ b/test/lang/strarray_static_test.ww @@ -0,0 +1,44 @@ +// strarray_static_test — module-level [N]str static-init: per-element .len +// header sums + per-element .ptr RELOC dereferenced to chars. Migrated from +// test/wcc/919_strarray_static_run.c. cstage build+run was T1; cs==ww .s byte-id +// rides T2 (test-lang-byteid). +// +// drew: assert THROUGH the per-element .ptr deref (not just .len) — a reloc-blind +// .len-only check would miss a wrong/swapped element relocation. The empty-slot +// and `...` repeat-suffix rows pin that an empty element doesn't shift the +// following element's reloc and that the repeat-fill row's DATAR resolves to the +// last explicit element. + +package strarray_static_test; + +let TLEN: [3]str = ["ab", "cde", "f"]; +let TPTR: [3]str = ["A", "B", "C"]; +let TVAR: [3]str = ["xx", "yyy", "z"]; +let TEMP: [2]str = ["", "Z"]; +let TREP: [3]str = ["X", "Y"...]; + +@test fn strtab_len() void = { + assert((TLEN[0].len + TLEN[1].len + TLEN[2].len): i32 == 6); +}; + +@test fn strtab_ptr_elem2() void = { + let p: *u8 = TPTR[2].ptr; + assert((*p): i32 == 67); +}; + +@test fn strtab_ptr_varindex() void = { + let i: i32 = 1; + let p: *u8 = TVAR[i].ptr; + assert((*p): i32 == 121); +}; + +@test fn strtab_empty_then_ptr() void = { + assert(TEMP[0].len == 0); + let p: *u8 = TEMP[1].ptr; + assert((*p): i32 == 90); +}; + +@test fn strtab_repeat_suffix() void = { + let p: *u8 = TREP[2].ptr; + assert((*p): i32 == 89); +}; diff --git a/test/lang/struct_composite_init_test.ww b/test/lang/struct_composite_init_test.ww new file mode 100644 index 00000000..c5fb7345 --- /dev/null +++ b/test/lang/struct_composite_init_test.ww @@ -0,0 +1,66 @@ +// struct_composite_init_test — module-level `let`/`def` composite-struct +// static-init, field read. Migrated from test/wcc/918_struct_composite_init_run.c +// (#129 Phase A.2). Pre-fix emit_lets/emit_defs skipped struct-typed decls +// (link: `undefined reference to main.NAME`) and a struct def read MOVSXD'd +// stack byte 0. Fix = emit_struct_data/emit_struct_lit_bytes walking the field +// list with per-field-offset zero-fill (rule 13). cstage build+run was T1; +// cs==ww .s byte-id rides T2 (test-lang-byteid). +// +// The float-field rows assert bit-exact (drew) via bits64. let_empty/norhs read +// 0 from the statically zero-filled DATA (a global, not a dirtied stack — no +// benign-zero trap; an under-emit would shorten the symbol, not pad zero). The +// 8B-struct row pins the !is_struct gate over the sz==8 scalar short-circuit. + +package struct_composite_init_test; + +type cfg_t = struct { a: i32, b: u64 }; +type ft = struct { a: f64, b: u32 }; +type s8 = struct { a: i32, b: i32 }; + +let CFG_L: cfg_t = cfg_t{a=1, b=2u64}; +def CFG_D: cfg_t = cfg_t{a=1, b=2u64}; +let F_L: ft = ft{a=1.5, b=99u32}; +def F_D: ft = ft{a=1.5, b=99u32}; +let Z: cfg_t = cfg_t{}; +let X8: s8 = s8{a=7, b=42}; +let CFG_NR: cfg_t; + +fn bits64(v: f64) u64 = { + let x: f64 = v; + let p: *u64 = (&x): *u64; + return *p; +}; + +@test fn let_int_struct() void = { + assert(CFG_L.a == 1); + assert(CFG_L.b == 2u64); +}; + +@test fn def_int_struct() void = { + assert(CFG_D.a == 1); + assert(CFG_D.b == 2u64); +}; + +@test fn let_float_field() void = { + assert(bits64(F_L.a) == 0x3FF8000000000000u64); + assert(F_L.b == 99u32); +}; + +@test fn def_float_field() void = { + assert(bits64(F_D.a) == 0x3FF8000000000000u64); + assert(F_D.b == 99u32); +}; + +@test fn let_empty_struct() void = { + assert(Z.a == 0); + assert(Z.b == 0u64); +}; + +@test fn let_int_struct_8b() void = { + assert(X8.a == 7); + assert(X8.b == 42); +}; + +@test fn let_norhs_struct() void = { + assert(CFG_NR.a == 0); +}; diff --git a/test/lang/structlit_arrfield_test.ww b/test/lang/structlit_arrfield_test.ww new file mode 100644 index 00000000..48cd77f7 --- /dev/null +++ b/test/lang/structlit_arrfield_test.ww @@ -0,0 +1,34 @@ +// structlit_arrfield_test — struct array-field init + read (global let/def and +// local lit). Migrated from test/wcc/949_structlit_arrfield_run.c (#249). BUG B: +// reading a [4]u8 field of a module-global struct SEGFAULTed on wwstage; BUG A: +// a local struct-lit array field fell to the scalar tail and dropped every +// element but the first. Fix = cg_structlit_fill array arm + def_isstructdef +// LOAD widening (ADDQ $field_off). cstage build+run was T1; cs==ww .s byte-id +// rides T2 (test-lang-byteid). The def row has a [3]u8 pad ahead of encmap, so +// the read exercises a non-zero field offset (the base64 std_encoding shape). + +package structlit_arrfield_test; + +type e1 = struct { encmap: [4]u8 }; +let GE: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] }; + +type e2 = struct { pad: [3]u8, encmap: [4]u8 }; +def GD: e2 = e2 { pad = [9u8, 9u8, 9u8], encmap = [65u8, 66u8, 67u8, 68u8] }; + +@test fn global_let_read() void = { + assert(GE.encmap[0]: i32 == 65); +}; + +@test fn global_def_read_off() void = { + assert(GD.encmap[2]: i32 == 67); +}; + +@test fn local_lit_read0() void = { + let g: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] }; + assert(g.encmap[0]: i32 == 65); +}; + +@test fn local_lit_read3() void = { + let g: e1 = e1 { encmap = [65u8, 66u8, 67u8, 68u8] }; + assert(g.encmap[3]: i32 == 68); +}; diff --git a/test/lang/valstruct_subsize_test.ww b/test/lang/valstruct_subsize_test.ww new file mode 100644 index 00000000..06be7de0 --- /dev/null +++ b/test/lang/valstruct_subsize_test.ww @@ -0,0 +1,70 @@ +// valstruct_subsize_test — sub-8 nested value-struct zero-init extent, local + +// global, distinct byte asserts. Migrated from +// test/wcc/949_valstruct_subsize_run.c. A nested {[N]u8} value-struct of ABI +// size 1/2/4 once emitted a stray MOVQ $0 (local) / 8 zero DATA bytes (global) +// on wwstage that cstage didn't. cstage build+run was T1; cs==ww .s byte-id +// rides T2 (test-lang-byteid). +// +// The D1/D2 rows WRITE then READ a byte so the value is deterministic (the +// robust falsifiable dimension). The ctl_*_16 rows are the negative control: a +// >8 multi-word value-struct still zero-inits — a wrongly-suppressed >8 zero arm +// would read stack garbage (and diverge from the still-zeroing cstage on the T2 +// byte-id, which is the real guarantee for the unwritten read). + +package valstruct_subsize_test; + +type in4 = struct { m: [4]u8 }; +type ov4 = struct { i: in4 }; +type in2 = struct { m: [2]u8 }; +type ov2 = struct { i: in2 }; +type in1 = struct { m: [1]u8 }; +type ov1 = struct { i: in1 }; +type in16 = struct { m: [16]u8 }; +type ov16 = struct { i: in16 }; + +let G4: ov4; +let G2: ov2; +let G1: ov1; +let G16: ov16; + +@test fn d1_local_4() void = { + let o: ov4; + o.i.m[0] = 66u8; + assert(o.i.m[0]: i32 == 66); +}; + +@test fn d1_local_2() void = { + let o: ov2; + o.i.m[1] = 55u8; + assert(o.i.m[1]: i32 == 55); +}; + +@test fn d1_local_1() void = { + let o: ov1; + o.i.m[0] = 44u8; + assert(o.i.m[0]: i32 == 44); +}; + +@test fn d2_global_4() void = { + G4.i.m[0] = 66u8; + assert(G4.i.m[0]: i32 == 66); +}; + +@test fn d2_global_2() void = { + G2.i.m[1] = 55u8; + assert(G2.i.m[1]: i32 == 55); +}; + +@test fn d2_global_1() void = { + G1.i.m[0] = 44u8; + assert(G1.i.m[0]: i32 == 44); +}; + +@test fn ctl_local_16() void = { + let o: ov16; + assert(o.i.m[7]: i32 == 0); +}; + +@test fn ctl_global_16() void = { + assert(G16.i.m[7]: i32 == 0); +}; diff --git a/test/wcc/719_signed_data_emit.c b/test/wcc/719_signed_data_emit.c index ae71e2de..4709ee10 100644 --- a/test/wcc/719_signed_data_emit.c +++ b/test/wcc/719_signed_data_emit.c @@ -11,8 +11,9 @@ * negative literal should have produced 0xFF... (link succeeded; * runtime read 0). The array arm hit the same gap. * - * Both 923_signed_data_emit_run and the broader bootstrap byte-id - * (995_self_rebuild) would catch a future regression, but this row + * Both test/lang/signed_data_emit_test.ww (the migrated runtime rows) + * and the broader bootstrap byte-id (995_self_rebuild) would catch a + * future regression, but this row * pins the *asm shape* itself — a future cgen refactor that emits * the slot via a different directive (e.g. via DATA + DATAR rather * than DATAW) would silently divergent even with green semantics. diff --git a/test/wcc/914_arr_u16_store_run.c b/test/wcc/914_arr_u16_store_run.c deleted file mode 100644 index 02fa9638..00000000 --- a/test/wcc/914_arr_u16_store_run.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 914_arr_u16_store_run — runtime + byte-id net for #128a: array- - * literal init into [N]u16 (or any [N]T where esz==2) must store with - * MOVW, not MOVQ. Pre-fix cstage's cgen.c:7180-7222 array-init dispatch - * routed esz==2 to MOVQ fall-through (the comment at 7194-7198 - * documented + deferred this until A_MOVW landed in w6a); the MOVQ - * wrote 8 bytes into a 2-byte slot, overlapping the next 6 bytes of - * stack. Adjacent fully-init writes accident-corrected via overlap - * (each MOVQ rewrote the prior MOVQ's trailing 6B), but a PARTIAL - * init left high garbage in slots that should have been default-zero. - * - * Fix is the now-unblocked dispatch: `else if (esz == 2) op = A_MOVW;` - * The wwstage emitter was already correct (uses MOVW); the cstage gap - * was the deferred TODO. Both stages now emit byte-identical MOVW for - * [N]u16 (and any aliased-narrow-element [N]T whose tinfo.size == 2). - * - * Rows cover (the bug is caught via the rule-10 cs==ww byte-id gate; - * ww doesn't accept truly-partial init literals, and adjacent MOVQ - * writes accident-correct the runtime values, so byte-id is the lever): - * - u16_full_init: fully-init [4]u16, regression guard (pre-fix - * accident-correct at runtime via MOVQ overlap; .s shifts - * MOVQ→MOVW, cs==ww BYTE-IDENTICAL now) - * - u16_small_values: small u16 values, summed (regression guard) - * - u8_control: [4]u8 baseline (already MOVB pre-fix, no shift) - * - i16_signed: signed-narrow [N]i16, same dispatch — verifies the - * fix isn't gated on unsignedness - * - * TY_NAMED alias of u16 (`type myw = u16; let a: [4]myw = …`) is a - * sibling miscompile filed separately: wwstage's array-init element- - * size dispatch reads `primsize(elemn.str)` which returns 0 for an - * alias name, leaving esz at 8 (wrong slot, wrong stride). Out of - * scope for #128a (cstage MOVW landing). - * - * Each row carries (a) cstage `ww build` + run asserting the exit - * code and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id). Post-#128a - * the partial-init row's cstage emission gains MOVW; both stages - * unchanged everywhere else. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - /* Fully-init [4]u16: pre-fix MOVQ overlap accident-corrected; - * post-fix proper MOVW per slot. Sum of last bytes = 0xBE = 190; - * mod 256 = 190. We assert per-element to catch any value drift. */ - { "u16_full_init", - "package main;\n" - "export fn main() i32 = {\n" - " let a: [4]u16 = [0xABCDu16, 0xBEEFu16, 0xC0DEu16, 0xDEADu16];\n" - " if (a[0] != 0xABCDu16) { return 1; };\n" - " if (a[1] != 0xBEEFu16) { return 2; };\n" - " if (a[2] != 0xC0DEu16) { return 3; };\n" - " if (a[3] != 0xDEADu16) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* Same shape with smaller values — pin that the dispatch fires - * on values that don't need the upper 16 bits. */ - { "u16_small_values", - "package main;\n" - "export fn main() i32 = {\n" - " let a: [4]u16 = [10u16, 20u16, 30u16, 40u16];\n" - " let s: i32 = 0;\n" - " s += a[0]: i32; s += a[1]: i32;\n" - " s += a[2]: i32; s += a[3]: i32;\n" - " return s;\n" - "};\n", 100 }, - /* [4]u8 control: already correct (MOVB pre-fix). Regression - * guard — asm should be unchanged. */ - { "u8_control", - "package main;\n" - "export fn main() i32 = {\n" - " let a: [4]u8 = [10u8, 20u8, 30u8, 40u8];\n" - " let s: i32 = 0;\n" - " s += a[0]: i32; s += a[1]: i32;\n" - " s += a[2]: i32; s += a[3]: i32;\n" - " return s;\n" - "};\n", 100 }, - /* [4]i16: signed-narrow, same MOVW dispatch (op chosen by esz, - * not signedness). Verifies the fix isn't gated. */ - { "i16_signed", - "package main;\n" - "export fn main() i32 = {\n" - " let a: [4]i16 = [10i16, 20i16, 30i16, -5i16];\n" - " let s: i32 = 0;\n" - " s += a[0]: i32; s += a[1]: i32;\n" - " s += a[2]: i32; s += a[3]: i32;\n" - " return s;\n" - "};\n", 55 /* 10+20+30+(-5) = 55 */ }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "arru16store: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwau16_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char src[128], outbin[128], rmcmd[160]; - snprintf(src, sizeof src, "%s/wwau16_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwau16_%d_%d", - tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { runwait(rmcmd); fail++; continue; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - char cs_s[128], ws_s[128]; - snprintf(cs_s, sizeof cs_s, "%s/wwau16_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwau16_%d_%d_ww.s", - tmpdir, getpid(), i); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d arr-u16-store tests failed\n", fail, n); - return 1; - } - printf("arru16store: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/917_def_float_lit_run.c b/test/wcc/917_def_float_lit_run.c deleted file mode 100644 index 25e67d3b..00000000 --- a/test/wcc/917_def_float_lit_run.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * 917_def_float_lit_run — runtime + byte-id net for #129 Phase A.1: - * module-level `def NAME: f64 = literal;` (and `def: f32 = …`) - * silently fell through emit_defs's int-only `fold_int_literal` gate, - * so no DATAW row landed in the .data section — `w6l` failed link - * with `undefined reference to 'main.NAME'`. Symmetric latent bug in - * emit_lets's float arm: it only handled bare N_FLOATLIT, never - * peeled N_UN(MINUS/PLUS, N_FLOATLIT), so `let g: f64 = -1.5;` - * silently zero-emitted into the same undef-ref shape. - * - * Phase A.1 fix (rule-12 sea-of-stars consolidation): - * - cstage: extract `emit_floatlit_data(out, c, dir, name, T, rhs)` - * helper, called by emit_lets's float arm (now collapsed) AND - * emit_defs (new float arm). N_CAST + N_UN(MINUS/PLUS, - * N_FLOATLIT) peeled inside the helper. - * - wwstage: parallel `emitfloatlitdata` helper. Negation via - * IEEE-754 sign-bit XOR (avoids dragging the math bitcast helpers - * into cgen). - * - LOAD side: cstage's N_IDENT float-let arm and wwstage's cgident - * def-branch both gated on let_islet/deflookup-but-not-float; the - * gate widens to also catch float defs (they emit through the - * same mod_mangle / emitsymname symbol). - * - * Bootstrap NEUTRAL: zero current `def: f{32,64} = lit` consumers in - * lib/ or selfhost/. The N_UN-peel collateral fix for lets has no - * shipped consumers either (audit: no `let g: f64 = -lit;` anywhere). - * - * Rows cover both fix sides (DATA emit + LOAD) and the N_UN collateral: - * - f64_def_pos: `def K: f64 = 1.5;` — was undef-ref pre-fix, exit - * 1 (1.5 → i32 truncates to 1). - * - f64_def_neg: `def K: f64 = -1.5;` — was undef-ref pre-fix; exit - * 255 (sign-bit flip via XOR; -1.5 → i32 truncates to -1 → 255 - * in unsigned exit byte). - * - f32_def_pos: `def K: f32 = 1.5f32; …` — same shape, f32 width. - * - f64_let_neg: `let g: f64 = -1.5;` — pre-existing latent bug - * (N_UN peel never added to emit_lets); now fixed by the same - * helper. - * - f64_let_pos: `let g: f64 = 1.5;` — regression guard (existing - * bare-N_FLOATLIT path). - * - f32_let_pos: `let g: f32 = 1.5f32;` — regression guard, f32 path. - * - * Each row carries (a) cstage `ww build` + run asserting exit code - * and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id). - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - { "f64_def_pos", - "package main;\n" - "def K: f64 = 1.5;\n" - "export fn main() i32 = {\n" - " let x: f64 = K;\n" - " return (x: i32);\n" - "};\n", 1 }, - { "f64_def_neg", - "package main;\n" - "def K: f64 = -1.5;\n" - "export fn main() i32 = {\n" - " let x: f64 = K;\n" - " return (x: i32);\n" - "};\n", 255 /* -1 as unsigned exit byte */ }, - { "f32_def_pos", - "package main;\n" - "def K: f32 = 1.5f32;\n" - "export fn main() i32 = {\n" - " let x: f32 = K;\n" - " return (x: i32);\n" - "};\n", 1 }, - /* Matrix-closure: f32 + neg combined directly. Exercises the - * f32-narrow path PLUS the top-byte-XOR negation in one row. - * The other rows cover each leg individually (f64_def_neg for - * negation, f32_def_pos for f32 narrow); this row pins they - * compose correctly. */ - { "f32_def_neg", - "package main;\n" - "def K: f32 = -1.5f32;\n" - "export fn main() i32 = {\n" - " let x: f32 = K;\n" - " return (x: i32);\n" - "};\n", 255 /* -1 as exit byte */ }, - /* Pre-existing latent: emit_lets's float arm never peeled - * N_UN(MINUS,N_FLOATLIT). The class-closure consolidation - * fix in emit_floatlit_data heals this too. */ - { "f64_let_neg", - "package main;\n" - "let g: f64 = -1.5;\n" - "export fn main() i32 = {\n" - " return (g: i32);\n" - "};\n", 255 }, - { "f64_let_pos", - "package main;\n" - "let g: f64 = 1.5;\n" - "export fn main() i32 = {\n" - " return (g: i32);\n" - "};\n", 1 }, - { "f32_let_pos", - "package main;\n" - "let g: f32 = 1.5f32;\n" - "export fn main() i32 = {\n" - " return (g: i32);\n" - "};\n", 1 }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "deflitf: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwdflf_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char rmcmd[128]; - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - char src[128], outbin[128], cs_s[128], ws_s[128]; - snprintf(src, sizeof src, "%s/wwdflf_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwdflf_%d_%d", - tmpdir, getpid(), i); - snprintf(cs_s, sizeof cs_s, "%s/wwdflf_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwdflf_%d_%d_ww.s", - tmpdir, getpid(), i); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; runwait(rmcmd); continue; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d def-float-lit tests failed\n", fail, n); - return 1; - } - printf("deflitf: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/918_struct_composite_init_run.c b/test/wcc/918_struct_composite_init_run.c deleted file mode 100644 index ca14ca90..00000000 --- a/test/wcc/918_struct_composite_init_run.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 918_struct_composite_init_run — runtime + byte-id net for #129 - * Phase A.2: module-level `let`/`def` with composite-struct - * initializer silently emitted undefined ref OR wrong bytes pre-fix. - * - * Pre-A.2 failure modes: - * - cstage emit_lets / wwstage emitletdataw skipped struct-typed lets - * entirely (`if (is_struct) continue;` / parallel) — link surfaced - * `undefined reference to 'main.NAME'`. - * - cstage emit_defs / wwstage emitdefconstants had no struct arm — - * same undef ref for def, plus a SEPARATE LOAD-side cgen bug - * emitting `MOVSXD (BP), AX` (reading stack frame byte 0) when the - * LOAD did get past the link. - * - * Phase A.2 fix (per A.1 SSoT-helper precedent): - * - cstage: emit_struct_data + emit_struct_lit_bytes helpers walk - * Tfield list in declaration order, zero-fill padding via per- - * field offsets (rule 13), dispatch per field type. Float-field - * bytes inlined (mirroring A.1's emit_floatlit_data shape but - * localised so the byte loop covers padding too). Nested struct - * recurses. Out-of-scope field kinds (array / str / slice / ptr) - * fatal loud per rule-7. - * - cstage: emit_lets + emit_defs gain struct arms routing through - * the helper. - * - cstage: LOAD-side widening at `if (u && u->kind == TY_STRUCT - * && lhs->kind == N_IDENT)` arm — the `let_islet`-gated LEAQ - * name(SB) shape now also fires for struct defs via the new - * `def_isstructdef` registry (mirror of letvars). - * - wwstage: parallel emitstructdata + emitstructlitbytes helpers, - * defent.dtnode field, defvarstructinfo (cgdot LOAD widening). - * - * Bootstrap NEUTRAL: zero `let/def: T = T{...}` consumers in lib/ or - * selfhost/. γ-cleanup is the first consumer (lib/math:floatinfo). - * - * Rows cover all A.2-scope shapes: - * - (a) `let CFG: cfg_t = cfg_t{a=1, b=2u64};` — plain mixed-int let - * - (b) `def CFG: cfg_t = cfg_t{a=1, b=2u64};` — plain mixed-int def - * (exercises LOAD-widening; both stages) - * - (c) `let F: ft = ft{a=1.5, b=99u32};` — let with float field - * - (d) `def F: ft = ft{a=1.5, b=99u32};` — def with float field - * (storage + LOAD + float-narrow path together) - * - (e) `let Z: zt = zt{};` — empty struct-lit zero-fill - * - (f) `let CFG: cfg_t;` — regression: no-rhs (pre-existing path - * unchanged) - * - * Each row carries (a) cstage `ww build` + run asserting exit code - * and (b) w6c vs w6c_ww `.s` cmp (rule-10 byte-id). - * - * Nested-struct shape (#3 in design report) is OMITTED here — the - * helper implements the recursion but #145 (parser/checker inner- - * literal field-name leak) blocks end-to-end correctness; nested - * row deferred until #145 lands. - * - * Array-in-struct shape parked to Phase A.3 boundary. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - { "let_int_struct", - "package main;\n" - "type cfg_t = struct { a: i32, b: u64 };\n" - "let CFG: cfg_t = cfg_t{a=1, b=2u64};\n" - "export fn main() i32 = {\n" - " return CFG.a;\n" - "};\n", 1 }, - { "def_int_struct", - "package main;\n" - "type cfg_t = struct { a: i32, b: u64 };\n" - "def CFG: cfg_t = cfg_t{a=1, b=2u64};\n" - "export fn main() i32 = {\n" - " return CFG.a;\n" - "};\n", 1 }, - { "let_float_field", - "package main;\n" - "type ft = struct { a: f64, b: u32 };\n" - "let F: ft = ft{a=1.5, b=99u32};\n" - "export fn main() i32 = {\n" - " return (F.a: i32);\n" - "};\n", 1 }, - { "def_float_field", - "package main;\n" - "type ft = struct { a: f64, b: u32 };\n" - "def F: ft = ft{a=1.5, b=99u32};\n" - "export fn main() i32 = {\n" - " return (F.a: i32);\n" - "};\n", 1 }, - { "let_empty_struct", - "package main;\n" - "type zt = struct { a: i32, b: u64 };\n" - "let Z: zt = zt{};\n" - "export fn main() i32 = {\n" - " return Z.a;\n" - "};\n", 0 }, - /* 8B struct hits the cstage emit_lets scalar-8B short-circuit - * (sz==8 fold_int_literal arm) — without the `!let_isstruct` - * gate the struct lit fold-fails and the let drops entirely, - * emitting no DATA. Both stages now route via the struct arm. */ - { "let_int_struct_8b", - "package main;\n" - "type s8 = struct { a: i32, b: i32 };\n" - "let X: s8 = s8{a=7, b=42};\n" - "export fn main() i32 = {\n" - " return X.a;\n" - "};\n", 7 }, - /* Regression: no-rhs path unchanged (emit_data_row_zero / wwstage - * parallel). */ - { "let_norhs_struct", - "package main;\n" - "type cfg_t = struct { a: i32, b: u64 };\n" - "let CFG: cfg_t;\n" - "export fn main() i32 = {\n" - " return CFG.a;\n" - "};\n", 0 }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "strcomp: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwstrc_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char src[128], outbin[128], cs_s[128], ws_s[128], rmcmd[160]; - snprintf(src, sizeof src, "%s/wwstrc_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwstrc_%d_%d", - tmpdir, getpid(), i); - snprintf(cs_s, sizeof cs_s, "%s/wwstrc_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwstrc_%d_%d_ww.s", - tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; runwait(rmcmd); continue; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d struct-composite tests failed\n", fail, n); - return 1; - } - printf("strcomp: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/919_array_static_init_run.c b/test/wcc/919_array_static_init_run.c deleted file mode 100644 index f02cff53..00000000 --- a/test/wcc/919_array_static_init_run.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * 919_array_static_init_run — runtime + byte-id net for #129 Phase - * A.3: module-level let/def with array initializer. - * - * Pre-A.3 state: - * - Int-element arrays (u8/i8/u16/u32/u64/i32 etc) already worked - * in both stages via fold_int_literal. - * - Float-element arrays ([N]f64, [N]f32) → undef-ref at link - * (emit_lets array arm fold_int_literal fails on FLOATLIT). - * - Array DEFs (def A: [N]T = [...]) → emit_defs no array arm - * (storage missing) AND cgindex broken (reads LEAQ (BP), BX — - * stack frame, not data section). - * - Array-in-struct field (`def D: dt = dt{tag=42, buf=[...]}`) → - * #129 A.2 rule-7 fatal "array field rhs not foldable" — the - * shape parked in A.2 awaiting A.3. - * - * Phase A.3 fix (mirror A.1/A.2 SSoT-helper precedent): - * - cstage: emit_array_data + emit_array_lit_bytes helpers with - * element-kind dispatch (int via fold_int_literal preserving - * bootstrap byte-id, float via inline bitcast + sign-XOR byte- - * loop mirror of A.1, struct via emit_struct_lit_bytes recursion - * mirror of A.2). Two-pass validate-then-emit avoids partial-byte - * corruption on rhs-fold-failure. - * - cstage: emit_lets array arm routes through helper; emit_defs - * gains array arm. - * - cstage: DefArray registry + def_isarraydef populated in - * let_collect; cgindex N_INDEX direct-ident `isglobal` gate - * widened to (let_islet || def_isarraydef). - * - cstage: emit_struct_lit_bytes (A.2 helper) gains TY_ARRAY field - * arm calling emit_array_lit_bytes recursively (closes A.2 parked - * shape 15). - * - wwstage: parallel emitarraydata + emitarraylitbytes; emitstruct - * litbytes TY_ARRAY arm; defvartnode helper; cgindex falls through - * to defvartnode after letvartnode nil. - * - * Bootstrap RISK: live consumers in lib/os, lib/bufio, lib/strings, - * lib/encoding/utf8 (dfa + masks), lib/strconv/stof_data - * (left_shift_table). All use typed-int-literal elements; the int-elem - * helper path is byte-for-byte preserved → bootstrap NEUTRAL. - * - * Rows (size strata 1B/2B/4B/8B × count strata 1/2/4 × int/float/struct/ - * empty/no-rhs/def-variant, avoiding the 16B-evade pattern from A.2): - * - * - (a) `let A: [4]u8 = [1u8, 2u8, 3u8, 4u8]` — 1B regression - * - (b) `let A: [4]u32 = [1u32, 2u32, 3u32, 4u32]` — 4B regression - * - (c) `let A: [2]u64 = [1u64, 2u64]` — 8B regression - * - (d) `let A: [4]i32 = [-1, -2, -3, -4]` — N_UN peel regression - * - (e) `let A: [4]f64 = [1.5, -2.5, 3.5, -4.5]` — NEW float-elem - * - (f) `let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32]` — NEW - * f32 narrow + sign-XOR per element - * - (g) `def A: [4]u32 = [11u32, 22u32, 33u32, 44u32]` — NEW - * def-storage + LOAD-widening - * - (h) `def A: [4]f64 = [1.5, 2.5, 3.5, 4.5]` — NEW def-variant of - * float - * - (i) `def D: dt = dt{tag=42, buf=[1u8,2u8,3u8,4u8]}` — NEW - * closes A.2 shape 15 (struct-with-array-field) - * - (j) `let A: [4]u8 = [0u8, 0u8, 0u8, 0u8]` — explicit-zero - * regression - * - (k) `let A: [1]u8 = [0u8]` — single-elem (matches lib/os/ - * emptypath pattern) - * - * Each row: cstage `ww build` + run asserting exit code + w6c vs - * w6c_ww `.s` cmp (rule-10 byte-id). - * - * #156 (PREREQ-1) extends this with 2D `[N][M]T` static-init (a) + - * double-index read (b) — the A.3 shape-14 capstone, consumer-driven by - * fold-4's powers_of_ten[596][2]u64. emit_array_lit_bytes gains a - * TY_ARRAY-element arm (recurse; esz=etype->size); cgindex leaves the - * sub-array ADDRESS for an array element (sister of #135). Rows - * let_2d_x, def_2d_u64 and let_struct_2d_field + the nested-`...` - * loud-reject (rule-7) below. The D.m[i][j] global-struct-field-array - * READ stays a - * pre-existing gap (#160, 1D+2D, cs≠ww) out of scope here. - * - * Deferred: - * - Pointer-element arrays `[N]*T = [&G, &H]` — needs DATAR per - * element (own task/fold). - * - `...` repeat with a nested-array element — loud-reject (#156 - * rule-7); no consumer (powers_of_ten is fully enumerated). - * - Bare-int `[N]u8 = [1, 2, 3, 4]` — #130 (checker issue). - * - Partial init `[4]u8 = [1u8]` — checker rejects (parser/checker - * decision). - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - { "let_u8_arr", - "package main;\n" - "let A: [4]u8 = [1u8, 2u8, 3u8, 4u8];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 1 }, - { "let_u32_arr", - "package main;\n" - "let A: [4]u32 = [1u32, 2u32, 3u32, 4u32];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 1 }, - { "let_u64_arr", - "package main;\n" - "let A: [2]u64 = [1u64, 2u64];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 1 }, - { "let_i32_neg_arr", - "package main;\n" - "let A: [4]i32 = [-1, -2, -3, -4];\n" - "export fn main() i32 = { return A[0]; };\n", 255 /* -1 */ }, - /* Float-element array — NEW in A.3. Includes both signs to exercise - * the sign-XOR byte-loop per element. */ - { "let_f64_arr", - "package main;\n" - "let A: [4]f64 = [1.5, -2.5, 3.5, -4.5];\n" - "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, - { "let_f32_arr", - "package main;\n" - "let A: [4]f32 = [1.5f32, -2.5f32, 3.5f32, -4.5f32];\n" - "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, - /* def-variant exercises the LOAD-widening (def_isarraydef) at - * cgindex/cgident. Storage emit also new. */ - { "def_u32_arr", - "package main;\n" - "def A: [4]u32 = [11u32, 22u32, 33u32, 44u32];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 11 }, - { "def_f64_arr", - "package main;\n" - "def A: [4]f64 = [1.5, 2.5, 3.5, 4.5];\n" - "export fn main() i32 = { return (A[0]: i32); };\n", 1 }, - /* The A.2-parked shape-15 — closes via emit_struct_lit_bytes - * TY_ARRAY field arm. */ - { "let_struct_with_arr_field", - "package main;\n" - "type dt = struct { tag: i32, buf: [4]u8 };\n" - "let D: dt = dt{tag=42, buf=[1u8, 2u8, 3u8, 4u8]};\n" - "export fn main() i32 = { return D.tag; };\n", 42 }, - { "let_u8_zero_arr", - "package main;\n" - "let A: [4]u8 = [0u8, 0u8, 0u8, 0u8];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 0 }, - { "let_u8_single", - "package main;\n" - "let A: [1]u8 = [7u8];\n" - "export fn main() i32 = { return A[0]: i32; };\n", 7 }, - /* #156 (PREREQ-1): 2D [N][M]T static-init (a) + double-index read - * (b) — the A.3 shape-14 capstone, consumer-driven by fold-4's - * powers_of_ten[596][2]u64. emit_array_lit_bytes recurses on the - * TY_ARRAY element (esz=etype->size, rule-13); cgindex leaves the - * sub-array ADDRESS (not a value) for an array element so the outer - * index dereferences the right cell (sister of #135). */ - { "let_2d_u64", - "package main;\n" - "let A: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];\n" - "export fn main() i32 = { return A[1][0]: i32; };\n", 3 }, - { "def_2d_u64", - "package main;\n" - "def A: [3][2]u64 = [[1u64,2u64],[3u64,4u64],[5u64,6u64]];\n" - "export fn main() i32 = { return A[2][1]: i32; };\n", 6 }, - /* variable-index read — the exact fold-4 access pattern - * (powers_of_ten[i][0]/[i][1]). 21 + 30 = 51. */ - { "let_2d_varidx", - "package main;\n" - "let A: [3][2]u64 = [[10u64,11u64],[20u64,21u64],[30u64,31u64]];\n" - "fn at(i: i32, j: i32) u64 = { return A[i][j]; };\n" - "export fn main() i32 = { return (at(1, 1) + at(2, 0)): i32; };\n", - 51 }, - /* 8-byte 2D: must NOT hit the sz==8 scalar short-circuit (the - * isarr8/N_TARRAY guard, #128 lesson) — routes to the array arm. */ - { "let_2d_u32_8byte", - "package main;\n" - "let A: [2][1]u32 = [[7u32],[9u32]];\n" - "export fn main() i32 = { return A[1][0]: i32; };\n", 9 }, - /* 2D write to one cell, sum all four — verifies the lvalue address - * targets the exact cell with no neighbour clobber. 1+2+99+4=106. */ - { "let_2d_write", - "package main;\n" - "let A: [2][2]u64 = [[1u64,2u64],[3u64,4u64]];\n" - "export fn main() i32 = { A[1][0] = 99u64; return " - "(A[0][0]+A[0][1]+A[1][0]+A[1][1]): i32; };\n", 106 }, - /* struct field that is itself a 2D array — static-init emit + - * layout (read D.tag). The D.m[i][j] field-array READ exercises a - * pre-existing global-struct-field-base bug (#137/#150 family, - * 1D+2D, cs≠ww) out of PREREQ-1 scope — the array bytes are - * covered by the cs==ww byte-id gate below. */ - { "let_struct_2d_field", - "package main;\n" - "type dt = struct { tag: i32, m: [2][2]u64 };\n" - "let D: dt = dt{tag=42, m=[[1u64,2u64],[3u64,4u64]]};\n" - "export fn main() i32 = { return D.tag; };\n", 42 }, - /* 3D — locks recursion-depth>2 in both emit (nested TY_ARRAY arm - * recurses twice) and read (double-then-single index, two - * address-leaves). [[[1,2],[3,4]],[[5,6],[7,8]]]; A[1][1][0] = 7. */ - { "let_3d_u8", - "package main;\n" - "let A: [2][2][2]u8 = " - "[[[1u8,2u8],[3u8,4u8]],[[5u8,6u8],[7u8,8u8]]];\n" - "export fn main() i32 = { return A[1][1][0]: i32; };\n", 7 }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "arrinit: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwari_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - char rmcmd[160]; - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - char src[128]; - snprintf(src, sizeof src, "%s/wwari_%d_%d.ww", - tmpdir, getpid(), i); - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; runwait(rmcmd); continue; } - fputs(rows[i].src, f); - fclose(f); - - char outbin[128]; - snprintf(outbin, sizeof outbin, "%s/wwari_%d_%d", - tmpdir, getpid(), i); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - char cs_s[128], ws_s[128]; - snprintf(cs_s, sizeof cs_s, "%s/wwari_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwari_%d_%d_ww.s", - tmpdir, getpid(), i); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - /* #156 rule-7: a `...` repeat marker with a nested-array element is - * a loud reject in BOTH stages (no consumer needs it; powers_of_ten - * is fully enumerated). The compile must FAIL, not silently emit - * wrong bytes. Separate from the rows table (which asserts build - * success). */ - { - char src[64]; - snprintf(src, sizeof src, "/tmp/wwari_%d_rej.ww", getpid()); - FILE *f = fopen(src, "wb"); - if (f != NULL) { - fputs("package main;\n" - "let A: [4][2]u64 = [[1u64, 2u64]...];\n" - "export fn main() i32 = { return 0; };\n", f); - fclose(f); - } - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s -o /dev/null %s 2>/dev/null", - w6c, src); - int rc_cs = runwait(cmd); - snprintf(cmd, sizeof cmd, "%s -o /dev/null %s 2>/dev/null", - w6c_ww, src); - int rc_ww = runwait(cmd); - n++; - if (rc_cs == 0 || rc_ww == 0) { - fprintf(stderr, "row[nested_ellipsis_reject]: expected " - "BOTH stages to reject (cs=%d ww=%d), want nonzero " - "(#156 rule-7)\n", rc_cs, rc_ww); - fail++; - } - unlink(src); - } - - if (fail) { - fprintf(stderr, "%d/%d array-static-init tests failed\n", fail, n); - return 1; - } - printf("arrinit: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/919_strarray_static_run.c b/test/wcc/919_strarray_static_run.c deleted file mode 100644 index 9b8cdd96..00000000 --- a/test/wcc/919_strarray_static_run.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 919_strarray_static_run — BUG #18. Runtime + cs==ww byte-id net for a - * module-level `let xs: [N]str = ["a","b",…];` static table. - * - * THE BUG (BOTH stages dropped it — shared-logic gap, not rule-10): - * A module-level [N]str static init emitted NO .data at all. The - * per-element str header carries a ptr→rodata relocation (not just - * bytes), so it can't ride emit_array_lit_bytes (byte-only): the str- - * element case fell through to fold_int_literal, returned 0, and - * emit_lets zero-init'd / skipped — leaving `main.` undefined. - * `w6l: undefined reference` at link. Function-LOCAL [N]str worked - * (runtime element stores); only the module-level STATIC DATA form was - * broken. - * - * THE FIX (#18): emit_strarray_data / emitstrarraydata apply the scalar- - * str-global pattern (DATAW header with a zero ptr placeholder + inline - * LE len, then a per-element `DATAR sym+idx*esz(SB),_S_n(SB)`) at each - * element offset. let_pre_intern / letpreintern pre-intern each element - * strlit so the _S_ rodata rows precede the DATAR references. Scoped to - * the DATAW (`let`) directive — A_DATAR requires a DATAW holder. - * - * EACH ROW CARRIES BOTH DIMENSIONS (801 model): - * (a) cstage `ww build` + run, asserting the exit — proves the table's - * .len bytes are correct AND each element's .ptr relocation - * resolves to the right rodata label (the rows deref a NON-zero - * element's first byte, so a dropped/wrong reloc gives a wrong - * char — built-in negative control). - * (b) w6c vs w6c_ww `.s` cmp — FAILS if the stages diverge. - * - * GATE POLARITY: must stay GREEN. A wrong exit means the static table - * relocations regressed; a byte-id FAIL means the stages diverged. - * - * NB: the rows read elements via the `.ptr`/`.len` pseudo-fields, NOT - * the `len()` builtin — `len(xs[i])` on an indexed str element is a - * separate pre-existing read-side miscompile (returns the ptr; filed - * alongside #18), orthogonal to the emission fix under test here. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - /* .len bytes: 2+3+1 == 6. A dropped table would fail to link. */ - { "strtab_len", - "package main;\n" - "let t: [3]str = [\"ab\",\"cde\",\"f\"];\n" - "export fn main() i32 = { return (t[0].len + t[1].len + t[2].len): i32; };\n", - 6 }, - /* element-2 .ptr reloc: *(t[2].ptr) == 'C' (67), NOT 'A' — proves - * the +2*esz relocation resolves to "C", not element 0. */ - { "strtab_ptr_elem2", - "package main;\n" - "let t: [3]str = [\"A\",\"B\",\"C\"];\n" - "export fn main() i32 = { let p: *u8 = t[2].ptr; return (*p): i32; };\n", - 67 }, - /* runtime-indexed .ptr: i=1, *(t[i].ptr) == 'y' (121) — the - * LEAQ tab(SB)+i*esz addressing reaches the right element's reloc. */ - { "strtab_ptr_varindex", - "package main;\n" - "let t: [3]str = [\"xx\",\"yyy\",\"z\"];\n" - "export fn main() i32 = { let i: i32 = 1; let p: *u8 = t[i].ptr; " - "return (*p): i32; };\n", - 121 }, - /* empty-element (no reloc, len 0) followed by a real element: t[0] - * len==0, *(t[1].ptr) == 'Z' (90) — the empty slot must not shift - * the following element's reloc offset. */ - { "strtab_empty_then_ptr", - "package main;\n" - "let t: [2]str = [\"\",\"Z\"];\n" - "export fn main() i32 = { if (t[0].len != 0) { return 88; }; " - "let p: *u8 = t[1].ptr; return (*p): i32; };\n", - 90 }, - /* repeat suffix `[X, Y...]` — the trailing `...` fills the rest of - * [3]str with the last explicit element ("Y"). t[2] is a repeat- - * filled slot: *(t[2].ptr) == 'Y' (89), NOT 'X' — proves the +48 - * fill row's DATAR resolves to last_ev ("Y"), exercising the - * repeat branch (its own len-fill + DATAR loop) the other rows skip. */ - { "strtab_repeat_suffix", - "package main;\n" - "let t: [3]str = [\"X\",\"Y\"...];\n" - "export fn main() i32 = { let p: *u8 = t[2].ptr; return (*p): i32; };\n", - 89 }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "strarray_static: w6c_ww missing — cannot run " - "the cs==ww byte-id gate\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwsas_%d_d_%d", getpid(), i); - mkdir(tmpdir, 0755); - char rmcmd[160]; - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - char src[128], outbin[128]; - snprintf(src, sizeof src, "%s/wwsas_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwsas_%d_%d", tmpdir, getpid(), i); - FILE *f = fopen(src, "wb"); - if (f == NULL) { runwait(rmcmd); fail++; continue; } - fputs(rows[i].src, f); - fclose(f); - - /* (a) cstage build + run. */ - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - /* (b) cs==ww byte-id gate. */ - char cs_s[128], ws_s[128]; - snprintf(cs_s, sizeof cs_s, "%s/wwsas_%d_%d_cs.s", tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwsas_%d_%d_ww.s", tmpdir, getpid(), i); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, "row[%s]: cstage/wwstage .s DIFFER " - "(rule-10 byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d strarray static-init tests failed\n", - fail, n); - return 1; - } - printf("strarray_static: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/923_signed_data_emit_run.c b/test/wcc/923_signed_data_emit_run.c deleted file mode 100644 index 45477d12..00000000 --- a/test/wcc/923_signed_data_emit_run.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 923_signed_data_emit_run — top-level `let` bindings of signed - * integer types must emit a module-scope DATA slot whose initialiser - * is the literal's two's-complement bytes (#19). - * - * Pre-fix both stages skipped the scalar DATAW arm when the rhs was - * N_UN(TK_MINUS, INTLIT). cstage's emit_lets fell through to the - * default `else continue;` so `let x: i8 = -1i8;` produced no DATAW - * row and the link failed with "undefined reference to x". Wwstage's - * emitletdataw silently left the slot at zero — link succeeded but - * the read returned 0 instead of -1, a corpus-coverage-blind bug. - * - * The array arm carried the same defect on both stages. cstage's - * walker bailed on the first non-foldable element (then dropped the - * whole DATAW row for the array via the `is_array continue` fall- - * through); wwstage emitted zeros at every unfoldable index, again - * silently. The utf8 DFA shape (`let dfa: [8]i8 = [0i8, -1i8, ...]`) - * is the canonical real-source trigger. - * - * Sister to #24, which fixed the same N_UN-fold gap on the `def`- - * emit side (emit_defs / emitdefconstants) via the shared - * fold_int_literal / foldintliteral helper. Task #19 routes the - * `let`-emit paths (scalar + array) through the same helper. - * - * Rows pin the full signed-int matrix (i8/i16/i32/i64) for both - * scalar and 1D array shapes, plus positive controls so a future - * regression of the gate that affects only the negative arm still - * leaves the positive rows green. The negative-zero (TK_MINUS over - * 0) and TK_TILDE rows pin the other two N_UN ops the helper covers. - * - * Stage matrix: cstage always; wwstage gated on `ww_ww` existing. - * Runtime checks all read through cast-strip + literal compare so a - * cgen-side narrow-load regression surfaces here rather than hiding - * behind the DATA slot's wider-than-elem padding. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "i8_neg_scalar", - "let x: i8 = -1i8;\n" - "fn main() i32 = { if (x != -1i8) { return 1; }; return 0; };\n", - 0 }, - { "i8_pos_scalar", - "let x: i8 = 42i8;\n" - "fn main() i32 = { if (x != 42i8) { return 1; }; return 0; };\n", - 0 }, - { "i16_neg_scalar", - "let x: i16 = -2i16;\n" - "fn main() i32 = { if (x != -2i16) { return 1; }; return 0; };\n", - 0 }, - { "i16_pos_scalar", - "let x: i16 = 1000i16;\n" - "fn main() i32 = { if (x != 1000i16) { return 1; }; return 0; };\n", - 0 }, - { "i32_neg_scalar", - "let x: i32 = -100i32;\n" - "fn main() i32 = { if (x != -100i32) { return 1; }; return 0; };\n", - 0 }, - { "i32_pos_scalar", - "let x: i32 = 100000i32;\n" - "fn main() i32 = { if (x != 100000i32) { return 1; }; return 0; };\n", - 0 }, - { "i64_neg_scalar", - "let x: i64 = -1000i64;\n" - "fn main() i32 = { if (x != -1000i64) { return 1; }; return 0; };\n", - 0 }, - { "i64_pos_scalar", - "let x: i64 = 1000000i64;\n" - "fn main() i32 = { if (x != 1000000i64) { return 1; }; return 0; };\n", - 0 }, - /* TK_TILDE over a literal — the other N_UN op fold_int_literal - * covers. ~0u64 == 0xFFFFFFFFFFFFFFFF == -1i64. */ - { "i64_tilde_scalar", - "let x: i64 = (~0u64): i64;\n" - "fn main() i32 = { if (x != -1i64) { return 1; }; return 0; };\n", - 0 }, - /* Array of i8: utf8 DFA shape. The negative entries silently - * zeroed pre-fix on wwstage; cstage emitted nothing at all and - * the link failed before this row could even build. */ - { "i8_arr_dfa", - "let dfa: [8]i8 = [0i8, -1i8, 1i8, 2i8, 0i8, 0i8, -1i8, -1i8];\n" - "fn main() i32 = {\n" - " if (dfa[0] != 0i8) { return 1; };\n" - " if (dfa[1] != -1i8) { return 2; };\n" - " if (dfa[2] != 1i8) { return 3; };\n" - " if (dfa[3] != 2i8) { return 4; };\n" - " if (dfa[6] != -1i8) { return 5; };\n" - " if (dfa[7] != -1i8) { return 6; };\n" - " return 0;\n" - "};\n", - 0 }, - { "i16_arr_mixed", - "let a: [4]i16 = [1i16, -2i16, 3i16, -4i16];\n" - "fn main() i32 = {\n" - " if (a[0] != 1i16) { return 1; };\n" - " if (a[1] != -2i16) { return 2; };\n" - " if (a[2] != 3i16) { return 3; };\n" - " if (a[3] != -4i16) { return 4; };\n" - " return 0;\n" - "};\n", - 0 }, - { "i32_arr_mixed", - "let a: [4]i32 = [10i32, -20i32, 30i32, -40i32];\n" - "fn main() i32 = {\n" - " if (a[0] != 10i32) { return 1; };\n" - " if (a[1] != -20i32) { return 2; };\n" - " if (a[2] != 30i32) { return 3; };\n" - " if (a[3] != -40i32) { return 4; };\n" - " return 0;\n" - "};\n", - 0 }, - { "i64_arr_mixed", - "let a: [4]i64 = [100i64, -200i64, 300i64, -400i64];\n" - "fn main() i32 = {\n" - " if (a[0] != 100i64) { return 1; };\n" - " if (a[1] != -200i64) { return 2; };\n" - " if (a[2] != 300i64) { return 3; };\n" - " if (a[3] != -400i64) { return 4; };\n" - " return 0;\n" - "};\n", - 0 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char src[128], tmpdir[64], outbin[128], rmcmd[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/sde_%d_d_%d", getpid(), i); - mkdir(tmpdir, 0755); - snprintf(src, sizeof src, "%s/sde_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/sde_%d_%d", tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) { runwait(rmcmd); return -1; } - fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - runwait(rmcmd); - return -1; - } - - int got = runwait(outbin); - - runwait(rmcmd); - return got; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[512]; - if (bin[0] != '/') { - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[640]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[640]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "signed_data_emit: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "signed_data_emit[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - if (fail) { - fprintf(stderr, - "signed_data_emit: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("signed_data_emit: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/946_const_slice_aggregate_run.c b/test/wcc/946_const_slice_aggregate_run.c deleted file mode 100644 index 62044b45..00000000 --- a/test/wcc/946_const_slice_aggregate_run.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * 946_const_slice_aggregate_run — #117/#119: const slice of (str,*fn) - * tuple rows + scalar &fn globals emit DATA (was both-stage LOUD at - * emit_slice_data / silent-no-DATA for the scalar &fn). - * - * #117: a `const [](str,*fn)` (fold-6's charclass_map shape) emitted NO - * DATA — emit_slice_data rode the scalar emit_array_lit_bytes backing and - * loud-stopped on the str/tuple/fn elements. Now the backing is k tuple - * rows (emit_tuple_row_*): each str element a 24B header + ptr→char DATAR, - * each &fn element an 8B slot + the BRAND-NEW &fn→DATAR reloc, at the 8B - * tuple-slot offsets (str@row+0/24B, *fn@row+24/8B = 32B/row, ken-confirmed - * layout). #119: a scalar `let p: *fn = &f` global wires the same reloc - * helper at the emit_lets 8B-scalar site (pre-#119: no DATA → undefined - * ref / garbage deref). - * - * POLARITY: align-BOTH — both stages were LOUD at base, no runtime - * reference. byte-id is BLIND (#263): the runtime READ-BACK is the net. - * The fn-reloc (the genuinely new machinery) is pinned at runtime with - * DISTINCT fns per row, so a wrong reloc is caught. - * - * READ-PATH NOTE (honest boundary): the indexed/ptr tuple-element FIELD - * reads off a const slice (`tbl[i].0`, `(&tbl[i]).0`) and the whole-element - * register-cursor read are pre-existing-broken (the #37/#58 index-cursor - * truncation + "unsupported field-read shape" — separate mechanisms, filed - * siblings; fold-6's compile arm also needs them). The one runtime - * observation available of the BACKING is the whole-element bind's word0 - * (loaded correctly even by the truncating cursor): so the fn-reloc rows - * put the *fn FIRST (word0) to read it back, and the consumer-ordering - * (str,*fn) rows pin `len(tbl)` (header) + cs==ww byte-id on the DATA. The - * str-element header+reloc reuses the proven emit_tuple_data machinery - * (941 t3_global_elem runtime-pinned) — verified here by byte-id. - * - * NNN<950, self-contained (/tmp, no imports) — rule-14's selfhost-sibling - * race does not apply (941/944/945 precedent). Every K_RUN row also pins - * cstage/wwstage asm byte-id. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa), cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -#define K_RUN 0 /* build+run both drivers, exit==want, + cs==ww byte-id */ -#define K_BUILDERR 1 /* build must FAIL with experr on BOTH drivers (rule 7) */ - -struct row { const char *label; const char *src; int want; - int kind; const char *experr; }; - -static int -errlog_has(const char *path, const char *needle) -{ - FILE *f = fopen(path, "rb"); - if (!f) return 0; - char buf[8192]; - size_t got = fread(buf, 1, sizeof buf - 1, f); - fclose(f); - buf[got] = '\0'; - return strstr(buf, needle) != NULL; -} - -static const struct row rows[] = { - /* #117 fn-reloc readback: *fn FIRST so the whole-element bind's - * word0 (the only backing word the truncating index-cursor loads - * correctly) IS the fn ptr. DISTINCT fns per row — a wrong reloc - * (or a swapped per-row offset) is caught by calling each back. */ - { "fnfirst_reloc", - "package main;\n" - "fn fa(c: rune) bool = { return c == 'a'; };\n" - "fn fz(c: rune) bool = { return c == 'z'; };\n" - "const tbl: [](*fn(c: rune) bool, str) = [(&fa, \"aa\"), (&fz, \"zzz\")];\n" - "export fn main() i32 = {\n" - " let e0 = tbl[0];\n" - " let e1 = tbl[1];\n" - " let f0 = e0.0;\n" - " let f1 = e1.0;\n" - " if (!(*f0)('a')) { return 1; };\n" - " if ((*f0)('z')) { return 2; };\n" - " if (!(*f1)('z')) { return 3; };\n" - " if ((*f1)('a')) { return 4; };\n" - " if (len(tbl) != 2) { return 5; };\n" - " return 0;\n" - "};\n", 0, K_RUN, NULL }, - /* fold-6's exact consumer ordering: (str,*fn). The str + fn element - * relocs at the consumer-ordering slot offsets are pinned by cs==ww - * byte-id on the DATA; len(tbl) confirms the slice header resolves. */ - { "consumer_str_fn", - "package main;\n" - "fn fa(c: rune) bool = { return c == 'a'; };\n" - "fn fz(c: rune) bool = { return c == 'z'; };\n" - "const tbl: [](str, *fn(c: rune) bool) = [(\"aa\", &fa), (\"zzz\", &fz)];\n" - "export fn main() i32 = {\n" - " if (len(tbl) != 2) { return 1; };\n" - " return 0;\n" - "};\n", 0, K_RUN, NULL }, - /* multi-row str backing: 3 rows of distinct str lengths — pins the - * per-row 32B stride of the str-header backing (byte-id) + header. */ - { "consumer_3row", - "package main;\n" - "fn fa(c: rune) bool = { return c == 'a'; };\n" - "const tbl: [](str, *fn(c: rune) bool) = " - "[(\"a\", &fa), (\"bb\", &fa), (\"ccc\", &fa)];\n" - "export fn main() i32 = {\n" - " if (len(tbl) != 3) { return 1; };\n" - " return 0;\n" - "};\n", 0, K_RUN, NULL }, - /* #117 broad-arm pin (rob): the TY_TUPLE arm also backs an ACCEPTED - * non-(str,*fn) scalar-tuple slice — (i64,str) with a TYPED i64 (a bare - * untyped int is ww-checker-rejected, #120). Scalar FIRST so the i64 - * reads back via the word0-correct whole-element cursor (#121 read-path: - * .1/word3 is truncated, same constraint as the fn-first row). DISTINCT - * values catch a wrong per-row stride/offset; len(t) pins the header; the - * str element rides the 32B backing (its DATAR + len pinned by cs==ww - * byte-id). Base f8be2ae has no TY_TUPLE arm → louds (broad arm is new). */ - { "scalar_tuple_slice", - "package main;\n" - "const t: [](i64, str) = [(10i64, \"a\"), (20i64, \"bb\")];\n" - "export fn main() i32 = {\n" - " let e0 = t[0];\n" - " let e1 = t[1];\n" - " let v0 = e0.0;\n" - " let v1 = e1.0;\n" - " if (v0 != 10) { return 1; };\n" - " if (v1 != 20) { return 2; };\n" - " if (len(t) != 2) { return 3; };\n" - " return 0;\n" - "};\n", 0, K_RUN, NULL }, - /* #119: scalar &fn module-globals — DISTINCT fns, each called back - * through the reloc (pre-#119: no DATA → undefined ref / garbage). */ - { "scalar_fnptr", - "package main;\n" - "fn fa(c: rune) bool = { return c == 'a'; };\n" - "fn fz(c: rune) bool = { return c == 'z'; };\n" - "let pf: *fn(c: rune) bool = &fa;\n" - "let pg: *fn(c: rune) bool = &fz;\n" - "export fn main() i32 = {\n" - " if (!(*pf)('a')) { return 1; };\n" - " if ((*pf)('z')) { return 2; };\n" - " if (!(*pg)('z')) { return 3; };\n" - " if ((*pg)('a')) { return 4; };\n" - " return 0;\n" - "};\n", 0, K_RUN, NULL }, - /* honest boundary (rule 7): a non-tuple aggregate element (here a - * bare []str) stays LOUD, symmetric both stages — #117 is NARROW to - * the (str,*fn) tuple form, not the full slice-of-aggregate family. */ - { "loud_slice_of_str", - "package main;\n" - "const xs: []str = [\"a\", \"b\"];\n" - "export fn main() i32 = { return len(xs): i32; };\n", 0, - K_BUILDERR, "slice-of-{str,slice,tagged}" }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[96], src[128], outbin[128], errf[128], rmcmd[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/csa_%d_d_%d", getpid(), i); - mkdir(tmpdir, 0755); - snprintf(src, sizeof src, "%s/csa_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/csa_%d_%d", tmpdir, getpid(), i); - snprintf(errf, sizeof errf, "%s/err", tmpdir); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) { runwait(rmcmd); return -1; } - fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s build -o %s %s >/dev/null 2>%s", - driver, outbin, src, errf); - int brc = runwait(cmd); - if (r->kind == K_BUILDERR) { - int ok = (brc != 0) - && (r->experr == NULL || errlog_has(errf, r->experr)); - if (!ok) - fprintf(stderr, "row[%s]: %s expected loud builderr " - "\"%s\" (brc=%d)\n", r->label, driver, - r->experr ? r->experr : "", brc); - runwait(rmcmd); - return ok ? 0 : 1; - } - if (brc != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - runwait(rmcmd); - return -1; - } - - int got = runwait(outbin); - - runwait(rmcmd); - if (got != r->want) { - fprintf(stderr, "row[%s]: %s exit %d, want %d\n", - r->label, driver, got, r->want); - return 1; - } - return 0; -} - -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char src[96], cs[96], ws[96], cmd[1024]; - snprintf(src, sizeof src, "/tmp/csa_asm_%d_%d.ww", getpid(), i); - snprintf(cs, sizeof cs, "/tmp/csa_asm_%d_%d_c.s", getpid(), i); - snprintf(ws, sizeof ws, "/tmp/csa_asm_%d_%d_w.s", getpid(), i); - - FILE *f = fopen(src, "wb"); - if (!f) return -1; - fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - unlink(src); - return -1; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - unlink(src); unlink(cs); - return -1; - } - int rc = slurp_eq(cs, ws); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - unlink(src); unlink(cs); unlink(ws); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2080]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[2120], wdrv[2120]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int i = 0; i < n; i++) { - total++; - if (run_driver(cdrv, &rows[i], i) != 0) fail++; - } - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (run_driver(wdrv, &rows[i], i) != 0) fail++; - } - for (int i = 0; i < n; i++) { - if (rows[i].kind == K_BUILDERR) - continue; - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) fail++; - } - } - - if (fail) { - fprintf(stderr, "const_slice_aggregate: %d/%d checks failed\n", - fail, total); - return 1; - } - printf("const_slice_aggregate: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/947_inferred_scalar_global_run.c b/test/wcc/947_inferred_scalar_global_run.c deleted file mode 100644 index 5e891a3d..00000000 --- a/test/wcc/947_inferred_scalar_global_run.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * 947_inferred_scalar_global_run — runtime + byte-id net for #66(b-i): an - * INFERRED int-literal module-global `let s = 42;` (no type annotation) was - * wwstage SILENT-WRONG. The checker stamps such a global with an - * N_TNAME("untyped_int") annotation; letemitsize / emitletdataw / the cgident - * global-read arm key on that annotation's name, which letscalarprim doesn't - * recognise — so the global was dropped from collectlets (no DATAW emitted) - * AND the read fell to the silent module-leaf (no `MOVQ main.s(SB)`), leaving - * `MOVSXD` to sign-extend a STALE AX. cstage instead type_default's the untyped - * int to the 8B machine word before emit, so it produced the correct - * `DATAW main.s` + `MOVQ main.s(SB), AX` (exit 42). cs≠ww, ww silent-wrong. - * - * Fix (wwstage only, cgen.ww defaultinferredlets, one choke-point before - * collectlets): rewrite the untyped_int annotation to the concrete machine - * word `int` — NOT i32 (that's the #108 truncation trap, opposite polarity) — - * so all three consumers resolve it as an 8B int global. The emitted DATAW + - * MOVQ then match cstage byte-for-byte (align ww UP). Guarded to N_INTLIT rhs - * ONLY: a const-EXPR inferred global (`let s = 7*6`) is #66(b-ii), a SEPARATE - * loud both-stage no-DATA gap, and must stay on its loud route. - * - * Each row carries (a) a cstage `ww build` + run asserting the exit code (R1 - * pre-fix: wwstage exit 136 / asm differs), and (b) a w6c vs w6c_ww `.s` cmp - * (rule-10 byte-id). R2 is the typed-annotation control (already cs==ww/42), - * locking no regression on the annotated path. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; int want_err; }; - -static const struct row rows[] = { - /* R1 — the #66(b-i) repro: inferred int-literal module-global, read - * back from main. Pre-fix wwstage emitted neither the DATAW nor the - * MOVQ → MOVSXD on stale AX → exit 136. Post-fix cs==ww, exit 42. */ - { "inferred", - "package main;\n" - "let s = 42;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 42, 0 }, - /* R2 — typed-annotation control: `let s: i64 = 42;` already worked - * (cs==ww, DATA emitted). Regression guard for the annotated path. */ - { "typed_ctrl", - "package main;\n" - "let s: i64 = 42;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 42, 0 }, - /* R3 — #134 neg leg: inferred unary-over-int-literal module-global - * `let s = -42;` (rhs N_UN(TK_MINUS) over N_INTLIT). Pre-fix wwstage - * emitted neither DATAW nor MOVQ (un-defaulted untyped_int annotation) - * → exit 168 (garbage). cstage folds the unary, emits DATAW + load - * (exit 214 = -42 low-8). Post-fix defaultinferredlets peels the unary - * and defaults to `int`, so cs==ww and both run -42 (exit 214). */ - { "neg_inferred", - "package main;\n" - "let s = -42;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 214, 0 }, - /* R4 — #134 neg typed control: `let s: int = -42;` (TYPED). Already - * cs==ww today (concrete annotation → letscalarprim fires). Locks the - * construction proof: R3's emitted .s is byte-identical to this typed - * control (the inferred decl IS the typed decl after defaulting). */ - { "neg_typed_ctrl", - "package main;\n" - "let s: int = -42;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 214, 0 }, - /* #133 — const-EXPR scalar module-global. The let pass-2 arm now - * const-folds an N_BIN / unary-over-N_BIN / def-ref rhs and stamps it - * to an N_INTLIT (mirroring the N_DEF arm), so cgen's literal-only - * DATA emitter lays the row in BOTH stages. Pre-fix: cstage LINK-FAILed - * (`undefined main.s` — read emitted, no DATA word) and wwstage was - * SILENT-WRONG (no DATA, no load, MOVSXD on stale AX → exit 152). */ - - /* C1 — inferred const-expr `let s = 7*6;` → 42 (N_BIN rhs). */ - { "const_inferred", - "package main;\n" - "let s = 7 * 6;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 42, 0 }, - /* C2 — typed const-expr (b-ii) `let s: i64 = 7*6;` → 42. Pre-fix this - * LINK-FAILed BOTH stages (annotation-independent no-DATA gap); the - * same stamp supplies the foldable value. */ - { "const_typed", - "package main;\n" - "let s: i64 = 7 * 6;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 42, 0 }, - /* C3 — def-ref through let `def K: int = 6; let s = K*7;` → 42. Proves - * eval_def_const's N_IDENT def-resolution reaches through the new let - * hook. */ - { "const_defref", - "package main;\n" - "def K: int = 6;\n" - "let s = K * 7;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 42, 0 }, - /* C4 — unary-over-binop `let s = -(2*3);` → -6 (low byte 250). Proves - * the N_UN ∘ N_BIN composition folds through eval_def_const. */ - { "const_unary_binop", - "package main;\n" - "let s = -(2 * 3);\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 250, 0 }, - /* C5 — loud guard: a div-by-zero const-expr module-global init stays a - * compile ERROR in BOTH stages, NOT silently zeroed. Asserts the - * eval_def_const error path is preserved through the let hook. */ - { "const_divzero", - "package main;\n" - "let s = 7 / 0;\n" - "export fn main() i32 = {\n" - " return s: i32;\n" - "};\n", 0, 1 }, - { NULL, NULL, 0, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "infglobal: w6c_ww missing — cannot run the " - "cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwisg_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char src[128], rmcmd[160]; - snprintf(src, sizeof src, "%s/wwisg_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - FILE *f = fopen(src, "wb"); - if (f == NULL) { runwait(rmcmd); fail++; continue; } - fputs(rows[i].src, f); - fclose(f); - - char cs_s[128], ws_s[128]; - snprintf(cs_s, sizeof cs_s, "%s/wwisg_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwisg_%d_%d_ww.s", - tmpdir, getpid(), i); - - /* Loud-guard rows (#133 R5): both stages must REJECT the - * source at compile (e.g. a div-by-zero const-expr init). No - * value to run / no byte-id — only the error-path preservation - * matters. Assert raw w6c AND w6c_ww both emit non-zero. */ - if (rows[i].want_err) { - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) == 0) { - fprintf(stderr, "row[%s]: w6c accepted a source " - "that must be rejected (loud guard)\n", - rows[i].label); - fail++; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) == 0) { - fprintf(stderr, "row[%s]: w6c_ww accepted a " - "source that must be rejected (loud " - "guard)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - continue; - } - - /* (a) cstage build + run. */ - char outbin[128]; - snprintf(outbin, sizeof outbin, "%s/wwisg_%d_%d", - tmpdir, getpid(), i); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - /* (b) cs==ww byte-id gate. */ - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d inferred-scalar-global tests failed\n", - fail, n); - return 1; - } - printf("infglobal: %d/%d ok (cstage run + cs==ww byte-id)\n", n, n); - return 0; -} diff --git a/test/wcc/949_structlit_arrfield_run.c b/test/wcc/949_structlit_arrfield_run.c deleted file mode 100644 index 90021385..00000000 --- a/test/wcc/949_structlit_arrfield_run.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * 949_structlit_arrfield_run — runtime + byte-id net for #249: struct - * array-field init/read silent miscompiles. Two distinct roots, both - * gate-blind (cs==ww broken identically pre-fix): - * - * BUG B — reading an array field of a module-GLOBAL struct value - * (`G.arr[i]`). The N_INDEX fallback's cg_dotbase_addr / dotbaseaddr - * helper (the #135 sibling) had no module-global-struct base arm: - * cstage emitted `LEAQ (BP)` (read the stack → 0), wwstage fell to - * cgexpr(N_DOT) which loaded the field VALUE as a pointer → SEGFAULT. - * The .data was already correct (emit_struct_lit_bytes #129 A.3); only - * the READ base address was wrong. Fix: a global value-struct base - * emits `LEAQ name(SB) (+ ADDQ field_off)`, mirroring the scalar - * global-field read (cgen.c:7532). const globals are def_isstructdef. - * - * BUG A — initializing an array field from a struct literal - * (`e{ arr = [..] }`) as a local. cg_structlit_fill / cgstructlitfill - * had no TY_ARRAY field arm; the array field fell to the generic - * scalar tail (cgexpr the N_ARRLIT → AX, store one sized word) which - * silently DROPPED every element. Fix: a TY_ARRAY field arm element- - * wise stores the N_ARRLIT at base+field_off+i*esz, reusing the proven - * N_LET array-init shape. The GLOBAL literal-init path is unaffected - * (it goes through emit_struct_lit_bytes, already correct). - * - * cstage `ww build` + run for exit code; w6c vs w6c_ww `.s` cmp for the - * rule-10 byte-id gate. u8 element rows only (a `[N]u8` read cast to i32 - * is byte-id; wider widths hit the i32-return MOVL/MOVSXD cs/ww - * divergence — see 949_dotbase_arr_run's deferral note). - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - /* BUG B: read [4]u8 field of a module-global `let` struct at idx 0 - * (field_off 0). Pre-fix cstage→0, wwstage→SEGFAULT. encmap[0]='A' - * (65). */ - { "global_let_read", - "package main;\n" - "type e = struct { encmap: [4]u8 };\n" - "let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n" - "export fn main() i32 = { return g.encmap[0]: i32; };\n", 65 }, - /* BUG B: read [4]u8 field of a module-global `def` (const) struct - * at idx 2, with a non-zero field offset (a [3]u8 pad ahead of it) — - * exercises def_isstructdef + the ADDQ $field_off arm. The base64 - * `const std_encoding` shape. pad ahead, encmap[2]='C' (67). */ - { "global_def_read_off", - "package main;\n" - "type e = struct { pad: [3]u8, encmap: [4]u8 };\n" - "def G: e = e { pad = [9u8, 9u8, 9u8]," - " encmap = [65u8, 66u8, 67u8, 68u8] };\n" - "export fn main() i32 = { return G.encmap[2]: i32; };\n", 67 }, - /* BUG A: local struct-literal init of a [4]u8 field, read idx 0. - * Pre-fix the array field fell to the generic scalar tail (cgexpr - * the N_ARRLIT → AX, store one word) and silently dropped every - * element → 0. encmap[0]='A' (65). */ - { "local_lit_read0", - "package main;\n" - "type e = struct { encmap: [4]u8 };\n" - "export fn main() i32 = {\n" - " let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n" - " return g.encmap[0]: i32;\n" - "};\n", 65 }, - /* BUG A: same init, read idx 3 — asserts the LAST element landed - * (the pre-fix single-word store would never reach it). 'D' (68). */ - { "local_lit_read3", - "package main;\n" - "type e = struct { encmap: [4]u8 };\n" - "export fn main() i32 = {\n" - " let g: e = e { encmap = [65u8, 66u8, 67u8, 68u8] };\n" - " return g.encmap[3]: i32;\n" - "};\n", 68 }, - /* NB: a trailing `...` repeat in a struct-LITERAL array field - * (`encmap = [7u8...]`) is rejected by the CHECKER ("[1]u8 not - * assignable to [4]u8") — the field type-check doesn't apply the - * repeat-length inference that bare `let a: [N]T = [v...]` gets. - * The cg_structlit_fill array arm mirrors the N_LET `...` handling - * for symmetry, but that path is checker-unreachable today (separate - * checker gap, not #249). No row exercises it. */ - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "structlit_arrfield: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwsaf_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char src[128], outbin[128], cs_s[160], ws_s[160], rmcmd[160]; - snprintf(src, sizeof src, "%s/wwsaf_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwsaf_%d_%d", - tmpdir, getpid(), i); - snprintf(cs_s, sizeof cs_s, "%s/wwsaf_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwsaf_%d_%d_ww.s", - tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; runwait(rmcmd); continue; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d structlit-arrfield tests failed\n", - fail, n); - return 1; - } - printf("structlit_arrfield: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/949_valstruct_subsize_run.c b/test/wcc/949_valstruct_subsize_run.c deleted file mode 100644 index 23e0d884..00000000 --- a/test/wcc/949_valstruct_subsize_run.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 949_valstruct_subsize_run — runtime + byte-id net for #254: a sub-8 - * (non-8-multiple) nested value-struct must size its zero-init extent - * from the type table's natural ABI size (cstage lu->size), NOT the - * slot-padded register-struct width. - * - * Root: wwstage conflated SLOT-size (round-to-8, for frame layout) with - * ABI-size (true). A nested value-struct field was sized via fieldsize() - * (cgenutil.ww TY_STRUCT -> ti.slotsize = 8), poisoning structabisize + - * registerstruct si.totsize to 8 for a struct whose true ABI size is 4. - * Two emission sites then over-sized: - * D1 (local): cglet zsz = structabisize = 8 hit the `zsz == 8` zero - * arm (cgenstmt.ww #213) -> a stray `MOVQ $0, off(BP)` that cstage - * (ABI 4 is sub-8 -> left uninit per the shared no-rhs policy) - * never emits. - * D2 (global): emitletdataw struct arm wrote si.totsize = 8 zero bytes - * of DATAW; cstage cg_let_emit_size returns u->size = 4. - * Both were SILENT cs!=ww divergences (gate-blind: a standalone wwstage - * is self-consistent; only the cs==ww .s cmp catches it). - * - * Fix (rule-13 SSoT): both sites source the extent from tinfo.size - * (peeling TY_NAMED), the same value cstage reads. fieldsize / - * registerstruct / frame slot-padding stay UNTOUCHED — moving the fix - * into the size helpers would shift nested-struct field offsets and - * re-diverge other byte-id. - * - * Rows cover the whole sub-8 class (ABI size 1/2/4) in both the local - * (D1) and global (D2) emission contexts, plus a >8 NEGATIVE control - * proving the fix didn't disable legitimate multi-word zero-init. Each - * row: cstage `ww build` + run for the exit code (correctness) AND - * w6c vs w6c_ww `.s` cmp for rule-10 byte-id (the silent-divergence net). - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - /* D1 local, ABI size 4 (inner {[4]u8}). Pre-fix wwstage emitted a - * stray MOVQ $0 cstage didn't -> .s differ. Write+read a byte so - * the exit is deterministic (sub-8 is left uninit by BOTH stages, - * matching cstage's no-rhs policy). */ - { "d1_local_4", - "package main;\n" - "type inner = struct { m: [4]u8 };\n" - "type outv = struct { i: inner };\n" - "export fn main() i32 = {\n" - " let o: outv;\n" - " o.i.m[0] = 66u8;\n" - " return o.i.m[0]: i32;\n" - "};\n", 66 }, - /* D1 local, ABI size 2 ([2]u8). */ - { "d1_local_2", - "package main;\n" - "type inner = struct { m: [2]u8 };\n" - "type outv = struct { i: inner };\n" - "export fn main() i32 = {\n" - " let o: outv;\n" - " o.i.m[1] = 55u8;\n" - " return o.i.m[1]: i32;\n" - "};\n", 55 }, - /* D1 local, ABI size 1 ([1]u8) — the tightest sub-8 case. */ - { "d1_local_1", - "package main;\n" - "type inner = struct { m: [1]u8 };\n" - "type outv = struct { i: inner };\n" - "export fn main() i32 = {\n" - " let o: outv;\n" - " o.i.m[0] = 44u8;\n" - " return o.i.m[0]: i32;\n" - "};\n", 44 }, - /* D2 global, ABI size 4. Pre-fix wwstage emitted DATAW of 8 zero - * bytes vs cstage's 4 -> .s differ. */ - { "d2_global_4", - "package main;\n" - "type inner = struct { m: [4]u8 };\n" - "type outv = struct { i: inner };\n" - "let g: outv;\n" - "export fn main() i32 = {\n" - " g.i.m[0] = 66u8;\n" - " return g.i.m[0]: i32;\n" - "};\n", 66 }, - /* D2 global, ABI size 2. */ - { "d2_global_2", - "package main;\n" - "type inner = struct { m: [2]u8 };\n" - "type outv = struct { i: inner };\n" - "let g: outv;\n" - "export fn main() i32 = {\n" - " g.i.m[1] = 55u8;\n" - " return g.i.m[1]: i32;\n" - "};\n", 55 }, - /* D2 global, ABI size 1. */ - { "d2_global_1", - "package main;\n" - "type inner = struct { m: [1]u8 };\n" - "type outv = struct { i: inner };\n" - "let g: outv;\n" - "export fn main() i32 = {\n" - " g.i.m[0] = 44u8;\n" - " return g.i.m[0]: i32;\n" - "};\n", 44 }, - /* NEGATIVE control — a >8 (multi-word) value-struct still zero- - * inits. Read an UNWRITTEN byte: a working multi-word zero-init - * fill makes it 0. If the fix had wrongly suppressed the >8 zero - * arm, this would read stack garbage (and byte-id would diff - * against the still-zeroing cstage). Local + global both proven. */ - { "ctl_local_16", - "package main;\n" - "type inner = struct { m: [16]u8 };\n" - "type outv = struct { i: inner };\n" - "export fn main() i32 = {\n" - " let o: outv;\n" - " return o.i.m[7]: i32;\n" - "};\n", 0 }, - { "ctl_global_16", - "package main;\n" - "type inner = struct { m: [16]u8 };\n" - "type outv = struct { i: inner };\n" - "let g: outv;\n" - "export fn main() i32 = {\n" - " return g.i.m[7]: i32;\n" - "};\n", 0 }, - { NULL, NULL, 0 } -}; - -static int -slurp_eq(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"); - FILE *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return -1; } - int rc = 0; - for (;;) { - int ca = fgetc(fa); - int cb = fgetc(fb); - if (ca != cb) { rc = -1; break; } - if (ca == EOF) break; - } - fclose(fa); fclose(fb); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[1100], w6c_ww[1100]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - if (access(w6c_ww, X_OK) != 0) { - fprintf(stderr, "valstruct_subsize: w6c_ww missing — cannot run " - "the cs==ww byte-id gate (the whole point of this test)\n"); - return 1; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wwvss_%d_d_%d", - getpid(), i); - mkdir(tmpdir, 0755); - - char rmcmd[160]; - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - char src[128], outbin[128], cs_s[128], ws_s[128]; - snprintf(src, sizeof src, "%s/wwvss_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wwvss_%d_%d", - tmpdir, getpid(), i); - snprintf(cs_s, sizeof cs_s, "%s/wwvss_%d_%d_cs.s", - tmpdir, getpid(), i); - snprintf(ws_s, sizeof ws_s, "%s/wwvss_%d_%d_ww.s", - tmpdir, getpid(), i); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; runwait(rmcmd); continue; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -o %s %s", - bin, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cstage build failed\n", - rows[i].label); - fail++; - runwait(rmcmd); - continue; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: cstage exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c, cs_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c failed\n", rows[i].label); - fail++; runwait(rmcmd); continue; - } - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", - w6c_ww, ws_s, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww failed\n", - rows[i].label); - fail++; runwait(rmcmd); continue; - } - if (slurp_eq(cs_s, ws_s) != 0) { - fprintf(stderr, - "row[%s]: cstage/wwstage .s DIFFER (rule-10 " - "byte-id violation)\n", rows[i].label); - fail++; - } - runwait(rmcmd); - } - - if (fail) { - fprintf(stderr, "%d/%d valstruct-subsize tests failed\n", - fail, n); - return 1; - } - printf("valstruct_subsize: %d/%d ok (cstage run + cs==ww byte-id)\n", - n, n); - return 0; -} diff --git a/test/wcc/989_nestfield_run.c b/test/wcc/989_nestfield_run.c deleted file mode 100644 index 1a949116..00000000 --- a/test/wcc/989_nestfield_run.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 989_nestfield_run — #44/#55 struct-layout SSoT: a struct with a nested - * sub-8 composite field plus a successor must address EVERY field at the - * checker's natural offset, identically on the write (construction) and - * read (field-access) paths. - * - * THE BUG (cat-A silent miscompile, gate-blind): wwstage had TWO struct- - * layout sources. `registerstruct` (selfhost/cmd/wcc/cgenutil.ww) rebuilt - * each field's `fi.foff` via `fieldsize` — SLOT-padded, so a nested - * `inner{x:u8,y:u8}` (size 2, slotsize 8) pushed every successor to an 8B - * boundary. The READ path (cgplaceaddr/dotbaseaddr) reads the checker's - * tfield.offset — NATURAL (inner align 1 → p at offset 1, z packed right - * after). So ww WROTE p/z at the slot-padded offset and READ them at the - * natural offset → garbage. The shape (nested sub-8 composite + a field - * after it) is corpus-ABSENT — ww uses both sources on its OWN structs, so - * if such a struct existed the bootstrap would mis-address itself and - * 400-green would be impossible; the gate cannot see it, this repro is the - * proof. cstage has no structinfo — it reads tfield directly, self- - * consistently natural (cmd/w6c/cgen.c). THE FIX: make ww's `fi.foff` a - * VIEW of tfield.offset (lock-step walk tstruct.list + ti.fields), so the - * second source collapses onto cstage's natural one (cs==ww preserved). - * - * Each program self-checks every field (write 1/2/3/.., read back, return - * the 1-based index of the first mismatch, 0 on all-correct). Pre-fix ww - * constructs at slot offsets and reads at natural → a non-zero return on - * the first composite-or-successor field, so cs(=0) != ww(!=0) AND ww != - * want. Both stages build+run (rule-10); the want is the absolute 0. - * - * This is a RUNTIME cs==ww check (both stages exit 0): it proves field - * offsets are natural and instruction-correct RELATIVE TO the struct base. - * It deliberately does NOT gate the absolute .s frame, which is still - * cs!=ww on this shape via a SEPARATE pre-existing producer — wwstage - * reserves the struct LOCAL's stack slot at slot-padded slotsize, cstage - * at natural (task #75). The frame-absolute teeth belong to #75's fix. - */ -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { - const char *label; - const char *src; - int want_exit; /* >= 0: pin the absolute value; -1: cs==ww only */ -}; - -static const struct row rows[] = { - /* (1) nested2 — outer2{a:u8, p:inner}: the core divergence. Natural - * p at offset 1; pre-fix slot-padded p at offset 8. Construction - * (write) vs field-access (read) disagree → o.p.x / o.p.y read wrong. - * Returns the 1-based index of the first mismatched field, 0 on ok. */ - { "nested2", - "package main;\n" - "type inner = struct { x: u8, y: u8 };\n" - "type outer2 = struct { a: u8, p: inner };\n" - "export fn main() int = {\n" - " let o: outer2 = outer2 { a = 5, p = inner { x = 6, y = 7 } };\n" - " if (o.a: int != 5) { return 1; };\n" - " if (o.p.x: int != 6) { return 2; };\n" - " if (o.p.y: int != 7) { return 3; };\n" - " return 0;\n" - "};\n", - 0 }, - - /* (2) nested3 — outer{a:u8, p:inner, z:i64}: z proves post-composite - * accumulation stays natural. Pre-fix z sat at the slot-padded offset - * past the 8B-padded inner; the natural read undershoots. The wide z - * value (0x44444444) is verified inside the program (the exit channel - * is 8-bit), so a truncated/mis-addressed z fails the in-program cmp. */ - { "nested3", - "package main;\n" - "type inner = struct { x: u8, y: u8 };\n" - "type outer = struct { a: u8, p: inner, z: i64 };\n" - "export fn main() int = {\n" - " let o: outer = outer { a = 1, p = inner { x = 2, y = 3 }, z = 0x44444444i64 };\n" - " if (o.a: int != 1) { return 1; };\n" - " if (o.p.x: int != 2) { return 2; };\n" - " if (o.p.y: int != 3) { return 3; };\n" - " if (o.z != 0x44444444i64) { return 4; };\n" - " return 0;\n" - "};\n", - 0 }, - - /* (3) control — flat struct {a:u8, b:i64}, no sub-8 composite field. - * Natural and slot-padded layouts coincide (b lands at 8 either way); - * proves the fix leaves the common case unmoved. */ - { "flat_ctl", - "package main;\n" - "type flat = struct { a: u8, b: i64 };\n" - "export fn main() int = {\n" - " let o: flat = flat { a = 9, b = 0x33333333i64 };\n" - " if (o.a: int != 9) { return 1; };\n" - " if (o.b != 0x33333333i64) { return 2; };\n" - " return 0;\n" - "};\n", - 0 }, -}; - -/* run_build — build+run `src` via `driver`; returns the binary's exit - * code, or -1 on a build failure. */ -static int -run_build(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], rmcmd[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/nestfld_%d_d_%d", getpid(), i); - mkdir(tmpdir, 0755); - snprintf(src, sizeof src, "%s/nestfld_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/nestfld_%d_%d", tmpdir, getpid(), i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) { runwait(rmcmd); return -2; } - fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - int brc = runwait(cmd); - - int got = -1; - if (brc == 0) got = runwait(outbin); - - runwait(rmcmd); - return brc == 0 ? got : -1; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024], wdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - int have_ww = (access(wdrv, X_OK) == 0); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int i = 0; i < n; i++) { - total++; - int gc = run_build(cdrv, &rows[i], i); - /* cstage must build+run */ - if (gc < 0) { - fprintf(stderr, "nestfield_run[cstage][%s]: build/run " - "failed (got %d)\n", rows[i].label, gc); - fail++; - continue; - } - if (rows[i].want_exit >= 0 && gc != rows[i].want_exit) { - fprintf(stderr, "nestfield_run[cstage][%s]: exit=%d " - "want=%d (field mismatch)\n", - rows[i].label, gc, rows[i].want_exit); - fail++; - } - if (!have_ww) { - fprintf(stderr, "nestfield_run: skip wwstage (no %s)\n", - wdrv); - continue; - } - int gw = run_build(wdrv, &rows[i], i); - /* rule-10: the cat-A invariant is cs == ww */ - if (gw != gc) { - fprintf(stderr, "nestfield_run[%s]: cs=%d != ww=%d " - "(struct field-offset divergence — #44/#55)\n", - rows[i].label, gc, gw); - fail++; - } - if (rows[i].want_exit >= 0 && gw != rows[i].want_exit) { - fprintf(stderr, "nestfield_run[wwstage][%s]: exit=%d " - "want=%d (field mismatch)\n", - rows[i].label, gw, rows[i].want_exit); - fail++; - } - } - - if (fail) { - fprintf(stderr, "nestfield_run: %d/%d checks failed\n", - fail, total); - return 1; - } - printf("nestfield_run: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/989_structlocal_frame.c b/test/wcc/989_structlocal_frame.c index 3c195c11..5f46db69 100644 --- a/test/wcc/989_structlocal_frame.c +++ b/test/wcc/989_structlocal_frame.c @@ -25,9 +25,9 @@ * 683 asm_byte_identical pattern). Byte-identity subsumes the frame: * pre-fix nested3 differs at `TEXT main,$32` vs `$16`, `SUBQ $32` vs * `$16`, and every `-24(BP)` vs `-16(BP)`; post-fix the two .s are - * byte-for-byte equal. The sibling 989_nestfield_run is the RUNTIME - * exit-code proof (deliberately NOT frame-gated — see its header); this - * file is the .s/frame-absolute one #75 owes. + * byte-for-byte equal. The sibling RUNTIME exit-code proof migrated to + * test/lang/nestfield_test.ww (@test field-read rows, cs==ww via the T2 + * byte-id gate); this file is the .s/frame-absolute one #75 owes. */ #include #include diff --git a/test/wcc/data/arr_nested_ellipsis_reject/case.ww b/test/wcc/data/arr_nested_ellipsis_reject/case.ww new file mode 100644 index 00000000..d8447e1a --- /dev/null +++ b/test/wcc/data/arr_nested_ellipsis_reject/case.ww @@ -0,0 +1,7 @@ +//ww:error "repeat with nested-array elements" +// #156/rule-7 carrier: a `...` repeat marker with a nested-array element must +// REJECT on both stages (no consumer needs it; powers_of_ten is fully +// enumerated). From test/wcc/919_array_static_init_run.c nested_ellipsis_reject. +package main; +let A: [4][2]u64 = [[1u64, 2u64]...]; +export fn main() i32 = { return 0; }; diff --git a/test/wcc/data/const_divzero_reject/case.ww b/test/wcc/data/const_divzero_reject/case.ww new file mode 100644 index 00000000..6b3e3ceb --- /dev/null +++ b/test/wcc/data/const_divzero_reject/case.ww @@ -0,0 +1,8 @@ +//ww:error "division by zero" +// #133/rule-7 carrier: a div-by-zero const-expr module-global init stays a +// COMPILE error in BOTH stages, NOT silently zeroed (the eval_def_const error +// path survives the let-hook). From test/wcc/947_inferred_scalar_global_run.c +// const_divzero. +package main; +let s = 7 / 0; +export fn main() i32 = { return s: i32; }; diff --git a/test/wcc/data/slice_of_str_reject/case.ww b/test/wcc/data/slice_of_str_reject/case.ww new file mode 100644 index 00000000..5821ecdc --- /dev/null +++ b/test/wcc/data/slice_of_str_reject/case.ww @@ -0,0 +1,8 @@ +//ww:error "slice-of-{str,slice,tagged}" +// #117/rule-7 carrier: a non-tuple aggregate element (a bare []str) in a +// const-slice static-init stays a LOUD reject in BOTH stages — #117 is narrow +// to the (str,*fn) tuple form. From test/wcc/946_const_slice_aggregate_run.c +// loud_slice_of_str. +package main; +const xs: []str = ["a", "b"]; +export fn main() i32 = { return len(xs): i32; };