typed/llvmir: compare observed results with the Rust backend (Phase 5)
ober
c500a1d1ff8bbf3aedfd285ffd09be99e01b196e
--- a/Makefile +++ b/Makefile @@ -44,12 +44,15 @@ TYPED_LLVMIR_SOURCES ?= tests/fixtures/typed/llvmir-basic.ss tests/fixtures/type TYPED_LLVMIR_DIR ?= build/typed/llvmir TYPED_LLVMIR_SMOKE_MODULE ?= sample_typed_llvmir_smoke TYPED_LLVMIR_SMOKE_EXPECT ?= 42 +TYPED_LLVMIR_PARITY_DIR ?= build/typed/llvmir-parity +TYPED_LLVMIR_PARITY_SOURCE ?= tests/fixtures/typed/llvmir-smoke.ss +TYPED_LLVMIR_PARITY_FN ?= sample_typed_llvmir_smoke::main # LLVM tool discovery for the typed LLVM IR backend: PATH first, then the # Homebrew LLVM keg (Apple Silicon, then Intel). Empty when no LLVM exists. LLVM_BIN ?= $(shell if command -v llvm-as >/dev/null 2>&1; then dirname "$$(command -v llvm-as)"; elif [ -x /opt/homebrew/opt/llvm/bin/llvm-as ]; then echo /opt/homebrew/opt/llvm/bin; elif [ -x /usr/local/opt/llvm/bin/llvm-as ]; then echo /usr/local/opt/llvm/bin; fi) TYPED_WRAPPER_DIR ?= build/typed/jerboa -.PHONY: help chez chez-cross build binary binary-typed binary-typed-smoke binary-cross native-cross pure-audit typecheck typed-rust typed-llvmir typed-llvmir-check typed-llvmir-smoke typed-wrappers typed-build typed-wrapper-smoke typed-split-tree-smoke typed-test typed-clean test test-reader test-core test-runtime test-stdlib test-ffi test-modules test-expanded test-contract test-ergo test-limits-primitives test-typed-core test-typed-parser test-typed-checker test-typed-rust test-typed-llvmir test-typed-wrappers test-pure-audit test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-security-profile test-native test-gaps native clean-native audit-native clean security security-production security-profile fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all check-docs check-docs-strict docker-build docker-push +.PHONY: help chez chez-cross build binary binary-typed binary-typed-smoke binary-cross native-cross pure-audit typecheck typed-rust typed-llvmir typed-llvmir-check typed-llvmir-smoke typed-llvmir-parity typed-wrappers typed-build typed-wrapper-smoke typed-split-tree-smoke typed-test typed-clean test test-reader test-core test-runtime test-stdlib test-ffi test-modules test-expanded test-contract test-ergo test-limits-primitives test-typed-core test-typed-parser test-typed-checker test-typed-rust test-typed-llvmir test-typed-wrappers test-pure-audit test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-security-profile test-native test-gaps native clean-native audit-native clean security security-production security-profile fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all check-docs check-docs-strict docker-build docker-push help: @echo "Usage: make <target>" @@ -86,6 +89,7 @@ help: @echo " typed-llvmir Generate textual LLVM IR (.ll) from Typed Jerboa" @echo " typed-llvmir-check Verify generated .ll with llvm-as + opt" @echo " typed-llvmir-smoke Build and run an LLVM-backend smoke executable" + @echo " typed-llvmir-parity Compare LLVM and Rust backend observed results" @echo " typed-wrappers Generate Jerboa wrappers for typed Rust exports" @echo " typed-build Generate Rust crate sources/wrappers and run cargo build" @echo " typed-wrapper-smoke Build and call generated typed wrappers through FFI" @@ -838,6 +842,36 @@ typed-llvmir-smoke: typed-llvmir-check exit 1; \ fi +# Behavior parity against the reference Rust backend: lower the same typed +# source through both backends, run both executables, and require identical +# observed results (process exit status), not identical generated source. +# The Rust side builds without cargo: rustc compiles the generated crate's +# lib.rs as an rlib plus a tiny harness main that calls the same entry. +typed-llvmir-parity: typed-llvmir-smoke + @command -v rustc >/dev/null 2>&1 \ + || { echo "typed-llvmir-parity: rustc not found (needed for the Rust reference build)" >&2; exit 1; } + @$(SCHEME) --libdirs $(LIBDIRS) --script support/typed-rust.ss \ + $(TYPED_LLVMIR_PARITY_DIR)/rust $(TYPED_LLVMIR_PARITY_SOURCE) + @rustc --edition 2021 --crate-type rlib \ + $(TYPED_LLVMIR_PARITY_DIR)/rust/src/lib.rs \ + --crate-name jt_parity -o $(TYPED_LLVMIR_PARITY_DIR)/libjt_parity.rlib \ + || { echo "typed-llvmir-parity: rustc rlib build failed" >&2; exit 1; } + @printf 'fn main() {\n std::process::exit(jt_parity::$(TYPED_LLVMIR_PARITY_FN)() as i32);\n}\n' \ + > $(TYPED_LLVMIR_PARITY_DIR)/main.rs + @rustc --edition 2021 $(TYPED_LLVMIR_PARITY_DIR)/main.rs \ + --extern jt_parity=$(TYPED_LLVMIR_PARITY_DIR)/libjt_parity.rlib \ + -o $(TYPED_LLVMIR_PARITY_DIR)/parity_rust \ + || { echo "typed-llvmir-parity: rustc harness build failed" >&2; exit 1; } + @if "$(TYPED_LLVMIR_PARITY_DIR)/parity_rust"; then rust_status=0; else rust_status=$$?; fi; \ + if "$(TYPED_LLVMIR_DIR)/$(TYPED_LLVMIR_SMOKE_MODULE)"; then llvm_status=0; else llvm_status=$$?; fi; \ + echo "typed-llvmir-parity: rust=$$rust_status llvm=$$llvm_status expected=$(TYPED_LLVMIR_SMOKE_EXPECT)"; \ + if [ "$$rust_status" -eq "$$llvm_status" ] && [ "$$rust_status" -eq "$(TYPED_LLVMIR_SMOKE_EXPECT)" ]; then \ + echo "typed-llvmir-parity: PASS — backends agree"; \ + else \ + echo "typed-llvmir-parity: FAIL — backend results differ" >&2; \ + exit 1; \ + fi + typed-wrappers: @$(SCHEME) --libdirs $(LIBDIRS) --script support/typed-wrappers.ss $(TYPED_WRAPPER_DIR) $(TYPED_RUST_SOURCES)