From 00df260a521e90bd6f8bb0032edd3ff2ae32448e Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Tue, 6 Oct 2026 18:29:45 +0100 Subject: [PATCH] check-x86-run.sh: expectations after #412 and #497 The -mm=none frame allocator check looked for aligned_alloc(i32, i32). Since #412 ProcessHeapPass renames it on Windows, under every model but gc, to the process-heap allocator __tslang_heap_aligned_alloc, which keeps the 32-bit size_t signature AsyncTargetWidthPass gave it. The check now requires that name with both parameters i32. await_order expected "after await" before "in g", recorded when an await of a void async function did not wait. Since #497 main waits on g()'s token, so "in g" always prints first (300/300 runs, x86 and x64). Co-Authored-By: Claude Opus 5.5 --- tslang/test/check-x86-run.sh | 22 ++++++++++++---------- tslang/test/x86/await_order.ts | 11 +++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tslang/test/check-x86-run.sh b/tslang/test/check-x86-run.sh index 2a07e76a0..45844354c 100755 --- a/tslang/test/check-x86-run.sh +++ b/tslang/test/check-x86-run.sh @@ -86,9 +86,9 @@ expected() { # sum(0..999) = 499500; sum of lengths of "round of 200" for r in 0..199 # = 200 * 13 + (10 * 1 + 90 * 2 + 100 * 3) = 3090 gc_stress) printf '499500\n3090\n' ;; - # Confirmed at x64 (docs/superpowers/plans/2026-09-22-32-bit-phase-4b-async.md): a - # non-async main resumes past `await g()` before g()'s body runs on the async runtime. - await_order) printf 'start\nafter await\nin g\n' ;; + # main waits on g()'s token, so g()'s body has run before main goes on (since #497; before + # it an await of a void async function did not wait, and the order was a race) + await_order) printf 'start\nin g\nafter await\n' ;; esac } @@ -211,6 +211,8 @@ done # width, so at i686 the callee reads (alignment, size=0) and the frame overflows its block. # The repair pass (task 2/3) must retype the declaration to the pointer width. When a collector # is linked in, GCPass rewrites each call to GC_malloc_uncollectable(size), which keeps that width. +# Under every other model on Windows, ProcessHeapPass (#412) renames aligned_alloc to the +# process-heap allocator __tslang_heap_aligned_alloc(alignment, size), which keeps it as well. emit_await_order_ir() { local mm="$1" local out="$work/await_order.$mm.ll" err status @@ -225,9 +227,9 @@ emit_await_order_ir() { printf '%s' "$out" } -# Only the parameter TYPES are checked: once aligned_alloc has the target's size_t signature, -# LLVM recognizes it as the C library function and adds attributes to the declaration, e.g. -# `declare noalias noundef ptr @aligned_alloc(i32 allocalign noundef, i32 noundef)`. +# Only the parameter TYPES are checked: an allocator's declaration may carry parameter attributes, +# e.g. `declare noalias noundef ptr @aligned_alloc(i32 allocalign noundef, i32 noundef)` once LLVM +# recognizes the C library function by its size_t signature. declared_with_i32_params() { grep -Eq "^declare .*ptr @$1\(i32( [^,]*)?, i32( [^)]*)?\)" "$2" } @@ -247,11 +249,11 @@ if out="$(emit_await_order_ir gc)"; then fi if out="$(emit_await_order_ir none)"; then - if declared_with_i32_params aligned_alloc "$out"; then - echo "ok x86 IR -mm=none: frame allocator is aligned_alloc(i32, i32)" + if declared_with_i32_params __tslang_heap_aligned_alloc "$out"; then + echo "ok x86 IR -mm=none: frame allocator is __tslang_heap_aligned_alloc(i32, i32)" else - echo "FAIL x86 IR -mm=none: frame allocator is aligned_alloc(i32, i32)" - grep -m1 -E '@aligned_alloc\(' "$out" | sed 's/^/ got: /' + echo "FAIL x86 IR -mm=none: frame allocator is __tslang_heap_aligned_alloc(i32, i32)" + grep -m1 -E '@(__tslang_heap_)?aligned_alloc\(' "$out" | sed 's/^/ got: /' fail=1 fi fi diff --git a/tslang/test/x86/await_order.ts b/tslang/test/x86/await_order.ts index 8c3141ccf..82429831f 100644 --- a/tslang/test/x86/await_order.ts +++ b/tslang/test/x86/await_order.ts @@ -1,8 +1,7 @@ -// Minimal repro for 32-bit async: a non-async main awaits an async function. Confirmed at x64 -// (docs/superpowers/plans/2026-09-22-32-bit-phase-4b-async.md): "after await" prints before -// "in g" because g() keeps running on the async runtime after main resumes past the await. -// check-x86-run.sh builds this for 32-bit Windows and compares its output exactly. That order is -// not normal TypeScript await semantics; a future fix to await in a non-async function is expected -// to change it, and this expected output with it. +// Minimal repro for 32-bit async: a non-async main awaits an async function. check-x86-run.sh +// builds this for 32-bit Windows and compares its output exactly: "in g" prints before +// "after await", because main waits on g()'s token before it goes on. Until #497 an await of a +// void async function did not wait, so g() ran on the async runtime after main had resumed (or +// not at all, if the program ended first) and the order was a race. async function g() { print("in g"); } function main() { print("start"); await g(); print("after await"); }