typed/llvmir: add Makefile generate + verify targets (Phase 3)

ober

f5743d41f5a61200cd498596eb9f86ef5d6c20ea

diff --git a/Makefile b/Makefile
index d426949..beda871 100644
--- a/Makefile
+++ b/Makefile
@@ -40,9 +40,14 @@ PURE_AUDIT_ARGS ?= --summary --discover $(PURE_AUDIT_ROOT)
 TYPED_SOURCES ?= tests/fixtures/typed/valid-split-tree.ss
 TYPED_RUST_SOURCES ?= $(TYPED_SOURCES)
 TYPED_RUST_DIR ?= build/typed/rust
+TYPED_LLVMIR_SOURCES ?= tests/fixtures/typed/llvmir-basic.ss tests/fixtures/typed/llvmir-if.ss tests/fixtures/typed/llvmir-call.ss
+TYPED_LLVMIR_DIR ?= build/typed/llvmir
+# 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-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-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>"
@@ -76,6 +81,9 @@ help:
 	@echo "                   Args: CHEZ_TARGET_MACHINE=<mt> CROSS_CC=<cc> [CROSS_NATIVE_FEATURES=tls,...]"
 	@echo "  typecheck        Typecheck Typed Jerboa sources"
 	@echo "  typed-rust       Generate Rust crate sources from Typed Jerboa"
+	@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-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"
@@ -792,6 +800,26 @@ typecheck:
 typed-rust:
 	@$(SCHEME) --libdirs $(LIBDIRS) --script support/typed-rust.ss $(TYPED_RUST_DIR) $(TYPED_RUST_SOURCES)
 
+typed-llvmir:
+	@$(SCHEME) --libdirs $(LIBDIRS) --script support/typed-llvmir.ss $(TYPED_LLVMIR_DIR) $(TYPED_LLVMIR_SOURCES)
+
+# Assemble and verify every generated .ll, then make sure it survives -O2.
+# Failures print the offending .ll path so the IR can be inspected directly.
+typed-llvmir-check: typed-llvmir
+	@if [ -z "$(LLVM_BIN)" ]; then \
+	    echo "typed-llvmir-check: LLVM tools not found (need llvm-as/opt on PATH or in a Homebrew llvm keg)" >&2; \
+	    exit 1; \
+	fi
+	@for f in $(TYPED_LLVMIR_DIR)/*.ll; do \
+	    "$(LLVM_BIN)/llvm-as" "$$f" -o "$${f%.ll}.bc" \
+	        || { echo "typed-llvmir-check: llvm-as failed on $$f" >&2; exit 1; }; \
+	    "$(LLVM_BIN)/opt" -passes=verify "$${f%.ll}.bc" -o /dev/null \
+	        || { echo "typed-llvmir-check: verifier failed on $$f" >&2; exit 1; }; \
+	    "$(LLVM_BIN)/opt" -O2 "$${f%.ll}.bc" -o "$${f%.ll}.opt.bc" \
+	        || { echo "typed-llvmir-check: opt -O2 failed on $$f" >&2; exit 1; }; \
+	    echo "typed-llvmir-check: OK $$f"; \
+	done
+
 typed-wrappers:
 	@$(SCHEME) --libdirs $(LIBDIRS) --script support/typed-wrappers.ss $(TYPED_WRAPPER_DIR) $(TYPED_RUST_SOURCES)