Skip to content

[serialization] Params should serialize scalar parameter metadata #9401

Description

@derek-gerstmann

Description

Halide serialization drops scalar-parameter value constraints

serialize_pipeline records the value metadata of a buffer parameter but silently discards it for a scalar parameter. Walking the IR closure from the output Funcs, the serializer sorts parameters into two buckets (src/Serialization.cpp): buffer params reached through Load/Store/output nodes go to parameters_in_pipeline and are emitted by serialize_parameter, which includes default_value / min_value / max_value / estimate; but a scalar param is only ever reached through a Variable node (e.g. a Param<int> used in an RDom bound), and the Variable case routes it to external_parameters, emitted by serialize_external_parameter — which keeps only {is_buffer, type, dimensions, name}. So a scalar Param<int> p; p.set_range(0, 100); p.set_estimate(4); round-trips as nothing more than "an int named p." Those constraints are not generator-specific bookkeeping: they live on Halide::Internal::Parameter, are equally reachable through the freestanding Param<T> / ImageParam API, and are consumed by bounds inference (a min/max range is what lets a runtime-parameterized extent become a compile-time-constant, e.g. bounded stack allocations; an estimate is what the autoscheduler reads). Dropping them makes serialization lossy in a way that can change the lowered pipeline, and asymmetric with the buffer-parameter path for no obvious reason.

The charitable reading is that this is intentional: serialize_pipeline hands the caller a map of the external parameters, and the deserialize side is expected to re-bind the live Parameter objects (with their constraints intact), so the on-disk blob was never meant to be self-describing for externals. That contract is defensible, but it is undocumented at the call site and creates a trap for any consumer that treats the .hlpipe as a complete, self-contained fingerprint of a pipeline (as an algorithm-equality check does): two pipelines that differ only in a scalar parameter's declared range/estimate serialize identically, even though they can compile to different code. Recommended fix, roughly in preference order: (1) serialize scalar min_value/max_value/default_value/estimate on the external-parameter path too, so the format is lossless and symmetric with buffers; or failing that (2) document the "externals are re-bound by the caller" contract prominently and expose the external-parameter constraints alongside the returned params map, so a caller can choose to fold them into its own fingerprint.

Reproducing case

Walking the IR of a serialized/deserailized pipeline should match the original IR's scalar parameter metadata.

How did you get Halide?

None

Halide version

No response

Halide commit (if known)

No response

Target

No response

Operating system

No response

Additional context

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew user-visible features or improvements to existing features.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions