Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bc67415
test: write every fixture function output on every path
thiremani Oct 7, 2026
52f9c8f
feat(compiler)!: require every function output to be definitely assigned
thiremani Oct 7, 2026
baf2169
refactor(compiler): drop the body-effect fixed point
thiremani Oct 7, 2026
f6e7e46
docs: describe definite outputs and per-template checks as implemented
thiremani Oct 7, 2026
00f4594
fix(compiler): report template text the flow checks cannot classify
thiremani Oct 7, 2026
7b56252
fix(compiler): keep each range a call passes through || and &&
thiremani Oct 7, 2026
2e67e0d
fix(compiler): report operators whose sides do not line up
thiremani Oct 7, 2026
3bec6c5
feat(compiler)!: reject ranges as function outputs
thiremani Oct 7, 2026
3e5d2b9
feat(compiler)!: iterate a bare range name wherever it is used
thiremani Oct 7, 2026
dc03287
fix(compiler): drive string markers in the order they appear
thiremani Oct 7, 2026
f51a590
refactor(compiler): leave range retypes to the type checker
thiremani Oct 9, 2026
51ed236
docs: say when the type checker reports a range retype
thiremani Oct 9, 2026
cbae638
fix(compiler): wait for every template before the flow checks
thiremani Oct 9, 2026
566dbb7
docs: drop the last mentions of ranges returned by calls
thiremani Oct 9, 2026
ce70aed
refactor(compiler): pass the classified template to the flow checks
thiremani Oct 10, 2026
206c84a
refactor(compiler): rename rangeFlow to writeClassifier
thiremani Oct 11, 2026
fd6214a
refactor(compiler): classify template writes with plain functions
thiremani Oct 12, 2026
f2fceed
style(compiler): separate loops from the returns after them
thiremani Oct 12, 2026
bf22b8c
refactor(compiler): move helpers next to their only callers
thiremani Oct 21, 2026
f9612e9
refactor(compiler): define a template's key beside funcKey
thiremani Oct 21, 2026
4df6c58
feat(compiler): copy a bare range name unless its loop is running
thiremani Oct 22, 2026
a5e139a
docs: describe bare range names as copies of their range
thiremani Oct 22, 2026
75e55aa
feat(compiler)!: iterate a bare range under a gate
thiremani Oct 22, 2026
89f66f9
docs: say a bare range iterates under a gate
thiremani Oct 22, 2026
5b5ba7e
fix(compiler): resolve conditional range bounds before the loop
thiremani Oct 23, 2026
bb8a453
docs: say how often a gate and an && condition run
thiremani Oct 23, 2026
ab01c2f
fix(compiler)!: build an iterated range literal once, before its loops
thiremani Oct 23, 2026
1d7e9a7
docs: say a range literal builds its range once
thiremani Oct 23, 2026
4b059b2
refactor(compiler): give a template's flow checks named passes
thiremani Oct 23, 2026
e5c236b
refactor(compiler): check a template's outputs at the end of its forw…
thiremani Oct 23, 2026
28302be
test: drop two gated range cases that other cases cover
thiremani Oct 24, 2026
0354150
test: give empty_range's || bound a fallback other than boundN
thiremani Oct 24, 2026
4fbbdee
test: give countInner two inner steps and countCmp a value to keep
thiremani Oct 24, 2026
0105027
test: check that a failed bound leaves new variables at zero
thiremani Oct 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,20 @@ y = Square(x)

Inputs are read-only — they flow in. Outputs flow out: the template may read one only after assigning it unconditionally, as in `sq = x * x` followed by `cube = sq * x`; before that, use a local. Read-only means the template cannot assign through the input name; it does not freeze a value shared with an output. A caller may reuse a variable as both argument and destination, `a = Square(a)`.

Every body that runs assigns every output on every path. A write under a condition, from a value that can fail, or driven by a range that may be empty can be skipped, so it needs a default first. A function keeps an old value only through an input its caller passes:

```python
y = Fib(n)
y = n
y = n > 1 Fib(n - 1) + Fib(n - 2)

out = Maybe(prev, x)
out = prev
out = x > 0 x
```

`a = Maybe(a, -1)` keeps `a`. A call therefore either writes all of its outputs or does not run at all: when an argument fails, when the statement's condition fails, or when its range is empty.

```python
out, seen = Fold(current, item)
out = current + item
Expand Down Expand Up @@ -219,14 +233,17 @@ lastSquare = Square(i) # 16
i # prints the descriptor: 0:5
```

A bare range is a value: assignment copies it and print shows its descriptor.
Using it in an operation creates a ranged computation: the assignment keeps
the final yield, brackets materialize all yields into an array, and passing it
to a template executes the call once for each value. The compiler can map
these operations to SIMD instructions — this is range-driven
A bare range is a value, written as a literal or held by a name: an assignment
without a gate copies it, and print shows its descriptor unless another
argument on the line loops over it. Using it under a gate or in an operation
creates a ranged computation: the assignment keeps the final yield, brackets
materialize all yields into an array, and passing it to a template executes
the call once for each value. The
compiler can map these operations to SIMD instructions — this is range-driven
auto-vectorization. Each named Range binding is a distinct driver: different
names form a cartesian domain when consumed together, even when their bounds
are equal.
are equal. A function cannot return a range; it returns the bounds, and the
caller builds the range.

Range-indexed array access follows the same rule:

Expand Down
15 changes: 5 additions & 10 deletions compiler/bounds.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,14 +481,6 @@ func collectArrayIndexAccesses(expr ast.Expression, out *[]*ast.ArrayRangeExpres
}
}

func (c *Compiler) loopRangeValuesByName(ranges []*RangeInfo) map[string]llvm.Value {
bounds := make(map[string]llvm.Value, len(ranges))
for _, ri := range ranges {
bounds[ri.Name] = c.rangeAggregateForRI(ri)
}
return bounds
}

func (c *Compiler) arraySymbolForAffineGuard(arrayExpr ast.Expression) (*Symbol, Type, bool) {
ident, ok := arrayExpr.(*ast.Identifier)
if !ok {
Expand All @@ -511,7 +503,7 @@ func (c *Compiler) arraySymbolForAffineGuard(arrayExpr ast.Expression) (*Symbol,
return arraySym, arrType.ElemType, true
}

func (c *Compiler) affineVersioningGuard(exprs []ast.Expression, ranges []*RangeInfo) (llvm.Value, map[*ast.ArrayRangeExpression]struct{}, bool) {
func (c *Compiler) affineVersioningGuard(exprs []ast.Expression, ranges []*RangeInfo, values []*Symbol) (llvm.Value, map[*ast.ArrayRangeExpression]struct{}, bool) {
if len(exprs) == 0 || len(ranges) == 0 {
return llvm.Value{}, nil, false
}
Expand All @@ -524,7 +516,10 @@ func (c *Compiler) affineVersioningGuard(exprs []ast.Expression, ranges []*Range
return llvm.Value{}, nil, false
}

boundsByName := c.loopRangeValuesByName(ranges)
boundsByName := make(map[string]llvm.Value, len(ranges))
for i, ri := range ranges {
boundsByName[ri.Name] = values[i].Val
}
fastAccess := make(map[*ast.ArrayRangeExpression]struct{})
guard := llvm.Value{}
hasGuard := false
Expand Down
Loading
Loading