Fix Constexpr method receivers in dynamic control-flow regions - #3580
Open
nodeeeeee wants to merge 1 commit into
Open
Fix Constexpr method receivers in dynamic control-flow regions#3580nodeeeeee wants to merge 1 commit into
nodeeeeee wants to merge 1 commit into
Conversation
nodeeeeee
force-pushed
the
fix-branch-constexpr
branch
2 times, most recently
from
September 3, 2026 11:48
105dcf8 to
0caf304
Compare
nodeeeeee
force-pushed
the
fix-branch-constexpr
branch
from
September 3, 2026 11:50
0caf304 to
09e7dff
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
I encountered this while implementing FlashAttention. The implementation
naturally groups the load and MMA paths into JIT methods on a compile-time
configuration object, and selects between them using the runtime warp index. A
reduced version looks like this:
Here,
selfinFlashAttention.load()andFlashAttention.mma()is acompile-time method receiver. The
faparameter infa4_device_body()refersto the same kind of compile-time object, made explicit by its
Constexprannotation.
Writing the device body as an actual instance method makes this code compile,
but only because the compiler has a special case that excludes a receiver
whose name is literally
self. Passing the same object as a namedConstexpr[FlashAttention]parameter should have equivalent staging semantics,but currently does not.
Problem
CuTe DSL treats
Constexpr[T]parameters as compile-time Python meta values.They do not have an MLIR representation and must not become arguments or
results of runtime control-flow regions.
However, when a method is called through a
Constexprreceiver inside adynamic
if, the receiver is incorrectly captured as a region argument:The region analyzer currently treats the base object of every method call as a
mutable runtime value, except when its name is literally
self.Consequently,
receiveris added to the values carried through the dynamicif. Lowering then attempts to flatten the plain PythonReceiverinstanceinto MLIR values and fails with:
This means
self.method()works because of the existingselfspecial case,while an explicitly annotated
receiver: Constexpr[Receiver]does not, despitehaving the same staging semantics.
Root cause
Constexpris a property of the original function parameter binding. The ASTpreprocessor removes parameter annotations while transforming the function, so
the later control-flow region analysis no longer knows which names refer to
Constexprparameters.RegionAnalyzer.visit_Call()therefore sees only a method call on a Pythonobject and adds its receiver to
invoked_args.Fix
This change:
is_arg_annotation_constexpr()helper to recordConstexprparameter names in the preprocessing session.control-flow regions.
Normal runtime receivers and decomposable DSL values continue to use the
existing region argument handling.
Regression test
A regression test uses a deliberately non-MLIR-decomposable Python class as a
Constexprreceiver and calls one of its JIT methods inside a dynamicif.The test calls
cute.compile(), so it verifies the complete lowering path thatpreviously failed.
Validation
Both sides of the comparison used the same
nvidia-cutlass-dsl 4.8.0.dev0native runtime components and the same test.Before this change
Base commit:
59e3a333(v4.8.0dev-6)The failure occurs because
_ConstexprReceiveris included in the valuespassed through the dynamic
if.After this change
Commit:
740f0a6c(v4.8.0dev-7)The new regression test together with the existing structured control-flow
tests also passes:
The warnings are existing
SmemAllocatordeprecation warnings and areunrelated to this change.