Skip to content

add_requirement() fails to transitively infer alignment #9328

Description

@mcourteaux

As #9327 is a problem, I was playing around with add_requirement() and set the alignment of extents, while equating stride to extents of lower dimensions to promise dense storage, like so:

      add_requirement(output.dim(0).extent() % bsx == 0);
      add_requirement(output.dim(1).extent() % bsy == 0);
      add_requirement(output.dim(1).stride() == output.dim(0).extent());
      add_requirement(output.dim(2).stride() == output.dim(0).extent() * output.dim(1).extent());

This emits the proper asserts 1 to 1. However, the generated code still seemed to not understand that output.dim(1).stride() must have the same alignment as output.dim(0).extent(), despite the fact that I required them to be equal.

Manually adding:

      add_requirement(output.dim(1).stride() % bsx == 0);
      add_requirement(output.dim(2).stride() % (bsx * bsy) == 0);

Clearly helped the generated code see more of the alignment. This should have been inferred automatically.

Activity

  1. mcourteaux commented on Aug 13, 2026

    @mcourteaux
    ContributorAuthor

    Personally, I'm much more in favor of promising dense storage with add_requirement() over fiddling with overwriting the stride with custom expressions like stride = stride / 16 * 16. To me, intuitively, the strides and extents etc are NOT in control by us, but by the calling code. You can pass a buffer with any configuration. So to me, those are read-only parameters to the pipeline. Setting them inside the schedule seems very counter-intuitive. I'd rather have them literally be read-only const Exprs inside those Buffers, on which we run a few checks to validate compatibility with the pipeline schedule. @abadams @alexreinking thoughts?

  2. alexreinking commented on Aug 13, 2026

    @alexreinking
    Member

    I agree with the core API usage issue. The setters are needlessly directional. If I have a matmul (C += A*B) pipeline, do I need to set the inner extent of A to match the outer extent of B and vice-versa? Plus, a declarative syntax obviates the need for hacky division tricks. You could write extent % 32 == 0 rather than extent = extent / 32 * 32. It's not even clear what that assignment means (as you observe).

    Only one caveat: moving this way is a breaking change for a lot of old code. I only counted ~100 uses internally and they're all about promising relationships between other min/extent/stride. So it's not an intractable port.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions