From 383fc9355e3cce05e6b628a33ab1cf9b1fea0004 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:16:01 +0100 Subject: [PATCH 01/16] dialects: (vector) Added stubs for transfer_read and transfer_write Fixed bug in TensorOrMemrefOf.verify (?) --- .../filecheck/dialects/vector/vector_ops.mlir | 7 +- xdsl/dialects/builtin.py | 4 +- xdsl/dialects/vector.py | 84 +++++++++++++++++++ 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/tests/filecheck/dialects/vector/vector_ops.mlir b/tests/filecheck/dialects/vector/vector_ops.mlir index 7d6d069aca..7d8fbf0cad 100644 --- a/tests/filecheck/dialects/vector/vector_ops.mlir +++ b/tests/filecheck/dialects/vector/vector_ops.mlir @@ -1,5 +1,5 @@ // RUN: XDSL_ROUNDTRIP - +#map = affine_map<(d0, d1) -> (d0)> builtin.module { func.func private @vector_test(%0 : memref<4x4xindex>, %1 : vector<1xi1>, %2 : index) { %3 = "vector.load"(%0, %2, %2) : (memref<4x4xindex>, index, index) -> vector<2xindex> @@ -10,6 +10,9 @@ builtin.module { "vector.maskedstore"(%0, %2, %2, %1, %6) : (memref<4x4xindex>, index, index, vector<1xi1>, vector<1xindex>) -> () "vector.print"(%6) : (vector<1xindex>) -> () %7 = "vector.create_mask"(%2) : (index) -> vector<2xi1> + %8 = "vector.transfer_read"(%0, %2, %2, %2) <{"in_bounds" = [true], "operandSegmentSizes" = array, "permutation_map" = #map}> : (memref<4x4xindex>, index, index, index) -> vector<4xindex> + "vector.transfer_write"(%8, %0, %2, %2) <{"in_bounds" = [true], "operandSegmentSizes" = array, "permutation_map" = #map}> : (vector<4xindex>, memref<4x4xindex>, index, index) -> () + func.return } } @@ -25,6 +28,8 @@ builtin.module { // CHECK-NEXT: "vector.maskedstore"(%0, %2, %2, %1, %6) : (memref<4x4xindex>, index, index, vector<1xi1>, vector<1xindex>) -> () // CHECK-NEXT: "vector.print"(%6) : (vector<1xindex>) -> () // CHECK-NEXT: %7 = "vector.create_mask"(%2) : (index) -> vector<2xi1> +// CHECK-NEXT: %8 = "vector.transfer_read"(%0, %2, %2, %2) <{"in_bounds" = [true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (memref<4x4xindex>, index, index, index) -> vector<4xindex> +// CHECK-NEXT: "vector.transfer_write"(%8, %0, %2, %2) <{"in_bounds" = [true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (vector<4xindex>, memref<4x4xindex>, index, index) -> () // CHECK-NEXT: func.return // CHECK-NEXT: } // CHECK-NEXT: } diff --git a/xdsl/dialects/builtin.py b/xdsl/dialects/builtin.py index e4bf295f56..95f9dac53d 100644 --- a/xdsl/dialects/builtin.py +++ b/xdsl/dialects/builtin.py @@ -1891,8 +1891,8 @@ def get_resolvers( } def verify(self, attr: Attribute, constraint_context: ConstraintContext) -> None: - if isinstance(attr, VectorType) or isinstance(attr, TensorType): - attr = cast(VectorType[Attribute] | TensorType[Attribute], attr) + if isinstance(attr, MemRefType) or isinstance(attr, TensorType): + attr = cast(MemRefType[Attribute] | TensorType[Attribute], attr) self.elem_constr.verify(attr.element_type, constraint_context) else: raise VerifyException(f"Expected tensor or memref type, got {attr}") diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 7432ba2442..3862ccae3e 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -3,8 +3,14 @@ from collections.abc import Sequence from xdsl.dialects.builtin import ( + I1, + AffineMapAttr, + ArrayAttr, + BoolAttr, IndexType, MemRefType, + TensorOrMemrefOf, + TensorType, VectorBaseTypeAndRankConstraint, VectorBaseTypeConstraint, VectorRankConstraint, @@ -13,9 +19,13 @@ ) from xdsl.ir import Attribute, Dialect, Operation, SSAValue from xdsl.irdl import ( + AttrSizedOperandSegments, IRDLOperation, irdl_op_definition, operand_def, + opt_operand_def, + opt_prop_def, + prop_def, result_def, traits_def, var_operand_def, @@ -292,6 +302,78 @@ def get(mask_operands: list[Operation | SSAValue]) -> CreatemaskOp: ) +@irdl_op_definition +class TransferReadOp(IRDLOperation): + name = "vector.transfer_read" + + source = operand_def(TensorOrMemrefOf(Attribute)) + indices = var_operand_def(IndexType) + padding = operand_def(Attribute) + mask = opt_operand_def(VectorType[I1]) + + permutation_map = prop_def(AffineMapAttr) + in_bounds = opt_prop_def(ArrayAttr[BoolAttr]) + + result = result_def(VectorType) + + irdl_options = [AttrSizedOperandSegments(as_property=True)] + + def verify_(self): + assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) + assert isa(self.result.type, VectorType[Attribute]) + # TODO verify. + + @staticmethod + def get( + source: SSAValue | Operation, + indices: Sequence[SSAValue | Operation], + padding: SSAValue | Operation, + result_type: Attribute, + mask: Sequence[SSAValue | Operation] | None = None, + permutation_map: AffineMapAttr | None = None, + in_bounds: ArrayAttr[BoolAttr] | None = None, + ): + return TransferReadOp.build( + operands=[source, indices, padding, mask], + result_types=[result_type], + properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, + ) + + +@irdl_op_definition +class TransferWriteOp(IRDLOperation): + name = "vector.transfer_write" + + vector = operand_def(VectorType[Attribute]) + source = operand_def(TensorOrMemrefOf(Attribute)) + indices = var_operand_def(IndexType) + mask = opt_operand_def(VectorType[I1]) + + in_bounds = prop_def(ArrayAttr[BoolAttr]) + permutation_map = prop_def(AffineMapAttr) + + irdl_options = [AttrSizedOperandSegments(as_property=True)] + + def verify_(self): + assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) + assert isa(self.vector.type, VectorType[Attribute]) + # TODO verify + + @staticmethod + def get( + vector: SSAValue | Operation, + source: SSAValue | Operation, + indices: Sequence[SSAValue | Operation], + mask: Sequence[SSAValue | Operation] | None = None, + permutation_map: AffineMapAttr | None = None, + in_bounds: ArrayAttr[BoolAttr] | None = None, + ): + return TransferWriteOp.build( + operands=[vector, source, indices, mask], + properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, + ) + + Vector = Dialect( "vector", [ @@ -303,6 +385,8 @@ def get(mask_operands: list[Operation | SSAValue]) -> CreatemaskOp: MaskedstoreOp, PrintOp, CreatemaskOp, + TransferReadOp, + TransferWriteOp, ], [], ) From 85a7c83b45f6f4980989cfa6a3c489f391ee87cd Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:26:46 +0000 Subject: [PATCH 02/16] Started working on verification of "vector.transfer_read" and "vector.transfer_write" ops This blew up and should now be several PRs --- tests/dialects/test_vector.py | 49 +++++++++++ xdsl/dialects/builtin.py | 19 +++-- xdsl/dialects/vector.py | 148 ++++++++++++++++++++++++++++++++-- xdsl/ir/affine/affine_expr.py | 11 +++ xdsl/ir/affine/affine_map.py | 36 ++++++++- 5 files changed, 248 insertions(+), 15 deletions(-) diff --git a/tests/dialects/test_vector.py b/tests/dialects/test_vector.py index 229b619f34..dec78d3a98 100644 --- a/tests/dialects/test_vector.py +++ b/tests/dialects/test_vector.py @@ -1,6 +1,7 @@ import pytest from xdsl.dialects.builtin import ( + AffineMapAttr, IndexType, IntAttr, MemRefType, @@ -18,8 +19,11 @@ MaskedstoreOp, PrintOp, StoreOp, + TransferReadOp, + TransferWriteOp, ) from xdsl.ir import Attribute, OpResult +from xdsl.ir.affine import AffineExpr, AffineMap from xdsl.utils.test_value import TestSSAValue @@ -517,3 +521,48 @@ def test_vector_create_mask_verify_indexing_exception(): match="Expected an operand value for each dimension of resultant mask.", ): create_mask.verify() + + +def test_vector_transfer_write_construction(): + x = AffineExpr.dimension(0) + vector_type = VectorType(IndexType(), [3]) + memref_type = MemRefType(IndexType(), [3, 3]) + permutation_map = AffineMapAttr(AffineMap(2, 0, (x,))) + + vector = TestSSAValue(vector_type) + source = TestSSAValue(memref_type) + index = TestSSAValue(IndexType()) + + transfer_write = TransferWriteOp( + vector, source, [index], permutation_map=permutation_map + ) + + assert transfer_write.vector is vector + assert transfer_write.source is source + assert len(transfer_write.indices) == 1 + assert transfer_write.indices[0] is index + assert transfer_write.permutation_map is permutation_map + + +def test_vector_transfer_read_construction(): + x = AffineExpr.dimension(0) + vector_type = VectorType(IndexType(), [3]) + memref_type = MemRefType(IndexType(), [3, 3]) + permutation_map = AffineMapAttr(AffineMap(2, 0, (x,))) + + source = TestSSAValue(memref_type) + index = TestSSAValue(IndexType()) + padding = TestSSAValue(IndexType()) + + transfer_read = TransferReadOp( + source, + [index], + padding, + vector_type, + permutation_map=permutation_map, + ) + + assert transfer_read.source is source + assert len(transfer_read.indices) == 1 + assert transfer_read.indices[0] is index + assert transfer_read.permutation_map is permutation_map diff --git a/xdsl/dialects/builtin.py b/xdsl/dialects/builtin.py index 95f9dac53d..837287725d 100644 --- a/xdsl/dialects/builtin.py +++ b/xdsl/dialects/builtin.py @@ -942,26 +942,33 @@ class VectorType( shape: ParameterDef[ArrayAttr[IntAttr]] element_type: ParameterDef[AttributeCovT] - num_scalable_dims: ParameterDef[IntAttr] + scalable_dims: ParameterDef[ArrayAttr[BoolAttr]] def __init__( self, element_type: AttributeCovT, shape: Iterable[int | IntAttr], - num_scalable_dims: int | IntAttr = 0, + scalable_dims: Sequence[bool] | ArrayAttr[BoolAttr] = [], ) -> None: shape = ArrayAttr( [IntAttr(dim) if isinstance(dim, int) else dim for dim in shape] ) - if isinstance(num_scalable_dims, int): - num_scalable_dims = IntAttr(num_scalable_dims) - super().__init__([shape, element_type, num_scalable_dims]) + + if not isa(scalable_dims, ArrayAttr[BoolAttr]): + assert isa(scalable_dims, Sequence[bool]) + scalable_dims = ArrayAttr( + [IntegerAttr.from_bool(value) for value in scalable_dims] + ) + super().__init__([shape, element_type, scalable_dims]) def get_num_dims(self) -> int: return len(self.shape.data) def get_num_scalable_dims(self) -> int: - return self.num_scalable_dims.data + return len(self.scalable_dims) + + def get_scalable_dims(self) -> tuple[bool, ...]: + return tuple(value.value.data == 1 for value in self.scalable_dims.data) def get_shape(self) -> tuple[int, ...]: return tuple(i.data for i in self.shape) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 3862ccae3e..f8a1c3bf85 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -5,9 +5,11 @@ from xdsl.dialects.builtin import ( I1, AffineMapAttr, + AnyFloat, ArrayAttr, BoolAttr, IndexType, + IntegerType, MemRefType, TensorOrMemrefOf, TensorType, @@ -18,6 +20,7 @@ i1, ) from xdsl.ir import Attribute, Dialect, Operation, SSAValue +from xdsl.ir.affine import AffineConstantExpr, AffineDimExpr, AffineMap from xdsl.irdl import ( AttrSizedOperandSegments, IRDLOperation, @@ -302,6 +305,137 @@ def get(mask_operands: list[Operation | SSAValue]) -> CreatemaskOp: ) +def verify_permutation_map( + op: TransferReadOp | TransferWriteOp, + permutation_map: AffineMap, +): + """ + TODO test + """ + + # This mirrors VectorOps.cpp -> verifyPermutationMap + seen: list[bool] = [False for _ in range(permutation_map.num_dims)] + + for expr in permutation_map.results: + if isa(expr, AffineConstantExpr): + if expr.value != 0: + raise VerifyException( + f'"{op.name}" requires a projected permutation_map (at most one dim or the zero constant can appear in each result)' + ) + continue + if not isa(expr, AffineDimExpr): + raise VerifyException( + f'"{op.name}" requires a projected permutation_map (at most one "dim or the zero constant can appear in each result)' + ) + if seen[expr.position]: + raise VerifyException( + f'"{op.name}" requires a permutation_map that is a permutation (found one dim used more than once)' + ) + seen[expr.position] = True + + +def verify_transfer_op( + op: TransferReadOp | TransferWriteOp, + shaped_type: MemRefType[Attribute] | TensorType[Attribute], + vector_type: VectorType[Attribute], + mask_type: VectorType[I1], + inferred_mask_type: VectorType[I1], + permutation_map: AffineMap, + in_bounds: ArrayAttr[BoolAttr], +): + """ + TODO test + """ + + # This mirrors VectorOps.cpp -> verifyTransferOp from MLIR + element_type = shaped_type.element_type + vector_element_type = vector_type.element_type + + if isa(element_type, VectorType[Attribute]): + # Memref or tensor has vector element type + # TODO verify vector element type + pass + else: + # Memref of tensor has scalar element type + if isa(vector_element_type, IndexType) and not isa(element_type, IndexType): + raise VerifyException( + "Element type of source is index, expected element type of vector also to be index" + ) + assert isa(vector_element_type, IntegerType | AnyFloat) + assert isa(element_type, IntegerType | AnyFloat) + + minor_size = ( + 1 if vector_type.get_num_dims() == 0 else vector_type.get_shape()[-1] + ) + result_vec_size = vector_element_type.bitwidth * minor_size + if result_vec_size % element_type.bitwidth != 0: + raise VerifyException( + f'"{op.name}" requires the bitwidth of the minor 1-D vector to be an integral multiple of the bitwidth of the source element type' + ) + + # Check that permutation map results match rank of vector type. + if len(permutation_map.results) != vector_type.get_num_dims(): + raise VerifyException( + f'"{op.name}" requires a permutation_map with result dims of the same rank as the vector type' + ) + + if permutation_map.num_symbols != 0: + raise VerifyException(f'"{op.name}" requires permutation_map without symbols') + + if permutation_map.num_dims != shaped_type.get_num_dims(): + raise VerifyException( + f'"{op.name}" requires a permutation_map with input dims of the same rank as the source type' + ) + + if mask_type is not None: + if mask_type != inferred_mask_type: + raise VerifyException( + f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' + ) + + if in_bounds is not None: + if len(in_bounds) != len(permutation_map.results): + raise VerifyException( + f'"{op.name}" expects the optional in_bounds attr of same rank as permutation_map results: {str(permutation_map)} vs in_bounds of of size {len(in_bounds)}' + ) + + for i in range(len(permutation_map.results)): + if ( + isa(permutation_map.results[i], AffineConstantExpr) + and not in_bounds.data[i].value.data + ): + raise VerifyException( + f'"{op.name}" requires broadcast dimensions to be in-bounds' + ) + + +def infer_transfer_op_mask_type( + vector_type: VectorType[Attribute], + affine_map: AffineMap, +): + """ + TODO test + """ + inverse_permutation_map = affine_map.compress_dims( + affine_map.get_unused_dims() + ).inverse_permutation() + + assert inverse_permutation_map is not None + + mask_shape = inverse_permutation_map.compose_with_values(vector_type.get_shape()) + + scalable_dims = inverse_permutation_map.eval( + [1 if dim_scalable else 0 for dim_scalable in vector_type.get_scalable_dims()], + [], + ) + + return VectorType( + i1, + mask_shape, + [dim_scalable == 1 for dim_scalable in scalable_dims], + ) + + @irdl_op_definition class TransferReadOp(IRDLOperation): name = "vector.transfer_read" @@ -321,10 +455,9 @@ class TransferReadOp(IRDLOperation): def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.result.type, VectorType[Attribute]) - # TODO verify. - @staticmethod - def get( + def __init__( + self, source: SSAValue | Operation, indices: Sequence[SSAValue | Operation], padding: SSAValue | Operation, @@ -333,7 +466,7 @@ def get( permutation_map: AffineMapAttr | None = None, in_bounds: ArrayAttr[BoolAttr] | None = None, ): - return TransferReadOp.build( + super().__init__( operands=[source, indices, padding, mask], result_types=[result_type], properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, @@ -357,10 +490,9 @@ class TransferWriteOp(IRDLOperation): def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.vector.type, VectorType[Attribute]) - # TODO verify - @staticmethod - def get( + def __init__( + self, vector: SSAValue | Operation, source: SSAValue | Operation, indices: Sequence[SSAValue | Operation], @@ -368,7 +500,7 @@ def get( permutation_map: AffineMapAttr | None = None, in_bounds: ArrayAttr[BoolAttr] | None = None, ): - return TransferWriteOp.build( + super().__init__( operands=[vector, source, indices, mask], properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, ) diff --git a/xdsl/ir/affine/affine_expr.py b/xdsl/ir/affine/affine_expr.py index eaa3c8178e..23c429be15 100644 --- a/xdsl/ir/affine/affine_expr.py +++ b/xdsl/ir/affine/affine_expr.py @@ -110,6 +110,17 @@ def eval(self, dims: Sequence[int], symbols: Sequence[int]) -> int: raise ValueError("Unreachable") + def is_function_of_dim(self, position: int) -> bool: + if isinstance(self, AffineDimExpr): + return self.position == position + + if isinstance(self, AffineBinaryOpExpr): + return self.lhs.is_function_of_dim(position) or self.rhs.is_function_of_dim( + position + ) + + return False + def _try_fold_constant( self, other: AffineExpr, kind: AffineBinaryOpKind ) -> AffineExpr | None: diff --git a/xdsl/ir/affine/affine_map.py b/xdsl/ir/affine/affine_map.py index 6baf554168..9491a3367c 100644 --- a/xdsl/ir/affine/affine_map.py +++ b/xdsl/ir/affine/affine_map.py @@ -4,8 +4,9 @@ from collections.abc import Callable, Sequence from dataclasses import dataclass from inspect import getfullargspec +from typing import cast -from xdsl.ir.affine import AffineDimExpr, AffineExpr +from xdsl.ir.affine import AffineConstantExpr, AffineDimExpr, AffineExpr AffineExprBuilderT = AffineExpr | int @@ -169,6 +170,19 @@ def compose(self, other: AffineMap) -> AffineMap: results=results, ) + def compose_with_values(self, values: Sequence[int]) -> tuple[int, ...]: + """ + TODO document + TODO test + Same as SmallVector AffineMap::compose(ArrayRef values) const from AffineMap.cpp + """ + assert self.num_symbols == 0 + expressions: list[AffineExpr] = [] + for value in values: + expressions.append(AffineExpr.constant(value)) + result_map = self.compose(AffineMap(0, 0, tuple(expressions))) + return tuple(cast(AffineConstantExpr, res).value for res in result_map.results) + def inverse_permutation(self) -> AffineMap | None: """ Returns a map of codomain to domain dimensions such that the first @@ -245,6 +259,26 @@ def compress_dims(self, selectors: Sequence[bool]) -> AffineMap: new_dims, new_symbols, result_num_dims, self.num_symbols ) + def is_function_of_dim(self, position: int) -> bool: + """ + TODO document + TODO test + """ + return any(result.is_function_of_dim(position) for result in self.results) + + def get_unused_dims(self) -> tuple[bool, ...]: + """ + TODO document + TODO test + """ + result: list[bool] = [True for _ in range(self.num_dims)] + + for dim in range(self.num_dims): + if self.is_function_of_dim(dim): + result[dim] = False + + return tuple(result) + def __str__(self) -> str: # Create comma seperated list of dims. dims = ["d" + str(i) for i in range(self.num_dims)] From c8ec10f3f4ae04988c0728e9582e024b98b2cd47 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:01:48 +0000 Subject: [PATCH 03/16] Continued working on verification of "vector.transfer_read" and "vector.transfer_write" ops --- xdsl/dialects/vector.py | 115 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index f8a1c3bf85..49ce2e77fe 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -1,5 +1,6 @@ from __future__ import annotations +from abc import ABC, abstractmethod from collections.abc import Sequence from xdsl.dialects.builtin import ( @@ -338,7 +339,7 @@ def verify_transfer_op( op: TransferReadOp | TransferWriteOp, shaped_type: MemRefType[Attribute] | TensorType[Attribute], vector_type: VectorType[Attribute], - mask_type: VectorType[I1], + mask_type: VectorType[I1] | None, inferred_mask_type: VectorType[I1], permutation_map: AffineMap, in_bounds: ArrayAttr[BoolAttr], @@ -436,8 +437,36 @@ def infer_transfer_op_mask_type( ) +class VectorTransferOp(ABC): + """ + TODO document + TODO test + Mirrors VectorTransferOpInterface from VectorInterfaces.h.inc + """ + + @abstractmethod + def get_permutation_map(self) -> AffineMap: + raise NotImplementedError() + + def is_broadcast_dim(self, dim: int) -> bool: + expr = self.get_permutation_map().results[dim] + if not isa(expr, AffineConstantExpr): + return False + return expr.value == 0 + + def has_broadcast_dim(self): + for dim in range(self.get_transfer_rank()): + if self.is_broadcast_dim(dim): + return True + + return False + + def get_transfer_rank(self) -> int: + return len(self.get_permutation_map().results) + + @irdl_op_definition -class TransferReadOp(IRDLOperation): +class TransferReadOp(IRDLOperation, VectorTransferOp): name = "vector.transfer_read" source = operand_def(TensorOrMemrefOf(Attribute)) @@ -455,6 +484,45 @@ class TransferReadOp(IRDLOperation): def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.result.type, VectorType[Attribute]) + if self.mask: + assert isa(self.mask.type, VectorType[I1]) + mask_type = self.mask.type + else: + mask_type = None + + if len(self.indices) != self.source.type.get_num_dims(): + raise VerifyException("Expected an index for each memref/tensor dimension.") + + inferred_mask_type = infer_transfer_op_mask_type( + self.result.type, + self.permutation_map.data, + ) + + verify_transfer_op( + self, + self.source.type, + self.result.type, + mask_type, + inferred_mask_type, + self.permutation_map.data, + self.in_bounds if self.in_bounds else ArrayAttr([]), + ) + + if isa(self.source.type.element_type, VectorType[Attribute]): + # TODO verify vector element type + pass + else: + # source memref/tensor has scalar element type + # TODO verify that padding type is a valid element_type for a vector + if self.source.type.element_type != self.padding.type: + raise VerifyException( + f'"{self.name}" requires formal padding and source of the same elemental type' + ) + + verify_permutation_map( + self, + self.permutation_map.data, + ) def __init__( self, @@ -472,9 +540,13 @@ def __init__( properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, ) + # override + def get_permutation_map(self): + return self.permutation_map.data + @irdl_op_definition -class TransferWriteOp(IRDLOperation): +class TransferWriteOp(IRDLOperation, VectorTransferOp): name = "vector.transfer_write" vector = operand_def(VectorType[Attribute]) @@ -490,6 +562,39 @@ class TransferWriteOp(IRDLOperation): def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.vector.type, VectorType[Attribute]) + if self.mask: + assert isa(self.mask.type, VectorType[I1]) + mask_type = self.mask.type + else: + mask_type = None + + if len(self.indices) != self.source.type.get_num_dims(): + raise VerifyException("Expected an index for each memref/tensor dimension.") + + if self.has_broadcast_dim(): + raise VerifyException( + f'"{self.name}" should not have broadcast dimensions.' + ) + + inferred_mask_type = infer_transfer_op_mask_type( + self.vector.type, + self.permutation_map.data, + ) + + verify_transfer_op( + self, + self.source.type, + self.vector.type, + mask_type, + inferred_mask_type, + self.permutation_map.data, + self.in_bounds, + ) + + verify_permutation_map( + self, + self.permutation_map.data, + ) def __init__( self, @@ -505,6 +610,10 @@ def __init__( properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, ) + # override + def get_permutation_map(self): + return self.permutation_map.data + Vector = Dialect( "vector", From ff8b9f9eff8ede74c8f68b424744f751712ebc28 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:07:03 +0000 Subject: [PATCH 04/16] Did some follow-up changes that resulted from VectorType expecting a ArrayAttr[BoolAttr] instead of a IntegerAttr --- tests/dialects/test_builtin.py | 33 +++++++++++++++++++-------------- xdsl/dialects/arith.py | 2 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/dialects/test_builtin.py b/tests/dialects/test_builtin.py index 1a983111fe..f622a4b249 100644 --- a/tests/dialects/test_builtin.py +++ b/tests/dialects/test_builtin.py @@ -321,37 +321,42 @@ def test_array_len_and_iter_attr(): @pytest.mark.parametrize( - "attr, dims, num_scalable_dims", + "attr, dims, scalable_dims", [ - (i32, (1, 2), 0), - (i32, (1, 2), 1), - (i32, (1, 1, 3), 0), - (i64, (1, 1, 3), 2), - (i64, (), 0), + (i32, (1, 2), (False, False)), + (i32, (1, 2), (True, False)), + (i32, (1, 1, 3), (False, False, False)), + (i64, (1, 1, 3), (True, True, False)), + (i64, (), ()), ], ) -def test_vector_constructor(attr: Attribute, dims: list[int], num_scalable_dims: int): - vec = VectorType(attr, dims, num_scalable_dims) +def test_vector_constructor( + attr: Attribute, dims: list[int], scalable_dims: list[bool] +): + vec = VectorType(attr, dims, scalable_dims) assert vec.get_num_dims() == len(dims) - assert vec.get_num_scalable_dims() == num_scalable_dims + assert vec.get_num_scalable_dims() == len(scalable_dims) + assert vec.get_scalable_dims() == ArrayAttr( + [IntegerAttr.from_bool(scalable) for scalable in scalable_dims] + ) assert vec.get_shape() == dims @pytest.mark.parametrize( - "dims, num_scalable_dims", + "dims, scalable_dims", [ ([], 1), - ([1, 2], 3), + ([1, 2], (True, True, True)), ([1], 2), ], ) -def test_vector_verifier_fail(dims: list[int], num_scalable_dims: int): +def test_vector_verifier_fail(dims: list[int], scalable_dims: list[bool]): with pytest.raises(VerifyException): - VectorType(i32, dims, num_scalable_dims) + VectorType(i32, dims, scalable_dims) with pytest.raises(VerifyException): - VectorType(i32, dims, -1) + VectorType(i32, dims, ()) def test_vector_rank_constraint_verify(): diff --git a/xdsl/dialects/arith.py b/xdsl/dialects/arith.py index 6850f33ffc..712fc8742a 100644 --- a/xdsl/dialects/arith.py +++ b/xdsl/dialects/arith.py @@ -437,7 +437,7 @@ def infer_overflow_type(input_type: Attribute) -> Attribute: return IntegerType(1) if isinstance(input_type, VectorType): return VectorType( - IntegerType(1), input_type.shape, input_type.num_scalable_dims + IntegerType(1), input_type.shape, input_type.scalable_dims ) if isinstance(input_type, UnrankedTensorType): return UnrankedTensorType(IntegerType(1)) From 9c87737e0f4897c5270633fb952cdb3e304df3b2 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:40:26 +0000 Subject: [PATCH 05/16] Reverted changes done to VectorType. vector.transfer_*: Disabled mask and inferred_mask comparison for now until VectorType is fixed --- tests/dialects/test_builtin.py | 33 +++++++++----------- xdsl/dialects/arith.py | 2 +- xdsl/dialects/builtin.py | 19 ++++-------- xdsl/dialects/vector.py | 55 +++++++++++++++++++++------------- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/tests/dialects/test_builtin.py b/tests/dialects/test_builtin.py index f622a4b249..1a983111fe 100644 --- a/tests/dialects/test_builtin.py +++ b/tests/dialects/test_builtin.py @@ -321,42 +321,37 @@ def test_array_len_and_iter_attr(): @pytest.mark.parametrize( - "attr, dims, scalable_dims", + "attr, dims, num_scalable_dims", [ - (i32, (1, 2), (False, False)), - (i32, (1, 2), (True, False)), - (i32, (1, 1, 3), (False, False, False)), - (i64, (1, 1, 3), (True, True, False)), - (i64, (), ()), + (i32, (1, 2), 0), + (i32, (1, 2), 1), + (i32, (1, 1, 3), 0), + (i64, (1, 1, 3), 2), + (i64, (), 0), ], ) -def test_vector_constructor( - attr: Attribute, dims: list[int], scalable_dims: list[bool] -): - vec = VectorType(attr, dims, scalable_dims) +def test_vector_constructor(attr: Attribute, dims: list[int], num_scalable_dims: int): + vec = VectorType(attr, dims, num_scalable_dims) assert vec.get_num_dims() == len(dims) - assert vec.get_num_scalable_dims() == len(scalable_dims) - assert vec.get_scalable_dims() == ArrayAttr( - [IntegerAttr.from_bool(scalable) for scalable in scalable_dims] - ) + assert vec.get_num_scalable_dims() == num_scalable_dims assert vec.get_shape() == dims @pytest.mark.parametrize( - "dims, scalable_dims", + "dims, num_scalable_dims", [ ([], 1), - ([1, 2], (True, True, True)), + ([1, 2], 3), ([1], 2), ], ) -def test_vector_verifier_fail(dims: list[int], scalable_dims: list[bool]): +def test_vector_verifier_fail(dims: list[int], num_scalable_dims: int): with pytest.raises(VerifyException): - VectorType(i32, dims, scalable_dims) + VectorType(i32, dims, num_scalable_dims) with pytest.raises(VerifyException): - VectorType(i32, dims, ()) + VectorType(i32, dims, -1) def test_vector_rank_constraint_verify(): diff --git a/xdsl/dialects/arith.py b/xdsl/dialects/arith.py index 712fc8742a..6850f33ffc 100644 --- a/xdsl/dialects/arith.py +++ b/xdsl/dialects/arith.py @@ -437,7 +437,7 @@ def infer_overflow_type(input_type: Attribute) -> Attribute: return IntegerType(1) if isinstance(input_type, VectorType): return VectorType( - IntegerType(1), input_type.shape, input_type.scalable_dims + IntegerType(1), input_type.shape, input_type.num_scalable_dims ) if isinstance(input_type, UnrankedTensorType): return UnrankedTensorType(IntegerType(1)) diff --git a/xdsl/dialects/builtin.py b/xdsl/dialects/builtin.py index 837287725d..95f9dac53d 100644 --- a/xdsl/dialects/builtin.py +++ b/xdsl/dialects/builtin.py @@ -942,33 +942,26 @@ class VectorType( shape: ParameterDef[ArrayAttr[IntAttr]] element_type: ParameterDef[AttributeCovT] - scalable_dims: ParameterDef[ArrayAttr[BoolAttr]] + num_scalable_dims: ParameterDef[IntAttr] def __init__( self, element_type: AttributeCovT, shape: Iterable[int | IntAttr], - scalable_dims: Sequence[bool] | ArrayAttr[BoolAttr] = [], + num_scalable_dims: int | IntAttr = 0, ) -> None: shape = ArrayAttr( [IntAttr(dim) if isinstance(dim, int) else dim for dim in shape] ) - - if not isa(scalable_dims, ArrayAttr[BoolAttr]): - assert isa(scalable_dims, Sequence[bool]) - scalable_dims = ArrayAttr( - [IntegerAttr.from_bool(value) for value in scalable_dims] - ) - super().__init__([shape, element_type, scalable_dims]) + if isinstance(num_scalable_dims, int): + num_scalable_dims = IntAttr(num_scalable_dims) + super().__init__([shape, element_type, num_scalable_dims]) def get_num_dims(self) -> int: return len(self.shape.data) def get_num_scalable_dims(self) -> int: - return len(self.scalable_dims) - - def get_scalable_dims(self) -> tuple[bool, ...]: - return tuple(value.value.data == 1 for value in self.scalable_dims.data) + return self.num_scalable_dims.data def get_shape(self) -> tuple[int, ...]: return tuple(i.data for i in self.shape) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 49ce2e77fe..964afaecd2 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -340,13 +340,15 @@ def verify_transfer_op( shaped_type: MemRefType[Attribute] | TensorType[Attribute], vector_type: VectorType[Attribute], mask_type: VectorType[I1] | None, - inferred_mask_type: VectorType[I1], + inferred_mask_type: VectorType[I1] | None, permutation_map: AffineMap, in_bounds: ArrayAttr[BoolAttr], ): """ TODO test """ + # WJOG9GVF + # TODO fix: remove None type from inferred_mask_type once 7S4F0FZA has been fixed # This mirrors VectorOps.cpp -> verifyTransferOp from MLIR element_type = shaped_type.element_type @@ -388,11 +390,15 @@ def verify_transfer_op( f'"{op.name}" requires a permutation_map with input dims of the same rank as the source type' ) - if mask_type is not None: - if mask_type != inferred_mask_type: - raise VerifyException( - f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' - ) + # WJOG9GVF + # TODO fix: uncomment this when 7S4F0FZA has been fixed + + # See 7S4F0FZA for more information + # if mask_type: + # if mask_type != inferred_mask_type: + # raise VerifyException( + # f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' + # ) if in_bounds is not None: if len(in_bounds) != len(permutation_map.results): @@ -413,28 +419,35 @@ def verify_transfer_op( def infer_transfer_op_mask_type( vector_type: VectorType[Attribute], affine_map: AffineMap, -): +) -> VectorType[I1] | None: """ TODO test """ - inverse_permutation_map = affine_map.compress_dims( - affine_map.get_unused_dims() - ).inverse_permutation() - assert inverse_permutation_map is not None + # 7S4F0FZA + # TODO uncomment and test this once VectorType has been fixed, see issue #3654 + # When you do this also fix all WJOG9GVF + + # inverse_permutation_map = affine_map.compress_dims( + # affine_map.get_unused_dims() + # ).inverse_permutation() + + # assert inverse_permutation_map is not None + + # mask_shape = inverse_permutation_map.compose_with_values(vector_type.get_shape()) - mask_shape = inverse_permutation_map.compose_with_values(vector_type.get_shape()) + # scalable_dims = inverse_permutation_map.eval( + # [1 if dim_scalable else 0 for dim_scalable in vector_type.get_scalable_dims()], + # [], + # ) - scalable_dims = inverse_permutation_map.eval( - [1 if dim_scalable else 0 for dim_scalable in vector_type.get_scalable_dims()], - [], - ) + # return VectorType( + # i1, + # mask_shape, + # [dim_scalable == 1 for dim_scalable in scalable_dims], + # ) - return VectorType( - i1, - mask_shape, - [dim_scalable == 1 for dim_scalable in scalable_dims], - ) + return None class VectorTransferOp(ABC): From 77d8acbdd36149963c4a28316ea4f439269fd469 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:54:36 +0000 Subject: [PATCH 06/16] Fixed bugs for vector.transfer_* --- tests/dialects/test_vector.py | 16 +++++++++++---- xdsl/dialects/vector.py | 38 ++++++++++++++++++----------------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/tests/dialects/test_vector.py b/tests/dialects/test_vector.py index dec78d3a98..e7573aac8b 100644 --- a/tests/dialects/test_vector.py +++ b/tests/dialects/test_vector.py @@ -527,6 +527,7 @@ def test_vector_transfer_write_construction(): x = AffineExpr.dimension(0) vector_type = VectorType(IndexType(), [3]) memref_type = MemRefType(IndexType(), [3, 3]) + # (x, y) -> x permutation_map = AffineMapAttr(AffineMap(2, 0, (x,))) vector = TestSSAValue(vector_type) @@ -534,12 +535,17 @@ def test_vector_transfer_write_construction(): index = TestSSAValue(IndexType()) transfer_write = TransferWriteOp( - vector, source, [index], permutation_map=permutation_map + vector, + source, + [index, index], + permutation_map=permutation_map, ) + transfer_write.verify() + assert transfer_write.vector is vector assert transfer_write.source is source - assert len(transfer_write.indices) == 1 + assert len(transfer_write.indices) == 2 assert transfer_write.indices[0] is index assert transfer_write.permutation_map is permutation_map @@ -556,13 +562,15 @@ def test_vector_transfer_read_construction(): transfer_read = TransferReadOp( source, - [index], + [index, index], padding, vector_type, permutation_map=permutation_map, ) + transfer_read.verify() + assert transfer_read.source is source - assert len(transfer_read.indices) == 1 + assert len(transfer_read.indices) == 2 assert transfer_read.indices[0] is index assert transfer_read.permutation_map is permutation_map diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 964afaecd2..2d9393f945 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -342,7 +342,7 @@ def verify_transfer_op( mask_type: VectorType[I1] | None, inferred_mask_type: VectorType[I1] | None, permutation_map: AffineMap, - in_bounds: ArrayAttr[BoolAttr], + in_bounds: ArrayAttr[BoolAttr] | None, ): """ TODO test @@ -360,21 +360,23 @@ def verify_transfer_op( pass else: # Memref of tensor has scalar element type - if isa(vector_element_type, IndexType) and not isa(element_type, IndexType): - raise VerifyException( - "Element type of source is index, expected element type of vector also to be index" - ) - assert isa(vector_element_type, IntegerType | AnyFloat) - assert isa(element_type, IntegerType | AnyFloat) + if isa(vector_element_type, IndexType): + if not isa(element_type, IndexType): + raise VerifyException( + "Element type of source is index, expected element type of vector also to be index" + ) + else: + assert isa(vector_element_type, IntegerType | AnyFloat) + assert isa(element_type, IntegerType | AnyFloat) - minor_size = ( - 1 if vector_type.get_num_dims() == 0 else vector_type.get_shape()[-1] - ) - result_vec_size = vector_element_type.bitwidth * minor_size - if result_vec_size % element_type.bitwidth != 0: - raise VerifyException( - f'"{op.name}" requires the bitwidth of the minor 1-D vector to be an integral multiple of the bitwidth of the source element type' + minor_size = ( + 1 if vector_type.get_num_dims() == 0 else vector_type.get_shape()[-1] ) + result_vec_size = vector_element_type.bitwidth * minor_size + if result_vec_size % element_type.bitwidth != 0: + raise VerifyException( + f'"{op.name}" requires the bitwidth of the minor 1-D vector to be an integral multiple of the bitwidth of the source element type' + ) # Check that permutation map results match rank of vector type. if len(permutation_map.results) != vector_type.get_num_dims(): @@ -400,7 +402,7 @@ def verify_transfer_op( # f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' # ) - if in_bounds is not None: + if in_bounds: if len(in_bounds) != len(permutation_map.results): raise VerifyException( f'"{op.name}" expects the optional in_bounds attr of same rank as permutation_map results: {str(permutation_map)} vs in_bounds of of size {len(in_bounds)}' @@ -432,7 +434,7 @@ def infer_transfer_op_mask_type( # affine_map.get_unused_dims() # ).inverse_permutation() - # assert inverse_permutation_map is not None + # assert inverse_permutation_map # mask_shape = inverse_permutation_map.compose_with_values(vector_type.get_shape()) @@ -518,7 +520,7 @@ def verify_(self): mask_type, inferred_mask_type, self.permutation_map.data, - self.in_bounds if self.in_bounds else ArrayAttr([]), + self.in_bounds, ) if isa(self.source.type.element_type, VectorType[Attribute]): @@ -567,7 +569,7 @@ class TransferWriteOp(IRDLOperation, VectorTransferOp): indices = var_operand_def(IndexType) mask = opt_operand_def(VectorType[I1]) - in_bounds = prop_def(ArrayAttr[BoolAttr]) + in_bounds = opt_prop_def(ArrayAttr[BoolAttr]) permutation_map = prop_def(AffineMapAttr) irdl_options = [AttrSizedOperandSegments(as_property=True)] From b7f554cde42a756c6e709a018c2bda55ab556abf Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:27:32 +0000 Subject: [PATCH 07/16] Did some refactoring in affine_map and affine_expr --- xdsl/ir/affine/affine_expr.py | 14 +++----------- xdsl/ir/affine/affine_map.py | 26 +++++++++++--------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/xdsl/ir/affine/affine_expr.py b/xdsl/ir/affine/affine_expr.py index 23c429be15..ef9ef8f716 100644 --- a/xdsl/ir/affine/affine_expr.py +++ b/xdsl/ir/affine/affine_expr.py @@ -110,17 +110,6 @@ def eval(self, dims: Sequence[int], symbols: Sequence[int]) -> int: raise ValueError("Unreachable") - def is_function_of_dim(self, position: int) -> bool: - if isinstance(self, AffineDimExpr): - return self.position == position - - if isinstance(self, AffineBinaryOpExpr): - return self.lhs.is_function_of_dim(position) or self.rhs.is_function_of_dim( - position - ) - - return False - def _try_fold_constant( self, other: AffineExpr, kind: AffineBinaryOpKind ) -> AffineExpr | None: @@ -282,6 +271,9 @@ def dfs(self) -> Iterator[AffineExpr]: def used_dims(self) -> set[int]: return {expr.position for expr in self.dfs() if isinstance(expr, AffineDimExpr)} + def is_function_of_dim(self, position: int) -> bool: + return position in self.used_dims() + class AffineBinaryOpKind(Enum): """Enum for the kind of storage node used in AffineExpr.""" diff --git a/xdsl/ir/affine/affine_map.py b/xdsl/ir/affine/affine_map.py index 9491a3367c..fc42a81321 100644 --- a/xdsl/ir/affine/affine_map.py +++ b/xdsl/ir/affine/affine_map.py @@ -260,24 +260,20 @@ def compress_dims(self, selectors: Sequence[bool]) -> AffineMap: ) def is_function_of_dim(self, position: int) -> bool: - """ - TODO document - TODO test - """ - return any(result.is_function_of_dim(position) for result in self.results) + return position in self.used_dims() - def get_unused_dims(self) -> tuple[bool, ...]: - """ - TODO document - TODO test - """ - result: list[bool] = [True for _ in range(self.num_dims)] + def used_dims(self) -> set[int]: + result: set[int] = set() + + for expr in self.results: + result = result.union(expr.used_dims()) + + return result - for dim in range(self.num_dims): - if self.is_function_of_dim(dim): - result[dim] = False + def unused_dims(self) -> set[int]: + dims = {i for i in range(self.num_dims)} - return tuple(result) + return dims.difference(self.used_dims()) def __str__(self) -> str: # Create comma seperated list of dims. From 0013c20963c26597bd7dfc7a3ffd863eb447b4e9 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:28:21 +0000 Subject: [PATCH 08/16] Added tests for newly added functions in affine_map.py and affine_expr.py --- tests/test_affine_builtins.py | 37 ++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/test_affine_builtins.py b/tests/test_affine_builtins.py index bf50e0c041..047b3a51b8 100644 --- a/tests/test_affine_builtins.py +++ b/tests/test_affine_builtins.py @@ -212,8 +212,43 @@ def test_compress_dims(): ) == AffineMap.from_callable(lambda d0, d1: (d1, d1)) -def test_used_dims(): +def test_affine_expr_used_dims(): assert AffineExpr.dimension(1).used_dims() == {1} assert (AffineExpr.dimension(2) + AffineExpr.dimension(3)).used_dims() == {2, 3} assert AffineExpr.symbol(4).used_dims() == set() assert AffineExpr.constant(5).used_dims() == set() + + +def test_affine_expr_is_function_of_dim(): + assert AffineExpr.dimension(0).is_function_of_dim(0) + assert not AffineExpr.dimension(1).is_function_of_dim(0) + assert not AffineExpr.constant(0).is_function_of_dim(0) + assert not AffineExpr.symbol(0).is_function_of_dim(0) + assert AffineMap(2, 0, (AffineExpr.dimension(0),)).results[0].is_function_of_dim(0) + assert not ( + AffineMap(2, 0, (AffineExpr.dimension(0),)).results[0].is_function_of_dim(1) + ) + assert ( + AffineMap.from_callable(lambda i, j: (i + j,)).results[0].is_function_of_dim(0) + ) + assert ( + AffineMap.from_callable(lambda i, j: (i + j,)).results[0].is_function_of_dim(1) + ) + + +def test_affine_map_is_function_of_dim(): + assert AffineMap.from_callable(lambda i, j: (i, j)).is_function_of_dim(0) + assert AffineMap.from_callable(lambda i, j: (i, j)).is_function_of_dim(1) + assert not AffineMap.from_callable(lambda i, j, _: (i, j)).is_function_of_dim(2) + + +def test_affine_map_used_dims(): + assert AffineMap.from_callable(lambda i, j: (i, j)).used_dims() == {0, 1} + assert AffineMap.from_callable(lambda i, j, _: (i + j,)).used_dims() == {0, 1} + assert AffineMap.from_callable(lambda i, _, k: (i, k)).used_dims() == {0, 2} + + +def test_affine_map_unused_dims(): + assert AffineMap.from_callable(lambda i, j: (i, j)).unused_dims() == set() + assert AffineMap.from_callable(lambda i, j, _: (i + j,)).unused_dims() == {2} + assert AffineMap.from_callable(lambda i, _, k: (i, k)).unused_dims() == {1} From 9217d31b364c2885ec193be866a1c59a9c29b930 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:33:08 +0000 Subject: [PATCH 09/16] Added unused_dims_bit_vector function to AffineMap --- tests/test_affine_builtins.py | 6 ++++++ xdsl/dialects/vector.py | 3 +-- xdsl/ir/affine/affine_map.py | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/test_affine_builtins.py b/tests/test_affine_builtins.py index 047b3a51b8..93fd248bb2 100644 --- a/tests/test_affine_builtins.py +++ b/tests/test_affine_builtins.py @@ -252,3 +252,9 @@ def test_affine_map_unused_dims(): assert AffineMap.from_callable(lambda i, j: (i, j)).unused_dims() == set() assert AffineMap.from_callable(lambda i, j, _: (i + j,)).unused_dims() == {2} assert AffineMap.from_callable(lambda i, _, k: (i, k)).unused_dims() == {1} + + +def test_unused_dims_bit_vector(): + assert AffineMap.from_callable(lambda i, j: (i, j)).unused_dims_bit_vector() == (False, False) + assert AffineMap.from_callable(lambda i, j, _: (i + j,)).unused_dims_bit_vector() == (False, False, True) + assert AffineMap.from_callable(lambda i, _, k: (i, k)).unused_dims_bit_vector() == (False, True, False) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 2d9393f945..d21168c6d2 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -417,7 +417,6 @@ def verify_transfer_op( f'"{op.name}" requires broadcast dimensions to be in-bounds' ) - def infer_transfer_op_mask_type( vector_type: VectorType[Attribute], affine_map: AffineMap, @@ -431,7 +430,7 @@ def infer_transfer_op_mask_type( # When you do this also fix all WJOG9GVF # inverse_permutation_map = affine_map.compress_dims( - # affine_map.get_unused_dims() + # affine_map.unused_dims_bit_vector() # ).inverse_permutation() # assert inverse_permutation_map diff --git a/xdsl/ir/affine/affine_map.py b/xdsl/ir/affine/affine_map.py index fc42a81321..ca39f0d461 100644 --- a/xdsl/ir/affine/affine_map.py +++ b/xdsl/ir/affine/affine_map.py @@ -275,6 +275,10 @@ def unused_dims(self) -> set[int]: return dims.difference(self.used_dims()) + def unused_dims_bit_vector(self) -> tuple[bool, ...]: + unused_dims = self.unused_dims() + return tuple(True if position in unused_dims else False for position in range(self.num_dims)) + def __str__(self) -> str: # Create comma seperated list of dims. dims = ["d" + str(i) for i in range(self.num_dims)] From a78a39b215f4f84cac3b3468671cc831df74c3ac Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:56:22 +0000 Subject: [PATCH 10/16] Fixed formatting --- tests/test_affine_builtins.py | 15 ++++++++++++--- xdsl/ir/affine/affine_map.py | 5 ++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_affine_builtins.py b/tests/test_affine_builtins.py index 93fd248bb2..03b0318223 100644 --- a/tests/test_affine_builtins.py +++ b/tests/test_affine_builtins.py @@ -255,6 +255,15 @@ def test_affine_map_unused_dims(): def test_unused_dims_bit_vector(): - assert AffineMap.from_callable(lambda i, j: (i, j)).unused_dims_bit_vector() == (False, False) - assert AffineMap.from_callable(lambda i, j, _: (i + j,)).unused_dims_bit_vector() == (False, False, True) - assert AffineMap.from_callable(lambda i, _, k: (i, k)).unused_dims_bit_vector() == (False, True, False) + assert AffineMap.from_callable(lambda i, j: (i, j)).unused_dims_bit_vector() == ( + False, + False, + ) + assert AffineMap.from_callable( + lambda i, j, _: (i + j,) + ).unused_dims_bit_vector() == (False, False, True) + assert AffineMap.from_callable(lambda i, _, k: (i, k)).unused_dims_bit_vector() == ( + False, + True, + False, + ) diff --git a/xdsl/ir/affine/affine_map.py b/xdsl/ir/affine/affine_map.py index ca39f0d461..9f4e4c63c8 100644 --- a/xdsl/ir/affine/affine_map.py +++ b/xdsl/ir/affine/affine_map.py @@ -277,7 +277,10 @@ def unused_dims(self) -> set[int]: def unused_dims_bit_vector(self) -> tuple[bool, ...]: unused_dims = self.unused_dims() - return tuple(True if position in unused_dims else False for position in range(self.num_dims)) + return tuple( + True if position in unused_dims else False + for position in range(self.num_dims) + ) def __str__(self) -> str: # Create comma seperated list of dims. From 7874eb6b30711ab8b898cb420d7154f265e14284 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:22:57 +0000 Subject: [PATCH 11/16] Transferred a bunch of lit tests for vector.transfer_* ops from MLIR --- .../vector/vector_transfer_read_verify.mlir | 43 ++++++++++++++++ .../vector/vector_transfer_write_verify.mlir | 49 +++++++++++++++++++ .../with-mlir/dialects/vector/ops.mlir | 25 ++++++++-- xdsl/dialects/vector.py | 12 +++-- 4 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir create mode 100644 tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir diff --git a/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir b/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir new file mode 100644 index 0000000000..f46195c84a --- /dev/null +++ b/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir @@ -0,0 +1,43 @@ +// RUN: xdsl-opt --split-input-file --verify-diagnostics %s | filecheck %s + +%source, %index, %padding = "test.op"() : () -> (vector<4x3xf32>, index, f32) +"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, index, index, f32) -> vector<1x1x2x3xf32> +// CHECK: Expected tensor or memref type + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (memref, index, index, index, f32) -> vector<128xf32> +// CHECK: Expected an index for each memref/tensor dimension. + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK: requires a permutation_map with input dims of the same rank as the source type + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK: requires a permutation_map with result dims of the same rank as the vector type + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) + +// ----- + +%source, %index, %padding = "test.op"() : () -> (memref, index, f32) +"vector.transfer_read"(%source, %index, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (memref, index, index, index, f32) -> vector<3x7xf32> +// CHECK: requires a permutation_map that is a permutation (found one dim used more than once) + +// TODO transfer other tests from mlir/test/Dialect/Vector/invalid.mlir once verification for vector element types is implemented diff --git a/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir b/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir new file mode 100644 index 0000000000..aebc36acb2 --- /dev/null +++ b/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir @@ -0,0 +1,49 @@ +// RUN: xdsl-opt --split-input-file --verify-diagnostics %s | filecheck %s + +%source, %index = "test.op"() : () -> (vector<4x3xf32>, index) +"vector.transfer_write"(%source, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, vector<4x3xf32>, index, index) -> () +// CHECK: Expected tensor or memref type + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<128xf32>, memref, index, index, index) -> () +// CHECK: Expected an index for each memref/tensor dimension + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (vector<128xf32>, memref, index, index) -> () +// CHECK: requires a permutation_map with input dims of the same rank as the source type + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<128xf32>, memref, index, index) -> () +// CHECK: requires a permutation_map with result dims of the same rank as the vector type + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (vector<128xf32>, memref, index, index) -> () +// CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (vector<128xf32>, memref, index, index) -> () +// CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<3x7xf32>, index) +"vector.transfer_write"(%vector, %source, %index, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (vector<3x7xf32>, memref, index, index, index) -> () +// CHECK: requires a permutation_map that is a permutation (found one dim used more than once) + +// ----- + +%source, %vector, %index = "test.op"() : () -> (memref, vector<7xf32>, index) +"vector.transfer_write"(%vector, %source, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (0)>}> : (vector<7xf32>, memref, index) -> () +// CHECK: requires a permutation_map that is a permutation (found one dim used more than once) + +// TODO transfer other tests from mlir/test/Dialect/Vector/invalid.mlir once verification for vector element types is implemented diff --git a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir index e4c2d5649c..eb5c5c6a8b 100644 --- a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir +++ b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir @@ -1,8 +1,7 @@ -// RUN: xdsl-opt --print-op-generic %s | mlir-opt --mlir-print-op-generic | xdsl-opt --print-op-generic | filecheck %s +// RUN: xdsl-opt --split-input-file --print-op-generic %s | mlir-opt --mlir-print-op-generic | xdsl-opt --print-op-generic | filecheck %s -builtin.module{ -%vector0, %vector1, %i0 = "test.op"() : () -> (vector, vector<3xindex>, index) +%vector0, %vector1, %i0= "test.op"() : () -> (vector, vector<3xindex>, index) // CHECK: %0, %1, %2 = "test.op"() : () -> (vector, vector<3xindex>, index) %0 = "vector.insertelement"(%i0, %vector0) : (index, vector) -> vector @@ -16,4 +15,22 @@ builtin.module{ %3 = "vector.extractelement"(%vector0) : (vector) -> index // CHECK-NEXT: %6 = "vector.extractelement"(%0) : (vector) -> index -} + + +// ----- +// Vector transfer ops 0d + +%tensor, %vector, %memref, %f= "test.op"() : () -> (tensor, vector, memref, f32) +// CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, vector, memref, f32) + +%1 = "vector.transfer_read"(%tensor, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (tensor, f32) -> vector +// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (tensor, f32) -> vector + +%2 = "vector.transfer_write"(%vector, %tensor) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, tensor) -> tensor +// CHECK-NEXT: %5 = "vector.transfer_write"(%1, %0) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, tensor) -> tensor + +%3 = "vector.transfer_read"(%memref, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (memref, f32) -> vector +// CHECK-NEXT: %6 = "vector.transfer_read"(%2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (memref, f32) -> vector + +"vector.transfer_write"(%vector, %memref) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, memref) -> () +// CHECK-NEXT: "vector.transfer_write"(%1, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, memref) -> () diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index b2ced913ef..ffff52bd5a 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -27,10 +27,12 @@ from xdsl.irdl import ( AttrSizedOperandSegments, IRDLOperation, + ParsePropInAttrDict, irdl_op_definition, operand_def, opt_operand_def, opt_prop_def, + opt_result_def, prop_def, result_def, traits_def, @@ -416,7 +418,7 @@ def verify_permutation_map( continue if not isa(expr, AffineDimExpr): raise VerifyException( - f'"{op.name}" requires a projected permutation_map (at most one "dim or the zero constant can appear in each result)' + f'"{op.name}" requires a projected permutation_map (at most one dim or the zero constant can appear in each result)' ) if seen[expr.position]: raise VerifyException( @@ -584,7 +586,9 @@ class TransferReadOp(IRDLOperation, VectorTransferOp): result = result_def(VectorType) - irdl_options = [AttrSizedOperandSegments(as_property=True)] + irdl_options = [AttrSizedOperandSegments(as_property=True), ParsePropInAttrDict()] + + # assembly_format = "$source `[` $indices `]` `,` $padding ( `,` $mask^ )? attr-dict `:` type($source) `,` type($result)" def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) @@ -662,7 +666,9 @@ class TransferWriteOp(IRDLOperation, VectorTransferOp): in_bounds = opt_prop_def(ArrayAttr[BoolAttr]) permutation_map = prop_def(AffineMapAttr) - irdl_options = [AttrSizedOperandSegments(as_property=True)] + result = opt_result_def(TensorType[Attribute]) + + irdl_options = [AttrSizedOperandSegments(as_property=True), ParsePropInAttrDict()] def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) From 47c55e92584c73b55c2d9ae8ca3b4f22d4861a34 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:40:13 +0000 Subject: [PATCH 12/16] Fixed bug in TransferWriteOp.__init__ and transfered more lit tests of transfer ops from MLIR --- .../with-mlir/dialects/vector/ops.mlir | 24 ++++++++++++++++--- xdsl/dialects/vector.py | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir index eb5c5c6a8b..70c738d11d 100644 --- a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir +++ b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir @@ -23,14 +23,32 @@ %tensor, %vector, %memref, %f= "test.op"() : () -> (tensor, vector, memref, f32) // CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, vector, memref, f32) -%1 = "vector.transfer_read"(%tensor, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (tensor, f32) -> vector +%0 = "vector.transfer_read"(%tensor, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (tensor, f32) -> vector // CHECK-NEXT: %4 = "vector.transfer_read"(%0, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (tensor, f32) -> vector -%2 = "vector.transfer_write"(%vector, %tensor) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, tensor) -> tensor +%1 = "vector.transfer_write"(%vector, %tensor) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, tensor) -> tensor // CHECK-NEXT: %5 = "vector.transfer_write"(%1, %0) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, tensor) -> tensor -%3 = "vector.transfer_read"(%memref, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (memref, f32) -> vector +%2 = "vector.transfer_read"(%memref, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (memref, f32) -> vector // CHECK-NEXT: %6 = "vector.transfer_read"(%2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (memref, f32) -> vector "vector.transfer_write"(%vector, %memref) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, memref) -> () // CHECK-NEXT: "vector.transfer_write"(%1, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, memref) -> () + +// ----- +// Vector transfer ops 0d from higher d + +%tensor, %memref, %index, %f= "test.op"() : () -> (tensor, memref, index, f32) +// CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, memref, index, f32) + +%0 = "vector.transfer_read"(%tensor, %index, %f) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector +// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector + +%1 = "vector.transfer_write"(%0, %tensor, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor +// CHECK-NEXT: %5 = "vector.transfer_write"(%4, %0, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor + +%2 = "vector.transfer_read"(%memref, %index, %index, %f) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector +// CHECK-NEXT: %6 = "vector.transfer_read"(%1, %2, %2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector + +"vector.transfer_write"(%2, %memref, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%6, %1, %2, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index ffff52bd5a..0bc4b8bf93 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -715,10 +715,12 @@ def __init__( mask: Sequence[SSAValue | Operation] | None = None, permutation_map: AffineMapAttr | None = None, in_bounds: ArrayAttr[BoolAttr] | None = None, + result_type: TensorType[Attribute] | None = None ): super().__init__( operands=[vector, source, indices, mask], properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, + result_types=[result_type] ) # override From f2c6f1532627e9da9d9ad3c5cae3a2838fc29064 Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:47:33 +0000 Subject: [PATCH 13/16] Fixed formatting --- xdsl/dialects/vector.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 0bc4b8bf93..d786413789 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -715,12 +715,12 @@ def __init__( mask: Sequence[SSAValue | Operation] | None = None, permutation_map: AffineMapAttr | None = None, in_bounds: ArrayAttr[BoolAttr] | None = None, - result_type: TensorType[Attribute] | None = None + result_type: TensorType[Attribute] | None = None, ): super().__init__( operands=[vector, source, indices, mask], properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, - result_types=[result_type] + result_types=[result_type], ) # override From 5b6c700b798b44aa406450e384735647c611a93c Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:21:39 +0000 Subject: [PATCH 14/16] Fixed a few issues with vector.transfer_read and vector.transfer_write Transferred more filecheck tests for transfer ops from MLIR --- tests/dialects/test_vector.py | 10 ++ .../with-mlir/dialects/vector/ops.mlir | 154 ++++++++++++++++-- xdsl/dialects/vector.py | 55 +++---- 3 files changed, 171 insertions(+), 48 deletions(-) diff --git a/tests/dialects/test_vector.py b/tests/dialects/test_vector.py index 64d227ce4d..097cee4da2 100644 --- a/tests/dialects/test_vector.py +++ b/tests/dialects/test_vector.py @@ -2,8 +2,10 @@ from xdsl.dialects.builtin import ( AffineMapAttr, + ArrayAttr, IndexType, IntAttr, + IntegerAttr, MemRefType, VectorType, i1, @@ -665,6 +667,9 @@ def test_vector_transfer_write_construction(): memref_type = MemRefType(IndexType(), [3, 3]) # (x, y) -> x permutation_map = AffineMapAttr(AffineMap(2, 0, (x,))) + in_bounds = ArrayAttr( + [IntegerAttr.from_bool(False) for _ in range(vector_type.get_num_dims())] + ) vector = TestSSAValue(vector_type) source = TestSSAValue(memref_type) @@ -674,6 +679,7 @@ def test_vector_transfer_write_construction(): vector, source, [index, index], + in_bounds, permutation_map=permutation_map, ) @@ -691,6 +697,9 @@ def test_vector_transfer_read_construction(): vector_type = VectorType(IndexType(), [3]) memref_type = MemRefType(IndexType(), [3, 3]) permutation_map = AffineMapAttr(AffineMap(2, 0, (x,))) + in_bounds = ArrayAttr( + [IntegerAttr.from_bool(False) for _ in range(vector_type.get_num_dims())] + ) source = TestSSAValue(memref_type) index = TestSSAValue(IndexType()) @@ -701,6 +710,7 @@ def test_vector_transfer_read_construction(): [index, index], padding, vector_type, + in_bounds, permutation_map=permutation_map, ) diff --git a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir index 70c738d11d..04365eb993 100644 --- a/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir +++ b/tests/filecheck/mlir-conversion/with-mlir/dialects/vector/ops.mlir @@ -1,6 +1,5 @@ // RUN: xdsl-opt --split-input-file --print-op-generic %s | mlir-opt --mlir-print-op-generic | xdsl-opt --print-op-generic | filecheck %s - %vector0, %vector1, %i0= "test.op"() : () -> (vector, vector<3xindex>, index) // CHECK: %0, %1, %2 = "test.op"() : () -> (vector, vector<3xindex>, index) @@ -19,36 +18,157 @@ // ----- // Vector transfer ops 0d +// See func vector_transfer_ops_0d in mlir/test/Dialect/Vector/ops.mlir %tensor, %vector, %memref, %f= "test.op"() : () -> (tensor, vector, memref, f32) // CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, vector, memref, f32) -%0 = "vector.transfer_read"(%tensor, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (tensor, f32) -> vector -// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (tensor, f32) -> vector +%0 = "vector.transfer_read"(%tensor, %f) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (tensor, f32) -> vector +// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %3) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (tensor, f32) -> vector -%1 = "vector.transfer_write"(%vector, %tensor) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, tensor) -> tensor -// CHECK-NEXT: %5 = "vector.transfer_write"(%1, %0) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, tensor) -> tensor +%1 = "vector.transfer_write"(%vector, %tensor) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, tensor) -> tensor +// CHECK-NEXT: %5 = "vector.transfer_write"(%1, %0) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, tensor) -> tensor -%2 = "vector.transfer_read"(%memref, %f) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (memref, f32) -> vector -// CHECK-NEXT: %6 = "vector.transfer_read"(%2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (memref, f32) -> vector +%2 = "vector.transfer_read"(%memref, %f) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (memref, f32) -> vector +// CHECK-NEXT: %6 = "vector.transfer_read"(%2, %3) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (memref, f32) -> vector -"vector.transfer_write"(%vector, %memref) <{operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, memref) -> () -// CHECK-NEXT: "vector.transfer_write"(%1, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, memref) -> () +"vector.transfer_write"(%vector, %memref) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<() -> ()>}> : (vector, memref) -> () +// CHECK-NEXT: "vector.transfer_write"(%1, %2) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<() -> ()>}> : (vector, memref) -> () // ----- // Vector transfer ops 0d from higher d +// func vector_transfer_ops_0d_from_higher_d in mlir/test/Dialect/Vector/ops.mlir %tensor, %memref, %index, %f= "test.op"() : () -> (tensor, memref, index, f32) // CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, memref, index, f32) -%0 = "vector.transfer_read"(%tensor, %index, %f) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector -// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector +%0 = "vector.transfer_read"(%tensor, %index, %f) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector +// CHECK-NEXT: %4 = "vector.transfer_read"(%0, %2, %3) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (tensor, index, f32) -> vector + +%1 = "vector.transfer_write"(%0, %tensor, %index) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor +// CHECK-NEXT: %5 = "vector.transfer_write"(%4, %0, %2) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor + +%2 = "vector.transfer_read"(%memref, %index, %index, %f) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector +// CHECK-NEXT: %6 = "vector.transfer_read"(%1, %2, %2, %3) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector + +"vector.transfer_write"(%2, %memref, %index, %index) <{in_bounds = [], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%6, %1, %2, %2) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () + +// ----- +// Vector transfer ops +// func vector_transfer_ops in mlir/test/Dialect/Vector/ops.mlir + +%0, %1, %2, %3, %4 = "test.op"() : () -> (memref, memref>, memref>, memref>, memref) +// CHECK: %0, %1, %2, %3, %4 = "test.op"() : () -> (memref, memref>, memref>, memref>, memref) + +%5, %6, %7, %8, %9, %10 = "test.op"() : () -> (index, f32, f32, i32, index, i1) +// CHECK-NEXT: %5, %6, %7, %8, %9, %10 = "test.op"() : () -> (index, f32, f32, i32, index, i1) + +%11, %12, %13, %14, %15 = "test.op"() : () -> (vector<4x3xf32>, vector<4x3xi32>, vector<4x3xindex>, vector<5xi1>, vector<4x5xi1>) +// CHECK-NEXT: %11, %12, %13, %14, %15 = "test.op"() : () -> (vector<4x3xf32>, vector<4x3xi32>, vector<4x3xindex>, vector<5xi1>, vector<4x5xi1>) + +%16 = "vector.transfer_read"(%0, %5, %5, %7) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %16 = "vector.transfer_read"(%0, %5, %5, %7) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> + +%17 = "vector.transfer_read"(%0, %5, %5, %7) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (memref, index, index, f32) -> vector<3x7xf32> +// CHECK-NEXT: %17 = "vector.transfer_read"(%0, %5, %5, %7) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (memref, index, index, f32) -> vector<3x7xf32> + +%18 = "vector.transfer_read"(%0, %5, %5, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %18 = "vector.transfer_read"(%0, %5, %5, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> + +%19 = "vector.transfer_read"(%0, %5, %5, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (memref, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %19 = "vector.transfer_read"(%0, %5, %5, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (memref, index, index, f32) -> vector<128xf32> + +%20 = "vector.transfer_read"(%1, %5, %5, %11) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (memref>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> +// CHECK-NEXT: %20 = "vector.transfer_read"(%1, %5, %5, %11) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (memref>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> + +%21 = "vector.transfer_read"(%1, %5, %5, %11) <{"in_bounds" = [false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (memref>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> +// CHECK-NEXT: %21 = "vector.transfer_read"(%1, %5, %5, %11) <{"in_bounds" = [false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (memref>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> + +%22 = "vector.transfer_read"(%2, %5, %5, %12) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref>, index, index, vector<4x3xi32>) -> vector<5x24xi8> +// CHECK-NEXT: %22 = "vector.transfer_read"(%2, %5, %5, %12) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref>, index, index, vector<4x3xi32>) -> vector<5x24xi8> + +%23 = "vector.transfer_read"(%3, %5, %5, %13) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref>, index, index, vector<4x3xindex>) -> vector<5x48xi8> +// CHECK-NEXT: %23 = "vector.transfer_read"(%3, %5, %5, %13) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref>, index, index, vector<4x3xindex>) -> vector<5x48xi8> + +%24 = "vector.transfer_read"(%0, %5, %5, %7, %14) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (memref, index, index, f32, vector<5xi1>) -> vector<5xf32> +// CHECK-NEXT: %24 = "vector.transfer_read"(%0, %5, %5, %7, %14) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (memref, index, index, f32, vector<5xi1>) -> vector<5xf32> + +%25 = "vector.transfer_read"(%4, %5, %5, %5, %7, %15) <{"in_bounds" = [false, false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1, d2) -> (d1, d0, 0)>}> : (memref, index, index, index, f32, vector<4x5xi1>) -> vector<5x4x8xf32> +// CHECK-NEXT: %25 = "vector.transfer_read"(%4, %5, %5, %5, %7, %15) <{"in_bounds" = [false, false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1, d2) -> (d1, d0, 0)>}> : (memref, index, index, index, f32, vector<4x5xi1>) -> vector<5x4x8xf32> + +"vector.transfer_write"(%16, %0, %5, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (vector<128xf32>, memref, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%16, %0, %5, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (vector<128xf32>, memref, index, index) -> () + +"vector.transfer_write"(%17, %0, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (vector<3x7xf32>, memref, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%17, %0, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (vector<3x7xf32>, memref, index, index) -> () + +"vector.transfer_write"(%20, %1, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, memref>, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%20, %1, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, memref>, index, index) -> () + +"vector.transfer_write"(%21, %1, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, memref>, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%21, %1, %5, %5) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, memref>, index, index) -> () + +"vector.transfer_write"(%22, %2, %5, %5) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x24xi8>, memref>, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%22, %2, %5, %5) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x24xi8>, memref>, index, index) -> () + +"vector.transfer_write"(%23, %3, %5, %5) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x48xi8>, memref>, index, index) -> () +// CHECK-NEXT: "vector.transfer_write"(%23, %3, %5, %5) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x48xi8>, memref>, index, index) -> () + +"vector.transfer_write"(%24, %0, %5, %5, %14) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (vector<5xf32>, memref, index, index, vector<5xi1>) -> () +// CHECK-NEXT: "vector.transfer_write"(%24, %0, %5, %5, %14) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (vector<5xf32>, memref, index, index, vector<5xi1>) -> () + +// ----- +// Vector transfer ops tensor +// func vector_transfer_ops_tensor in mlir/test/Dialect/Vector/ops.mlir + +%0, %1, %2, %3 = "test.op"() : () -> (tensor, tensor>, tensor>, tensor>) +// CHECK: %0, %1, %2, %3 = "test.op"() : () -> (tensor, tensor>, tensor>, tensor>) + +%4, %5, %6, %7, %8 = "test.op"() : () -> (index, f32, f32, i32, index) +// CHECK-NEXT: %4, %5, %6, %7, %8 = "test.op"() : () -> (index, f32, f32, i32, index) + +%9, %10, %11 = "test.op"() : () -> (vector<4x3xf32>, vector<4x3xi32>, vector<4x3xindex>) +// CHECK-NEXT: %9, %10, %11 = "test.op"() : () -> (vector<4x3xf32>, vector<4x3xi32>, vector<4x3xindex>) + +%12 = "vector.transfer_read"(%0, %4, %4, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (tensor, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %12 = "vector.transfer_read"(%0, %4, %4, %6) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (tensor, index, index, f32) -> vector<128xf32> + +%13 = "vector.transfer_read"(%0, %4, %4, %6) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (tensor, index, index, f32) -> vector<3x7xf32> +// CHECK-NEXT: %13 = "vector.transfer_read"(%0, %4, %4, %6) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (tensor, index, index, f32) -> vector<3x7xf32> + +%14 = "vector.transfer_read"(%0, %4, %4, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (tensor, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %14 = "vector.transfer_read"(%0, %4, %4, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (tensor, index, index, f32) -> vector<128xf32> + +%15 = "vector.transfer_read"(%0, %4, %4, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (tensor, index, index, f32) -> vector<128xf32> +// CHECK-NEXT: %15 = "vector.transfer_read"(%0, %4, %4, %5) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1)>}> : (tensor, index, index, f32) -> vector<128xf32> + +%16 = "vector.transfer_read"(%1, %4, %4, %9) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (tensor>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> +// CHECK-NEXT: %16 = "vector.transfer_read"(%1, %4, %4, %9) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (tensor>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> + +%17 = "vector.transfer_read"(%1, %4, %4, %9) <{"in_bounds" = [false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (tensor>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> +// CHECK-NEXT: %17 = "vector.transfer_read"(%1, %4, %4, %9) <{"in_bounds" = [false, true], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (tensor>, index, index, vector<4x3xf32>) -> vector<1x1x4x3xf32> + +%18 = "vector.transfer_read"(%2, %4, %4, %10) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (tensor>, index, index, vector<4x3xi32>) -> vector<5x24xi8> +// CHECK-NEXT: %18 = "vector.transfer_read"(%2, %4, %4, %10) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (tensor>, index, index, vector<4x3xi32>) -> vector<5x24xi8> + +%19 = "vector.transfer_read"(%3, %4, %4, %11) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (tensor>, index, index, vector<4x3xindex>) -> vector<5x48xi8> +// CHECK-NEXT: %19 = "vector.transfer_read"(%3, %4, %4, %11) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (tensor>, index, index, vector<4x3xindex>) -> vector<5x48xi8> + +%20 = "vector.transfer_write"(%12, %0, %4, %4) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (vector<128xf32>, tensor, index, index) -> tensor +// CHECK-NEXT: %20 = "vector.transfer_write"(%12, %0, %4, %4) <{"in_bounds" = [false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0)>}> : (vector<128xf32>, tensor, index, index) -> tensor + +%21 = "vector.transfer_write"(%13, %0, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (vector<3x7xf32>, tensor, index, index) -> tensor +// CHECK-NEXT: %21 = "vector.transfer_write"(%13, %0, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d1, d0)>}> : (vector<3x7xf32>, tensor, index, index) -> tensor + +%22 = "vector.transfer_write"(%16, %1, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, tensor>, index, index) -> tensor> +// CHECK-NEXT: %22 = "vector.transfer_write"(%16, %1, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, tensor>, index, index) -> tensor> -%1 = "vector.transfer_write"(%0, %tensor, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor -// CHECK-NEXT: %5 = "vector.transfer_write"(%4, %0, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0) -> ()>}> : (vector, tensor, index) -> tensor +%23 = "vector.transfer_write"(%17, %1, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, tensor>, index, index) -> tensor> +// CHECK-NEXT: %23 = "vector.transfer_write"(%17, %1, %4, %4) <{"in_bounds" = [false, false], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<1x1x4x3xf32>, tensor>, index, index) -> tensor> -%2 = "vector.transfer_read"(%memref, %index, %index, %f) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector -// CHECK-NEXT: %6 = "vector.transfer_read"(%1, %2, %2, %3) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (memref, index, index, f32) -> vector +%24 = "vector.transfer_write"(%18, %2, %4, %4) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x24xi8>, tensor>, index, index) -> tensor> +// CHECK-NEXT: %24 = "vector.transfer_write"(%18, %2, %4, %4) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x24xi8>, tensor>, index, index) -> tensor> -"vector.transfer_write"(%2, %memref, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () -// CHECK-NEXT: "vector.transfer_write"(%6, %1, %2, %2) <{"operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector, memref, index, index) -> () +%25 = "vector.transfer_write"(%19, %3, %4, %4) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x48xi8>, tensor>, index, index) -> tensor> +// CHECK-NEXT: %25 = "vector.transfer_write"(%19, %3, %4, %4) <{"in_bounds" = [], "operandSegmentSizes" = array, "permutation_map" = affine_map<(d0, d1) -> ()>}> : (vector<5x48xi8>, tensor>, index, index) -> tensor> diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index d786413789..123ecaa1a9 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -31,7 +31,6 @@ irdl_op_definition, operand_def, opt_operand_def, - opt_prop_def, opt_result_def, prop_def, result_def, @@ -432,17 +431,15 @@ def verify_transfer_op( shaped_type: MemRefType[Attribute] | TensorType[Attribute], vector_type: VectorType[Attribute], mask_type: VectorType[I1] | None, + # WJOG9GVF: TODO fix: remove None type from inferred_mask_type once 7S4F0FZA has been fixed inferred_mask_type: VectorType[I1] | None, permutation_map: AffineMap, - in_bounds: ArrayAttr[BoolAttr] | None, + in_bounds: ArrayAttr[BoolAttr], ): """ - TODO test + This mirrors VectorOps.cpp -> verifyTransferOp from MLIR """ - # WJOG9GVF - # TODO fix: remove None type from inferred_mask_type once 7S4F0FZA has been fixed - # This mirrors VectorOps.cpp -> verifyTransferOp from MLIR element_type = shaped_type.element_type vector_element_type = vector_type.element_type @@ -470,11 +467,11 @@ def verify_transfer_op( f'"{op.name}" requires the bitwidth of the minor 1-D vector to be an integral multiple of the bitwidth of the source element type' ) - # Check that permutation map results match rank of vector type. - if len(permutation_map.results) != vector_type.get_num_dims(): - raise VerifyException( - f'"{op.name}" requires a permutation_map with result dims of the same rank as the vector type' - ) + # Check that permutation map results match rank of vector type. + if len(permutation_map.results) != vector_type.get_num_dims(): + raise VerifyException( + f'"{op.name}" requires a permutation_map with result dims of the same rank as the vector type' + ) if permutation_map.num_symbols != 0: raise VerifyException(f'"{op.name}" requires permutation_map without symbols') @@ -484,31 +481,27 @@ def verify_transfer_op( f'"{op.name}" requires a permutation_map with input dims of the same rank as the source type' ) - # WJOG9GVF - # TODO fix: uncomment this when 7S4F0FZA has been fixed - - # See 7S4F0FZA for more information + # WJOG9GVF: TODO fix: uncomment this when 7S4F0FZA has been fixed # if mask_type: # if mask_type != inferred_mask_type: # raise VerifyException( # f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' # ) - if in_bounds: - if len(in_bounds) != len(permutation_map.results): + if len(in_bounds) != len(permutation_map.results): + raise VerifyException( + f'"{op.name}" expects the optional in_bounds attr of same rank as permutation_map results: {str(permutation_map)} vs in_bounds of of size {len(in_bounds)}' + ) + + for i in range(len(permutation_map.results)): + if ( + isa(permutation_map.results[i], AffineConstantExpr) + and not in_bounds.data[i].value.data + ): raise VerifyException( - f'"{op.name}" expects the optional in_bounds attr of same rank as permutation_map results: {str(permutation_map)} vs in_bounds of of size {len(in_bounds)}' + f'"{op.name}" requires broadcast dimensions to be in-bounds' ) - for i in range(len(permutation_map.results)): - if ( - isa(permutation_map.results[i], AffineConstantExpr) - and not in_bounds.data[i].value.data - ): - raise VerifyException( - f'"{op.name}" requires broadcast dimensions to be in-bounds' - ) - def infer_transfer_op_mask_type( vector_type: VectorType[Attribute], @@ -582,7 +575,7 @@ class TransferReadOp(IRDLOperation, VectorTransferOp): mask = opt_operand_def(VectorType[I1]) permutation_map = prop_def(AffineMapAttr) - in_bounds = opt_prop_def(ArrayAttr[BoolAttr]) + in_bounds = prop_def(ArrayAttr[BoolAttr]) result = result_def(VectorType) @@ -639,9 +632,9 @@ def __init__( indices: Sequence[SSAValue | Operation], padding: SSAValue | Operation, result_type: Attribute, + in_bounds: ArrayAttr[BoolAttr], mask: Sequence[SSAValue | Operation] | None = None, permutation_map: AffineMapAttr | None = None, - in_bounds: ArrayAttr[BoolAttr] | None = None, ): super().__init__( operands=[source, indices, padding, mask], @@ -663,7 +656,7 @@ class TransferWriteOp(IRDLOperation, VectorTransferOp): indices = var_operand_def(IndexType) mask = opt_operand_def(VectorType[I1]) - in_bounds = opt_prop_def(ArrayAttr[BoolAttr]) + in_bounds = prop_def(ArrayAttr[BoolAttr]) permutation_map = prop_def(AffineMapAttr) result = opt_result_def(TensorType[Attribute]) @@ -712,9 +705,9 @@ def __init__( vector: SSAValue | Operation, source: SSAValue | Operation, indices: Sequence[SSAValue | Operation], + in_bounds: ArrayAttr[BoolAttr], mask: Sequence[SSAValue | Operation] | None = None, permutation_map: AffineMapAttr | None = None, - in_bounds: ArrayAttr[BoolAttr] | None = None, result_type: TensorType[Attribute] | None = None, ): super().__init__( From a7022507a3f50351631a5e2c9fcd25022bb00e2d Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Sat, 28 Dec 2024 17:43:46 +0000 Subject: [PATCH 15/16] Fixed vector.tranfer_* filechecks Added the (now mandatory) in_bounds property --- .../vector/vector_transfer_read_verify.mlir | 18 +++++++++--------- .../vector/vector_transfer_write_verify.mlir | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir b/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir index f46195c84a..2a91859943 100644 --- a/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir +++ b/tests/filecheck/dialects/vector/vector_transfer_read_verify.mlir @@ -1,43 +1,43 @@ // RUN: xdsl-opt --split-input-file --verify-diagnostics %s | filecheck %s %source, %index, %padding = "test.op"() : () -> (vector<4x3xf32>, index, f32) -"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, index, index, f32) -> vector<1x1x2x3xf32> -// CHECK: Expected tensor or memref type +"vector.transfer_read"(%source, %index, %index, %padding) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, index, index, f32) -> vector<1x1x2x3xf32> +// CHECK: Expected tensor or memref type, got vector<4x3xf32> // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (memref, index, index, index, f32) -> vector<128xf32> -// CHECK: Expected an index for each memref/tensor dimension. +"vector.transfer_read"(%source, %index, %index, %index, %padding) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (memref, index, index, index, f32) -> vector<128xf32> +// CHECK: Expected an index for each memref/tensor dimension // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> +"vector.transfer_read"(%source, %index, %index, %padding) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (memref, index, index, f32) -> vector<128xf32> // CHECK: requires a permutation_map with input dims of the same rank as the source type // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (memref, index, index, f32) -> vector<128xf32> +"vector.transfer_read"(%source, %index, %index, %padding) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (memref, index, index, f32) -> vector<128xf32> // CHECK: requires a permutation_map with result dims of the same rank as the vector type // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (memref, index, index, f32) -> vector<128xf32> +"vector.transfer_read"(%source, %index, %index, %padding) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (memref, index, index, f32) -> vector<128xf32> // CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (memref, index, index, f32) -> vector<128xf32> +"vector.transfer_read"(%source, %index, %index, %padding) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (memref, index, index, f32) -> vector<128xf32> // CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) // ----- %source, %index, %padding = "test.op"() : () -> (memref, index, f32) -"vector.transfer_read"(%source, %index, %index, %index, %padding) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (memref, index, index, index, f32) -> vector<3x7xf32> +"vector.transfer_read"(%source, %index, %index, %index, %padding) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (memref, index, index, index, f32) -> vector<3x7xf32> // CHECK: requires a permutation_map that is a permutation (found one dim used more than once) // TODO transfer other tests from mlir/test/Dialect/Vector/invalid.mlir once verification for vector element types is implemented diff --git a/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir b/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir index aebc36acb2..11465b0ad8 100644 --- a/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir +++ b/tests/filecheck/dialects/vector/vector_transfer_write_verify.mlir @@ -1,49 +1,49 @@ // RUN: xdsl-opt --split-input-file --verify-diagnostics %s | filecheck %s %source, %index = "test.op"() : () -> (vector<4x3xf32>, index) -"vector.transfer_write"(%source, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, vector<4x3xf32>, index, index) -> () +"vector.transfer_write"(%source, %source, %index, %index) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<4x3xf32>, vector<4x3xf32>, index, index) -> () // CHECK: Expected tensor or memref type // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<128xf32>, memref, index, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index, %index) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<() -> (0)>}> : (vector<128xf32>, memref, index, index, index) -> () // CHECK: Expected an index for each memref/tensor dimension // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (vector<128xf32>, memref, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (d0)>}> : (vector<128xf32>, memref, index, index) -> () // CHECK: requires a permutation_map with input dims of the same rank as the source type // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<128xf32>, memref, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0, d1)>}> : (vector<128xf32>, memref, index, index) -> () // CHECK: requires a permutation_map with result dims of the same rank as the vector type // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (vector<128xf32>, memref, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + d1)>}> : (vector<128xf32>, memref, index, index) -> () // CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<128xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (vector<128xf32>, memref, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1) -> (d0 + 1)>}> : (vector<128xf32>, memref, index, index) -> () // CHECK: requires a projected permutation_map (at most one dim or the zero constant can appear in each result) // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<3x7xf32>, index) -"vector.transfer_write"(%vector, %source, %index, %index, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (vector<3x7xf32>, memref, index, index, index) -> () +"vector.transfer_write"(%vector, %source, %index, %index, %index) <{in_bounds=[true, true], operandSegmentSizes = array, permutation_map = affine_map<(d0, d1, d2) -> (d0, d0)>}> : (vector<3x7xf32>, memref, index, index, index) -> () // CHECK: requires a permutation_map that is a permutation (found one dim used more than once) // ----- %source, %vector, %index = "test.op"() : () -> (memref, vector<7xf32>, index) -"vector.transfer_write"(%vector, %source, %index) <{operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (0)>}> : (vector<7xf32>, memref, index) -> () +"vector.transfer_write"(%vector, %source, %index) <{in_bounds=[true], operandSegmentSizes = array, permutation_map = affine_map<(d0) -> (0)>}> : (vector<7xf32>, memref, index) -> () // CHECK: requires a permutation_map that is a permutation (found one dim used more than once) // TODO transfer other tests from mlir/test/Dialect/Vector/invalid.mlir once verification for vector element types is implemented From b3319626fb5ce29052efdba7b4163e6337518f6f Mon Sep 17 00:00:00 2001 From: watermelonwolverine <29666253+watermelonwolverine@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:41:42 +0000 Subject: [PATCH 16/16] Perfomed some clean-up and undid all changes which aren't ready yet and depend on issue #3654 to be fixed --- xdsl/dialects/vector.py | 79 ++---------------------------------- xdsl/ir/affine/affine_map.py | 2 - 2 files changed, 3 insertions(+), 78 deletions(-) diff --git a/xdsl/dialects/vector.py b/xdsl/dialects/vector.py index 123ecaa1a9..b9fb0f1b8c 100644 --- a/xdsl/dialects/vector.py +++ b/xdsl/dialects/vector.py @@ -402,10 +402,9 @@ def verify_permutation_map( permutation_map: AffineMap, ): """ - TODO test + This mirrors VectorOps.cpp -> verifyPermutationMap """ - # This mirrors VectorOps.cpp -> verifyPermutationMap seen: list[bool] = [False for _ in range(permutation_map.num_dims)] for expr in permutation_map.results: @@ -430,9 +429,6 @@ def verify_transfer_op( op: TransferReadOp | TransferWriteOp, shaped_type: MemRefType[Attribute] | TensorType[Attribute], vector_type: VectorType[Attribute], - mask_type: VectorType[I1] | None, - # WJOG9GVF: TODO fix: remove None type from inferred_mask_type once 7S4F0FZA has been fixed - inferred_mask_type: VectorType[I1] | None, permutation_map: AffineMap, in_bounds: ArrayAttr[BoolAttr], ): @@ -481,13 +477,6 @@ def verify_transfer_op( f'"{op.name}" requires a permutation_map with input dims of the same rank as the source type' ) - # WJOG9GVF: TODO fix: uncomment this when 7S4F0FZA has been fixed - # if mask_type: - # if mask_type != inferred_mask_type: - # raise VerifyException( - # f'"{op.name}" inferred mask type ({inferred_mask_type}) and mask operand type ({mask_type}) don\'t match' - # ) - if len(in_bounds) != len(permutation_map.results): raise VerifyException( f'"{op.name}" expects the optional in_bounds attr of same rank as permutation_map results: {str(permutation_map)} vs in_bounds of of size {len(in_bounds)}' @@ -503,44 +492,8 @@ def verify_transfer_op( ) -def infer_transfer_op_mask_type( - vector_type: VectorType[Attribute], - affine_map: AffineMap, -) -> VectorType[I1] | None: - """ - TODO test - """ - - # 7S4F0FZA - # TODO uncomment and test this once VectorType has been fixed, see issue #3654 - # When you do this also fix all WJOG9GVF - - # inverse_permutation_map = affine_map.compress_dims( - # affine_map.unused_dims_bit_vector() - # ).inverse_permutation() - - # assert inverse_permutation_map - - # mask_shape = inverse_permutation_map.compose_with_values(vector_type.get_shape()) - - # scalable_dims = inverse_permutation_map.eval( - # [1 if dim_scalable else 0 for dim_scalable in vector_type.get_scalable_dims()], - # [], - # ) - - # return VectorType( - # i1, - # mask_shape, - # [dim_scalable == 1 for dim_scalable in scalable_dims], - # ) - - return None - - class VectorTransferOp(ABC): """ - TODO document - TODO test Mirrors VectorTransferOpInterface from VectorInterfaces.h.inc """ @@ -581,31 +534,17 @@ class TransferReadOp(IRDLOperation, VectorTransferOp): irdl_options = [AttrSizedOperandSegments(as_property=True), ParsePropInAttrDict()] - # assembly_format = "$source `[` $indices `]` `,` $padding ( `,` $mask^ )? attr-dict `:` type($source) `,` type($result)" - def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.result.type, VectorType[Attribute]) - if self.mask: - assert isa(self.mask.type, VectorType[I1]) - mask_type = self.mask.type - else: - mask_type = None if len(self.indices) != self.source.type.get_num_dims(): raise VerifyException("Expected an index for each memref/tensor dimension.") - inferred_mask_type = infer_transfer_op_mask_type( - self.result.type, - self.permutation_map.data, - ) - verify_transfer_op( self, self.source.type, self.result.type, - mask_type, - inferred_mask_type, self.permutation_map.data, self.in_bounds, ) @@ -642,7 +581,7 @@ def __init__( properties={"permutation_map": permutation_map, "in_bounds": in_bounds}, ) - # override + # override VectorTransferOp.get_permutation_map def get_permutation_map(self): return self.permutation_map.data @@ -666,11 +605,6 @@ class TransferWriteOp(IRDLOperation, VectorTransferOp): def verify_(self): assert isa(self.source.type, MemRefType[Attribute] | TensorType[Attribute]) assert isa(self.vector.type, VectorType[Attribute]) - if self.mask: - assert isa(self.mask.type, VectorType[I1]) - mask_type = self.mask.type - else: - mask_type = None if len(self.indices) != self.source.type.get_num_dims(): raise VerifyException("Expected an index for each memref/tensor dimension.") @@ -680,17 +614,10 @@ def verify_(self): f'"{self.name}" should not have broadcast dimensions.' ) - inferred_mask_type = infer_transfer_op_mask_type( - self.vector.type, - self.permutation_map.data, - ) - verify_transfer_op( self, self.source.type, self.vector.type, - mask_type, - inferred_mask_type, self.permutation_map.data, self.in_bounds, ) @@ -716,7 +643,7 @@ def __init__( result_types=[result_type], ) - # override + # override VectorTransferOp.get_permutation_map def get_permutation_map(self): return self.permutation_map.data diff --git a/xdsl/ir/affine/affine_map.py b/xdsl/ir/affine/affine_map.py index 9f4e4c63c8..2bb18a9f29 100644 --- a/xdsl/ir/affine/affine_map.py +++ b/xdsl/ir/affine/affine_map.py @@ -172,8 +172,6 @@ def compose(self, other: AffineMap) -> AffineMap: def compose_with_values(self, values: Sequence[int]) -> tuple[int, ...]: """ - TODO document - TODO test Same as SmallVector AffineMap::compose(ArrayRef values) const from AffineMap.cpp """ assert self.num_symbols == 0