tccquickr

tccquickr compiles a declared subset of R into typed IR and then into C, Fortran, and TinyCC-JIT kernels. Programs enter through declare(type(...)), become S7 value graphs with symbolic shapes and effects, and lower into one or more backend-neutral loop nests — SAC-style with-loops — before any target syntax exists. Unsupported R is a classed diagnostic, never an implicit fallback.

Every chunk in this README executes when the document is knit, so the claims below are checked against the installed package, not maintained by hand.

Install

install.packages(
  "tccquickr",
  repos = c("https://sounkou-bioinfo.r-universe.dev", getOption("repos"))
)
# or
remotes::install_github("sounkou-bioinfo/tccquickr")

From declared R to a running kernel

A matrix-vector product, declared with symbolic dimensions:

library(tccquickr)

matrix_vector <- function(x, w) {
  declare(type(x = double(n, p), w = double(p)))
  x %*% w
}

The analysis lowers this into a typed loop nest — one map axis over n, one reduce axis over p folding with sum — and the C backend prints that nest:

program <- tccq_analyze(matrix_vector, strict = TRUE)@value
c_plan <- tccq_plan_backend(
  program,
  tccq_c_backend(),
  tccq_backend_context(mode = "source", target = "c")
)
cat(c_plan@value@products@attrs$source)
#> #include <math.h>
#> #include <limits.h>
#> #include <stddef.h>
#> #include <stdlib.h>
#> #define TCCQ_NA_LOGICAL INT_MIN
#> 
#> double *tccq_c_9794934(const double *input_0001, const double *input_0002, int extent_n, int extent_p, int result_count_0001) {
#>   if (result_count_0001 < 0) {
#>     return NULL;
#>   }
#>   double *output = (double *)malloc(sizeof(double) * (size_t)result_count_0001);
#>   if (output == NULL) {
#>     return NULL;
#>   }
#>   for (int axis_0001 = 0; axis_0001 < extent_n; ++axis_0001) {
#>     double accumulator_0001 = 0.0;
#>     for (int axis_0002 = 0; axis_0002 < extent_p; ++axis_0002) {
#>       accumulator_0001 = (accumulator_0001 + (input_0001[axis_0001 + axis_0002 * extent_n] * input_0002[axis_0002]));
#>     }
#>     output[axis_0001] = accumulator_0001;
#>   }
#>   return output;
#> }

The extent parameters come from the declared dimension symbols, so the generated boundary knows that ncol(x) and length(w) are the same p and checks it. TinyCC compiles the same source in-process and the callable agrees with R:

jit_plan <- tccq_plan_backend(
  program,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
matvec <- jit_plan@value@products@attrs$callable

set.seed(1)
x <- matrix(rnorm(12), nrow = 3)
w <- rnorm(4)
all.equal(matvec(x, w), drop(x %*% w))
#> [1] TRUE

Stencils work the same way: affine slice bounds become typed affine extents (n - 2 is a dimension fact, not a printed string), and the loop nest shifts accesses instead of materializing slices:

tiled_stencil_1d <- function(x) {
  declare(type(x = double(n)))
  x[1:(n - 2L)] + x[2:(n - 1L)] + x[3:n]
}

stencil_jit <- tccq_plan_backend(
  tccq_analyze(tiled_stencil_1d, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
stencil <- stencil_jit@value@products@attrs$callable
v <- c(1, 2, 4, 8, 16, 32, 64)
all.equal(stencil(v), v[1:5] + v[2:6] + v[3:7])
#> [1] TRUE

Programs are no longer limited to one loop nest. A scalar reduction feeding later work becomes its own all-reduce nest. Its reducer advances typed neutral state, then projects a distinct typed materialized scalar slot that the final nest reads. The backend interface assigns source names to both values; the loop nest contains no target names or generic metadata bag. This SAC-style composition is visible in the emitted source:

normalize <- function(x) {
  declare(type(x = double(n)))
  s <- sum(x)
  x / s
}

normalize_plan <- tccq_plan_backend(
  tccq_analyze(normalize, strict = TRUE)@value,
  tccq_c_backend(),
  tccq_backend_context(mode = "source", target = "c")
)
cat(normalize_plan@value@products@attrs$source)
#> #include <math.h>
#> #include <limits.h>
#> #include <stddef.h>
#> #include <stdlib.h>
#> #define TCCQ_NA_LOGICAL INT_MIN
#> 
#> double *tccq_c_960543494(const double *input_0001, int extent_n, int result_count_0001) {
#>   if (result_count_0001 < 0) {
#>     return NULL;
#>   }
#>   double *output = (double *)malloc(sizeof(double) * (size_t)result_count_0001);
#>   if (output == NULL) {
#>     return NULL;
#>   }
#>   double intermediate_0001;
#>   double accumulator_0001 = 0.0;
#>   for (int axis_0001 = 0; axis_0001 < extent_n; ++axis_0001) {
#>     accumulator_0001 = (accumulator_0001 + input_0001[axis_0001]);
#>   }
#>   intermediate_0001 = accumulator_0001;
#>   for (int axis_0001 = 0; axis_0001 < extent_n; ++axis_0001) {
#>     output[axis_0001] = (input_0001[axis_0001] / intermediate_0001);
#>   }
#>   return output;
#> }
normalize_jit <- tccq_plan_backend(
  tccq_analyze(normalize, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
normalize_kernel <- normalize_jit@value@products@attrs$callable
v <- c(1, 2, 3, 4)
all.equal(normalize_kernel(v), v / sum(v))
#> [1] TRUE

The declared subset today

Types. double formals may have any rank with symbolic or constant dimensions. Scalar logical values use R’s three-state integer representation through the generated ABI: C int, Fortran integer(c_int), and TinyCC i32. Boundary wrappers reject missing logical formals, while computed comparisons preserve missingness until a value is returned or consumed by control. Other declared base types analyze but do not reach the source backends yet.

A generated callable with control carries a typed error channel. When its result is an array, the function interface uses caller-owned output storage rather than returning an owned pointer: C, Rtinycc, and Fortran can inspect the status before exposing the output, and allocation or condition failures remain ordered classed diagnostics instead of sentinel pointers.

Elementwise operations. +, -, *, /, ^, sqrt, and exp use scalar broadcast over any rank. Scalar numeric <, <=, >, >=, ==, and != produce typed logical values for control conditions; their current implementation deliberately rejects array operands. Registries can add leaf renderers without touching the printers. A composite operation instead uses TccqOpBody: one parameterized R expression that lowering expands through the same registry into ordinary typed values. Expansion checks the signature’s result type and verifies that the primitive effects fit inside the body’s declared effect contract. A body can refer only to its parameters, literals, and calls resolved by the registry; free symbols and special-forcing calls are structured refusals. Bodies may call other neutral bodies, which expand transitively through the same registry. This is typed inline expansion for fusion, not a separately linked function mechanism: every composite name is gone before expression trees, fusion, loop nests, or source backends see the program. Every neutral operation expression then owns its complete TccqLoweredOperation and typed effect; it does not duplicate the selected implementation or hide pass facts in expression attributes.

sigmoid_registry <- tccq_op_registry_add(
  tccq_default_op_registry(),
  tccq_op_impl(
    "sigmoid",
    target = "neutral",
    region_kind = "kernel",
    effect = tccq_effect(reads = TRUE, may_warn = TRUE),
    body = tccq_op_body(function(value) 1 / (1 + exp(-value))),
    elementwise = tccq_elementwise_spec(
      "sigmoid",
      1L,
      result_type = function(input_types, result_shape) {
        tccq_type("double", result_shape)
      }
    )
  )
)

sigmoid_kernel <- function(x) {
  declare(type(x = double(n)))
  sigmoid(x)
}

sigmoid_program <- tccq_analyze(sigmoid_kernel, registry = sigmoid_registry)
sigmoid_plans <- list(
  c = tccq_plan_backend(sigmoid_program@value, tccq_c_backend()),
  fortran = tccq_plan_backend(sigmoid_program@value, tccq_fortran_backend())
)
unname(vapply(
  sigmoid_plans,
  function(plan) plan@value@products@body@op,
  character(1)
))
#> [1] "/" "/"

Reductions and contractions. TccqReductionSpec is the common reducer protocol rather than a promise that every reduction has one scalar accumulator. TccqFoldReductionSpec gives sum, mean, colSums, rowSums, colMeans, and rowMeans one identity/combine/finalize state component. which.max uses TccqArgReductionSpec and a typed TccqReductionState containing a seen flag, selected value, and one-based selected index. The loop planner owns that state; C, TinyCC, and Fortran only render its typed transition and result projection. The current scalar ABI cannot represent R’s integer(0) result, so an empty or all-missing input reports the classed runtime.reduction_has_no_value diagnostic instead of inventing an index. %*%, crossprod, and tcrossprod use a typed TccqContractionSpec, so contracted dimensions and transposition remain axis facts rather than target-source conventions.

Branches. A pure if with a scalar logical condition, an explicit else, and identical arm types lowers to TccqBranch. The branch retains the special forcing facts from TccqCallSemantics; C and Fortran emit conditional statements, so the unselected arm is not evaluated, and native call boundaries report a missing computed condition through a typed TccqBackendErrorChannel as R does. Loop-nest lowering represents value-producing control as a typed TccqValueBlock containing TccqConditional and TccqAssignment values. TccqConditional is the value-producing subtype of the general procedural TccqIf, so printers consume one condition-and-arm shape for both expression control and sequential control; arithmetic in each assignment remains a neutral TccqExpression. Pure branches may nest in result arms, directly as another branch’s condition, or under pure elementwise operations. The normalizer evaluates each control-valued operand into a block-owned write target before its consumer. That target retains the full semantic array type while carrying the scalar storage type actually written in each loop iteration; the shared function interface assigns its generated name through a typed value binding. ABI parameters, scalar locals, physical allocations, and symbolic extents are bindings rather than parallel name/id/type arrays. Every value block names the write target produced by its terminal paths. The general TccqBlock owns lexical statements and their exact effect without claiming to yield a value; TccqValueBlock adds the terminal-result contract needed by the current expression loop nests. A reducer or contraction can therefore consume a conditional element from a block-local target while the target is still in scope. A reduction or contraction selected inside an arm becomes an intermediate loop nest carrying an ordered typed guard path, so nested branches execute and materialize only the selected nests. The guard path is the storage execution scope: extraction rejects an unscheduled value reached through incompatible paths, C uses nullable owned buffers, and Fortran uses guarded allocatable arrays. The retained TccqBranch effect describes the original source computation, while a normalized TccqConditional effect describes only the work left in its statement arms after guarded operations have been extracted.

Sequential recurrence. The executable sequential slice uses abstract TccqLoop as the shared loop contract. TccqWhile adds a scalar logical header condition; TccqRepeat enters its typed body unconditionally. Loop-carried variables are mutable TccqCell values, deliberately distinct from the immutable TccqLocalBinding used by the top-level SSA schedule. Cell reads remain neutral expressions; writes and concrete loop statements live in a typed TccqValueBlock. break and next become TccqLoopTransfer statements aimed at the nearest enclosing loop. They are typed control completion rather than fabricated read/write effects. TccqControlCompletion records normal, break, and continue outcomes separately from TccqEffect. Blocks compose those outcomes in evaluation order, nested loops consume their own transfers, and definite-assignment joins consider only branch arms that can reach the next statement. A scalar cell may therefore be introduced by its first assignment inside a loop when that assignment dominates every normal-path read; unreachable writes never establish dominance, and loop writes are not assumed to run after a possibly empty loop. TccqFor adds a scalar iteration cell and a TccqIterationPlan that separates one-time source evaluation, the one-dimensional TccqDomain, and selection of the current element. A stored rank-1 atomic vector selects through a neutral expression carrying TccqAccess. A virtual unit sequence selects through TccqIndexExpr when its extent is either a declared dimension already present in the ABI or a non-negative integer literal. A symbolic source is a TccqDimensionReference, distinct from an ordinary scalar formal or local that happens to use the same name. The registry declares the behavior with TccqIterationSpec; C, Fortran, and Rtinycc never recognize the seq_len spelling. A scalar read with exactly one selector per source axis becomes TccqIndexedValue only when each axis has a TccqIndexProof. That proof keeps the iterator target and cell reference, iteration domain, source extent, zero-based affine access, and any normalized selector operation together. Bare index has offset zero. The first shifted form is canonical index + 1L; it is admitted only when the source extent is at least one element larger than the complete iteration domain. The retained typed + implementation and evaluator facts show which operation was normalized, while the bounds proof discharges integer overflow and subscript warnings for that range. TccqArity gives the rank-polymorphic subscript an open argument-count contract instead of inventing a maximum array rank. The access domain contains the unique loop axes, so x[index, index] is one loop mapped onto two source axes rather than a fabricated two-dimensional iteration. Assigning to an iterator invalidates its proof for the complete loop body, and stored-vector iteration supplies no such proof. Unproved scalar selectors, tagged arguments such as drop, and indirect indexed sources remain structured diagnostics. The same proof-bearing expression reaches C, TinyCC, and Fortran; their shared affine access map accounts for target index conventions. The iterator is initialized on entry to the body but remains uninitialized after a possibly empty loop, so post-loop reads are refused until non-emptiness is proven. A nested procedural if is a TccqIf whose consequent and alternative are general typed blocks; omitting else produces an explicit empty alternative block. Positional statement switch is a TccqSwitch with one scalar integer selector, a typed local selector target, and ordered typed alternative blocks. The selector is evaluated exactly once through a local binding in the shared backend function interface. Its completion retains normal fallthrough for an unmatched position, while an arm’s break or next still targets the surrounding R loop. C therefore emits ordered conditional arms instead of a native C switch, which would capture break and change the program’s meaning; Fortran consumes the same neutral statement. Character selection, numeric-double coercion and warnings, missing alternatives, and value-producing switch remain structured refusals. C, Fortran, and Rtinycc consume that same structured body without encoding recurrence as a TccqLoopNest. The body is the structured form of TccqProgramSchedule, so there is still one top-level owner of order; the schedule constructor validates result identity, graph references, exact cell and local ownership, graph-consistent target types, and initialization dominance over normally completing paths. Arbitrary scalar extents, general ranges, lists, computed iterables, labeled or nonlocal transfer, and array-carried state remain structured refusals rather than emitter conventions.

extent_sequence_sum <- function(x) {
  declare(type(x = double(n)))
  total <- 0
  for (index in seq_len(n)) total <- total + index
  total
}

extent_sequence_plan <- tccq_plan_backend(
  tccq_analyze(extent_sequence_sum, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
extent_sequence <- extent_sequence_plan@value@products@attrs$callable
identical(extent_sequence(numeric(5)), 15)
#> [1] TRUE
indexed_sum <- function(x) {
  declare(type(x = double(n)))
  total <- 0
  for (index in seq_len(n)) total <- total + x[index]
  total
}

indexed_sum_plan <- tccq_plan_backend(
  tccq_analyze(indexed_sum, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
indexed_sum_kernel <- indexed_sum_plan@value@products@attrs$callable
identical(indexed_sum_kernel(c(1, 2, 3)), 6)
#> [1] TRUE

shifted_indexed_sum <- function(x) {
  declare(type(x = double(4)))
  total <- 0
  for (index in seq_len(3L)) total <- total + x[index + 1L]
  total
}

shifted_indexed_plan <- tccq_plan_backend(
  tccq_analyze(shifted_indexed_sum, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
shifted_indexed_kernel <- shifted_indexed_plan@value@products@attrs$callable
identical(shifted_indexed_kernel(c(1, 2, 3, 4)), 9)
#> [1] TRUE

indexed_matrix_sum <- function(x) {
  declare(type(x = double(n, p)))
  total <- 0
  for (row in seq_len(n)) {
    for (column in seq_len(p)) total <- total + x[row, column]
  }
  total
}

indexed_matrix_plan <- tccq_plan_backend(
  tccq_analyze(indexed_matrix_sum, strict = TRUE)@value,
  tccq_rtinycc_backend(),
  tccq_backend_context(mode = "jit", target = "c")
)
indexed_matrix_kernel <- indexed_matrix_plan@value@products@attrs$callable
m <- matrix(as.double(1:6), nrow = 2)
identical(indexed_matrix_kernel(m), sum(m))
#> [1] TRUE

Slices and bindings. Rank-1 x[a:b] accepts bounds affine in declared dimension symbols. A TccqProgramSchedule owns either contiguous TccqEvaluationStep values or one structured TccqValueBlock, never both. In the linear form every executable top-level expression has a step, including statements whose values are not bound. Assignment steps carry a single-assignment TccqLocalBinding; the schedule, not value ids or source text, owns R evaluation order. Each neutral reference carries one typed TccqExpressionReference that distinguishes the expression value from the logical source value it reads and owns its optional symbol, lexical binding, slice offsets, and affine TccqAccess. That logical source is distinct from a later physical TccqStorageAllocation. Each step retains the exact local bindings read, because different lexical names may alias one lowered value. The loop-nest planner sees those reads as TccqBindingReference leaves rather than walking back into and re-evaluating their definition graphs. It visits schedule steps before the returned expression. A reduction defined before a later if therefore materializes once without that if’s guards; when the definition itself is conditional, its intermediate nests retain the definition’s selected-arm guards. Later consumers reuse that schedule rather than moving evaluation to a use site.

The first local fusion rule is intentionally stricter than textual f(g(x)). A definition is kept as an expression only when it has one exact lexical read in the immediately following elementwise step, producer and consumer have the same iteration shape, and neither typed effect may write, allocate, cross a boundary, error, or warn. The resulting TccqStorageSlot@materialized = FALSE is consumed by the shared loop-nest planner, so C, TinyCC, and Fortran all remove the same intermediate. Duplicate reads, later reads, branches, reductions, contractions, and warning-capable operations such as sqrt remain materialized. Purity alone is not treated as a proof that eager R evaluation can be reordered.

Verified program optimization. TccqProgramOptimization is an explicit opt-in contract for a typed program transformation and its verifier. The first implementation removes assignments only from a structured neutral body, only when a compiler-owned local or cell is never read or otherwise required, and only when the assigned expression cannot write, allocate, cross a boundary, error, or warn. It removes newly dead assignment chains to a fixed point, rebuilds typed control blocks and region facts, then tccq_compile() invokes its verifier independently before handing one common body to C, TinyCC, and Fortran. The source value graph and storage plan remain intact; graph-level dead-value elimination, liveness rewriting, and pass composition are deliberately separate future work. Source backends validate executable region values together with declared ABI formals and the result, so dead provenance does not become target work.

Composition. Non-root reductions and contractions become intermediate nests — named scalars for rank-0 results and materialized temporary buffers otherwise — so x / sum(x), colSums(x) + 1, (x %*% w) + y, and cs <- colSums(x); cs / sum(cs) compile as ordered nest sequences. A value consumed twice materializes once. Every nest carries the typed storage slot that receives its result, and every reducer carries a separate typed scalar state. TccqBackendFunctionInterface binds generated names to each state component for C, TinyCC, and Fortran.

A materialized temporary slot owns a TccqStorageAllocation. Two same-typed buffer slots share that physical identity only when schedule-derived, complete expression liveness proves that the first dies before the second definition and neither slot is control-dependent. A direct consumer therefore overlaps its producer, while a buffer reduced to a retained scalar can be reused by a later buffer. The shared allocation is consumed by all source paths: C emits one allocation and one free, and Fortran emits one automatic array. Non-materialized expressions own no allocation, and guarded buffers remain distinct.

Dimensions and recycling. A declared dimension symbol is a scalar in the body: colSums(x) / n reads the extent parameter already carried by the ABI. Rank-mixed operands follow R’s recycling rule with GNU-R as the oracle. A shorter operand recycles over column-major order through a typed modulo-linear access only when divisibility is provable. That TccqAccess owns the typed consumer shape used to linearize the logical axis order; it does not pass dimensions to the printer through metadata. Non-conformable arrays are refused as R refuses them.

Compilation succeeds when at least one backend produces a working plan; a backend that cannot lower a program reports typed feasibility diagnostics without vetoing the suite.

Apotheosis suite

The targets are explicit probes, each exercising one compiler idea, plus composite programs that force the ideas together. The table below is computed at knit time by running every probe through tccq_compile(); a probe either compiles through the core backends or names the diagnostic where it stops.

probes <- list(
  map_chain = function(x, y) {
    declare(type(x = double(n), y = double(n)))
    exp(sqrt(x) + y)
  },
  map_reduce = function(x, y) {
    declare(type(x = double(n), y = double(n)))
    sum(exp(x) * y)
  },
  matrix_reduce = function(x, y) {
    declare(type(x = double(n, p), y = double(n, p)))
    sum(exp(x) * y)
  },
  matrix_map = function(x, y) {
    declare(type(x = double(n, p), y = double(n, p)))
    sqrt(x) + y
  },
  column_sums = function(x) {
    declare(type(x = double(n, p)))
    colSums(x)
  },
  matrix_vector = function(x, w) {
    declare(type(x = double(n, p), w = double(p)))
    x %*% w
  },
  matrix_multiply = function(x, y) {
    declare(type(x = double(n, p), y = double(p, q)))
    x %*% y
  },
  tiled_stencil_1d = function(x) {
    declare(type(x = double(n)))
    x[1:(n - 2L)] + x[2:(n - 1L)] + x[3:n]
  },
  scalar_composition = function(x, y) {
    declare(type(x = double(n), y = double(n)))
    (x - sum(x)) / sum(y * y)
  },
  array_composition = function(x, w) {
    declare(type(x = double(n, p), w = double(p)))
    cs <- colSums(x) * w
    cs / sum(cs)
  },
  column_means_chain = function(x, y) {
    declare(type(x = double(n, p), y = double(p, q)))
    m <- x %*% y
    sqrt(exp(colSums(m) / n))
  },
  logistic_forward_pass = function(x, w) {
    declare(type(x = double(n, p), w = double(p)))
    mu <- colSums(x) / n
    sigma <- sqrt(colSums((x - mu)^2) / (n - 1))
    z <- (x - mu) / sigma
    eta <- z %*% w
    1 / (1 + exp(-eta))
  },
  argument_maximum = function(x) {
    declare(type(x = double(n)))
    which.max(x)
  },
  raw_buffer_roundtrip = function(bytes, scratch) {
    declare(type(bytes = raw(n), scratch = buffer(n)))
    bytes
  },
  conditional_map = function(x, flag) {
    declare(type(x = double(n), flag = logical()))
    if (flag) x else -x
  },
  nested_conditional_map = function(x, primary, secondary) {
    declare(type(x = double(n), primary = logical(), secondary = logical()))
    if (primary) if (secondary) x else -x else x
  },
  computed_condition_map = function(x, primary, secondary) {
    declare(type(x = double(n), primary = logical(), secondary = logical()))
    if (if (primary) secondary else primary) x else -x
  },
  conditional_composition = function(x, flag) {
    declare(type(x = double(n), flag = logical()))
    exp((if (flag) x else -x) + 1)
  },
  conditional_reduce = function(x, flag) {
    declare(type(x = double(n), flag = logical()))
    sum(if (flag) x else -x)
  },
  selected_reduce = function(x, flag) {
    declare(type(x = double(n), flag = logical()))
    if (flag) sum(x) else 0
  },
  control_flow_probe = function(x, flag) {
    declare(type(x = double(n), flag = logical()))
    out <- 0
    i <- 1L
    repeat {
      if (i > n) {
        break
      }
      out <- out + ifelse(flag, x[i], -x[i])
      i <- i + 1L
    }
    switch(if (flag) "sum" else "neg", sum = out, neg = -out)
  },
  apply_reduce_probe = function(x) {
    declare(type(x = double(n, p)))
    Reduce(`+`, lapply(seq_len(p), function(j) sum(x[, j])))
  },
  logistic_gradient = function(x, y, w, lambda) {
    declare(type(
      x = double(n, p),
      y = double(n),
      w = double(p),
      lambda = double()
    ))
    mu <- colMeans(x)
    sigma <- sqrt(colSums((x - mu)^2) / (n - 1L))
    z <- (x - mu) / sigma
    eta <- z %*% w
    prob <- 1 / (1 + exp(-eta))
    grad <- crossprod(z, prob - y) / n + lambda * w
    w - 0.01 * grad
  },
  viterbi_decode = function(init, trans, emit) {
    declare(type(
      init = double(k),
      trans = double(k, k),
      emit = double(t, k)
    ))
    score <- init + emit[1L, ]
    back <- matrix(0L, nrow = t, ncol = k)
    for (step in 2:t) {
      next_score <- score
      for (state in 1:k) {
        candidate <- score + trans[, state]
        best <- which.max(candidate)
        next_score[state] <- candidate[best] + emit[step, state]
        back[step, state] <- best
      }
      score <- next_score
    }
    list(score = score, back = back)
  }
)
probe_status <- function(fn) {
  compiled <- tccq_compile(fn, strict = FALSE)
  if (compiled@success) {
    return("compiles through at least one configured backend")
  }
  diagnostic <- compiled@diagnostics[[1L]]
  sprintf("`%s`", diagnostic@code)
}
knitr::kable(data.frame(
  probe = names(probes),
  status = vapply(probes, probe_status, character(1)),
  row.names = NULL
))
probe status
map_chain compiles through at least one configured backend
map_reduce compiles through at least one configured backend
matrix_reduce compiles through at least one configured backend
matrix_map compiles through at least one configured backend
column_sums compiles through at least one configured backend
matrix_vector compiles through at least one configured backend
matrix_multiply compiles through at least one configured backend
tiled_stencil_1d compiles through at least one configured backend
scalar_composition compiles through at least one configured backend
array_composition compiles through at least one configured backend
column_means_chain compiles through at least one configured backend
logistic_forward_pass compiles through at least one configured backend
argument_maximum compiles through at least one configured backend
raw_buffer_roundtrip backend.unsupported_type
conditional_map compiles through at least one configured backend
nested_conditional_map compiles through at least one configured backend
computed_condition_map compiles through at least one configured backend
conditional_composition compiles through at least one configured backend
conditional_reduce compiles through at least one configured backend
selected_reduce compiles through at least one configured backend
control_flow_probe frontend.unimplemented_call
apply_reduce_probe frontend.unimplemented_call
logistic_gradient compiles through at least one configured backend
viterbi_decode frontend.unimplemented_call

The failing rows are the roadmap: every one must move deeper through the same typed IR — loop regions and recurrences for Viterbi, general indexing and access regions, raw/buffer bridges, and apply-family folds. Failures must stay specific enough that the next typed concept to add is obvious.

Design

The compiler core is typed all the way down: S7 schemas for values, shapes, effects, regions, and plans; s7contract interfaces between phases; classed diagnostics instead of error strings; neutral expression and statement values; one TccqLoopNest abstraction for data-parallel iteration; and structured TccqBlock/TccqIf/TccqSwitch/TccqLoop values for sequential recurrence, with TccqIterationPlan owning sequential source and element selection. Every source backend consumes the same neutral handoff. The full phase-by-phase story — call semantics, operation registries, lowering, loop nests, bridges, backend planning, fusion — lives in docs/architecture.md, with the root direction in docs/root.md and repo rules in AGENTS.md.