Three authoring forms are refused with a message that names neither the
construct nor what to write instead. Each cost a debugging round to identify,
and in each case the fix in the source is one character to one line — so the
whole cost was the diagnostic.
tilefoundry 0.0.2.dev43+g45032b967 (45032b9), target nvidia.h200_sxm.
1. tf.concat with a list
return tf.concat([xs[:, 32:64], xs[:, 0:32]], axis=1)
expression.attribute: pattern did not match (role 'inputs') at case.py:22:26
The parser wants varargs — tf.concat(a, b, axis=1). The list form is how
torch, numpy, jax and tvm all spell it, so it is the first thing an author
tries. Nothing in the message says concat, says list, or says varargs.
Either accept the sequence form or say tf.concat takes its inputs as varargs, not a sequence.
2. A docstring in a @func body
@func
def f(x: Tensor[(N, W), "f32"]) -> Tensor[(N, W), "f32"]:
"""What this stage does."""
with Mesh(("cta",), layout=(N,), names=("u",)) as m:
return tf.reshard(x, (N @ m.u, W), "smem")
expression.attribute: pattern did not match (role 'statement_value') at case.py:20:5
Every other Python function may carry one, and the shipped models put their
prose in # comments — which reads like a style choice until you find out it
is enforced. Dropping a leading string constant from the body is a two-line
change in the block pattern; refusing it with a @func body may not hold a docstring; use # comments is a one-line change. Either is better than
pointing at column 5 of a string literal.
3. A bare loop variable as a slice bound
for t in tile(S, N):
xs = tf.reshard(x[:, t:t + N, :], (1, N @ m.u, W), "smem")
tilefoundry: error: dim_expr: expected int, DimVar, or Expr, got slice
base = t + 0 then x[:, base:base + N, :] is accepted and identical.
docs/tutorial/authoring.md writes base = start + 0 in Stage5_CachePrepared
without saying why, which is the only hint available. The message describes a
slice arriving where a dim was expected, which is the opposite of the problem
(a loop variable arrived where a dim was expected, inside a slice). Accepting
the bare variable is the right fix; failing that, say a loop induction variable must be bound to a name before it is used as a slice bound: write base = t + 0.
Reproducer
One file per case, each a whole program; tools/issues/authoring_diagnostics.py
in our tree runs all five we hit and prints the last stderr line of each. The
three above are reproduced by:
tilefoundry analyze case.py:M /tmp/r.txt --compute-cost --dim seq_len=8192
with case.py as the snippet plus this prelude:
from __future__ import annotations
from tilefoundry import func, module
from tilefoundry.dsl import ConstTensor, DimVar, Mesh, Tensor, tf
from tilefoundry.dsl.tf import * # noqa: F401, F403
from tilefoundry.ir.types.shard import Topology
from tilefoundry.target import CudaTarget
N, W = 128, 64
S = DimVar("seq_len", 0, 8193)
_H200, _CTA = CudaTarget("nvidia.h200_sxm"), Topology("cta", N)
@module(entry="f", target=_H200, topologies=(_CTA,))
class M:
...
Why these three together
They share one shape: the parser fails a pattern and reports the pattern's
name. expression.attribute: pattern did not match (role 'inputs') is a fact
about the matcher, not about the program. A pattern that is the last
alternative to fail on a call to a known op could name that op and what it
expected; that one change covers cases 1 and 2 and most of what an author hits
while learning the grammar.
Three authoring forms are refused with a message that names neither the
construct nor what to write instead. Each cost a debugging round to identify,
and in each case the fix in the source is one character to one line — so the
whole cost was the diagnostic.
tilefoundry 0.0.2.dev43+g45032b967(45032b9), targetnvidia.h200_sxm.1.
tf.concatwith a listThe parser wants varargs —
tf.concat(a, b, axis=1). The list form is howtorch, numpy, jax and tvm all spell it, so it is the first thing an author
tries. Nothing in the message says
concat, sayslist, or saysvarargs.Either accept the sequence form or say
tf.concat takes its inputs as varargs, not a sequence.2. A docstring in a
@funcbodyEvery other Python function may carry one, and the shipped models put their
prose in
#comments — which reads like a style choice until you find out itis enforced. Dropping a leading string constant from the body is a two-line
change in the block pattern; refusing it with
a @func body may not hold a docstring; use # commentsis a one-line change. Either is better thanpointing at column 5 of a string literal.
3. A bare loop variable as a slice bound
base = t + 0thenx[:, base:base + N, :]is accepted and identical.docs/tutorial/authoring.mdwritesbase = start + 0inStage5_CachePreparedwithout saying why, which is the only hint available. The message describes a
slice arriving where a dim was expected, which is the opposite of the problem
(a loop variable arrived where a dim was expected, inside a slice). Accepting
the bare variable is the right fix; failing that, say
a loop induction variable must be bound to a name before it is used as a slice bound: write base = t + 0.Reproducer
One file per case, each a whole program;
tools/issues/authoring_diagnostics.pyin our tree runs all five we hit and prints the last stderr line of each. The
three above are reproduced by:
with
case.pyas the snippet plus this prelude:Why these three together
They share one shape: the parser fails a pattern and reports the pattern's
name.
expression.attribute: pattern did not match (role 'inputs')is a factabout the matcher, not about the program. A pattern that is the last
alternative to fail on a call to a known op could name that op and what it
expected; that one change covers cases 1 and 2 and most of what an author hits
while learning the grammar.