Skip to content

dialects: (affine) Add the VectorLoadOp and VectorStoreOp operations#5365

Open
jakedves wants to merge 4 commits intoxdslproject:mainfrom
jakedves:vector-ops
Open

dialects: (affine) Add the VectorLoadOp and VectorStoreOp operations#5365
jakedves wants to merge 4 commits intoxdslproject:mainfrom
jakedves:vector-ops

Conversation

@jakedves
Copy link
Collaborator

Adds the vector load/store ops to the affine dialect as in MLIR, with xDSL and MLIR roundtrip tests

jakedves and others added 3 commits October 14, 2025 16:16
Co-Authored-By: Nick Brown <11333808+mesham@users.noreply.github.com>
Co-Authored-By: Nick Brown <11333808+mesham@users.noreply.github.com>
Co-Authored-By: Nick Brown <11333808+mesham@users.noreply.github.com>
@jakedves jakedves self-assigned this Oct 14, 2025
@jakedves jakedves added the dialects Changes on the dialects label Oct 14, 2025
@codecov
Copy link

codecov bot commented Oct 14, 2025

Codecov Report

❌ Patch coverage is 61.29032% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.90%. Comparing base (ac2ee17) to head (26e7241).

Files with missing lines Patch % Lines
xdsl/dialects/affine.py 61.29% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5365      +/-   ##
==========================================
- Coverage   85.91%   85.90%   -0.02%     
==========================================
  Files         378      378              
  Lines       53986    54016      +30     
  Branches     6178     6181       +3     
==========================================
+ Hits        46384    46401      +17     
- Misses       6127     6140      +13     
  Partials     1475     1475              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

func.func @affine_vector_load() -> vector<8xf32> {
%0 = "test.op"() : () -> memref<100x100xf32>
// CHECK: %{{.*}} = "test.op"() : () -> memref<100x100xf32>
%1 = "affine.vector_load"(%0) <{map = affine_map<() -> (1, 2)>}> : (memref<100x100xf32>) -> vector<8xf32>
Copy link
Member

Choose a reason for hiding this comment

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

can you please add custom syntax for these?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is quite difficult to handle with the syntax so may have to come back to this later.

I think this would be simple with a way to parse the affine expressions which I think exists, but can't find the exact call to use.

Some reference test cases that work in MLIR:

%0 = memref.alloc() : memref<100x100xf32>
affine.for %i0 = 0 to 10 {
    affine.for %i1 = 0 to 16 step 4 {
        %1 = affine.vector_load %0[3, 7] : memref<100x100xf32>, vector<4xf32>
        %2 = affine.vector_load %0[%i0, %i1] : memref<100x100xf32>, vector<4xf32>
        %3 = affine.vector_load %0[%i0, 7] : memref<100x100xf32>, vector<4xf32>
        %4 = affine.vector_load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<4xf32>
        %5 = affine.vector_load %0[%i0, %i1 + 7] : memref<100x100xf32>, vector<4xf32>
        %6 = affine.vector_load %0[3 + %i1, %i1 + 7] : memref<100x100xf32>, vector<4xf32>
        %7 = affine.vector_load %0[3 + %i0 * 7 + %i1, 7] : memref<100x100xf32>, vector<4xf32>
        affine.vector_store %1, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>, vector<4xf32>
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

oh that's funky

Copy link
Member

Choose a reason for hiding this comment

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

I can sort of imagine how to do it, both in a hacky way and an unhacky way

Copy link
Member

Choose a reason for hiding this comment

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

The hacky way would be to do string substitution to map s0 to %i0 and so on

Copy link
Member

Choose a reason for hiding this comment

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

I just realized that our existing implementation of vector.transfer_read and vector.transfer_write, which are also supposed to support this system, are broken... It would be great to handle this properly. If you have the time to have a stab at this in a separate PR fixing the custom syntax in these ops that would be great, otherwise I'll try to have a go this weekend.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I could probably have a go but I'm not free for this until sometime next week

Copy link
Member

Choose a reason for hiding this comment

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

I finally have time, will look at it over the next week

Copy link
Member

Choose a reason for hiding this comment

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

I think I opened the PRs for the relevant helpers #5464, #5465, once these are merged can you please have a go at using the code for the custom syntax here?

Copy link
Member

Choose a reason for hiding this comment

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

Hi @jakedves! Happy new year :) Do you have some time to look at this in the next few weeks?

Comment on lines +401 to +409
memref: SSAValue,
indices: Sequence[SSAValue],
map: AffineMapAttr | None = None,
result_type: Attribute | None = None,
):
if not isa(memref_type := memref.type, MemRefType[TypeAttribute]):
raise ValueError(
"affine.vector_load memref operand must be of type MemRefType"
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
memref: SSAValue,
indices: Sequence[SSAValue],
map: AffineMapAttr | None = None,
result_type: Attribute | None = None,
):
if not isa(memref_type := memref.type, MemRefType[TypeAttribute]):
raise ValueError(
"affine.vector_load memref operand must be of type MemRefType"
)
memref: SSAValue[MemRefType],
indices: Sequence[SSAValue],
map: AffineMapAttr | None = None,
result_type: Attribute | None = None,
):

Possibly cleaner?

if map is None:
# Create identity map for memrefs with at least one dimension or () -> ()
# for zero-dimensional memrefs.
if not isinstance(memref_type := memref.type, MemRefType):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feels like the same could be done here

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

Labels

dialects Changes on the dialects

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants