Skip to content
Merged
28 changes: 28 additions & 0 deletions .trinity/seals/ml_thread_model.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"built_by": "t27c-bootstrap@0.5.2+353cf1df0",
"closure": [],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:f8a801fb1cab50b79d71e48f082d9a20631cc186a95ff556c0c95e28d3f673ff",
"gen_hash_rust": "sha256:0259f9a227a8fa9e4d44d206ce067466968359dda7faf078b6dc2eff2c98ecb9",
"gen_hash_verilog": "sha256:0c848643da8632ad81793d4fc7c75b7ca0bf90cbc1e188816579329c89f53389",
"gen_hash_zig": "sha256:a0ea2b547770300e1d014bebb7155f36285b2897d81053c71e8b112037851590",
"module": "thread_model",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T05:50:29Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:4496b1af159ece6df6faa55f966b8a25f87ef7e20fc896607bbf9507ec91704e",
"spec_path": "specs/ml/thread_model.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 6,
"total": 6,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10",
"zig": "0.16.0"
}
}
18 changes: 9 additions & 9 deletions .trinity/seals/ml_train_hslm.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"built_by": "t27c-bootstrap@0.5.2+589e8e088",
"built_by": "t27c-bootstrap@0.5.2+353cf1df0",
"closure": [
{
"spec": "specs/base/types.t27",
Expand All @@ -19,23 +19,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:d1aab3569e7f81a5c9dde33f807f336fdf635a444123851f3af2337054e78adc",
"gen_hash_rust": "sha256:bc122390cb0e4fbb5874cb9a3b673821dac1ec2688218810ceeed920723680e0",
"gen_hash_verilog": "sha256:62ccb084432145a73480df7b3341a8e850ef4f3f09d48cbb063d392d9f6dd285",
"gen_hash_zig": "sha256:1173b9ccf2990e4d0bd8478d24c85f5fd40c7d5c0c410535a403f3dc0ccd9518",
"gen_hash_c": "sha256:822f833d6c18b7e4934d3b2d642f2c148fe1f474a913a8d3ae8b5d66a8574e3e",
"gen_hash_rust": "sha256:e51f59949e0422e8c502718227650dc98a439ef672bf30f57cb81845fca2eed9",
"gen_hash_verilog": "sha256:9e721a0fd0edb9a087beff8610b322cf6c08058be2eae63646179ebac438d0b7",
"gen_hash_zig": "sha256:932f799ed156fede9141759f9f8d0f06c23700006b5362756b8e67d4a6d51b5e",
"module": "train_hslm",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T05:47:55Z",
"sealed_at": "2026-10-19T05:50:26Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:b4c888de5e9f260644eb98b0374fa55820be75a5a01b7ec988097b1cc9c65ddc",
"spec_hash": "sha256:84db90108f99fb68a750e82e6cd104f669900631495eafa9ae50574f956e23c4",
"spec_path": "specs/ml/train_hslm.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 29,
"total": 29,
"passed": 30,
"total": 30,
"vacuous": 0
},
"toolchain": {
Expand Down
87 changes: 40 additions & 47 deletions bootstrap/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,6 @@ impl Node {
children: Vec::new(),
}
}

#[allow(dead_code)]
pub fn with_child(mut self, child: Node) -> Self {
self.children.push(child);
self
}
}

// ============================================================================
Expand Down Expand Up @@ -1332,11 +1326,6 @@ impl Parser {
self.current.kind == kind
}

#[allow(dead_code)]
fn check_peek(&self, kind: TokenKind) -> bool {
self.peek.kind == kind
}

fn expect(&mut self, kind: TokenKind) -> Result<(), String> {
if !self.check(kind) {
return Err(format!(
Expand Down Expand Up @@ -2038,6 +2027,15 @@ the parser used to read it as `{}` followed by a negation",
continue;
}

// #10876: `threadlocal var` -- one copy of the variable per thread (Zig `threadlocal var`).
if self.current.kind == TokenKind::Ident && self.current.lexeme == "threadlocal" && self.peek.kind == TokenKind::KwVar {
self.advance();
let mut decl = self.parse_var_decl(false)?;
decl.extra_kind = "threadlocal".to_string();
module.children.push(decl);
continue;
}

// W458: allow bare expression / assignment statements at module
// level so functions with array parameters can be called from the
// module body (e.g. `read_mem(rom_array, idx);`). These are emitted
Expand Down Expand Up @@ -7352,6 +7350,26 @@ fn __t27_host_write(fd: i32, b: []const u8) i32 { return __t27_host_ret(__t27_po
fn __t27_host_close(fd: i32) i32 { return __t27_host_ret(__t27_posix.system.close(fd)); }
"#;

/// #10876: OS threads in 256 numbered slots. thread_spawn(slot, f, arg) runs f(arg) on a new thread
/// and returns false when the slot is busy or the OS refuses; thread_join(slot) waits for it.
const THREAD_ZIG: &str = r#"
const __t27_Thread = @import("std").Thread;
var __t27_threads: [256]?__t27_Thread = [_]?__t27_Thread{null} ** 256;
fn __t27_thread_spawn(slot: usize, comptime f: anytype, arg: usize) bool {
if (slot >= __t27_threads.len or __t27_threads[slot] != null) return false;
__t27_threads[slot] = __t27_Thread.spawn(.{}, f, .{arg}) catch return false;
return true;
}
fn __t27_thread_join(slot: usize) bool {
if (slot >= __t27_threads.len) return false;
const t = __t27_threads[slot] orelse return false;
t.join();
__t27_threads[slot] = null;
return true;
}
fn __t27_thread_cores() usize { return __t27_Thread.getCpuCount() catch 1; }
"#;

pub struct Codegen {
output: String,
indent: u32,
Expand Down Expand Up @@ -8243,6 +8261,11 @@ impl Codegen {
if host {
self.write(HOST_IO_ZIG);
}
let mut threads = false;
Self::visit_calls(&ast.children, &mut |c| threads |= matches!(c.name.as_str(), "thread_spawn" | "thread_join" | "thread_cores"));
if threads {
self.write(THREAD_ZIG);
}
}

/// Generate Zig code with project-aware import resolution.
Expand Down Expand Up @@ -8418,6 +8441,9 @@ impl Codegen {
// module-level name emitted `const` and Zig refused the assignment.
// gen-verilog got this right all along -- it emits a `reg`.
let kw = if node.extra_mutable { "var" } else { "const" };
if node.extra_kind == "threadlocal" {
self.write("threadlocal ");
}
self.write(&format!("{} {}", kw, node.name));

if !node.extra_type.is_empty() {
Expand Down Expand Up @@ -10423,6 +10449,9 @@ impl Codegen {
"host_read" => Some("__t27_host_read"),
"host_write" => Some("__t27_host_write"),
"host_close" => Some("__t27_host_close"),
"thread_spawn" => Some("__t27_thread_spawn"),
"thread_join" => Some("__t27_thread_join"),
"thread_cores" => Some("__t27_thread_cores"),
_ => None,
};
if let Some(b) = builtin {
Expand Down Expand Up @@ -23595,15 +23624,6 @@ impl Compiler {
Self::ast_is_icarus_lowerable(&ast, &structs, &functions, false)
}

/// W534: reason string version of the structural classifier.
pub fn icarus_lowerability_reason(source: &str) -> Result<String, String> {
match Self::is_icarus_lowerable(source) {
Ok(true) => Ok(String::new()),
Ok(false) => Err("not lowerable".to_string()),
Err(e) => Err(e),
}
}

fn collect_function_names(
node: &Node,
functions: &mut std::collections::HashSet<String>,
Expand Down Expand Up @@ -30993,18 +31013,6 @@ impl AsmConfig {
}
}

pub fn align_address(addr: u32, alignment: u32) -> u32 {
if alignment == 0 {
return addr;
}
let remainder = addr % alignment;
if remainder == 0 {
addr
} else {
addr + alignment - remainder
}
}

#[derive(Debug, Clone)]
pub struct HirAssembler {
pub config: AsmConfig,
Expand Down Expand Up @@ -31195,10 +31203,6 @@ impl TbResetCfg {
duration_cycles: duration,
}
}

pub fn reset_end_cycle(&self) -> u32 {
self.delay_cycles.saturating_add(self.duration_cycles)
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -32325,17 +32329,6 @@ impl TimingModel {
}
}

pub fn path_delay(arcs: &[TimingArc]) -> u32 {
arcs.iter().map(|a| a.delay_ps).sum()
}

pub fn worst_path_delay(paths: &[TimingPath]) -> u32 {
if paths.is_empty() {
return 0;
}
paths.iter().map(|p| p.total_delay_ps).max().unwrap_or(0)
}

#[derive(Debug, Clone)]
pub struct PowerDomain {
pub name: String,
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/stage0/FROZEN_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
88b8cb73ceda740a7dd5f29d895dcce4da3a3df9a9b2fc8571b43a023af7a263 bootstrap/src/compiler.rs
509db03c8f4d1f846c0a15e07208b0564886c65e2c0eeb4b5c013e4533fe1f6c bootstrap/src/compiler.rs
Loading
Loading