Python frontend: 195 of 576 autogenerated programs refused, 8 distinct causes (one hang, three crashes)
- Dominant language
- Python
- Stars
- 593
- Forks
- 163
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 60
Description
# DaCe python-frontend issues found sweeping 576 autogenerated programs (2026-08-06)
Measured in `~/Work/optarena` against `~/Work/dace` @ `ecad3253f` (extended). Every program is
AUTOGENERATED from a numpy reference, so each of these is a construct the generator emits and the
kernel silently loses its DaCe column over. Filed, not fixed (this session's scope).
---
## 1. A runtime scalar is re-promoted to a FRESH symbol at every shape/slice use (64 kernels)
The single largest cause. A padded workspace is allocated from a scalar and then written through a
slice built from the SAME scalar:
```python
padded = np.zeros((n, c, h + 2 * padding, w + 2 * padding), dtype=x.dtype)
padded[:, :, padding:padding + h, padding:padding + w] = x
```
The frontend promotes each USE of `padding` to its own `__sym__`, so the write's extent
becomes `__sym_padded_slice - __sym_padding` and cannot be proven equal to `x`'s `height`:
```
IndexError: could not broadcast input array from shape [batch_size, in_channels, height, width]
into shape [__sym___inl1_n_0, __sym___inl1_c_in_0,
__sym___inl1_padded_slice - __sym___inl1_padding, ...]
```
Reusing one promoted symbol per scalar VERSION would make equal-by-construction extents provable.
Reachable via `dace/frontend/python/replacements/utils.py:169` `broadcast_together`.
## 2. A chained comparison raises a BODYLESS NotImplementedError (48 kernels)
`dace/frontend/python/newast.py:5349`:
```python
def visit_Compare(self, node: ast.Compare):
if len(node.ops) > 1 or len(node.comparators) > 1:
raise NotImplementedError
```
`if 0 <= oy < oh:` is the single commonest bounds test in ported conv/pool code. Two separate
defects: the feature is missing, AND the refusal names neither the construct nor the file. An
unsupported construct must name itself. (Worked around in the generator by splitting the chain,
but only where the middle operand is a Name/Constant -- the split evaluates it twice.)
## 3. `numpy.matmul` has no SDFG implementation registered (17 kernels)
`DaceSyntaxError: Function "numpy.matmul" is not registered with an SDFG implementation`. `np.dot`
and the `@` operator work; `np.matmul` does not, which reads as an oversight rather than a
decision.
## 4. Assigning a module-level `dc.symbol` inside a program crashes with a bare KeyError (10 kernels)
`npwx, nvec, nvecx, npol = (int(npwx), ...)` or `nx, ny, nz = u0.shape` at the top of a program
whose ARRAY SHAPES already name those symbols. `_visit_assign` (`newast.py:3541`, `add_scalar` at
`:3703` with `find_new_name=True`) creates a transient that shadows the symbol the argument shapes
are declared with, and the parse dies later as `KeyError: npwx` / `nx` / `nfrag` / `nproma` / `I`.
Refusing the reassignment by name would be a fix; the KeyError is a crash.
## 5. `or` over symbol equalities: `'Equality' object is not iterable` (4 kernels)
`if dim == 0 or dim == -2:` where `dim` is a symbol. `visit_BoolOp` (`newast.py:5340`) folds the
values pairwise through `_visit_op`; a sympy `Equality` then reaches code that iterates it.
`TypeError: 'Equality' object is not iterable` -- a crash, and it makes any symbolic branch guard
unusable.
## 6. `np.where(cond, scalar, scalar)` is refused (6 kernels)
`ValueError: Both x and y cannot be scalars in numpy.where`. numpy allows it; it is how a ported
GELU/clamp writes a two-way select.
## 7. The frontend HANGS parsing cloudsc (1 kernel)
`hpcagent_bench/benchmarks/scientific_computing/structured_grids/cloudsc/cloudsc_dace.py` does not
finish `to_sdfg(simplify=False)` in 180 s -- stuck, not slow. A kernel that hangs the parse is its
own finding: it also means any sweep that does not run one process per kernel reports a FLOOR.
## 8. Bitwise operators on a symbol raise NameError -- ONE bare `eval` (latent, 0 kernels today)
`dace/frontend/python/replacements/utils.py:236`:
```python
pyval = eval(astutils.unparse(representative_value)) # no globals dict
```
silently borrows `utils.py`'s module globals, which contain no symbolic head name. Reached whenever
a symbolic operand meets an array/scalar (`operators.py:657-706`).
Shifts survive the identical path only by accident: `sym_type` substitutes a representative value
first, and `left_shift.eval` / `right_shift.eval` (`symbolic.py:1830-1860`) FOLD when both args are
Numbers, collapsing to a literal. `bitwise_and|or|xor|invert` (`symbolic.py:1812-1825`) are
**bodyless** (`class bitwise_and(DaceFunction): pass`), so the string stays `bitwise_and(1, 3)` and
the bare `eval` raises. Giving that `eval` a real globals dict fixes every bitwise operator at once.
Frontend `_pyop2symtype` (`replacements/operators.py:713-727`) has exactly ONE binary entry,
`"//" -> int_floor`. Bitwise operators need entries, and they must map to the BARE classes:
patched to the `__`-prefixed variants, codegen emits `__left_shift(N, 1)` into C++
(`'__left_shift' was not declared in this scope`) -- those are half-wired, produced by the parser
and printed by `symstr` but absent from `symbolic.py:3299`'s binop map.
Two traps for whoever implements it:
* Cover BOTH directions -- `1 << N` fails as `'int' and 'symbol'` where `N << 1` works.
* `logical_left_shift` / `logical_right_shift` (`symbolic.py:1862-1895`) are the Fortran ISHFT
zero-fill lowering. Python's `>>` on a negative int is ARITHMETIC. Picking the logical variant
from the python frontend is a silent miscompile, not a missing feature.
Contributor guide
Research direction
Start by reproducing the 576-program sweep, then read the named entry points in dace/frontend/python/newast.py, replacements/utils.py, replacements/operators.py, and symbolic.py. Treat the eight causes as separate investigations; done means each failure has a focused regression case and the affected frontend behavior no longer crashes, hangs, or rejects supported constructs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- numpy, python
- Domain
- compilers, testing-qa
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100