Skip to content

refactor(ptodsl): make signless iN the only integer identity during tracing; demote siN/uiN to wrapper metadata and boundaries #1424

Description

@Zhendong404

Background

Issue #1405 (fixed by #1408) exposed a structural fragility in PTODSL's scalar lowering: integer values live in two type domains at once.

  • The MLIR arith domain only accepts signless iN (per MLIR's design philosophy, signedness is a property of the operationdivsi vs divui — not of the type).
  • The authored PTODSL domain carries siN/uiN as value types throughout tracing.

The two domains are bridged by unrealized_conversion_cast strip/restore pairs (_strip_integer_signedness / _restore_integer_signedness in ptodsl/ptodsl/_types.py). This op is designed as a dialect-conversion placeholder ("this type will be legalized away later"), not as an everyday signedness bookkeeping device. Using it this way means every integer value can exist in a split form — a bare signless SSA value paired with an out-of-band signedness annotation — and any tracer path that caches, constant-folds, or otherwise reuses an intermediate SSA value with a stale annotation can emit invalid IR (in #1405: a si32 to i32 cast whose operand was actually an i32 constant).

#1408 fixes the literal-arithmetic instance of this, but the fix is symptomatic: it removes some strip/restore round trips rather than making the value/annotation mismatch structurally impossible. Other reuse paths (constant folding in _tracing/, control flow, sub-kernel boundaries) can still desync the two.

Proposal

Make signless the only integer identity inside tracing:

  1. Value layer: during tracing, every integer SSA value is signless iN. siN/uiN never appear as intermediate value types, so _strip/_restore_integer_signedness disappear from hot paths.
  2. Metadata layer: the frontend wrappers (_SurfaceValue / RuntimeValue in _surface_values.py) carry signedness as pure Python-side metadata whose only purpose is operator selection (FloorDivSIOp vs DivUIOp, slt vs ult, MaxSI vs MaxUI, ...). Sites that currently reverse-engineer signedness from value.type string prefixes (e.g. _runtime_scalar_ops.py) read the metadata instead.
  3. Boundary layer: siN/uiN are still materialized at boundaries — kernel signatures/ABI, VMI storage — with exactly one strip on entry and one restore on exit per value. No cast chains.

After this, an SSA value has exactly one integer identity; signedness no longer lives in the IR at all, so there is nothing for the tracer to desync.

Suggested migration path

  1. Land fix(ptodsl): preserve signless arithmetic operand types #1408 (after fixing its unsigned-semantics regression) as the stopgap.
  2. Add a signedness metadata field to the runtime-value wrappers; make _runtime_scalar_ops.py prefer metadata and fall back to the type. This step is independently testable.
  3. Remove _strip/_restore from hot paths module by module (_scalar_adaptation.py, _scalar_coercion.py, _runtime_index_ops.py, control flow, sub-kernels), keeping them only at ABI/storage boundaries (consider renaming to _adapt_abi_signedness so misuse is visible in review).
  4. Regression coverage: signed and unsigned runtime scalars mixed with literals across add/sub/mul/floordiv/mod/compare/min/max, including values >= 2^31 for the unsigned cases.

Non-goals

  • Changing the public DSL surface: pto.si32/pto.ui32 declarations and their numeric semantics stay as they are.
  • Changing kernel ABI types.

Refs: #1405, #1408

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions