Skip to content

Conversation

@Lunderberg
Copy link
Contributor

@Lunderberg Lunderberg commented Feb 28, 2024

  • The T.match_buffer at the start of a function may contain repeated use of the same data var. For example, a function that must accept two DLTensor objects with the same backing allocation.

  • The "buffer_bind_scope" is an older style of match buffer, and may be the point of definition for variables.

  • A BufferRealize node may act either as an annotation of an external buffer (which indices are used), or as a point of definition for a local buffer (allocation extents of that buffer).

@Lucien0
Copy link
Contributor

Lucien0 commented Mar 1, 2024

Hi @Lunderberg , I tested my cases with this pr, and they are all working properly now. Thanks for your help!

- The `T.match_buffer` at the start of a function may contain repeated
  use of the same data var.  For example, a function that must accept
  two `DLTensor` objects with the same backing allocation.

- The `"buffer_bind_scope"` is an older style of match buffer, and may
  be the point of definition for variables.
@Lunderberg Lunderberg force-pushed the tir_well_formed_bugfixes branch from 848d539 to 8ffcead Compare March 8, 2024 17:26
Copy link
Contributor

@slyubomirsky slyubomirsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to have a more systematic approach to a feature like points of definition in a MatchBuffer. I commented on some parts of the implementation that I couldn't entirely follow.

// tir::Var they annotate.
context = WithDef(iter_var.value(), path->Attr("node"));
context.push_back(WithDef(iter_var.value(), path->Attr("node")));
} else if (op->attr_key == attr::buffer_bind_scope) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth commenting that this acts as an older form of MatchBuffer, per the PR description.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and added a comment with description.

Visit(op->value, path->Attr("value"));

std::optional<DefContext<IterVar>> context = std::nullopt;
std::vector<std::variant<DefContext<IterVar>, DefContext<Var>>> context;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ever used? I don't see any reads from it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There aren't any reads from it, as it holds a scoped context manager. On destruction, the DefContext<T> object removes items from TIRVisitorWithPath::in_scope_definitions_, and calls the ExitDef handler of the child class.

Also, thank you for pointing this one out. When switching from std::optional to std::vector, I forgot to add a while(context.size()) context.pop_back(); loop in case child classes rely on ExitDef being called in the reverse order from EnterDef.

Visit(op->condition, path->Attr("condition"));
Visit(op->bounds, path->Attr("bounds"));
auto context = WithDef(op->buffer, path->Attr("buffer"));
auto context = WithDefIfUndefined(op->buffer->data, path->Attr("buffer")->Attr("data"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine this accounts for the case where a BufferRealize can act as a point of definition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct. In cases where the buffer's backing allocation is defined externally, the BufferRealize is an annotation of the bounds where the external buffer is accessed. Otherwise, BufferRealize is an allocation. Prior to this commit, only the external backing allocation was handled.

}
Visit(op->body, path->Attr("body"));

while (context.size()) {
Copy link
Contributor

@slyubomirsky slyubomirsky Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the change. It's probably worth also putting in a comment that this is to ensure that the defs expire, otherwise it seems like spooky action at a distance. Not 100% sure, as the name "DefContext" does imply that it's an RAII sort of thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I tried to follow the existing FooContext naming structure (e.g. arith::ConstraintContext).

Copy link
Contributor

@slyubomirsky slyubomirsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the clarifications. The changes seem reasonable and they address issues that have arisen elsewhere.

@Lunderberg Lunderberg merged commit 695f958 into apache:main Mar 14, 2024
@Lunderberg Lunderberg deleted the tir_well_formed_bugfixes branch March 14, 2024 10:51
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
)

* [TIR] Improve well-formed check's handling of match buffer

- The `T.match_buffer` at the start of a function may contain repeated
  use of the same data var.  For example, a function that must accept
  two `DLTensor` objects with the same backing allocation.

- The `"buffer_bind_scope"` is an older style of match buffer, and may
  be the point of definition for variables.

* Improved comment, added context.pop_back()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants