Skip to main content

logicaffeine_compile/codegen_tt/
wrap.rs

1//! Wraps the LOGOS→C compute (the proven ≡VM body from [`crate::codegen_c`]) into
2//! a single-Tensix-core TT-Metalium program: a compute kernel that runs the body
3//! on `RISCV_0` and streams `Show` to DPRINT, plus the host orchestrator and CMake.
4
5use super::runtime::{TT_CMAKE_TEMPLATE, TT_HOST_TEMPLATE, TT_KERNEL_PREAMBLE};
6use super::{TtArtifact, KERNEL_FILE_NAME};
7use crate::codegen_c::runtime::C_GC_COLLECTOR;
8
9/// The C program's entry (`crate::codegen_c` emits exactly this), renamed so the
10/// kernel can call it from `kernel_main` without defining a second `main`.
11const C_MAIN_SIG: &str = "int main(int argc, char **argv) {";
12const KERNEL_MAIN_SIG: &str = "static int logos_main(int argc, char **argv) {";
13
14/// Build the TT-Metalium artifact from the self-contained C translation of the
15/// program. The C body is reused verbatim except: system `#include <...>` lines
16/// are dropped (the kernel preamble supplies the on-core headers) and `main` is
17/// renamed to `logos_main`, which `kernel_main` invokes.
18pub fn wrap_as_tt(oracle_c: &str) -> TtArtifact {
19    // Host stack/segment discovery cannot run on a Tensix core. The remaining
20    // runtime provides allocator fallbacks for the on-core C library.
21    let device_c = oracle_c.replace(C_GC_COLLECTOR, "");
22    let body = strip_system_includes(&device_c).replace(C_MAIN_SIG, KERNEL_MAIN_SIG);
23
24    let kernel_cpp = format!(
25        "{preamble}{body}\n\nvoid kernel_main() {{\n    (void) logos_main(0, (char **)0);\n}}\n",
26        preamble = TT_KERNEL_PREAMBLE,
27        body = body,
28    );
29
30    let host_cpp = TT_HOST_TEMPLATE.replace("{KERNEL_FILE}", KERNEL_FILE_NAME);
31    let cmake = TT_CMAKE_TEMPLATE.replace("{KERNEL_FILE}", KERNEL_FILE_NAME);
32
33    TtArtifact {
34        kernel_cpp,
35        host_cpp,
36        cmake,
37        oracle_c: oracle_c.to_string(),
38    }
39}
40
41/// Drop `#include <...>` system-header lines: on a Tensix baby core those come
42/// from the kernel preamble / tt-metal's on-core newlib, not glibc. Local
43/// `#include "..."` lines (the C backend emits none) are preserved.
44fn strip_system_includes(c: &str) -> String {
45    let mut out = String::with_capacity(c.len());
46    for line in c.lines() {
47        let t = line.trim_start();
48        if t.starts_with("#include <") && t.ends_with('>') {
49            continue;
50        }
51        out.push_str(line);
52        out.push('\n');
53    }
54    out
55}
56
57#[cfg(test)]
58#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/codegen_tt/wrap/tests.rs"]
59mod tests;