Repository: xdslproject/xdsl
Pull request #4196: dialects: (vector) vector.fma expects vectors of floats
Author: login: superlopuh
Labels: name: dialects
description: Changes on the dialects
Created: 2025-04-07T20:52:13Z | Merged: 2025-04-08T17:03:17Z

Just tried to run our dialect tests through mlir-opt and failed, this constraint brings us in line with MLIR.


Diff:
diff --git a/tests/filecheck/dialects/vector/vector_fma_invalid.mlir b/tests/filecheck/dialects/vector/vector_fma_invalid.mlir
new file mode 100644
index 0000000000..796c5bb10b
--- /dev/null
+++ b/tests/filecheck/dialects/vector/vector_fma_invalid.mlir
@@ -0,0 +1,49 @@
+// RUN: xdsl-opt %s --verify-diagnostics --split-input-file | filecheck %s
+
+
+%0, %1 = "test.op"() : () -> (vector<2xindex>, vector<3xindex>)
+
+%2 = "vector.fma"(%0, %0, %1) : (vector<2xindex>, vector<2xindex>, vector<3xindex>) -> vector<2xindex>
+// CHECK: Unexpected attribute index
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<3xf32>)
+
+%2 = "vector.fma"(%0, %0, %1) : (vector<2xf32>, vector<2xf32>, vector<3xf32>) -> vector<2xf32>
+// CHECK: attribute vector<2xf32> expected from variable 'T', but got vector<3xf32>
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<2xf64>)
+
+%2 = "vector.fma"(%1, %1, %0) : (vector<2xf64>, vector<2xf64>, vector<2xf32>) -> vector<2xf64>
+// CHECK: attribute vector<2xf64> expected from variable 'T', but got vector<2xf32>
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<3xf32>)
+
+%2 = "vector.fma"(%1, %0, %0) : (vector<3xf32>, vector<2xf32>, vector<2xf32>) -> vector<2xf32>
+// CHECK: attribute vector<3xf32> expected from variable 'T', but got vector<2xf32>
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<2xf64>)
+
+%2 = "vector.fma"(%0, %1, %1) : (vector<2xf32>, vector<2xf64>, vector<2xf64>) -> vector<2xf64>
+// CHECK: attribute vector<2xf32> expected from variable 'T', but got vector<2xf64>
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<3xf32>)
+
+%2 = "vector.fma"(%0, %1, %0) : (vector<2xf32>, vector<3xf32>, vector<2xf32>) -> vector<2xf32>
+// CHECK: attribute vector<2xf32> expected from variable 'T', but got vector<3xf32>
+
+// -----
+
+%0, %1 = "test.op"() : () -> (vector<2xf32>, vector<2xf64>)
+
+%2 = "vector.fma"(%1, %0, %1) : (vector<2xf64>, vector<2xf32>, vector<2xf64>) -> vector<2xf64>
+// CHECK: attribute vector<2xf64> expected from variable 'T', but got vector<2xf32>
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_acc_shape_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_acc_shape_matching.mlir
deleted file mode 100644
index 4ca95639ed..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_acc_shape_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<3xindex>)
-
-  %2 = "vector.fma"(%0, %0, %1) : (vector<2xindex>, vector<2xindex>, vector<3xindex>) -> vector<2xindex>
-  // CHECK: attribute vector<2xindex> expected from variable 'T', but got vector<3xindex>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_acc_type_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_acc_type_matching.mlir
deleted file mode 100644
index 39992e8fbc..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_acc_type_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<2xi32>)
-
-  %2 = "vector.fma"(%1, %1, %0) : (vector<2xi32>, vector<2xi32>, vector<2xindex>) -> vector<2xi32>
-  // CHECK: attribute vector<2xi32> expected from variable 'T', but got vector<2xindex>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_lhs_shape_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_lhs_shape_matching.mlir
deleted file mode 100644
index b0a387831d..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_lhs_shape_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<3xindex>)
-
-  %2 = "vector.fma"(%1, %0, %0) : (vector<3xindex>, vector<2xindex>, vector<2xindex>) -> vector<2xindex>
-  // CHECK: attribute vector<3xindex> expected from variable 'T', but got vector<2xindex>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_lhs_type_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_lhs_type_matching.mlir
deleted file mode 100644
index 92bfc838a0..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_lhs_type_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<2xi32>)
-
-  %2 = "vector.fma"(%0, %1, %1) : (vector<2xindex>, vector<2xi32>, vector<2xi32>) -> vector<2xi32>
-  // CHECK: attribute vector<2xindex> expected from variable 'T', but got vector<2xi32>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_rhs_shape_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_rhs_shape_matching.mlir
deleted file mode 100644
index eb62f4a1d3..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_rhs_shape_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<3xindex>)
-
-  %2 = "vector.fma"(%0, %1, %0) : (vector<2xindex>, vector<3xindex>, vector<2xindex>) -> vector<2xindex>
-  // CHECK: attribute vector<2xindex> expected from variable 'T', but got vector<3xindex>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_fma_res_rhs_type_matching.mlir b/tests/filecheck/dialects/vector/vector_fma_res_rhs_type_matching.mlir
deleted file mode 100644
index 32289e90a3..0000000000
--- a/tests/filecheck/dialects/vector/vector_fma_res_rhs_type_matching.mlir
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: xdsl-opt %s --verify-diagnostics | filecheck %s
-
-"builtin.module"() ({
-
-  %0, %1 = "test.op"() : () -> (vector<2xindex>, vector<2xi32>)
-
-  %2 = "vector.fma"(%1, %0, %1) : (vector<2xi32>, vector<2xindex>, vector<2xi32>) -> vector<2xi32>
-  // CHECK: attribute vector<2xi32> expected from variable 'T', but got vector<2xindex>
-
-}) : () -> ()
diff --git a/tests/filecheck/dialects/vector/vector_ops.mlir b/tests/filecheck/dialects/vector/vector_ops.mlir
index 784cc06e8a..6107240dc2 100644
--- a/tests/filecheck/dialects/vector/vector_ops.mlir
+++ b/tests/filecheck/dialects/vector/vector_ops.mlir
@@ -1,10 +1,10 @@
 // RUN: XDSL_ROUNDTRIP
 
-func.func private @vector_test(%base : memref<4x4xindex>, %vec : vector<1xi1>, %i : index) {
+func.func private @vector_test(%base : memref<4x4xindex>, %vec : vector<1xi1>, %i : index, %fvec : vector<2xf32>) {
   %load = vector.load %base[%i, %i] : memref<4x4xindex>, vector<2xindex>
   vector.store %load, %base[%i, %i] : memref<4x4xindex>, vector<2xindex>
   %broadcast = vector.broadcast %i : index to vector<1xindex>
-  %fma = vector.fma %load, %load, %load : vector<2xindex>
+  %fma = vector.fma %fvec, %fvec, %fvec : vector<2xf32>
   %masked_load = vector.maskedload %base[%i, %i], %vec, %broadcast : memref<4x4xindex>, vector<1xi1>, vector<1xindex> into vector<1xindex>
   vector.maskedstore %base[%i, %i], %vec, %masked_load : memref<4x4xindex>, vector<1xi1>, vector<1xindex>
   "vector.print"(%masked_load) : (vector<1xindex>) -> ()
@@ -14,11 +14,11 @@ func.func private @vector_test(%base : memref<4x4xindex>, %vec : vector<1xi1>, %
 
 
 // CHECK:      builtin.module {
-// CHECK-NEXT:   func.func private @vector_test(%base : memref<4x4xindex>, %vec : vector<1xi1>, %i : index) {
+// CHECK-NEXT:   func.func private @vector_test(%base : memref<4x4xindex>, %vec : vector<1xi1>, %i : index, %fvec : vector<2xf32>) {
 // CHECK-NEXT:     %load = vector.load %base[%i, %i] : memref<4x4xindex>, vector<2xindex>
 // CHECK-NEXT:     vector.store %load, %base[%i, %i] : memref<4x4xindex>, vector<2xindex>
 // CHECK-NEXT:     %broadcast = vector.broadcast %i : index to vector<1xindex>
-// CHECK-NEXT:     %fma = vector.fma %load, %load, %load : vector<2xindex>
+// CHECK-NEXT:     %fma = vector.fma %fvec, %fvec, %fvec : vector<2xf32>
 // CHECK-NEXT:     %masked_load = vector.maskedload %base[%i, %i], %vec, %broadcast : memref<4x4xindex>, vector<1xi1>, vector<1xindex> into vector<1xindex>
 // CHECK-NEXT:     vector.maskedstore %base[%i, %i], %vec, %masked_load : memref<4x4xindex>, vector<1xi1>, vector<1xindex>
 // CHECK-NEXT:     "vector.print"(%masked_load) : (vector<1xindex>) -> ()
diff --git a/tests/filecheck/dialects/vector/vector_pure_ops.mlir b/tests/filecheck/dialects/vector/vector_pure_ops.mlir
index c113bdff1d..256c9db677 100644
--- a/tests/filecheck/dialects/vector/vector_pure_ops.mlir
+++ b/tests/filecheck/dialects/vector/vector_pure_ops.mlir
@@ -1,13 +1,13 @@
 // RUN: xdsl-opt %s -p cse | filecheck %s
 
-%m0, %i0 = "test.op"() : () -> (memref<4x4xindex>, index)
+%m0, %i0, %vf = "test.op"() : () -> (memref<4x4xindex>, index, vector<2xf32>)
 %load = vector.load %m0[%i0, %i0] : memref<4x4xindex>, vector<2xindex>
 vector.store %load, %m0[%i0, %i0] : memref<4x4xindex>, vector<2xindex>
 %broadcast = vector.broadcast %i0 : index to vector<1xindex>
-%fma = vector.fma %load, %load, %load : vector<2xindex>
+%fma = vector.fma %vf, %vf, %vf : vector<2xf32>
 %extract_op = "vector.extractelement"(%broadcast, %i0) : (vector<1xindex>, index) -> index
 "vector.insertelement"(%extract_op, %broadcast, %i0) : (index, vector<1xindex>, index) -> vector<1xindex>
 /// Check that unused results from vector.broadcast and vector.fma are eliminated
-// CHECK:       %m0, %i0 = "test.op"() : () -> (memref<4x4xindex>, index)
+// CHECK:       %m0, %i0, %vf = "test.op"() : () -> (memref<4x4xindex>, index, vector<2xf32>)
 // CHECK-NEXT:  %load = vector.load %m0[%i0, %i0] : memref<4x4xindex>, vector<2xindex>
 // CHECK-NEXT:  vector.store %load, %m0[%i0, %i0] : memref<4x4xindex>, vector<2xindex>
diff --git a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/fma.mlir b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/fma.mlir
new file mode 100644
index 0000000000..3db7f1bcc4
--- /dev/null
+++ b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/fma.mlir
@@ -0,0 +1,8 @@
+// RUN: xdsl-opt --print-op-generic %s | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt | filecheck %s
+// RUN: xdsl-opt %s | mlir-opt --mlir-print-op-generic --allow-unregistered-dialect | xdsl-opt | filecheck %s
+
+
+%vf = "test.op"() : () -> vector<2xf32>
+%fma = vector.fma %vf, %vf, %vf : vector<2xf32>
+
+// CHECK: %1 = vector.fma %0, %0, %0 : vector<2xf32>
diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py
index 03f5943bf4..ed19a606ee 100644
--- a/xdsl/dialects/vector.py
+++ b/xdsl/dialects/vector.py
@@ -4,6 +4,7 @@
 from typing import ClassVar
 
 from xdsl.dialects.builtin import (
+    AnyFloatConstr,
     IndexType,
     IndexTypeConstr,
     MemRefType,
@@ -18,7 +19,6 @@
 from xdsl.irdl import (
     IRDLOperation,
     VarConstraint,
-    base,
     irdl_op_definition,
     operand_def,
     opt_operand_def,
@@ -128,7 +128,7 @@ def get(source: Operation | SSAValue) -> BroadcastOp:
 class FMAOp(IRDLOperation):
     name = "vector.fma"
 
-    T: ClassVar = VarConstraint("T", base(VectorType))
+    T: ClassVar = VarConstraint("T", VectorType.constr(AnyFloatConstr))
 
     lhs = operand_def(T)
     rhs = operand_def(T)


Reviews:
user: login: superlopuh
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-07T22:11:39Z
user: login: math-fehr
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-08T03:15:46Z
user: login: alexarice
body: If the purpose of this was to bring us in line with mlir-opt should we not have a interop test? (Maybe I've misunderstood the purpose of this PR)
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-08T09:22:10Z
user: login: superlopuh
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T09:24:27Z

Review comments:
diff_hunk: @@ -128,7 +130,9 @@ def get(source: Operation | SSAValue) -> BroadcastOp:
 class FMAOp(IRDLOperation):
     name = "vector.fma"
 
-    T: ClassVar = VarConstraint("T", base(VectorType))
+    T: ClassVar = VarConstraint(
+        "T", ParamAttrConstraint(VectorType, (AnyAttr(), AnyFloatConstr, AnyAttr()))
+    )
path: xdsl/dialects/vector.py
user: login: superlopuh
body: Probably best for @math-fehr to merge this first, then use that here:

https://github.com/xdslproject/xdsl/pull/4191/files#diff-b8dee9509fcf97e7a54db20b56724fbe2905745d98c46d0e54547672203e198aR1093-R1108
created_at: 2025-04-07T22:11:39Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,49 @@
+// RUN: xdsl-opt %s --verify-diagnostics --split-input-file | filecheck %s
path: tests/filecheck/dialects/vector/vector_fma_invalid.mlir
user: login: alexarice
body: Is this file just the merging of the deleted files?
created_at: 2025-04-08T09:21:24Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,49 @@
+// RUN: xdsl-opt %s --verify-diagnostics --split-input-file | filecheck %s
path: tests/filecheck/dialects/vector/vector_fma_invalid.mlir
user: login: superlopuh
body: Yep and adding one new one for the fact that it's a float
created_at: 2025-04-08T09:24:26Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-04-07T21:10:33Z
body: ## [Codecov](https://app.codecov.io/gh/xdslproject/xdsl/pull/4196?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=xdslproject) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 88.92%. Comparing base [(`69ef195`)](https://app.codecov.io/gh/xdslproject/xdsl/commit/69ef195ef914ab56da5a8ed6a86ab6810b49ee7b?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=xdslproject) to head [(`62abebf`)](https://app.codecov.io/gh/xdslproject/xdsl/commit/62abebf8d3405b31ad4211b89f092f2cd1953db3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=xdslproject).
> Report is 454 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #4196      +/-   ##
==========================================
- Coverage   88.92%   88.92%   -0.01%     
==========================================
  Files         325      325              
  Lines       44345    44359      +14     
  Branches     5471     5471              
==========================================
+ Hits        39436    39448      +12     
- Misses       3563     3564       +1     
- Partials     1346     1347       +1     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/xdslproject/xdsl/pull/4196?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=xdslproject).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=xdslproject).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: superlopuh
created_at: 2025-04-08T09:29:31Z
body: You're right that we should have at least one test for mlir interop, I added one, but it's hard to have a test for the same exclusion of types, so it's just a single roundtrip test for 2xf32.
author_association: MEMBER